diff options
172 files changed, 31461 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c7c5991 --- /dev/null +++ b/CMakeLists.txt | |||
@@ -0,0 +1,383 @@ | |||
1 | # Copyright (c) 2018 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 | # detect AppleClang; needs to come before project() | ||
6 | cmake_policy(SET CMP0025 NEW) | ||
7 | |||
8 | project(libfido2 C) | ||
9 | cmake_minimum_required(VERSION 3.0) | ||
10 | |||
11 | include(CheckCCompilerFlag) | ||
12 | include(CheckFunctionExists) | ||
13 | include(CheckIncludeFiles) | ||
14 | include(CheckTypeSize) | ||
15 | include(GNUInstallDirs) | ||
16 | |||
17 | set(CMAKE_COLOR_MAKEFILE off) | ||
18 | set(CMAKE_VERBOSE_MAKEFILE on) | ||
19 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) | ||
20 | |||
21 | set(FIDO_MAJOR "1") | ||
22 | set(FIDO_MINOR "3") | ||
23 | set(FIDO_PATCH "0") | ||
24 | set(FIDO_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}.${FIDO_PATCH}) | ||
25 | |||
26 | add_definitions(-D_FIDO_MAJOR=${FIDO_MAJOR}) | ||
27 | add_definitions(-D_FIDO_MINOR=${FIDO_MINOR}) | ||
28 | add_definitions(-D_FIDO_PATCH=${FIDO_PATCH}) | ||
29 | |||
30 | if(WIN32) | ||
31 | add_definitions(-DWIN32_LEAN_AND_MEAN) | ||
32 | endif() | ||
33 | |||
34 | if(APPLE) | ||
35 | set(CMAKE_INSTALL_NAME_DIR | ||
36 | "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") | ||
37 | endif() | ||
38 | |||
39 | # /dev/urandom | ||
40 | if(UNIX) | ||
41 | add_definitions(-DHAS_DEV_URANDOM) | ||
42 | endif() | ||
43 | |||
44 | # Observe OpenBSD's library versioning scheme. | ||
45 | if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") | ||
46 | set(LIB_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}) | ||
47 | set(LIB_SOVERSION ${LIB_VERSION}) | ||
48 | else() | ||
49 | set(LIB_VERSION ${FIDO_VERSION}) | ||
50 | set(LIB_SOVERSION ${FIDO_MAJOR}) | ||
51 | endif() | ||
52 | |||
53 | if(MSVC) | ||
54 | if((NOT CBOR_INCLUDE_DIRS) OR (NOT CBOR_LIBRARY_DIRS) OR | ||
55 | (NOT CRYPTO_INCLUDE_DIRS) OR (NOT CRYPTO_LIBRARY_DIRS)) | ||
56 | message(FATAL_ERROR "please provide definitions for " | ||
57 | "{CBOR,CRYPTO}_{INCLUDE,LIBRARY}_DIRS when building " | ||
58 | "under msvc") | ||
59 | endif() | ||
60 | set(CBOR_LIBRARIES cbor) | ||
61 | set(CRYPTO_LIBRARIES crypto-45) | ||
62 | set(MSVC_DISABLED_WARNINGS_LIST | ||
63 | "C4200" # nonstandard extension used: zero-sized array in | ||
64 | # struct/union; | ||
65 | "C4204" # nonstandard extension used: non-constant aggregate | ||
66 | # initializer; | ||
67 | "C4706" # assignment within conditional expression; | ||
68 | "C4996" # The POSIX name for this item is deprecated. Instead, | ||
69 | # use the ISO C and C++ conformant name | ||
70 | ) | ||
71 | # The construction in the following 3 lines was taken from LibreSSL's | ||
72 | # CMakeLists.txt. | ||
73 | string(REPLACE "C" " -wd" MSVC_DISABLED_WARNINGS_STR | ||
74 | ${MSVC_DISABLED_WARNINGS_LIST}) | ||
75 | 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}") | ||
77 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Z7") | ||
78 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi") | ||
79 | else() | ||
80 | include(FindPkgConfig) | ||
81 | pkg_search_module(CBOR libcbor) | ||
82 | pkg_search_module(CRYPTO libcrypto REQUIRED) | ||
83 | |||
84 | # XXX workaround libcbor's missing .pc file | ||
85 | if(NOT CBOR_FOUND) | ||
86 | check_include_files(cbor.h HAVE_CBOR_H) | ||
87 | if(NOT HAVE_CBOR_H) | ||
88 | message(FATAL_ERROR "could not find cbor header files") | ||
89 | endif() | ||
90 | set(CBOR_LIBRARIES "cbor") | ||
91 | endif() | ||
92 | |||
93 | if(CMAKE_SYSTEM_NAME STREQUAL "Linux") | ||
94 | pkg_search_module(UDEV libudev REQUIRED) | ||
95 | set(UDEV_NAME "udev") | ||
96 | # Define be32toh(). | ||
97 | add_definitions(-D_GNU_SOURCE) | ||
98 | elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") | ||
99 | set(BASE_LIBRARIES usbhid) | ||
100 | endif() | ||
101 | |||
102 | if(MINGW) | ||
103 | # MinGW is stuck with a flavour of C89. | ||
104 | add_definitions(-DFIDO_NO_DIAGNOSTIC) | ||
105 | add_definitions(-DWC_ERR_INVALID_CHARS=0x80) | ||
106 | endif() | ||
107 | |||
108 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") | ||
109 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra") | ||
110 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") | ||
111 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow") | ||
112 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wwrite-strings") | ||
113 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-prototypes") | ||
114 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wbad-function-cast") | ||
115 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic") | ||
116 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic-errors") | ||
117 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-all") | ||
118 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") | ||
119 | |||
120 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g2") | ||
121 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer") | ||
122 | |||
123 | if(FUZZ) | ||
124 | if(LIBFUZZER) | ||
125 | set(FUZZ_LDFLAGS "-fsanitize=fuzzer") | ||
126 | endif() | ||
127 | add_definitions(-DFIDO_FUZZ) | ||
128 | endif() | ||
129 | |||
130 | if(ASAN) | ||
131 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address,leak") | ||
132 | endif() | ||
133 | |||
134 | if(MSAN) | ||
135 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory") | ||
136 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-memory-track-origins") | ||
137 | endif() | ||
138 | |||
139 | if(UBSAN) | ||
140 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined") | ||
141 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-trap=undefined") | ||
142 | endif() | ||
143 | |||
144 | if(COVERAGE) | ||
145 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-instr-generate -fcoverage-mapping") | ||
146 | endif() | ||
147 | endif() | ||
148 | |||
149 | # Use -Wshorten-64-to-32 if available. | ||
150 | check_c_compiler_flag("-Wshorten-64-to-32" HAVE_SHORTEN_64_TO_32) | ||
151 | if(HAVE_SHORTEN_64_TO_32) | ||
152 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshorten-64-to-32") | ||
153 | endif() | ||
154 | |||
155 | # Avoid https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 | ||
156 | if(CMAKE_COMPILER_IS_GNUCC) | ||
157 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-result") | ||
158 | endif() | ||
159 | |||
160 | # Decide which keyword to use for thread-local storage. | ||
161 | if(CMAKE_COMPILER_IS_GNUCC OR | ||
162 | CMAKE_C_COMPILER_ID STREQUAL "Clang" OR | ||
163 | CMAKE_C_COMPILER_ID STREQUAL "AppleClang") | ||
164 | set(TLS "__thread") | ||
165 | elseif(WIN32) | ||
166 | set(TLS "__declspec(thread)") | ||
167 | endif() | ||
168 | |||
169 | add_definitions(-DTLS=${TLS}) | ||
170 | |||
171 | # endian.h | ||
172 | check_include_files(endian.h HAVE_ENDIAN_H) | ||
173 | if(HAVE_ENDIAN_H) | ||
174 | add_definitions(-DHAVE_ENDIAN_H) | ||
175 | endif() | ||
176 | |||
177 | # err.h | ||
178 | check_include_files(err.h HAVE_ERR_H) | ||
179 | if(HAVE_ERR_H) | ||
180 | add_definitions(-DHAVE_ERR_H) | ||
181 | endif() | ||
182 | |||
183 | # unistd.h | ||
184 | check_include_files(unistd.h HAVE_UNISTD_H) | ||
185 | if(HAVE_UNISTD_H) | ||
186 | add_definitions(-DHAVE_UNISTD_H) | ||
187 | endif() | ||
188 | |||
189 | # signal.h | ||
190 | check_include_files(signal.h HAVE_SIGNAL_H) | ||
191 | if(HAVE_SIGNAL_H) | ||
192 | add_definitions(-DHAVE_SIGNAL_H) | ||
193 | endif() | ||
194 | |||
195 | # strlcpy | ||
196 | check_function_exists(strlcpy HAVE_STRLCPY) | ||
197 | if(HAVE_STRLCPY) | ||
198 | add_definitions(-DHAVE_STRLCPY) | ||
199 | endif() | ||
200 | |||
201 | # strlcat | ||
202 | check_function_exists(strlcpy HAVE_STRLCAT) | ||
203 | if(HAVE_STRLCAT) | ||
204 | add_definitions(-DHAVE_STRLCAT) | ||
205 | endif() | ||
206 | |||
207 | # recallocarray | ||
208 | check_function_exists(recallocarray HAVE_RECALLOCARRAY) | ||
209 | if(HAVE_RECALLOCARRAY) | ||
210 | add_definitions(-DHAVE_RECALLOCARRAY) | ||
211 | endif() | ||
212 | |||
213 | # XXX getpagesize is incorrectly detected when cross-compiling | ||
214 | # with mingw on Linux. Avoid. | ||
215 | if(NOT WIN32) | ||
216 | check_function_exists(getpagesize HAVE_GETPAGESIZE) | ||
217 | endif() | ||
218 | if(HAVE_GETPAGESIZE) | ||
219 | add_definitions(-DHAVE_GETPAGESIZE) | ||
220 | endif() | ||
221 | |||
222 | # sysconf | ||
223 | check_function_exists(sysconf HAVE_SYSCONF) | ||
224 | if(HAVE_SYSCONF) | ||
225 | add_definitions(-DHAVE_SYSCONF) | ||
226 | endif() | ||
227 | |||
228 | # memset_s | ||
229 | if(APPLE) | ||
230 | add_definitions(-D__STDC_WANT_LIB_EXT1__=1) | ||
231 | endif() | ||
232 | check_function_exists(memset_s HAVE_MEMSET_S) | ||
233 | if(HAVE_MEMSET_S) | ||
234 | add_definitions(-DHAVE_MEMSET_S) | ||
235 | endif() | ||
236 | |||
237 | # explicit_bzero | ||
238 | if(NOT LIBFUZZER) | ||
239 | check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO) | ||
240 | if(HAVE_EXPLICIT_BZERO) | ||
241 | add_definitions(-DHAVE_EXPLICIT_BZERO) | ||
242 | endif() | ||
243 | endif() | ||
244 | |||
245 | # timingsafe_bcmp | ||
246 | check_function_exists(timingsafe_bcmp HAVE_TIMINGSAFE_BCMP) | ||
247 | if(HAVE_TIMINGSAFE_BCMP) | ||
248 | add_definitions(-DHAVE_TIMINGSAFE_BCMP) | ||
249 | endif() | ||
250 | |||
251 | # readpassphrase | ||
252 | check_function_exists(readpassphrase HAVE_READPASSPHRASE) | ||
253 | if(HAVE_READPASSPHRASE) | ||
254 | add_definitions(-DHAVE_READPASSPHRASE) | ||
255 | endif() | ||
256 | |||
257 | # getline | ||
258 | check_function_exists(getline HAVE_GETLINE) | ||
259 | if(HAVE_GETLINE) | ||
260 | add_definitions(-DHAVE_GETLINE) | ||
261 | endif() | ||
262 | |||
263 | # getopt | ||
264 | check_function_exists(getopt HAVE_GETOPT) | ||
265 | if(HAVE_GETOPT) | ||
266 | add_definitions(-DHAVE_GETOPT) | ||
267 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-qual") | ||
268 | else() | ||
269 | if(CMAKE_COMPILER_IS_GNUCC) | ||
270 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-discarded-qualifiers") | ||
271 | endif() | ||
272 | if(CMAKE_C_COMPILER_ID STREQUAL "Clang") | ||
273 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-incompatible-pointer-types-discards-qualifiers") | ||
274 | endif() | ||
275 | endif() | ||
276 | |||
277 | # usable sigaction | ||
278 | set(CMAKE_EXTRA_INCLUDE_FILES signal.h) | ||
279 | check_function_exists(sigaction HAVE_SIGACTION) | ||
280 | check_type_size("sig_atomic_t" HAVE_SIG_ATOMIC_T) | ||
281 | if(HAVE_SIGACTION AND (NOT HAVE_SIG_ATOMIC_T STREQUAL "")) | ||
282 | add_definitions(-DSIGNAL_EXAMPLE) | ||
283 | endif() | ||
284 | set(CMAKE_EXTRA_INCLUDE_FILES) | ||
285 | |||
286 | # arc4random_buf | ||
287 | check_function_exists(arc4random_buf HAVE_ARC4RANDOM_BUF) | ||
288 | if(HAVE_ARC4RANDOM_BUF) | ||
289 | add_definitions(-DHAVE_ARC4RANDOM_BUF) | ||
290 | endif() | ||
291 | |||
292 | # getentropy | ||
293 | check_function_exists(getentropy HAVE_GETENTROPY) | ||
294 | if(HAVE_GETENTROPY) | ||
295 | add_definitions(-DHAVE_GETENTROPY) | ||
296 | endif() | ||
297 | |||
298 | # export list | ||
299 | if(CMAKE_C_COMPILER_ID STREQUAL "AppleClang") | ||
300 | # clang + lld | ||
301 | string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} | ||
302 | " -exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/src/export.llvm") | ||
303 | elseif(NOT MSVC) | ||
304 | # clang/gcc + gnu ld | ||
305 | string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} | ||
306 | " -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/export.gnu") | ||
307 | if(NOT WIN32) | ||
308 | string(CONCAT CMAKE_SHARED_LINKER_FLAGS | ||
309 | ${CMAKE_SHARED_LINKER_FLAGS} | ||
310 | " -Wl,-z,noexecstack -Wl,-z,relro,-z,now") | ||
311 | string(CONCAT CMAKE_EXE_LINKER_FLAGS | ||
312 | ${CMAKE_EXE_LINKER_FLAGS} | ||
313 | " -Wl,-z,noexecstack -Wl,-z,relro,-z,now") | ||
314 | if(FUZZ) | ||
315 | file(STRINGS fuzz/wrapped.sym WRAPPED_SYMBOLS) | ||
316 | foreach(s ${WRAPPED_SYMBOLS}) | ||
317 | string(CONCAT CMAKE_SHARED_LINKER_FLAGS | ||
318 | ${CMAKE_SHARED_LINKER_FLAGS} | ||
319 | " -Wl,--wrap=${s}") | ||
320 | endforeach() | ||
321 | endif() | ||
322 | endif() | ||
323 | else() | ||
324 | string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} | ||
325 | " /def:${CMAKE_CURRENT_SOURCE_DIR}/src/export.msvc") | ||
326 | endif() | ||
327 | |||
328 | include_directories(${CMAKE_SOURCE_DIR}/src) | ||
329 | include_directories(${CBOR_INCLUDE_DIRS}) | ||
330 | include_directories(${CRYPTO_INCLUDE_DIRS}) | ||
331 | |||
332 | link_directories(${CBOR_LIBRARY_DIRS}) | ||
333 | link_directories(${CRYPTO_LIBRARY_DIRS}) | ||
334 | |||
335 | message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}") | ||
336 | message(STATUS "CMAKE_C_COMPILER_ID: ${CMAKE_C_COMPILER_ID}") | ||
337 | message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}") | ||
338 | message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}") | ||
339 | message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") | ||
340 | message(STATUS "CBOR_INCLUDE_DIRS: ${CBOR_INCLUDE_DIRS}") | ||
341 | message(STATUS "CBOR_LIBRARY_DIRS: ${CBOR_LIBRARY_DIRS}") | ||
342 | message(STATUS "CBOR_LIBRARIES: ${CBOR_LIBRARIES}") | ||
343 | message(STATUS "CRYPTO_INCLUDE_DIRS: ${CRYPTO_INCLUDE_DIRS}") | ||
344 | message(STATUS "CRYPTO_LIBRARY_DIRS: ${CRYPTO_LIBRARY_DIRS}") | ||
345 | message(STATUS "CRYPTO_LIBRARIES: ${CRYPTO_LIBRARIES}") | ||
346 | message(STATUS "BASE_LIBRARIES: ${BASE_LIBRARIES}") | ||
347 | message(STATUS "VERSION: ${FIDO_VERSION}") | ||
348 | message(STATUS "LIB_VERSION: ${LIB_VERSION}") | ||
349 | message(STATUS "LIB_SOVERSION: ${LIB_SOVERSION}") | ||
350 | message(STATUS "FUZZ: ${FUZZ}") | ||
351 | message(STATUS "AFL: ${AFL}") | ||
352 | message(STATUS "LIBFUZZER: ${LIBFUZZER}") | ||
353 | message(STATUS "ASAN: ${ASAN}") | ||
354 | message(STATUS "MSAN: ${MSAN}") | ||
355 | message(STATUS "COVERAGE: ${COVERAGE}") | ||
356 | message(STATUS "TLS: ${TLS}") | ||
357 | |||
358 | if(CMAKE_SYSTEM_NAME STREQUAL "Linux") | ||
359 | message(STATUS "UDEV_INCLUDE_DIRS: ${UDEV_INCLUDE_DIRS}") | ||
360 | message(STATUS "UDEV_LIBRARY_DIRS: ${UDEV_LIBRARY_DIRS}") | ||
361 | message(STATUS "UDEV_LIBRARIES: ${UDEV_LIBRARIES}") | ||
362 | message(STATUS "UDEV_RULES_DIR: ${UDEV_RULES_DIR}") | ||
363 | endif() | ||
364 | |||
365 | subdirs(src) | ||
366 | subdirs(examples) | ||
367 | subdirs(tools) | ||
368 | subdirs(man) | ||
369 | |||
370 | if(NOT WIN32) | ||
371 | if(CMAKE_BUILD_TYPE STREQUAL "Debug") | ||
372 | if(NOT MSAN AND NOT LIBFUZZER) | ||
373 | subdirs(regress) | ||
374 | endif() | ||
375 | endif() | ||
376 | if(FUZZ) | ||
377 | subdirs(fuzz) | ||
378 | endif() | ||
379 | |||
380 | if(CMAKE_SYSTEM_NAME STREQUAL "Linux") | ||
381 | subdirs(udev) | ||
382 | endif() | ||
383 | endif() | ||
@@ -0,0 +1,24 @@ | |||
1 | Copyright (c) 2018 Yubico AB. All rights reserved. | ||
2 | |||
3 | Redistribution and use in source and binary forms, with or without | ||
4 | modification, are permitted provided that the following conditions are | ||
5 | met: | ||
6 | |||
7 | 1. Redistributions of source code must retain the above copyright | ||
8 | notice, this list of conditions and the following disclaimer. | ||
9 | 2. Redistributions in binary form must reproduce the above copyright | ||
10 | notice, this list of conditions and the following disclaimer in | ||
11 | the documentation and/or other materials provided with the | ||
12 | distribution. | ||
13 | |||
14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
15 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
16 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
17 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
18 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
20 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
21 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
22 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
@@ -0,0 +1,73 @@ | |||
1 | * Version 1.3.0 (2019-11-28) | ||
2 | ** assert/hmac: encode public key as per spec, gh#60. | ||
3 | ** fido2-cred: fix creation of resident keys. | ||
4 | ** fido2-{assert,cred}: support for hmac-secret extension. | ||
5 | ** hid_osx: detect device removal, gh#56. | ||
6 | ** hid_osx: fix device detection in MacOS Catalina. | ||
7 | ** New API calls: | ||
8 | - fido_assert_set_authdata_raw; | ||
9 | - fido_assert_sigcount; | ||
10 | - fido_cred_set_authdata_raw; | ||
11 | - fido_dev_cancel. | ||
12 | ** Middleware library for use by OpenSSH. | ||
13 | ** Support for biometric enrollment. | ||
14 | ** Support for OpenBSD. | ||
15 | ** Support for self-attestation. | ||
16 | |||
17 | * Version 1.2.0 (released 2019-07-26) | ||
18 | ** Credential management support. | ||
19 | ** New API reflecting FIDO's 3-state booleans (true, false, absent): | ||
20 | - fido_assert_set_up; | ||
21 | - fido_assert_set_uv; | ||
22 | - fido_cred_set_rk; | ||
23 | - fido_cred_set_uv. | ||
24 | ** Command-line tools for Windows. | ||
25 | ** Documentation and reliability fixes. | ||
26 | ** fido_{assert,cred}_set_options() are now marked as deprecated. | ||
27 | |||
28 | * Version 1.1.0 (released 2019-05-08) | ||
29 | ** MacOS: fix IOKit crash on HID read. | ||
30 | ** Windows: fix contents of release file. | ||
31 | ** EdDSA (Ed25519) support. | ||
32 | ** fido_dev_make_cred: fix order of CBOR map keys. | ||
33 | ** fido_dev_get_assert: plug memory leak when operating on U2F devices. | ||
34 | |||
35 | * Version 1.0.0 (released 2019-03-21) | ||
36 | ** Native HID support on Linux, MacOS, and Windows. | ||
37 | ** fido2-{assert,cred}: new -u option to force U2F on dual authenticators. | ||
38 | ** fido2-assert: support for multiple resident keys with the same RP. | ||
39 | ** Strict checks for CTAP2 compliance on received CBOR payloads. | ||
40 | ** Better fuzzing harnesses. | ||
41 | ** Documentation and reliability fixes. | ||
42 | |||
43 | * Version 0.4.0 (released 2019-01-07) | ||
44 | ** fido2-assert: print the user id for resident credentials. | ||
45 | ** Fix encoding of COSE algorithms when making a credential. | ||
46 | ** Rework purpose of fido_cred_set_type; no ABI change. | ||
47 | ** Minor documentation and code fixes. | ||
48 | |||
49 | * Version 0.3.0 (released 2018-09-11) | ||
50 | ** Various reliability fixes. | ||
51 | ** Merged fuzzing instrumentation. | ||
52 | ** Added regress tests. | ||
53 | ** Added support for FIDO 2's hmac-secret extension. | ||
54 | ** New API calls: | ||
55 | - fido_assert_hmac_secret_len; | ||
56 | - fido_assert_hmac_secret_ptr; | ||
57 | - fido_assert_set_extensions; | ||
58 | - fido_assert_set_hmac_salt; | ||
59 | - fido_cred_set_extensions; | ||
60 | - fido_dev_force_fido2. | ||
61 | ** Support for native builds with Microsoft Visual Studio 17. | ||
62 | |||
63 | * Version 0.2.0 (released 2018-06-20) | ||
64 | ** Added command-line tools. | ||
65 | ** Added a couple of missing get functions. | ||
66 | |||
67 | * Version 0.1.1 (released 2018-06-05) | ||
68 | ** Added documentation. | ||
69 | ** Added OpenSSL 1.0 support. | ||
70 | ** Minor fixes. | ||
71 | |||
72 | * Version 0.1.0 (released 2018-05-18) | ||
73 | ** First beta release. | ||
diff --git a/README.adoc b/README.adoc new file mode 100644 index 0000000..8693417 --- /dev/null +++ b/README.adoc | |||
@@ -0,0 +1,88 @@ | |||
1 | == libfido2 | ||
2 | |||
3 | image:https://api.travis-ci.org/Yubico/libfido2.svg?branch=master["Build Status (Travis)", link="https://travis-ci.org/Yubico/libfido2"] | ||
4 | image:https://github.com/yubico/libfido2/workflows/windows/badge.svg["windows build status (github actions)", link="https://github.com/Yubico/libfido2/actions"] | ||
5 | image:https://img.shields.io/badge/license-BSD-blue.svg["License", link="https://raw.githubusercontent.com/Yubico/libfido2/master/LICENSE"] | ||
6 | |||
7 | *libfido2* provides library functionality and command-line tools to | ||
8 | communicate with a FIDO device over USB, and to verify attestation and | ||
9 | assertion signatures. | ||
10 | |||
11 | *libfido2* supports the FIDO U2F (CTAP 1) and FIDO 2.0 (CTAP 2) protocols. | ||
12 | |||
13 | For usage, see the `examples/` directory. | ||
14 | |||
15 | === License | ||
16 | |||
17 | *libfido2* is licensed under the BSD 2-clause license. See the _LICENSE_ | ||
18 | file for the full license text. | ||
19 | |||
20 | === Supported Platforms | ||
21 | |||
22 | *libfido2* is known to work on Linux, MacOS, Windows, and OpenBSD. | ||
23 | |||
24 | === Documentation | ||
25 | |||
26 | Documentation is available in troff and HTML formats. An | ||
27 | https://developers.yubico.com/libfido2/Manuals/[online mirror of *libfido2*'s documentation] | ||
28 | is also available. | ||
29 | |||
30 | === Installation | ||
31 | |||
32 | ==== Releases | ||
33 | |||
34 | The current release of *libfido2* is 1.3.0. Please consult Yubico's | ||
35 | https://developers.yubico.com/libfido2/Releases[release page] for source | ||
36 | and binary releases. | ||
37 | |||
38 | ==== Ubuntu | ||
39 | |||
40 | $ sudo apt-add-repository ppa:yubico/stable | ||
41 | $ sudo apt update | ||
42 | $ sudo apt install libfido2-dev | ||
43 | |||
44 | Or from source, on UNIX-like systems: | ||
45 | |||
46 | $ (rm -rf build && mkdir build && cd build && cmake ..) | ||
47 | $ make -C build | ||
48 | $ sudo make -C build install | ||
49 | |||
50 | Depending on the platform, the PKG_CONFIG_PATH environment variable may need to | ||
51 | be set. | ||
52 | |||
53 | *libfido2* depends on https://github.com/pjk/libcbor[libcbor] and | ||
54 | https://github.com/libressl-portable/portable[LibreSSL] (alternatively, | ||
55 | https://www.openssl.org[OpenSSL] may be used). On Linux, libudev (part of | ||
56 | https://www.freedesktop.org/wiki/Software/systemd[systemd]) is also required. | ||
57 | |||
58 | For complete, OS-specific installation instructions, please refer to the | ||
59 | `.travis/` (Linux, MacOS) and `windows/` directories. | ||
60 | |||
61 | On Linux, you will need to add a udev rule to be able to access the FIDO | ||
62 | device, or run as root. For example, the udev rule may contain the following: | ||
63 | |||
64 | ---- | ||
65 | #udev rule for allowing HID access to Yubico devices for FIDO support. | ||
66 | |||
67 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", \ | ||
68 | MODE="0664", GROUP="plugdev", ATTRS{idVendor}=="1050" | ||
69 | ---- | ||
70 | |||
71 | On Windows 1903 and newer versions, access to FIDO devices has been restricted | ||
72 | to applications using the operating system's native API. Use of *libfido2* | ||
73 | is still possible in privileged applications. | ||
74 | |||
75 | === OpenSSH Integration | ||
76 | |||
77 | *libfido2* includes middleware allowing https://www.openssh.com[OpenSSH] to | ||
78 | talk to U2F/FIDO2 devices. Note that server support is required for | ||
79 | authentication. 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/docker/bionic/Dockerfile b/docker/bionic/Dockerfile new file mode 100644 index 0000000..9225ed8 --- /dev/null +++ b/docker/bionic/Dockerfile | |||
@@ -0,0 +1,14 @@ | |||
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 | ||
7 | FROM ubuntu:bionic | ||
8 | ENV DEBIAN_FRONTEND noninteractive | ||
9 | RUN apt-get -qq update && apt-get -qq upgrade | ||
10 | RUN apt-get install -qq packaging-dev debian-keyring devscripts equivs gnupg python sudo | ||
11 | ADD https://raw.githubusercontent.com/dainnilsson/scripts/master/make-ppa /make-ppa | ||
12 | RUN chmod +x /make-ppa | ||
13 | WORKDIR /workdir | ||
14 | ENTRYPOINT ["/make-ppa"] | ||
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..957311e --- /dev/null +++ b/examples/CMakeLists.txt | |||
@@ -0,0 +1,44 @@ | |||
1 | # Copyright (c) 2018 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 | list(APPEND COMPAT_SOURCES | ||
6 | ../openbsd-compat/getopt_long.c | ||
7 | ../openbsd-compat/strlcat.c | ||
8 | ../openbsd-compat/strlcpy.c | ||
9 | ) | ||
10 | |||
11 | if(WIN32) | ||
12 | list(APPEND COMPAT_SOURCES ../openbsd-compat/posix_win.c) | ||
13 | endif() | ||
14 | |||
15 | # drop -rdynamic | ||
16 | set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") | ||
17 | |||
18 | # manifest | ||
19 | add_executable(manifest manifest.c ${COMPAT_SOURCES}) | ||
20 | target_link_libraries(manifest fido2) | ||
21 | |||
22 | # info | ||
23 | add_executable(info info.c ${COMPAT_SOURCES}) | ||
24 | target_link_libraries(info fido2) | ||
25 | |||
26 | # reset | ||
27 | add_executable(reset reset.c util.c ${COMPAT_SOURCES}) | ||
28 | target_link_libraries(reset fido2) | ||
29 | |||
30 | # cred | ||
31 | add_executable(cred cred.c util.c ${COMPAT_SOURCES}) | ||
32 | target_link_libraries(cred fido2) | ||
33 | |||
34 | # assert | ||
35 | add_executable(assert assert.c util.c ${COMPAT_SOURCES}) | ||
36 | target_link_libraries(assert fido2) | ||
37 | |||
38 | # setpin | ||
39 | add_executable(setpin setpin.c ${COMPAT_SOURCES}) | ||
40 | target_link_libraries(setpin fido2) | ||
41 | |||
42 | # retries | ||
43 | add_executable(retries retries.c ${COMPAT_SOURCES}) | ||
44 | target_link_libraries(retries fido2) | ||
diff --git a/examples/README.adoc b/examples/README.adoc new file mode 100644 index 0000000..091c6bc --- /dev/null +++ b/examples/README.adoc | |||
@@ -0,0 +1,81 @@ | |||
1 | = Examples | ||
2 | |||
3 | === Definitions | ||
4 | |||
5 | The following definitions are used in the description below: | ||
6 | |||
7 | - <device> | ||
8 | |||
9 | The file system path or subsystem-specific identification string of a | ||
10 | FIDO device. | ||
11 | |||
12 | - <pin>, [oldpin] | ||
13 | |||
14 | Strings passed directly in the executed command's argument vector. | ||
15 | |||
16 | - <cred_id> | ||
17 | |||
18 | The file system path of a file containing a FIDO credential ID in | ||
19 | binary representation. | ||
20 | |||
21 | - <pubkey> | ||
22 | |||
23 | The file system path of a file containing a NIST P-256 public key in | ||
24 | PEM format. | ||
25 | |||
26 | === Description | ||
27 | |||
28 | The following examples are provided: | ||
29 | |||
30 | - manifest | ||
31 | |||
32 | Prints a list of configured FIDO devices. | ||
33 | |||
34 | - info <device> | ||
35 | |||
36 | Prints information about <device>. | ||
37 | |||
38 | - reset <device> | ||
39 | |||
40 | Performs a factory reset on <device>. | ||
41 | |||
42 | - setpin <pin> [oldpin] <device> | ||
43 | |||
44 | Configures <pin> as the new PIN of <device>. If [oldpin] is provided, | ||
45 | the device's PIN is changed from [oldpin] to <pin>. | ||
46 | |||
47 | - cred [-t ecdsa|rsa|eddsa] [-k pubkey] [-ei cred_id] [-P pin] [-T seconds] | ||
48 | [-hruv] <device> | ||
49 | |||
50 | Creates a new credential on <device> and verify that the credential | ||
51 | was signed by the authenticator. The device's attestation certificate | ||
52 | is not verified. If option -k is specified, the credential's public | ||
53 | key is stored in <pubkey>. If option -i is specified, the credential | ||
54 | ID is stored in <cred_id>. The -e option may be used to add <cred_id> | ||
55 | to the list of excluded credentials. If option -h is specified, | ||
56 | the hmac-secret FIDO2 extension is enabled on the generated | ||
57 | credential. If option -r is specified, the generated credential | ||
58 | will involve a resident key. User verification may be requested | ||
59 | through the -v option. If option -u is specified, the credential | ||
60 | is generated using U2F (CTAP1) instead of FIDO2 (CTAP2) commands. | ||
61 | The -T option may be used to enforce a timeout of <seconds>. | ||
62 | |||
63 | - assert [-t ecdsa|rsa|eddsa] [-a cred_id] [-h hmac_secret] [-s hmac_salt] | ||
64 | [-P pin] [-T seconds] [-puv] <pubkey> <device> | ||
65 | |||
66 | Asks <device> for a FIDO2 assertion corresponding to [cred_id], | ||
67 | which may be omitted for resident keys. The obtained assertion | ||
68 | is verified using <pubkey>. The -p option requests that the user | ||
69 | be present. User verification may be requested through the -v | ||
70 | option. If option -u is specified, the assertion is generated using | ||
71 | U2F (CTAP1) instead of FIDO2 (CTAP2) commands. If option -s is | ||
72 | specified, a FIDO2 hmac-secret is requested from the authenticator, | ||
73 | and the contents of <hmac_salt> are used as the salt. If option -h | ||
74 | is specified, the resulting hmac-secret is stored in <hmac_secret>. | ||
75 | The -T option may be used to enforce a timeout of <seconds>. | ||
76 | |||
77 | - retries <device> | ||
78 | Get the number of PIN attempts left on <device> before lockout. | ||
79 | |||
80 | Debugging is possible through the use of the FIDO_DEBUG environment variable. | ||
81 | If set, libfido2 will produce a log of its transactions with the authenticator. | ||
diff --git a/examples/assert.c b/examples/assert.c new file mode 100644 index 0000000..a421a51 --- /dev/null +++ b/examples/assert.c | |||
@@ -0,0 +1,329 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <openssl/ec.h> | ||
8 | |||
9 | #include <stdbool.h> | ||
10 | #include <stdio.h> | ||
11 | #include <stdlib.h> | ||
12 | #include <string.h> | ||
13 | #ifdef HAVE_UNISTD_H | ||
14 | #include <unistd.h> | ||
15 | #endif | ||
16 | |||
17 | #include "../openbsd-compat/openbsd-compat.h" | ||
18 | |||
19 | #include "fido.h" | ||
20 | #include "fido/es256.h" | ||
21 | #include "fido/rs256.h" | ||
22 | #include "fido/eddsa.h" | ||
23 | #include "extern.h" | ||
24 | |||
25 | #ifdef SIGNAL_EXAMPLE | ||
26 | extern volatile sig_atomic_t got_signal; | ||
27 | #endif | ||
28 | |||
29 | static const unsigned char cdh[32] = { | ||
30 | 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7, | ||
31 | 0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56, | ||
32 | 0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52, | ||
33 | 0x35, 0x2d, 0xa2, 0x62, 0x4a, 0xbe, 0x89, 0x76, | ||
34 | }; | ||
35 | |||
36 | static void | ||
37 | usage(void) | ||
38 | { | ||
39 | fprintf(stderr, "usage: assert [-t ecdsa|rsa|eddsa] [-a cred_id] " | ||
40 | "[-h hmac_secret] [-s hmac_salt] [-P pin] [-T seconds] [-puv] " | ||
41 | "<pubkey> <device>\n"); | ||
42 | exit(EXIT_FAILURE); | ||
43 | } | ||
44 | |||
45 | static void | ||
46 | verify_assert(int type, const unsigned char *authdata_ptr, size_t authdata_len, | ||
47 | const unsigned char *sig_ptr, size_t sig_len, bool up, bool uv, int ext, | ||
48 | const char *key) | ||
49 | { | ||
50 | fido_assert_t *assert = NULL; | ||
51 | EC_KEY *ec = NULL; | ||
52 | RSA *rsa = NULL; | ||
53 | EVP_PKEY *eddsa = NULL; | ||
54 | es256_pk_t *es256_pk = NULL; | ||
55 | rs256_pk_t *rs256_pk = NULL; | ||
56 | eddsa_pk_t *eddsa_pk = NULL; | ||
57 | void *pk; | ||
58 | int r; | ||
59 | |||
60 | /* credential pubkey */ | ||
61 | switch (type) { | ||
62 | case COSE_ES256: | ||
63 | if ((ec = read_ec_pubkey(key)) == NULL) | ||
64 | errx(1, "read_ec_pubkey"); | ||
65 | |||
66 | if ((es256_pk = es256_pk_new()) == NULL) | ||
67 | errx(1, "es256_pk_new"); | ||
68 | |||
69 | if (es256_pk_from_EC_KEY(es256_pk, ec) != FIDO_OK) | ||
70 | errx(1, "es256_pk_from_EC_KEY"); | ||
71 | |||
72 | pk = es256_pk; | ||
73 | EC_KEY_free(ec); | ||
74 | ec = NULL; | ||
75 | |||
76 | break; | ||
77 | case COSE_RS256: | ||
78 | if ((rsa = read_rsa_pubkey(key)) == NULL) | ||
79 | errx(1, "read_rsa_pubkey"); | ||
80 | |||
81 | if ((rs256_pk = rs256_pk_new()) == NULL) | ||
82 | errx(1, "rs256_pk_new"); | ||
83 | |||
84 | if (rs256_pk_from_RSA(rs256_pk, rsa) != FIDO_OK) | ||
85 | errx(1, "rs256_pk_from_RSA"); | ||
86 | |||
87 | pk = rs256_pk; | ||
88 | RSA_free(rsa); | ||
89 | rsa = NULL; | ||
90 | |||
91 | break; | ||
92 | case COSE_EDDSA: | ||
93 | if ((eddsa = read_eddsa_pubkey(key)) == NULL) | ||
94 | errx(1, "read_eddsa_pubkey"); | ||
95 | |||
96 | if ((eddsa_pk = eddsa_pk_new()) == NULL) | ||
97 | errx(1, "eddsa_pk_new"); | ||
98 | |||
99 | if (eddsa_pk_from_EVP_PKEY(eddsa_pk, eddsa) != FIDO_OK) | ||
100 | errx(1, "eddsa_pk_from_EVP_PKEY"); | ||
101 | |||
102 | pk = eddsa_pk; | ||
103 | EVP_PKEY_free(eddsa); | ||
104 | eddsa = NULL; | ||
105 | |||
106 | break; | ||
107 | default: | ||
108 | errx(1, "unknown credential type %d", type); | ||
109 | } | ||
110 | |||
111 | if ((assert = fido_assert_new()) == NULL) | ||
112 | errx(1, "fido_assert_new"); | ||
113 | |||
114 | /* client data hash */ | ||
115 | r = fido_assert_set_clientdata_hash(assert, cdh, sizeof(cdh)); | ||
116 | if (r != FIDO_OK) | ||
117 | errx(1, "fido_assert_set_clientdata_hash: %s (0x%x)", | ||
118 | fido_strerr(r), r); | ||
119 | |||
120 | /* relying party */ | ||
121 | r = fido_assert_set_rp(assert, "localhost"); | ||
122 | if (r != FIDO_OK) | ||
123 | errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r); | ||
124 | |||
125 | /* authdata */ | ||
126 | r = fido_assert_set_count(assert, 1); | ||
127 | if (r != FIDO_OK) | ||
128 | errx(1, "fido_assert_set_count: %s (0x%x)", fido_strerr(r), r); | ||
129 | r = fido_assert_set_authdata(assert, 0, authdata_ptr, authdata_len); | ||
130 | if (r != FIDO_OK) | ||
131 | errx(1, "fido_assert_set_authdata: %s (0x%x)", fido_strerr(r), r); | ||
132 | |||
133 | /* extension */ | ||
134 | r = fido_assert_set_extensions(assert, ext); | ||
135 | if (r != FIDO_OK) | ||
136 | errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r), | ||
137 | r); | ||
138 | |||
139 | /* user presence */ | ||
140 | if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) | ||
141 | errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r); | ||
142 | |||
143 | /* user verification */ | ||
144 | if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) | ||
145 | errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r); | ||
146 | |||
147 | /* sig */ | ||
148 | r = fido_assert_set_sig(assert, 0, sig_ptr, sig_len); | ||
149 | if (r != FIDO_OK) | ||
150 | errx(1, "fido_assert_set_sig: %s (0x%x)", fido_strerr(r), r); | ||
151 | |||
152 | r = fido_assert_verify(assert, 0, type, pk); | ||
153 | if (r != FIDO_OK) | ||
154 | errx(1, "fido_assert_verify: %s (0x%x)", fido_strerr(r), r); | ||
155 | |||
156 | es256_pk_free(&es256_pk); | ||
157 | rs256_pk_free(&rs256_pk); | ||
158 | eddsa_pk_free(&eddsa_pk); | ||
159 | |||
160 | fido_assert_free(&assert); | ||
161 | } | ||
162 | |||
163 | int | ||
164 | main(int argc, char **argv) | ||
165 | { | ||
166 | bool up = false; | ||
167 | bool uv = false; | ||
168 | bool u2f = false; | ||
169 | fido_dev_t *dev = NULL; | ||
170 | fido_assert_t *assert = NULL; | ||
171 | const char *pin = NULL; | ||
172 | const char *hmac_out = NULL; | ||
173 | unsigned char *body = NULL; | ||
174 | long long seconds = 0; | ||
175 | size_t len; | ||
176 | int type = COSE_ES256; | ||
177 | int ext = 0; | ||
178 | int ch; | ||
179 | int r; | ||
180 | |||
181 | if ((assert = fido_assert_new()) == NULL) | ||
182 | errx(1, "fido_assert_new"); | ||
183 | |||
184 | while ((ch = getopt(argc, argv, "P:T:a:h:ps:t:uv")) != -1) { | ||
185 | switch (ch) { | ||
186 | case 'P': | ||
187 | pin = optarg; | ||
188 | break; | ||
189 | case 'T': | ||
190 | #ifndef SIGNAL_EXAMPLE | ||
191 | errx(1, "-T not supported"); | ||
192 | #endif | ||
193 | if (base10(optarg, &seconds) < 0) | ||
194 | errx(1, "base10: %s", optarg); | ||
195 | if (seconds <= 0 || seconds > 30) | ||
196 | errx(1, "-T: %s must be in (0,30]", optarg); | ||
197 | break; | ||
198 | case 'a': | ||
199 | if (read_blob(optarg, &body, &len) < 0) | ||
200 | errx(1, "read_blob: %s", optarg); | ||
201 | if ((r = fido_assert_allow_cred(assert, body, | ||
202 | len)) != FIDO_OK) | ||
203 | errx(1, "fido_assert_allow_cred: %s (0x%x)", | ||
204 | fido_strerr(r), r); | ||
205 | free(body); | ||
206 | body = NULL; | ||
207 | break; | ||
208 | case 'h': | ||
209 | hmac_out = optarg; | ||
210 | break; | ||
211 | case 'p': | ||
212 | up = true; | ||
213 | break; | ||
214 | case 's': | ||
215 | ext = FIDO_EXT_HMAC_SECRET; | ||
216 | if (read_blob(optarg, &body, &len) < 0) | ||
217 | errx(1, "read_blob: %s", optarg); | ||
218 | if ((r = fido_assert_set_hmac_salt(assert, body, | ||
219 | len)) != FIDO_OK) | ||
220 | errx(1, "fido_assert_set_hmac_salt: %s (0x%x)", | ||
221 | fido_strerr(r), r); | ||
222 | free(body); | ||
223 | body = NULL; | ||
224 | break; | ||
225 | case 't': | ||
226 | if (strcmp(optarg, "ecdsa") == 0) | ||
227 | type = COSE_ES256; | ||
228 | else if (strcmp(optarg, "rsa") == 0) | ||
229 | type = COSE_RS256; | ||
230 | else if (strcmp(optarg, "eddsa") == 0) | ||
231 | type = COSE_EDDSA; | ||
232 | else | ||
233 | errx(1, "unknown type %s", optarg); | ||
234 | break; | ||
235 | case 'u': | ||
236 | u2f = true; | ||
237 | break; | ||
238 | case 'v': | ||
239 | uv = true; | ||
240 | break; | ||
241 | default: | ||
242 | usage(); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | argc -= optind; | ||
247 | argv += optind; | ||
248 | |||
249 | if (argc != 2) | ||
250 | usage(); | ||
251 | |||
252 | fido_init(0); | ||
253 | |||
254 | if ((dev = fido_dev_new()) == NULL) | ||
255 | errx(1, "fido_dev_new"); | ||
256 | |||
257 | r = fido_dev_open(dev, argv[1]); | ||
258 | if (r != FIDO_OK) | ||
259 | errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); | ||
260 | if (u2f) | ||
261 | fido_dev_force_u2f(dev); | ||
262 | |||
263 | /* client data hash */ | ||
264 | r = fido_assert_set_clientdata_hash(assert, cdh, sizeof(cdh)); | ||
265 | if (r != FIDO_OK) | ||
266 | errx(1, "fido_assert_set_clientdata_hash: %s (0x%x)", | ||
267 | fido_strerr(r), r); | ||
268 | |||
269 | /* relying party */ | ||
270 | r = fido_assert_set_rp(assert, "localhost"); | ||
271 | if (r != FIDO_OK) | ||
272 | errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r); | ||
273 | |||
274 | /* extensions */ | ||
275 | r = fido_assert_set_extensions(assert, ext); | ||
276 | if (r != FIDO_OK) | ||
277 | errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r), | ||
278 | r); | ||
279 | |||
280 | /* user presence */ | ||
281 | if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) | ||
282 | errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r); | ||
283 | |||
284 | /* user verification */ | ||
285 | if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) | ||
286 | errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r); | ||
287 | |||
288 | #ifdef SIGNAL_EXAMPLE | ||
289 | prepare_signal_handler(SIGINT); | ||
290 | if (seconds) { | ||
291 | prepare_signal_handler(SIGALRM); | ||
292 | alarm((unsigned)seconds); | ||
293 | } | ||
294 | #endif | ||
295 | |||
296 | r = fido_dev_get_assert(dev, assert, pin); | ||
297 | if (r != FIDO_OK) { | ||
298 | #ifdef SIGNAL_EXAMPLE | ||
299 | if (got_signal) | ||
300 | fido_dev_cancel(dev); | ||
301 | #endif | ||
302 | errx(1, "fido_dev_get_assert: %s (0x%x)", fido_strerr(r), r); | ||
303 | } | ||
304 | |||
305 | r = fido_dev_close(dev); | ||
306 | if (r != FIDO_OK) | ||
307 | errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); | ||
308 | |||
309 | fido_dev_free(&dev); | ||
310 | |||
311 | if (fido_assert_count(assert) != 1) | ||
312 | errx(1, "fido_assert_count: %d signatures returned", | ||
313 | (int)fido_assert_count(assert)); | ||
314 | |||
315 | 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_sig_len(assert, 0), up, uv, ext, argv[0]); | ||
318 | |||
319 | if (hmac_out != NULL) { | ||
320 | /* extract the hmac secret */ | ||
321 | if (write_blob(hmac_out, fido_assert_hmac_secret_ptr(assert, 0), | ||
322 | fido_assert_hmac_secret_len(assert, 0)) < 0) | ||
323 | errx(1, "write_blob"); | ||
324 | } | ||
325 | |||
326 | fido_assert_free(&assert); | ||
327 | |||
328 | exit(0); | ||
329 | } | ||
diff --git a/examples/cred.c b/examples/cred.c new file mode 100644 index 0000000..e471f7e --- /dev/null +++ b/examples/cred.c | |||
@@ -0,0 +1,303 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <openssl/ec.h> | ||
8 | #include <openssl/pem.h> | ||
9 | |||
10 | #include <errno.h> | ||
11 | #include <stdbool.h> | ||
12 | #include <stdio.h> | ||
13 | #include <stdlib.h> | ||
14 | #include <string.h> | ||
15 | #ifdef HAVE_UNISTD_H | ||
16 | #include <unistd.h> | ||
17 | #endif | ||
18 | |||
19 | #include "../openbsd-compat/openbsd-compat.h" | ||
20 | |||
21 | #include "fido.h" | ||
22 | #include "extern.h" | ||
23 | |||
24 | #ifdef SIGNAL_EXAMPLE | ||
25 | extern volatile sig_atomic_t got_signal; | ||
26 | #endif | ||
27 | |||
28 | static const unsigned char cdh[32] = { | ||
29 | 0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb, | ||
30 | 0xdd, 0xd7, 0xfb, 0x06, 0x37, 0x62, 0xea, 0x26, | ||
31 | 0x20, 0x44, 0x8e, 0x69, 0x7c, 0x03, 0xf2, 0x31, | ||
32 | 0x2f, 0x99, 0xdc, 0xaf, 0x3e, 0x8a, 0x91, 0x6b, | ||
33 | }; | ||
34 | |||
35 | static const unsigned char user_id[32] = { | ||
36 | 0x78, 0x1c, 0x78, 0x60, 0xad, 0x88, 0xd2, 0x63, | ||
37 | 0x32, 0x62, 0x2a, 0xf1, 0x74, 0x5d, 0xed, 0xb2, | ||
38 | 0xe7, 0xa4, 0x2b, 0x44, 0x89, 0x29, 0x39, 0xc5, | ||
39 | 0x56, 0x64, 0x01, 0x27, 0x0d, 0xbb, 0xc4, 0x49, | ||
40 | }; | ||
41 | |||
42 | static void | ||
43 | usage(void) | ||
44 | { | ||
45 | fprintf(stderr, "usage: cred [-t ecdsa|rsa|eddsa] [-k pubkey] " | ||
46 | "[-ei cred_id] [-P pin] [-T seconds] [-hruv] <device>\n"); | ||
47 | exit(EXIT_FAILURE); | ||
48 | } | ||
49 | |||
50 | static void | ||
51 | verify_cred(int type, const char *fmt, const unsigned char *authdata_ptr, | ||
52 | size_t authdata_len, const unsigned char *x509_ptr, size_t x509_len, | ||
53 | const unsigned char *sig_ptr, size_t sig_len, bool rk, bool uv, int ext, | ||
54 | const char *key_out, const char *id_out) | ||
55 | { | ||
56 | fido_cred_t *cred; | ||
57 | int r; | ||
58 | |||
59 | if ((cred = fido_cred_new()) == NULL) | ||
60 | errx(1, "fido_cred_new"); | ||
61 | |||
62 | /* type */ | ||
63 | r = fido_cred_set_type(cred, type); | ||
64 | if (r != FIDO_OK) | ||
65 | errx(1, "fido_cred_set_type: %s (0x%x)", fido_strerr(r), r); | ||
66 | |||
67 | /* client data hash */ | ||
68 | r = fido_cred_set_clientdata_hash(cred, cdh, sizeof(cdh)); | ||
69 | if (r != FIDO_OK) | ||
70 | errx(1, "fido_cred_set_clientdata_hash: %s (0x%x)", | ||
71 | fido_strerr(r), r); | ||
72 | |||
73 | /* relying party */ | ||
74 | r = fido_cred_set_rp(cred, "localhost", "sweet home localhost"); | ||
75 | if (r != FIDO_OK) | ||
76 | errx(1, "fido_cred_set_rp: %s (0x%x)", fido_strerr(r), r); | ||
77 | |||
78 | /* authdata */ | ||
79 | r = fido_cred_set_authdata(cred, authdata_ptr, authdata_len); | ||
80 | if (r != FIDO_OK) | ||
81 | errx(1, "fido_cred_set_authdata: %s (0x%x)", fido_strerr(r), r); | ||
82 | |||
83 | /* extensions */ | ||
84 | r = fido_cred_set_extensions(cred, ext); | ||
85 | if (r != FIDO_OK) | ||
86 | errx(1, "fido_cred_set_extensions: %s (0x%x)", fido_strerr(r), r); | ||
87 | |||
88 | /* resident key */ | ||
89 | if (rk && (r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK) | ||
90 | errx(1, "fido_cred_set_rk: %s (0x%x)", fido_strerr(r), r); | ||
91 | |||
92 | /* user verification */ | ||
93 | if (uv && (r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) | ||
94 | errx(1, "fido_cred_set_uv: %s (0x%x)", fido_strerr(r), r); | ||
95 | |||
96 | /* x509 */ | ||
97 | r = fido_cred_set_x509(cred, x509_ptr, x509_len); | ||
98 | if (r != FIDO_OK) | ||
99 | errx(1, "fido_cred_set_x509: %s (0x%x)", fido_strerr(r), r); | ||
100 | |||
101 | /* sig */ | ||
102 | r = fido_cred_set_sig(cred, sig_ptr, sig_len); | ||
103 | if (r != FIDO_OK) | ||
104 | errx(1, "fido_cred_set_sig: %s (0x%x)", fido_strerr(r), r); | ||
105 | |||
106 | /* fmt */ | ||
107 | r = fido_cred_set_fmt(cred, fmt); | ||
108 | if (r != FIDO_OK) | ||
109 | errx(1, "fido_cred_set_fmt: %s (0x%x)", fido_strerr(r), r); | ||
110 | |||
111 | r = fido_cred_verify(cred); | ||
112 | if (r != FIDO_OK) | ||
113 | errx(1, "fido_cred_verify: %s (0x%x)", fido_strerr(r), r); | ||
114 | |||
115 | if (key_out != NULL) { | ||
116 | /* extract the credential pubkey */ | ||
117 | if (type == COSE_ES256) { | ||
118 | if (write_ec_pubkey(key_out, fido_cred_pubkey_ptr(cred), | ||
119 | fido_cred_pubkey_len(cred)) < 0) | ||
120 | errx(1, "write_ec_pubkey"); | ||
121 | } else if (type == COSE_RS256) { | ||
122 | if (write_rsa_pubkey(key_out, fido_cred_pubkey_ptr(cred), | ||
123 | fido_cred_pubkey_len(cred)) < 0) | ||
124 | errx(1, "write_rsa_pubkey"); | ||
125 | } else if (type == COSE_EDDSA) { | ||
126 | if (write_eddsa_pubkey(key_out, fido_cred_pubkey_ptr(cred), | ||
127 | fido_cred_pubkey_len(cred)) < 0) | ||
128 | errx(1, "write_eddsa_pubkey"); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | if (id_out != NULL) { | ||
133 | /* extract the credential id */ | ||
134 | if (write_blob(id_out, fido_cred_id_ptr(cred), | ||
135 | fido_cred_id_len(cred)) < 0) | ||
136 | errx(1, "write_blob"); | ||
137 | } | ||
138 | |||
139 | fido_cred_free(&cred); | ||
140 | } | ||
141 | |||
142 | int | ||
143 | main(int argc, char **argv) | ||
144 | { | ||
145 | bool rk = false; | ||
146 | bool uv = false; | ||
147 | bool u2f = false; | ||
148 | fido_dev_t *dev; | ||
149 | fido_cred_t *cred = NULL; | ||
150 | const char *pin = NULL; | ||
151 | const char *key_out = NULL; | ||
152 | const char *id_out = NULL; | ||
153 | unsigned char *body = NULL; | ||
154 | long long seconds = 0; | ||
155 | size_t len; | ||
156 | int type = COSE_ES256; | ||
157 | int ext = 0; | ||
158 | int ch; | ||
159 | int r; | ||
160 | |||
161 | if ((cred = fido_cred_new()) == NULL) | ||
162 | errx(1, "fido_cred_new"); | ||
163 | |||
164 | while ((ch = getopt(argc, argv, "P:T:e:hi:k:rt:uv")) != -1) { | ||
165 | switch (ch) { | ||
166 | case 'P': | ||
167 | pin = optarg; | ||
168 | break; | ||
169 | case 'T': | ||
170 | #ifndef SIGNAL_EXAMPLE | ||
171 | errx(1, "-T not supported"); | ||
172 | #endif | ||
173 | if (base10(optarg, &seconds) < 0) | ||
174 | errx(1, "base10: %s", optarg); | ||
175 | if (seconds <= 0 || seconds > 30) | ||
176 | errx(1, "-T: %s must be in (0,30]", optarg); | ||
177 | break; | ||
178 | case 'e': | ||
179 | if (read_blob(optarg, &body, &len) < 0) | ||
180 | errx(1, "read_blob: %s", optarg); | ||
181 | r = fido_cred_exclude(cred, body, len); | ||
182 | if (r != FIDO_OK) | ||
183 | errx(1, "fido_cred_exclude: %s (0x%x)", | ||
184 | fido_strerr(r), r); | ||
185 | free(body); | ||
186 | body = NULL; | ||
187 | break; | ||
188 | case 'h': | ||
189 | ext = FIDO_EXT_HMAC_SECRET; | ||
190 | break; | ||
191 | case 'i': | ||
192 | id_out = optarg; | ||
193 | break; | ||
194 | case 'k': | ||
195 | key_out = optarg; | ||
196 | break; | ||
197 | case 'r': | ||
198 | rk = true; | ||
199 | break; | ||
200 | case 't': | ||
201 | if (strcmp(optarg, "ecdsa") == 0) | ||
202 | type = COSE_ES256; | ||
203 | else if (strcmp(optarg, "rsa") == 0) | ||
204 | type = COSE_RS256; | ||
205 | else if (strcmp(optarg, "eddsa") == 0) | ||
206 | type = COSE_EDDSA; | ||
207 | else | ||
208 | errx(1, "unknown type %s", optarg); | ||
209 | break; | ||
210 | case 'u': | ||
211 | u2f = true; | ||
212 | break; | ||
213 | case 'v': | ||
214 | uv = true; | ||
215 | break; | ||
216 | default: | ||
217 | usage(); | ||
218 | } | ||
219 | } | ||
220 | |||
221 | argc -= optind; | ||
222 | argv += optind; | ||
223 | |||
224 | if (argc != 1) | ||
225 | usage(); | ||
226 | |||
227 | fido_init(0); | ||
228 | |||
229 | if ((dev = fido_dev_new()) == NULL) | ||
230 | errx(1, "fido_dev_new"); | ||
231 | |||
232 | if ((r = fido_dev_open(dev, argv[0])) != FIDO_OK) | ||
233 | errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); | ||
234 | if (u2f) | ||
235 | fido_dev_force_u2f(dev); | ||
236 | |||
237 | /* type */ | ||
238 | r = fido_cred_set_type(cred, type); | ||
239 | if (r != FIDO_OK) | ||
240 | errx(1, "fido_cred_set_type: %s (0x%x)", fido_strerr(r), r); | ||
241 | |||
242 | /* client data hash */ | ||
243 | r = fido_cred_set_clientdata_hash(cred, cdh, sizeof(cdh)); | ||
244 | if (r != FIDO_OK) | ||
245 | errx(1, "fido_cred_set_clientdata_hash: %s (0x%x)", | ||
246 | fido_strerr(r), r); | ||
247 | |||
248 | /* relying party */ | ||
249 | r = fido_cred_set_rp(cred, "localhost", "sweet home localhost"); | ||
250 | if (r != FIDO_OK) | ||
251 | errx(1, "fido_cred_set_rp: %s (0x%x)", fido_strerr(r), r); | ||
252 | |||
253 | /* user */ | ||
254 | r = fido_cred_set_user(cred, user_id, sizeof(user_id), "john smith", | ||
255 | "jsmith", NULL); | ||
256 | if (r != FIDO_OK) | ||
257 | errx(1, "fido_cred_set_user: %s (0x%x)", fido_strerr(r), r); | ||
258 | |||
259 | /* extensions */ | ||
260 | r = fido_cred_set_extensions(cred, ext); | ||
261 | if (r != FIDO_OK) | ||
262 | errx(1, "fido_cred_set_extensions: %s (0x%x)", fido_strerr(r), r); | ||
263 | |||
264 | /* resident key */ | ||
265 | if (rk && (r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK) | ||
266 | errx(1, "fido_cred_set_rk: %s (0x%x)", fido_strerr(r), r); | ||
267 | |||
268 | /* user verification */ | ||
269 | if (uv && (r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) | ||
270 | errx(1, "fido_cred_set_uv: %s (0x%x)", fido_strerr(r), r); | ||
271 | |||
272 | #ifdef SIGNAL_EXAMPLE | ||
273 | prepare_signal_handler(SIGINT); | ||
274 | if (seconds) { | ||
275 | prepare_signal_handler(SIGALRM); | ||
276 | alarm((unsigned)seconds); | ||
277 | } | ||
278 | #endif | ||
279 | |||
280 | r = fido_dev_make_cred(dev, cred, pin); | ||
281 | if (r != FIDO_OK) { | ||
282 | #ifdef SIGNAL_EXAMPLE | ||
283 | if (got_signal) | ||
284 | fido_dev_cancel(dev); | ||
285 | #endif | ||
286 | errx(1, "fido_makecred: %s (0x%x)", fido_strerr(r), r); | ||
287 | } | ||
288 | |||
289 | r = fido_dev_close(dev); | ||
290 | if (r != FIDO_OK) | ||
291 | errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); | ||
292 | |||
293 | fido_dev_free(&dev); | ||
294 | |||
295 | verify_cred(type, fido_cred_fmt(cred), fido_cred_authdata_ptr(cred), | ||
296 | fido_cred_authdata_len(cred), fido_cred_x5c_ptr(cred), | ||
297 | fido_cred_x5c_len(cred), fido_cred_sig_ptr(cred), | ||
298 | fido_cred_sig_len(cred), rk, uv, ext, key_out, id_out); | ||
299 | |||
300 | fido_cred_free(&cred); | ||
301 | |||
302 | exit(0); | ||
303 | } | ||
diff --git a/examples/extern.h b/examples/extern.h new file mode 100644 index 0000000..578b8c4 --- /dev/null +++ b/examples/extern.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | #ifndef _EXTERN_H_ | ||
8 | #define _EXTERN_H_ | ||
9 | |||
10 | #include <openssl/ec.h> | ||
11 | #include <openssl/evp.h> | ||
12 | #include <openssl/rsa.h> | ||
13 | |||
14 | #ifdef HAVE_SIGNAL_H | ||
15 | #include <signal.h> | ||
16 | #endif | ||
17 | |||
18 | /* util.c */ | ||
19 | EC_KEY *read_ec_pubkey(const char *); | ||
20 | RSA *read_rsa_pubkey(const char *); | ||
21 | EVP_PKEY *read_eddsa_pubkey(const char *); | ||
22 | int base10(const char *, long long *); | ||
23 | int read_blob(const char *, unsigned char **, size_t *); | ||
24 | int write_blob(const char *, const unsigned char *, size_t); | ||
25 | int write_ec_pubkey(const char *, const void *, size_t); | ||
26 | int write_rsa_pubkey(const char *, const void *, size_t); | ||
27 | int write_eddsa_pubkey(const char *, const void *, size_t); | ||
28 | #ifdef SIGNAL_EXAMPLE | ||
29 | void prepare_signal_handler(int); | ||
30 | #endif | ||
31 | |||
32 | #endif /* _EXTERN_H_ */ | ||
diff --git a/examples/info.c b/examples/info.c new file mode 100644 index 0000000..e79729c --- /dev/null +++ b/examples/info.c | |||
@@ -0,0 +1,216 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <openssl/ec.h> | ||
8 | |||
9 | #include <stdbool.h> | ||
10 | #include <stdint.h> | ||
11 | #include <stdio.h> | ||
12 | #include <stdlib.h> | ||
13 | #include <string.h> | ||
14 | |||
15 | #include "../openbsd-compat/openbsd-compat.h" | ||
16 | |||
17 | #include "fido.h" | ||
18 | |||
19 | /* | ||
20 | * Pretty-print a device's capabilities flags and return the result. | ||
21 | */ | ||
22 | static void | ||
23 | format_flags(char *ret, size_t retlen, uint8_t flags) | ||
24 | { | ||
25 | memset(ret, 0, retlen); | ||
26 | |||
27 | if (flags & FIDO_CAP_WINK) { | ||
28 | if (strlcat(ret, "wink,", retlen) >= retlen) | ||
29 | goto toolong; | ||
30 | } else { | ||
31 | if (strlcat(ret, "nowink,", retlen) >= retlen) | ||
32 | goto toolong; | ||
33 | } | ||
34 | |||
35 | if (flags & FIDO_CAP_CBOR) { | ||
36 | if (strlcat(ret, " cbor,", retlen) >= retlen) | ||
37 | goto toolong; | ||
38 | } else { | ||
39 | if (strlcat(ret, " nocbor,", retlen) >= retlen) | ||
40 | goto toolong; | ||
41 | } | ||
42 | |||
43 | if (flags & FIDO_CAP_NMSG) { | ||
44 | if (strlcat(ret, " nomsg", retlen) >= retlen) | ||
45 | goto toolong; | ||
46 | } else { | ||
47 | if (strlcat(ret, " msg", retlen) >= retlen) | ||
48 | goto toolong; | ||
49 | } | ||
50 | |||
51 | return; | ||
52 | toolong: | ||
53 | strlcpy(ret, "toolong", retlen); | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * Print a FIDO device's attributes on stdout. | ||
58 | */ | ||
59 | static void | ||
60 | print_attr(const fido_dev_t *dev) | ||
61 | { | ||
62 | char flags_txt[128]; | ||
63 | |||
64 | printf("proto: 0x%02x\n", fido_dev_protocol(dev)); | ||
65 | printf("major: 0x%02x\n", fido_dev_major(dev)); | ||
66 | printf("minor: 0x%02x\n", fido_dev_minor(dev)); | ||
67 | printf("build: 0x%02x\n", fido_dev_build(dev)); | ||
68 | |||
69 | format_flags(flags_txt, sizeof(flags_txt), fido_dev_flags(dev)); | ||
70 | printf("caps: 0x%02x (%s)\n", fido_dev_flags(dev), flags_txt); | ||
71 | } | ||
72 | |||
73 | /* | ||
74 | * Auxiliary function to print an array of strings on stdout. | ||
75 | */ | ||
76 | static void | ||
77 | print_str_array(const char *label, char * const *sa, size_t len) | ||
78 | { | ||
79 | if (len == 0) | ||
80 | return; | ||
81 | |||
82 | printf("%s strings: ", label); | ||
83 | |||
84 | for (size_t i = 0; i < len; i++) | ||
85 | printf("%s%s", i > 0 ? ", " : "", sa[i]); | ||
86 | |||
87 | printf("\n"); | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * Auxiliary function to print (char *, bool) pairs on stdout. | ||
92 | */ | ||
93 | static void | ||
94 | print_opt_array(const char *label, char * const *name, const bool *value, | ||
95 | size_t len) | ||
96 | { | ||
97 | if (len == 0) | ||
98 | return; | ||
99 | |||
100 | printf("%s: ", label); | ||
101 | |||
102 | for (size_t i = 0; i < len; i++) | ||
103 | printf("%s%s%s", i > 0 ? ", " : "", | ||
104 | value[i] ? "" : "no", name[i]); | ||
105 | |||
106 | printf("\n"); | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * Auxiliary function to print an authenticator's AAGUID on stdout. | ||
111 | */ | ||
112 | static void | ||
113 | print_aaguid(const unsigned char *buf, size_t buflen) | ||
114 | { | ||
115 | printf("aaguid: "); | ||
116 | |||
117 | while (buflen--) | ||
118 | printf("%02x", *buf++); | ||
119 | |||
120 | printf("\n"); | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * Auxiliary function to print an authenticator's maximum message size on | ||
125 | * stdout. | ||
126 | */ | ||
127 | static void | ||
128 | print_maxmsgsiz(uint64_t maxmsgsiz) | ||
129 | { | ||
130 | printf("maxmsgsiz: %d\n", (int)maxmsgsiz); | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * Auxiliary function to print an array of bytes on stdout. | ||
135 | */ | ||
136 | static void | ||
137 | print_byte_array(const char *label, const uint8_t *ba, size_t len) | ||
138 | { | ||
139 | if (len == 0) | ||
140 | return; | ||
141 | |||
142 | printf("%s: ", label); | ||
143 | |||
144 | for (size_t i = 0; i < len; i++) | ||
145 | printf("%s%u", i > 0 ? ", " : "", (unsigned)ba[i]); | ||
146 | |||
147 | printf("\n"); | ||
148 | } | ||
149 | |||
150 | static void | ||
151 | getinfo(const char *path) | ||
152 | { | ||
153 | fido_dev_t *dev; | ||
154 | fido_cbor_info_t *ci; | ||
155 | int r; | ||
156 | |||
157 | fido_init(0); | ||
158 | |||
159 | if ((dev = fido_dev_new()) == NULL) | ||
160 | errx(1, "fido_dev_new"); | ||
161 | if ((r = fido_dev_open(dev, path)) != FIDO_OK) | ||
162 | errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); | ||
163 | |||
164 | print_attr(dev); | ||
165 | |||
166 | if (fido_dev_is_fido2(dev) == false) | ||
167 | goto end; | ||
168 | if ((ci = fido_cbor_info_new()) == NULL) | ||
169 | errx(1, "fido_cbor_info_new"); | ||
170 | if ((r = fido_dev_get_cbor_info(dev, ci)) != FIDO_OK) | ||
171 | errx(1, "fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r); | ||
172 | |||
173 | /* print supported protocol versions */ | ||
174 | print_str_array("version", fido_cbor_info_versions_ptr(ci), | ||
175 | fido_cbor_info_versions_len(ci)); | ||
176 | |||
177 | /* print supported extensions */ | ||
178 | print_str_array("extension", fido_cbor_info_extensions_ptr(ci), | ||
179 | fido_cbor_info_extensions_len(ci)); | ||
180 | |||
181 | /* print aaguid */ | ||
182 | print_aaguid(fido_cbor_info_aaguid_ptr(ci), | ||
183 | fido_cbor_info_aaguid_len(ci)); | ||
184 | |||
185 | /* print supported options */ | ||
186 | print_opt_array("options", fido_cbor_info_options_name_ptr(ci), | ||
187 | fido_cbor_info_options_value_ptr(ci), | ||
188 | fido_cbor_info_options_len(ci)); | ||
189 | |||
190 | /* print maximum message size */ | ||
191 | print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci)); | ||
192 | |||
193 | /* print supported pin protocols */ | ||
194 | print_byte_array("pin protocols", fido_cbor_info_protocols_ptr(ci), | ||
195 | fido_cbor_info_protocols_len(ci)); | ||
196 | |||
197 | fido_cbor_info_free(&ci); | ||
198 | end: | ||
199 | if ((r = fido_dev_close(dev)) != FIDO_OK) | ||
200 | errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); | ||
201 | |||
202 | fido_dev_free(&dev); | ||
203 | } | ||
204 | |||
205 | int | ||
206 | main(int argc, char **argv) | ||
207 | { | ||
208 | if (argc != 2) { | ||
209 | fprintf(stderr, "usage: info <device>\n"); | ||
210 | exit(EXIT_FAILURE); | ||
211 | } | ||
212 | |||
213 | getinfo(argv[1]); | ||
214 | |||
215 | exit(0); | ||
216 | } | ||
diff --git a/examples/manifest.c b/examples/manifest.c new file mode 100644 index 0000000..895447a --- /dev/null +++ b/examples/manifest.c | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <openssl/ec.h> | ||
8 | |||
9 | #include <stdbool.h> | ||
10 | #include <stdio.h> | ||
11 | #include <stdlib.h> | ||
12 | |||
13 | #include "../openbsd-compat/openbsd-compat.h" | ||
14 | |||
15 | #include "fido.h" | ||
16 | |||
17 | int | ||
18 | main(void) | ||
19 | { | ||
20 | fido_dev_info_t *devlist; | ||
21 | size_t ndevs; | ||
22 | int r; | ||
23 | |||
24 | fido_init(0); | ||
25 | |||
26 | if ((devlist = fido_dev_info_new(64)) == NULL) | ||
27 | errx(1, "fido_dev_info_new"); | ||
28 | |||
29 | if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK) | ||
30 | errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r); | ||
31 | |||
32 | for (size_t i = 0; i < ndevs; i++) { | ||
33 | const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i); | ||
34 | printf("%s: vendor=0x%04x, product=0x%04x (%s %s)\n", | ||
35 | fido_dev_info_path(di), | ||
36 | (uint16_t)fido_dev_info_vendor(di), | ||
37 | (uint16_t)fido_dev_info_product(di), | ||
38 | fido_dev_info_manufacturer_string(di), | ||
39 | fido_dev_info_product_string(di)); | ||
40 | } | ||
41 | |||
42 | fido_dev_info_free(&devlist, ndevs); | ||
43 | |||
44 | exit(0); | ||
45 | } | ||
diff --git a/examples/reset.c b/examples/reset.c new file mode 100644 index 0000000..36a7de2 --- /dev/null +++ b/examples/reset.c | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | /* | ||
8 | * Perform a factory reset on a given authenticator. | ||
9 | */ | ||
10 | |||
11 | #include <openssl/ec.h> | ||
12 | |||
13 | #include <stdbool.h> | ||
14 | #include <stdint.h> | ||
15 | #include <stdio.h> | ||
16 | #include <stdlib.h> | ||
17 | |||
18 | #include "../openbsd-compat/openbsd-compat.h" | ||
19 | |||
20 | #include "fido.h" | ||
21 | #include "extern.h" | ||
22 | |||
23 | #ifdef SIGNAL_EXAMPLE | ||
24 | extern volatile sig_atomic_t got_signal; | ||
25 | #endif | ||
26 | |||
27 | int | ||
28 | main(int argc, char **argv) | ||
29 | { | ||
30 | fido_dev_t *dev; | ||
31 | int r; | ||
32 | |||
33 | if (argc != 2) { | ||
34 | fprintf(stderr, "usage: reset <device>\n"); | ||
35 | exit(EXIT_FAILURE); | ||
36 | } | ||
37 | |||
38 | fido_init(0); | ||
39 | |||
40 | if ((dev = fido_dev_new()) == NULL) | ||
41 | errx(1, "fido_dev_new"); | ||
42 | |||
43 | if ((r = fido_dev_open(dev, argv[1])) != FIDO_OK) | ||
44 | errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); | ||
45 | |||
46 | #ifdef SIGNAL_EXAMPLE | ||
47 | prepare_signal_handler(SIGINT); | ||
48 | #endif | ||
49 | |||
50 | if ((r = fido_dev_reset(dev)) != FIDO_OK) { | ||
51 | #ifdef SIGNAL_EXAMPLE | ||
52 | if (got_signal) | ||
53 | fido_dev_cancel(dev); | ||
54 | #endif | ||
55 | errx(1, "fido_reset: %s (0x%x)", fido_strerr(r), r); | ||
56 | } | ||
57 | |||
58 | if ((r = fido_dev_close(dev)) != FIDO_OK) | ||
59 | errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); | ||
60 | |||
61 | fido_dev_free(&dev); | ||
62 | |||
63 | exit(0); | ||
64 | } | ||
diff --git a/examples/retries.c b/examples/retries.c new file mode 100644 index 0000000..3ed7558 --- /dev/null +++ b/examples/retries.c | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | /* | ||
8 | * Get an authenticator's number of PIN attempts left. | ||
9 | */ | ||
10 | |||
11 | #include <openssl/ec.h> | ||
12 | |||
13 | #include <stdbool.h> | ||
14 | #include <stdio.h> | ||
15 | #include <stdlib.h> | ||
16 | |||
17 | #include "../openbsd-compat/openbsd-compat.h" | ||
18 | |||
19 | #include "fido.h" | ||
20 | |||
21 | int | ||
22 | main(int argc, char **argv) | ||
23 | { | ||
24 | fido_dev_t *dev; | ||
25 | int n; | ||
26 | int r; | ||
27 | |||
28 | if (argc != 2) { | ||
29 | fprintf(stderr, "usage: retries <device>\n"); | ||
30 | exit(EXIT_FAILURE); | ||
31 | } | ||
32 | |||
33 | fido_init(0); | ||
34 | |||
35 | if ((dev = fido_dev_new()) == NULL) | ||
36 | errx(1, "fido_dev_new"); | ||
37 | |||
38 | if ((r = fido_dev_open(dev, argv[1])) != FIDO_OK) | ||
39 | errx(1, "fido_open: %s (0x%x)", fido_strerr(r), r); | ||
40 | |||
41 | if ((r = fido_dev_get_retry_count(dev, &n)) != FIDO_OK) | ||
42 | errx(1, "fido_get_retries: %s (0x%x)", fido_strerr(r), r); | ||
43 | |||
44 | if ((r = fido_dev_close(dev)) != FIDO_OK) | ||
45 | errx(1, "fido_close: %s (0x%x)", fido_strerr(r), r); | ||
46 | |||
47 | fido_dev_free(&dev); | ||
48 | |||
49 | printf("%d\n", n); | ||
50 | |||
51 | exit(0); | ||
52 | } | ||
diff --git a/examples/setpin.c b/examples/setpin.c new file mode 100644 index 0000000..75d3d4a --- /dev/null +++ b/examples/setpin.c | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | /* | ||
8 | * Configure a PIN on a given authenticator. | ||
9 | */ | ||
10 | |||
11 | #include <openssl/ec.h> | ||
12 | |||
13 | #include <stdbool.h> | ||
14 | #include <stdint.h> | ||
15 | #include <stdio.h> | ||
16 | #include <stdlib.h> | ||
17 | |||
18 | #include "../openbsd-compat/openbsd-compat.h" | ||
19 | |||
20 | #include "fido.h" | ||
21 | |||
22 | static void | ||
23 | setpin(const char *path, const char *pin, const char *oldpin) | ||
24 | { | ||
25 | fido_dev_t *dev; | ||
26 | int r; | ||
27 | |||
28 | fido_init(0); | ||
29 | |||
30 | if ((dev = fido_dev_new()) == NULL) | ||
31 | errx(1, "fido_dev_new"); | ||
32 | |||
33 | if ((r = fido_dev_open(dev, path)) != FIDO_OK) | ||
34 | errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); | ||
35 | |||
36 | if ((r = fido_dev_set_pin(dev, pin, oldpin)) != FIDO_OK) | ||
37 | errx(1, "fido_setpin: %s (0x%x)", fido_strerr(r), r); | ||
38 | |||
39 | if ((r = fido_dev_close(dev)) != FIDO_OK) | ||
40 | errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); | ||
41 | |||
42 | fido_dev_free(&dev); | ||
43 | } | ||
44 | |||
45 | int | ||
46 | main(int argc, char **argv) | ||
47 | { | ||
48 | if (argc < 3 || argc > 4) { | ||
49 | fprintf(stderr, "usage: setpin <pin> [oldpin] <device>\n"); | ||
50 | exit(EXIT_FAILURE); | ||
51 | } | ||
52 | |||
53 | if (argc == 3) | ||
54 | setpin(argv[2], argv[1], NULL); | ||
55 | else | ||
56 | setpin(argv[3], argv[1], argv[2]); | ||
57 | |||
58 | exit(0); | ||
59 | } | ||
diff --git a/examples/util.c b/examples/util.c new file mode 100644 index 0000000..2f6a845 --- /dev/null +++ b/examples/util.c | |||
@@ -0,0 +1,415 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <sys/types.h> | ||
8 | #include <sys/stat.h> | ||
9 | |||
10 | #include <openssl/ec.h> | ||
11 | #include <openssl/evp.h> | ||
12 | #include <openssl/pem.h> | ||
13 | |||
14 | #include <errno.h> | ||
15 | #include <fcntl.h> | ||
16 | #include <limits.h> | ||
17 | #include <stdbool.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <string.h> | ||
20 | #ifdef HAVE_SIGNAL_H | ||
21 | #include <signal.h> | ||
22 | #endif | ||
23 | #ifdef HAVE_UNISTD_H | ||
24 | #include <unistd.h> | ||
25 | #endif | ||
26 | #ifdef _MSC_VER | ||
27 | #include "../openbsd-compat/posix_win.h" | ||
28 | #endif | ||
29 | |||
30 | #include "../openbsd-compat/openbsd-compat.h" | ||
31 | |||
32 | #include "fido.h" | ||
33 | #include "fido/es256.h" | ||
34 | #include "fido/rs256.h" | ||
35 | #include "fido/eddsa.h" | ||
36 | #include "extern.h" | ||
37 | |||
38 | #ifdef SIGNAL_EXAMPLE | ||
39 | volatile sig_atomic_t got_signal = 0; | ||
40 | |||
41 | static void | ||
42 | signal_handler(int signo) | ||
43 | { | ||
44 | (void)signo; | ||
45 | got_signal = 1; | ||
46 | } | ||
47 | |||
48 | void | ||
49 | prepare_signal_handler(int signo) | ||
50 | { | ||
51 | struct sigaction sa; | ||
52 | |||
53 | memset(&sa, 0, sizeof(sa)); | ||
54 | |||
55 | sigemptyset(&sa.sa_mask); | ||
56 | sa.sa_handler = signal_handler; | ||
57 | |||
58 | if (sigaction(signo, &sa, NULL) < 0) | ||
59 | err(1, "sigaction"); | ||
60 | } | ||
61 | #endif | ||
62 | |||
63 | int | ||
64 | base10(const char *str, long long *ll) | ||
65 | { | ||
66 | char *ep; | ||
67 | |||
68 | *ll = strtoll(str, &ep, 10); | ||
69 | if (str == ep || *ep != '\0') | ||
70 | return (-1); | ||
71 | else if (*ll == LLONG_MIN && errno == ERANGE) | ||
72 | return (-1); | ||
73 | else if (*ll == LLONG_MAX && errno == ERANGE) | ||
74 | return (-1); | ||
75 | |||
76 | return (0); | ||
77 | } | ||
78 | |||
79 | int | ||
80 | write_blob(const char *path, const unsigned char *ptr, size_t len) | ||
81 | { | ||
82 | int fd, ok = -1; | ||
83 | ssize_t n; | ||
84 | |||
85 | if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) { | ||
86 | warn("open %s", path); | ||
87 | goto fail; | ||
88 | } | ||
89 | |||
90 | if ((n = write(fd, ptr, len)) < 0) { | ||
91 | warn("write"); | ||
92 | goto fail; | ||
93 | } | ||
94 | if ((size_t)n != len) { | ||
95 | warnx("write"); | ||
96 | goto fail; | ||
97 | } | ||
98 | |||
99 | ok = 0; | ||
100 | fail: | ||
101 | if (fd != -1) { | ||
102 | close(fd); | ||
103 | } | ||
104 | |||
105 | return (ok); | ||
106 | } | ||
107 | |||
108 | int | ||
109 | read_blob(const char *path, unsigned char **ptr, size_t *len) | ||
110 | { | ||
111 | int fd, ok = -1; | ||
112 | struct stat st; | ||
113 | ssize_t n; | ||
114 | |||
115 | *ptr = NULL; | ||
116 | *len = 0; | ||
117 | |||
118 | if ((fd = open(path, O_RDONLY)) < 0) { | ||
119 | warn("open %s", path); | ||
120 | goto fail; | ||
121 | } | ||
122 | if (fstat(fd, &st) < 0) { | ||
123 | warn("stat %s", path); | ||
124 | goto fail; | ||
125 | } | ||
126 | if (st.st_size < 0) { | ||
127 | warnx("stat %s: invalid size", path); | ||
128 | goto fail; | ||
129 | } | ||
130 | *len = (size_t)st.st_size; | ||
131 | if ((*ptr = malloc(*len)) == NULL) { | ||
132 | warn("malloc"); | ||
133 | goto fail; | ||
134 | } | ||
135 | if ((n = read(fd, *ptr, *len)) < 0) { | ||
136 | warn("read"); | ||
137 | goto fail; | ||
138 | } | ||
139 | if ((size_t)n != *len) { | ||
140 | warnx("read"); | ||
141 | goto fail; | ||
142 | } | ||
143 | |||
144 | ok = 0; | ||
145 | fail: | ||
146 | if (fd != -1) { | ||
147 | close(fd); | ||
148 | } | ||
149 | if (ok < 0) { | ||
150 | free(*ptr); | ||
151 | *ptr = NULL; | ||
152 | *len = 0; | ||
153 | } | ||
154 | |||
155 | return (ok); | ||
156 | } | ||
157 | |||
158 | EC_KEY * | ||
159 | read_ec_pubkey(const char *path) | ||
160 | { | ||
161 | FILE *fp = NULL; | ||
162 | EVP_PKEY *pkey = NULL; | ||
163 | EC_KEY *ec = NULL; | ||
164 | |||
165 | if ((fp = fopen(path, "r")) == NULL) { | ||
166 | warn("fopen"); | ||
167 | goto fail; | ||
168 | } | ||
169 | |||
170 | if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { | ||
171 | warnx("PEM_read_PUBKEY"); | ||
172 | goto fail; | ||
173 | } | ||
174 | if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { | ||
175 | warnx("EVP_PKEY_get1_EC_KEY"); | ||
176 | goto fail; | ||
177 | } | ||
178 | |||
179 | fail: | ||
180 | if (fp != NULL) { | ||
181 | fclose(fp); | ||
182 | } | ||
183 | if (pkey != NULL) { | ||
184 | EVP_PKEY_free(pkey); | ||
185 | } | ||
186 | |||
187 | return (ec); | ||
188 | } | ||
189 | |||
190 | int | ||
191 | write_ec_pubkey(const char *path, const void *ptr, size_t len) | ||
192 | { | ||
193 | FILE *fp = NULL; | ||
194 | EVP_PKEY *pkey = NULL; | ||
195 | es256_pk_t *pk = NULL; | ||
196 | int fd = -1; | ||
197 | int ok = -1; | ||
198 | |||
199 | if ((pk = es256_pk_new()) == NULL) { | ||
200 | warnx("es256_pk_new"); | ||
201 | goto fail; | ||
202 | } | ||
203 | |||
204 | if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { | ||
205 | warnx("es256_pk_from_ptr"); | ||
206 | goto fail; | ||
207 | } | ||
208 | |||
209 | if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) { | ||
210 | warn("open %s", path); | ||
211 | goto fail; | ||
212 | } | ||
213 | |||
214 | if ((fp = fdopen(fd, "w")) == NULL) { | ||
215 | warn("fdopen"); | ||
216 | goto fail; | ||
217 | } | ||
218 | fd = -1; /* owned by fp now */ | ||
219 | |||
220 | if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) { | ||
221 | warnx("es256_pk_to_EVP_PKEY"); | ||
222 | goto fail; | ||
223 | } | ||
224 | |||
225 | if (PEM_write_PUBKEY(fp, pkey) == 0) { | ||
226 | warnx("PEM_write_PUBKEY"); | ||
227 | goto fail; | ||
228 | } | ||
229 | |||
230 | ok = 0; | ||
231 | fail: | ||
232 | es256_pk_free(&pk); | ||
233 | |||
234 | if (fp != NULL) { | ||
235 | fclose(fp); | ||
236 | } | ||
237 | if (fd != -1) { | ||
238 | close(fd); | ||
239 | } | ||
240 | if (pkey != NULL) { | ||
241 | EVP_PKEY_free(pkey); | ||
242 | } | ||
243 | |||
244 | return (ok); | ||
245 | } | ||
246 | |||
247 | RSA * | ||
248 | read_rsa_pubkey(const char *path) | ||
249 | { | ||
250 | FILE *fp = NULL; | ||
251 | EVP_PKEY *pkey = NULL; | ||
252 | RSA *rsa = NULL; | ||
253 | |||
254 | if ((fp = fopen(path, "r")) == NULL) { | ||
255 | warn("fopen"); | ||
256 | goto fail; | ||
257 | } | ||
258 | |||
259 | if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { | ||
260 | warnx("PEM_read_PUBKEY"); | ||
261 | goto fail; | ||
262 | } | ||
263 | if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) { | ||
264 | warnx("EVP_PKEY_get1_RSA"); | ||
265 | goto fail; | ||
266 | } | ||
267 | |||
268 | fail: | ||
269 | if (fp != NULL) { | ||
270 | fclose(fp); | ||
271 | } | ||
272 | if (pkey != NULL) { | ||
273 | EVP_PKEY_free(pkey); | ||
274 | } | ||
275 | |||
276 | return (rsa); | ||
277 | } | ||
278 | |||
279 | int | ||
280 | write_rsa_pubkey(const char *path, const void *ptr, size_t len) | ||
281 | { | ||
282 | FILE *fp = NULL; | ||
283 | EVP_PKEY *pkey = NULL; | ||
284 | rs256_pk_t *pk = NULL; | ||
285 | int fd = -1; | ||
286 | int ok = -1; | ||
287 | |||
288 | if ((pk = rs256_pk_new()) == NULL) { | ||
289 | warnx("rs256_pk_new"); | ||
290 | goto fail; | ||
291 | } | ||
292 | |||
293 | if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { | ||
294 | warnx("rs256_pk_from_ptr"); | ||
295 | goto fail; | ||
296 | } | ||
297 | |||
298 | if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) { | ||
299 | warn("open %s", path); | ||
300 | goto fail; | ||
301 | } | ||
302 | |||
303 | if ((fp = fdopen(fd, "w")) == NULL) { | ||
304 | warn("fdopen"); | ||
305 | goto fail; | ||
306 | } | ||
307 | fd = -1; /* owned by fp now */ | ||
308 | |||
309 | if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) { | ||
310 | warnx("rs256_pk_to_EVP_PKEY"); | ||
311 | goto fail; | ||
312 | } | ||
313 | |||
314 | if (PEM_write_PUBKEY(fp, pkey) == 0) { | ||
315 | warnx("PEM_write_PUBKEY"); | ||
316 | goto fail; | ||
317 | } | ||
318 | |||
319 | ok = 0; | ||
320 | fail: | ||
321 | rs256_pk_free(&pk); | ||
322 | |||
323 | if (fp != NULL) { | ||
324 | fclose(fp); | ||
325 | } | ||
326 | if (fd != -1) { | ||
327 | close(fd); | ||
328 | } | ||
329 | if (pkey != NULL) { | ||
330 | EVP_PKEY_free(pkey); | ||
331 | } | ||
332 | |||
333 | return (ok); | ||
334 | } | ||
335 | |||
336 | EVP_PKEY * | ||
337 | read_eddsa_pubkey(const char *path) | ||
338 | { | ||
339 | FILE *fp = NULL; | ||
340 | EVP_PKEY *pkey = NULL; | ||
341 | |||
342 | if ((fp = fopen(path, "r")) == NULL) { | ||
343 | warn("fopen"); | ||
344 | goto fail; | ||
345 | } | ||
346 | |||
347 | if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { | ||
348 | warnx("PEM_read_PUBKEY"); | ||
349 | goto fail; | ||
350 | } | ||
351 | |||
352 | fail: | ||
353 | if (fp) { | ||
354 | fclose(fp); | ||
355 | } | ||
356 | |||
357 | return (pkey); | ||
358 | } | ||
359 | |||
360 | int | ||
361 | write_eddsa_pubkey(const char *path, const void *ptr, size_t len) | ||
362 | { | ||
363 | FILE *fp = NULL; | ||
364 | EVP_PKEY *pkey = NULL; | ||
365 | eddsa_pk_t *pk = NULL; | ||
366 | int fd = -1; | ||
367 | int ok = -1; | ||
368 | |||
369 | if ((pk = eddsa_pk_new()) == NULL) { | ||
370 | warnx("eddsa_pk_new"); | ||
371 | goto fail; | ||
372 | } | ||
373 | |||
374 | if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) { | ||
375 | warnx("eddsa_pk_from_ptr"); | ||
376 | goto fail; | ||
377 | } | ||
378 | |||
379 | if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) { | ||
380 | warn("open %s", path); | ||
381 | goto fail; | ||
382 | } | ||
383 | |||
384 | if ((fp = fdopen(fd, "w")) == NULL) { | ||
385 | warn("fdopen"); | ||
386 | goto fail; | ||
387 | } | ||
388 | fd = -1; /* owned by fp now */ | ||
389 | |||
390 | if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { | ||
391 | warnx("eddsa_pk_to_EVP_PKEY"); | ||
392 | goto fail; | ||
393 | } | ||
394 | |||
395 | if (PEM_write_PUBKEY(fp, pkey) == 0) { | ||
396 | warnx("PEM_write_PUBKEY"); | ||
397 | goto fail; | ||
398 | } | ||
399 | |||
400 | ok = 0; | ||
401 | fail: | ||
402 | eddsa_pk_free(&pk); | ||
403 | |||
404 | if (fp != NULL) { | ||
405 | fclose(fp); | ||
406 | } | ||
407 | if (fd != -1) { | ||
408 | close(fd); | ||
409 | } | ||
410 | if (pkey != NULL) { | ||
411 | EVP_PKEY_free(pkey); | ||
412 | } | ||
413 | |||
414 | return (ok); | ||
415 | } | ||
diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt new file mode 100644 index 0000000..ad30aa3 --- /dev/null +++ b/fuzz/CMakeLists.txt | |||
@@ -0,0 +1,44 @@ | |||
1 | # Copyright (c) 2019 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 | list(APPEND COMPAT_SOURCES | ||
6 | ../openbsd-compat/strlcpy.c | ||
7 | ../openbsd-compat/strlcat.c | ||
8 | ) | ||
9 | |||
10 | list(APPEND COMMON_SOURCES | ||
11 | mutator_aux.c | ||
12 | uniform_random.c | ||
13 | ) | ||
14 | |||
15 | |||
16 | # fuzz_cred | ||
17 | add_executable(fuzz_cred fuzz_cred.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) | ||
18 | target_compile_options(fuzz_cred PRIVATE ${FUZZ_LDFLAGS}) | ||
19 | set_target_properties(fuzz_cred PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) | ||
20 | target_link_libraries(fuzz_cred fido2_shared) | ||
21 | |||
22 | # fuzz_assert | ||
23 | add_executable(fuzz_assert fuzz_assert.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) | ||
24 | target_compile_options(fuzz_assert PRIVATE ${FUZZ_LDFLAGS}) | ||
25 | set_target_properties(fuzz_assert PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) | ||
26 | target_link_libraries(fuzz_assert fido2_shared) | ||
27 | |||
28 | # fuzz_mgmt | ||
29 | add_executable(fuzz_mgmt fuzz_mgmt.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) | ||
30 | target_compile_options(fuzz_mgmt PRIVATE ${FUZZ_LDFLAGS}) | ||
31 | set_target_properties(fuzz_mgmt PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) | ||
32 | target_link_libraries(fuzz_mgmt fido2_shared) | ||
33 | |||
34 | # fuzz_credman | ||
35 | add_executable(fuzz_credman fuzz_credman.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) | ||
36 | target_compile_options(fuzz_credman PRIVATE ${FUZZ_LDFLAGS}) | ||
37 | set_target_properties(fuzz_credman PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) | ||
38 | target_link_libraries(fuzz_credman fido2_shared) | ||
39 | |||
40 | # fuzz_bio | ||
41 | add_executable(fuzz_bio fuzz_bio.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) | ||
42 | target_compile_options(fuzz_bio PRIVATE ${FUZZ_LDFLAGS}) | ||
43 | set_target_properties(fuzz_bio PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) | ||
44 | target_link_libraries(fuzz_bio fido2_shared) | ||
diff --git a/fuzz/README b/fuzz/README new file mode 100644 index 0000000..ecb02bb --- /dev/null +++ b/fuzz/README | |||
@@ -0,0 +1,157 @@ | |||
1 | libfido2 can be fuzzed using AFL or libFuzzer, with or without | ||
2 | ASAN/MSAN/UBSAN. | ||
3 | |||
4 | AFL is more convenient when fuzzing the path from the authenticator to | ||
5 | libfido2 in an existing application. To do so, use preload-snoop.c with a real | ||
6 | authenticator to obtain an initial corpus, rebuild libfido2 with -DFUZZ=1 | ||
7 | -DAFL=1, and use preload-fuzz.c to read device data from stdin. Examples of | ||
8 | this approach can be found in the harnesses under fuzz/harnesses/ that fuzz | ||
9 | the standalone examples and tools bundled with libfido2. | ||
10 | |||
11 | libFuzzer is better suited for bespoke fuzzers; see fuzz_cred.c, fuzz_credman.c, | ||
12 | fuzz_assert.c, and fuzz_mgmt.c for examples. To build these harnesses, | ||
13 | use -DFUZZ=1 -DLIBFUZZER=1. | ||
14 | |||
15 | To run under ASAN/MSAN/UBSAN, libfido2 needs to be linked against flavours of | ||
16 | libcbor and OpenSSL built with the respective sanitiser. In order to keep | ||
17 | memory utilisation at a manageable level, you can either enforce limits at | ||
18 | the OS level (e.g. cgroups on Linux) or, alternatively, patch libcbor with | ||
19 | the diff at the bottom of this file. | ||
20 | |||
21 | 1. 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 | |||
27 | 1.1 Decide where your workspace will live | ||
28 | |||
29 | $ export FAKEROOT=/home/pedro/fakeroot | ||
30 | $ mkdir -p ${FAKEROOT}/src | ||
31 | |||
32 | 1.2 Building libcbor with ASAN | ||
33 | |||
34 | $ git clone https://github.com/pjk/libcbor ${FAKEROOT}/src/libcbor | ||
35 | $ cd ${FAKEROOT}/src/libcbor | ||
36 | |||
37 | Assuming 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 | |||
49 | 1.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 | |||
59 | 1.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 | |||
72 | 2. 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 | |||
78 | 2.1 Decide where your workspace will live | ||
79 | |||
80 | $ export FAKEROOT=/home/pedro/fakeroot | ||
81 | $ mkdir -p ${FAKEROOT}/src | ||
82 | |||
83 | 2.2 Building libcbor with MSAN | ||
84 | |||
85 | $ git clone https://github.com/pjk/libcbor ${FAKEROOT}/src/libcbor | ||
86 | $ cd ${FAKEROOT}/src/libcbor | ||
87 | |||
88 | Assuming 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 | |||
100 | 2.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 | |||
111 | 2.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 | |||
124 | 3. Running the libFuzzer harnesses | ||
125 | |||
126 | When running under ASAN, you may want to set ASAN_OPTIONS to | ||
127 | 'allocator_may_return_null=1:detect_stack_use_after_return=1'. | ||
128 | |||
129 | The 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 -max_len=17408 CORPUS_DIR | ||
133 | |||
134 | You may want to use -jobs or -workers depending on the number of logical | ||
135 | cores available for fuzzing. | ||
136 | |||
137 | 4. Auxiliary scripts | ||
138 | |||
139 | A set of harnesses and auxiliary scripts can be found under harnesses/. To | ||
140 | compile coverage reports, adjust the harnesses to your setup and run 'report'. | ||
141 | |||
142 | diff --git src/cbor/internal/memory_utils.c src/cbor/internal/memory_utils.c | ||
143 | index aa049a2..e294b38 100644 | ||
144 | --- src/cbor/internal/memory_utils.c | ||
145 | +++ src/cbor/internal/memory_utils.c | ||
146 | @@ -28,7 +28,10 @@ bool _cbor_safe_to_multiply(size_t a, size_t b) { | ||
147 | |||
148 | void* _cbor_alloc_multiple(size_t item_size, size_t item_count) { | ||
149 | if (_cbor_safe_to_multiply(item_size, item_count)) { | ||
150 | - return _CBOR_MALLOC(item_size * item_count); | ||
151 | + if (item_count > 1000) { | ||
152 | + return NULL; | ||
153 | + } else | ||
154 | + return _CBOR_MALLOC(item_size * item_count); | ||
155 | } else { | ||
156 | return NULL; | ||
157 | } | ||
diff --git a/fuzz/corpus.tgz b/fuzz/corpus.tgz new file mode 100644 index 0000000..9da3099 --- /dev/null +++ b/fuzz/corpus.tgz | |||
Binary files differ | |||
diff --git a/fuzz/functions.txt b/fuzz/functions.txt new file mode 100644 index 0000000..cd652f2 --- /dev/null +++ b/fuzz/functions.txt | |||
@@ -0,0 +1,564 @@ | |||
1 | File '/home/pedro/projects/libfido2/src/aes256.c': | ||
2 | Name Regions Miss Cover Lines Miss Cover | ||
3 | ----------------------------------------------------------------------------- | ||
4 | aes256_cbc_enc 28 0 100.00% 41 0 100.00% | ||
5 | aes256_cbc_dec 28 0 100.00% 41 0 100.00% | ||
6 | ----------------------------------------------------------------------------- | ||
7 | TOTAL 56 0 100.00% 82 0 100.00% | ||
8 | |||
9 | File '/home/pedro/projects/libfido2/src/assert.c': | ||
10 | Name Regions Miss Cover Lines Miss Cover | ||
11 | --------------------------------------------------------------------------------------- | ||
12 | fido_dev_get_assert 35 3 91.43% 38 4 89.47% | ||
13 | fido_check_flags 13 0 100.00% 18 0 100.00% | ||
14 | fido_verify_sig_es256 17 2 88.24% 31 7 77.42% | ||
15 | fido_verify_sig_rs256 17 2 88.24% 31 7 77.42% | ||
16 | fido_verify_sig_eddsa 23 2 91.30% 43 7 83.72% | ||
17 | fido_assert_verify 48 4 91.67% 79 4 94.94% | ||
18 | fido_assert_set_clientdata_hash 6 0 100.00% 6 0 100.00% | ||
19 | fido_assert_set_hmac_salt 10 0 100.00% 7 0 100.00% | ||
20 | fido_assert_set_rp 12 1 91.67% 14 3 78.57% | ||
21 | fido_assert_allow_cred 13 2 84.62% 29 3 89.66% | ||
22 | fido_assert_set_extensions 9 0 100.00% 8 0 100.00% | ||
23 | fido_assert_set_options 6 6 0.00% 6 6 0.00% | ||
24 | fido_assert_set_up 2 0 100.00% 5 0 100.00% | ||
25 | fido_assert_set_uv 2 0 100.00% 5 0 100.00% | ||
26 | fido_assert_clientdata_hash_ptr 1 0 100.00% 3 0 100.00% | ||
27 | fido_assert_clientdata_hash_len 1 0 100.00% 3 0 100.00% | ||
28 | fido_assert_new 1 0 100.00% 3 0 100.00% | ||
29 | fido_assert_reset_tx 1 0 100.00% 15 0 100.00% | ||
30 | fido_assert_reset_rx 6 0 100.00% 24 0 100.00% | ||
31 | fido_assert_free 6 0 100.00% 13 0 100.00% | ||
32 | fido_assert_count 1 0 100.00% 3 0 100.00% | ||
33 | fido_assert_rp_id 1 0 100.00% 3 0 100.00% | ||
34 | fido_assert_flags 4 0 100.00% 6 0 100.00% | ||
35 | fido_assert_sigcount 4 0 100.00% 6 0 100.00% | ||
36 | fido_assert_authdata_ptr 4 0 100.00% 6 0 100.00% | ||
37 | fido_assert_authdata_len 4 0 100.00% 6 0 100.00% | ||
38 | fido_assert_sig_ptr 4 0 100.00% 6 0 100.00% | ||
39 | fido_assert_sig_len 4 0 100.00% 6 0 100.00% | ||
40 | fido_assert_id_ptr 4 0 100.00% 6 0 100.00% | ||
41 | fido_assert_id_len 4 0 100.00% 6 0 100.00% | ||
42 | fido_assert_user_id_ptr 4 0 100.00% 6 0 100.00% | ||
43 | fido_assert_user_id_len 4 0 100.00% 6 0 100.00% | ||
44 | fido_assert_user_icon 4 0 100.00% 6 0 100.00% | ||
45 | fido_assert_user_name 4 0 100.00% 6 0 100.00% | ||
46 | fido_assert_user_display_name 4 0 100.00% 6 0 100.00% | ||
47 | fido_assert_hmac_secret_ptr 4 0 100.00% 6 0 100.00% | ||
48 | fido_assert_hmac_secret_len 4 0 100.00% 6 0 100.00% | ||
49 | fido_assert_set_authdata 24 0 100.00% 35 0 100.00% | ||
50 | fido_assert_set_authdata_raw 24 0 100.00% 34 0 100.00% | ||
51 | fido_assert_set_sig 14 0 100.00% 17 0 100.00% | ||
52 | fido_assert_set_count 10 0 100.00% 21 0 100.00% | ||
53 | assert.c:fido_dev_get_assert_wait 21 0 100.00% 16 0 100.00% | ||
54 | assert.c:fido_dev_get_assert_tx 58 4 93.10% 84 11 86.90% | ||
55 | assert.c:fido_dev_get_assert_rx 20 0 100.00% 38 0 100.00% | ||
56 | assert.c:adjust_assert_count 24 0 100.00% 33 0 100.00% | ||
57 | assert.c:parse_assert_reply 11 0 100.00% 25 0 100.00% | ||
58 | assert.c:fido_get_next_assert_tx 9 0 100.00% 11 0 100.00% | ||
59 | assert.c:fido_get_next_assert_rx 16 2 87.50% 26 4 84.62% | ||
60 | assert.c:decrypt_hmac_secrets 9 1 88.89% 15 4 73.33% | ||
61 | assert.c:check_extensions 4 0 100.00% 9 0 100.00% | ||
62 | assert.c:get_signed_hash 32 0 100.00% 46 0 100.00% | ||
63 | assert.c:fido_assert_clean_authdata 1 0 100.00% 9 0 100.00% | ||
64 | assert.c:fido_assert_clean_sig 1 0 100.00% 5 0 100.00% | ||
65 | --------------------------------------------------------------------------------------- | ||
66 | TOTAL 569 29 94.90% 901 60 93.34% | ||
67 | |||
68 | File '/home/pedro/projects/libfido2/src/authkey.c': | ||
69 | Name Regions Miss Cover Lines Miss Cover | ||
70 | --------------------------------------------------------------------------------------- | ||
71 | fido_dev_authkey 1 0 100.00% 3 0 100.00% | ||
72 | authkey.c:fido_dev_authkey_wait 10 0 100.00% 9 0 100.00% | ||
73 | authkey.c:fido_dev_authkey_tx 19 0 100.00% 33 0 100.00% | ||
74 | authkey.c:fido_dev_authkey_rx 7 0 100.00% 18 0 100.00% | ||
75 | authkey.c:parse_authkey 8 0 100.00% 12 0 100.00% | ||
76 | --------------------------------------------------------------------------------------- | ||
77 | TOTAL 45 0 100.00% 75 0 100.00% | ||
78 | |||
79 | File '/home/pedro/projects/libfido2/src/bio.c': | ||
80 | Name Regions Miss Cover Lines Miss Cover | ||
81 | --------------------------------------------------------------------------------------- | ||
82 | fido_bio_dev_get_template_array 5 2 60.00% 6 0 100.00% | ||
83 | fido_bio_dev_set_template_name 7 0 100.00% 6 0 100.00% | ||
84 | fido_bio_dev_enroll_begin 24 2 91.67% 36 0 100.00% | ||
85 | fido_bio_dev_enroll_continue 5 2 60.00% 6 0 100.00% | ||
86 | fido_bio_dev_enroll_cancel 1 1 0.00% 3 3 0.00% | ||
87 | fido_bio_dev_enroll_remove 1 0 100.00% 3 0 100.00% | ||
88 | fido_bio_dev_get_info 1 0 100.00% 3 0 100.00% | ||
89 | fido_bio_template_name 1 0 100.00% 3 0 100.00% | ||
90 | fido_bio_template_id_ptr 1 0 100.00% 3 0 100.00% | ||
91 | fido_bio_template_id_len 1 0 100.00% 3 0 100.00% | ||
92 | fido_bio_template_array_count 1 0 100.00% 3 0 100.00% | ||
93 | fido_bio_template_array_new 1 0 100.00% 3 0 100.00% | ||
94 | fido_bio_template_new 1 0 100.00% 3 0 100.00% | ||
95 | fido_bio_template_array_free 6 0 100.00% 10 0 100.00% | ||
96 | fido_bio_template_free 6 0 100.00% 10 0 100.00% | ||
97 | fido_bio_template_set_name 8 0 100.00% 9 0 100.00% | ||
98 | fido_bio_template_set_id 8 0 100.00% 10 0 100.00% | ||
99 | fido_bio_template 4 0 100.00% 6 0 100.00% | ||
100 | fido_bio_enroll_new 1 0 100.00% 3 0 100.00% | ||
101 | fido_bio_info_new 1 0 100.00% 3 0 100.00% | ||
102 | fido_bio_info_type 1 0 100.00% 3 0 100.00% | ||
103 | fido_bio_info_max_samples 1 0 100.00% 3 0 100.00% | ||
104 | fido_bio_enroll_free 6 0 100.00% 11 0 100.00% | ||
105 | fido_bio_info_free 6 0 100.00% 9 0 100.00% | ||
106 | fido_bio_enroll_remaining_samples 1 0 100.00% 3 0 100.00% | ||
107 | fido_bio_enroll_last_status 1 0 100.00% 3 0 100.00% | ||
108 | bio.c:bio_get_template_array_wait 11 0 100.00% 9 0 100.00% | ||
109 | bio.c:bio_tx 43 0 100.00% 65 0 100.00% | ||
110 | bio.c:bio_prepare_hmac 18 0 100.00% 36 0 100.00% | ||
111 | bio.c:bio_rx_template_array 12 0 100.00% 21 0 100.00% | ||
112 | bio.c:bio_parse_template_array 26 1 96.15% 34 4 88.24% | ||
113 | bio.c:decode_template_array 12 1 91.67% 23 3 86.96% | ||
114 | bio.c:decode_template 9 0 100.00% 18 0 100.00% | ||
115 | bio.c:bio_set_template_name_wait 19 0 100.00% 24 0 100.00% | ||
116 | bio.c:bio_enroll_begin_wait 17 1 94.12% 24 3 87.50% | ||
117 | bio.c:bio_rx_enroll_begin 16 0 100.00% 29 0 100.00% | ||
118 | bio.c:bio_parse_enroll_status 20 0 100.00% 31 0 100.00% | ||
119 | bio.c:bio_parse_template_id 8 0 100.00% 12 0 100.00% | ||
120 | bio.c:bio_enroll_continue_wait 19 0 100.00% 25 0 100.00% | ||
121 | bio.c:bio_rx_enroll_continue 12 0 100.00% 22 0 100.00% | ||
122 | bio.c:bio_enroll_cancel_wait 11 11 0.00% 12 12 0.00% | ||
123 | bio.c:bio_enroll_remove_wait 17 0 100.00% 24 0 100.00% | ||
124 | bio.c:bio_get_info_wait 11 0 100.00% 11 0 100.00% | ||
125 | bio.c:bio_rx_info 12 0 100.00% 21 0 100.00% | ||
126 | bio.c:bio_reset_info 1 0 100.00% 4 0 100.00% | ||
127 | bio.c:bio_parse_info 20 0 100.00% 31 0 100.00% | ||
128 | bio.c:bio_reset_template_array 4 0 100.00% 8 0 100.00% | ||
129 | bio.c:bio_reset_template 1 0 100.00% 6 0 100.00% | ||
130 | bio.c:bio_reset_enroll 3 0 100.00% 7 0 100.00% | ||
131 | --------------------------------------------------------------------------------------- | ||
132 | TOTAL 422 21 95.02% 661 25 96.22% | ||
133 | |||
134 | File '/home/pedro/projects/libfido2/src/blob.c': | ||
135 | Name Regions Miss Cover Lines Miss Cover | ||
136 | --------------------------------------------------------------------------------------- | ||
137 | fido_blob_new 1 0 100.00% 3 0 100.00% | ||
138 | fido_blob_set 11 1 90.91% 25 4 84.00% | ||
139 | fido_blob_free 8 0 100.00% 16 0 100.00% | ||
140 | fido_free_blob_array 9 0 100.00% 17 0 100.00% | ||
141 | fido_blob_encode 6 0 100.00% 6 0 100.00% | ||
142 | fido_blob_decode 1 0 100.00% 3 0 100.00% | ||
143 | fido_blob_is_empty 3 0 100.00% 3 0 100.00% | ||
144 | --------------------------------------------------------------------------------------- | ||
145 | TOTAL 39 1 97.44% 73 4 94.52% | ||
146 | |||
147 | File '/home/pedro/projects/libfido2/src/buf.c': | ||
148 | Name Regions Miss Cover Lines Miss Cover | ||
149 | --------------------------------------------------------------------------------------- | ||
150 | fido_buf_read 4 0 100.00% 10 0 100.00% | ||
151 | fido_buf_write 4 1 75.00% 10 1 90.00% | ||
152 | --------------------------------------------------------------------------------------- | ||
153 | TOTAL 8 1 87.50% 20 1 95.00% | ||
154 | |||
155 | File '/home/pedro/projects/libfido2/src/cbor.c': | ||
156 | Name Regions Miss Cover Lines Miss Cover | ||
157 | --------------------------------------------------------------------------------------- | ||
158 | cbor_map_iter 20 1 95.00% 30 4 86.67% | ||
159 | cbor_array_iter 12 0 100.00% 20 0 100.00% | ||
160 | cbor_parse_reply 27 0 100.00% 43 0 100.00% | ||
161 | cbor_vector_free 6 0 100.00% 5 0 100.00% | ||
162 | cbor_bytestring_copy 14 0 100.00% 22 0 100.00% | ||
163 | cbor_string_copy 14 0 100.00% 23 0 100.00% | ||
164 | cbor_add_bytestring 14 0 100.00% 26 0 100.00% | ||
165 | cbor_add_string 14 0 100.00% 26 0 100.00% | ||
166 | cbor_add_bool 14 0 100.00% 26 0 100.00% | ||
167 | cbor_flatten_vector 14 1 92.86% 21 1 95.24% | ||
168 | cbor_build_frame 15 0 100.00% 32 0 100.00% | ||
169 | cbor_encode_rp_entity 13 0 100.00% 14 0 100.00% | ||
170 | cbor_encode_user_entity 21 0 100.00% 18 0 100.00% | ||
171 | cbor_encode_pubkey_param 36 0 100.00% 48 0 100.00% | ||
172 | cbor_encode_pubkey 10 0 100.00% 13 0 100.00% | ||
173 | cbor_encode_pubkey_list 18 2 88.89% 23 0 100.00% | ||
174 | cbor_encode_extensions 13 1 92.31% 16 0 100.00% | ||
175 | cbor_encode_options 13 0 100.00% 14 0 100.00% | ||
176 | cbor_encode_assert_options 13 0 100.00% 14 0 100.00% | ||
177 | cbor_encode_pin_auth 8 0 100.00% 12 0 100.00% | ||
178 | cbor_encode_pin_opt 1 0 100.00% 3 0 100.00% | ||
179 | cbor_encode_pin_enc 4 0 100.00% 12 0 100.00% | ||
180 | cbor_encode_change_pin_auth 44 1 97.73% 69 3 95.65% | ||
181 | cbor_encode_set_pin_auth 17 0 100.00% 28 0 100.00% | ||
182 | cbor_encode_pin_hash_enc 15 0 100.00% 27 0 100.00% | ||
183 | cbor_encode_hmac_secret_param 41 1 97.56% 66 4 93.94% | ||
184 | cbor_decode_fmt 9 0 100.00% 18 0 100.00% | ||
185 | cbor_decode_pubkey 21 1 95.24% 32 2 93.75% | ||
186 | cbor_decode_cred_authdata 31 0 100.00% 46 0 100.00% | ||
187 | cbor_decode_assert_authdata 23 0 100.00% 44 0 100.00% | ||
188 | cbor_decode_attstmt 8 0 100.00% 10 0 100.00% | ||
189 | cbor_decode_uint64 4 0 100.00% 10 0 100.00% | ||
190 | cbor_decode_cred_id 8 0 100.00% 10 0 100.00% | ||
191 | cbor_decode_user 8 0 100.00% 10 0 100.00% | ||
192 | cbor_decode_rp_entity 8 0 100.00% 10 0 100.00% | ||
193 | cbor.c:ctap_check_cbor 28 0 100.00% 32 0 100.00% | ||
194 | cbor.c:check_key_type 8 0 100.00% 9 0 100.00% | ||
195 | cbor.c:cbor_add_arg 13 0 100.00% 28 0 100.00% | ||
196 | cbor.c:sha256 7 0 100.00% 15 0 100.00% | ||
197 | cbor.c:get_cose_alg 36 0 100.00% 48 0 100.00% | ||
198 | cbor.c:find_cose_alg 35 0 100.00% 40 0 100.00% | ||
199 | cbor.c:decode_attcred 25 0 100.00% 58 0 100.00% | ||
200 | cbor.c:decode_extensions 16 4 75.00% 34 6 82.35% | ||
201 | cbor.c:decode_extension 19 19 0.00% 27 27 0.00% | ||
202 | cbor.c:decode_hmac_secret 16 0 100.00% 32 0 100.00% | ||
203 | cbor.c:decode_hmac_secret_aux 7 0 100.00% 17 0 100.00% | ||
204 | cbor.c:decode_attstmt_entry 29 0 100.00% 39 0 100.00% | ||
205 | cbor.c:decode_x5c 4 0 100.00% 8 0 100.00% | ||
206 | cbor.c:decode_cred_id_entry 10 0 100.00% 23 0 100.00% | ||
207 | cbor.c:decode_user_entry 25 0 100.00% 39 0 100.00% | ||
208 | cbor.c:decode_rp_entity_entry 15 0 100.00% 29 0 100.00% | ||
209 | --------------------------------------------------------------------------------------- | ||
210 | TOTAL 844 31 96.33% 1319 47 96.44% | ||
211 | |||
212 | File '/home/pedro/projects/libfido2/src/cred.c': | ||
213 | Name Regions Miss Cover Lines Miss Cover | ||
214 | --------------------------------------------------------------------------------------- | ||
215 | fido_dev_make_cred 12 0 100.00% 9 0 100.00% | ||
216 | fido_check_rp_id 4 0 100.00% 14 0 100.00% | ||
217 | fido_cred_verify 45 0 100.00% 71 0 100.00% | ||
218 | fido_cred_verify_self 54 10 81.48% 90 14 84.44% | ||
219 | fido_cred_new 1 0 100.00% 3 0 100.00% | ||
220 | fido_cred_reset_tx 1 0 100.00% 20 0 100.00% | ||
221 | fido_cred_reset_rx 1 0 100.00% 8 0 100.00% | ||
222 | fido_cred_free 6 1 83.33% 13 0 100.00% | ||
223 | fido_cred_set_authdata 22 0 100.00% 36 0 100.00% | ||
224 | fido_cred_set_authdata_raw 22 2 90.91% 35 4 88.57% | ||
225 | fido_cred_set_x509 12 0 100.00% 16 0 100.00% | ||
226 | fido_cred_set_sig 12 0 100.00% 16 0 100.00% | ||
227 | fido_cred_exclude 14 2 85.71% 25 3 88.00% | ||
228 | fido_cred_set_clientdata_hash 6 0 100.00% 6 0 100.00% | ||
229 | fido_cred_set_rp 18 2 88.89% 26 6 76.92% | ||
230 | fido_cred_set_user 33 4 87.88% 50 13 74.00% | ||
231 | fido_cred_set_extensions 9 0 100.00% 8 0 100.00% | ||
232 | fido_cred_set_options 6 6 0.00% 6 6 0.00% | ||
233 | fido_cred_set_rk 2 0 100.00% 5 0 100.00% | ||
234 | fido_cred_set_uv 2 0 100.00% 5 0 100.00% | ||
235 | fido_cred_set_fmt 16 4 75.00% 15 1 93.33% | ||
236 | fido_cred_set_type 17 2 88.24% 9 1 88.89% | ||
237 | fido_cred_type 1 0 100.00% 3 0 100.00% | ||
238 | fido_cred_flags 1 0 100.00% 3 0 100.00% | ||
239 | fido_cred_clientdata_hash_ptr 1 0 100.00% 3 0 100.00% | ||
240 | fido_cred_clientdata_hash_len 1 0 100.00% 3 0 100.00% | ||
241 | fido_cred_x5c_ptr 1 0 100.00% 3 0 100.00% | ||
242 | fido_cred_x5c_len 1 0 100.00% 3 0 100.00% | ||
243 | fido_cred_sig_ptr 1 0 100.00% 3 0 100.00% | ||
244 | fido_cred_sig_len 1 0 100.00% 3 0 100.00% | ||
245 | fido_cred_authdata_ptr 1 0 100.00% 3 0 100.00% | ||
246 | fido_cred_authdata_len 1 0 100.00% 3 0 100.00% | ||
247 | fido_cred_pubkey_ptr 9 0 100.00% 20 0 100.00% | ||
248 | fido_cred_pubkey_len 9 0 100.00% 20 0 100.00% | ||
249 | fido_cred_id_ptr 1 0 100.00% 3 0 100.00% | ||
250 | fido_cred_id_len 1 0 100.00% 3 0 100.00% | ||
251 | fido_cred_fmt 1 0 100.00% 3 0 100.00% | ||
252 | fido_cred_rp_id 1 0 100.00% 3 0 100.00% | ||
253 | fido_cred_rp_name 1 0 100.00% 3 0 100.00% | ||
254 | fido_cred_user_name 1 0 100.00% 3 0 100.00% | ||
255 | fido_cred_display_name 1 0 100.00% 3 0 100.00% | ||
256 | fido_cred_user_id_ptr 1 0 100.00% 3 0 100.00% | ||
257 | fido_cred_user_id_len 1 0 100.00% 3 0 100.00% | ||
258 | cred.c:fido_dev_make_cred_wait 10 0 100.00% 9 0 100.00% | ||
259 | cred.c:fido_dev_make_cred_tx 59 0 100.00% 81 0 100.00% | ||
260 | cred.c:fido_dev_make_cred_rx 22 0 100.00% 28 0 100.00% | ||
261 | cred.c:parse_makecred_reply 10 0 100.00% 23 0 100.00% | ||
262 | cred.c:check_extensions 4 0 100.00% 9 0 100.00% | ||
263 | cred.c:get_signed_hash_packed 23 1 95.65% 38 3 92.11% | ||
264 | cred.c:get_signed_hash_u2f 22 0 100.00% 20 0 100.00% | ||
265 | cred.c:verify_sig 27 1 96.30% 40 4 90.00% | ||
266 | cred.c:fido_cred_clean_authdata 1 0 100.00% 9 0 100.00% | ||
267 | cred.c:fido_cred_clean_x509 1 0 100.00% 5 0 100.00% | ||
268 | cred.c:fido_cred_clean_sig 1 0 100.00% 5 0 100.00% | ||
269 | --------------------------------------------------------------------------------------- | ||
270 | TOTAL 532 35 93.42% 850 55 93.53% | ||
271 | |||
272 | File '/home/pedro/projects/libfido2/src/credman.c': | ||
273 | Name Regions Miss Cover Lines Miss Cover | ||
274 | --------------------------------------------------------------------------------------- | ||
275 | fido_credman_get_dev_metadata 9 2 77.78% 8 0 100.00% | ||
276 | fido_credman_get_dev_rk 9 2 77.78% 8 0 100.00% | ||
277 | fido_credman_del_dev_rk 9 2 77.78% 8 0 100.00% | ||
278 | fido_credman_get_dev_rp 9 2 77.78% 8 0 100.00% | ||
279 | fido_credman_rk_new 1 0 100.00% 3 0 100.00% | ||
280 | fido_credman_rk_free 6 1 83.33% 10 0 100.00% | ||
281 | fido_credman_rk_count 1 0 100.00% 3 0 100.00% | ||
282 | fido_credman_rk 4 0 100.00% 6 0 100.00% | ||
283 | fido_credman_metadata_new 1 0 100.00% 3 0 100.00% | ||
284 | fido_credman_metadata_free 6 1 83.33% 9 0 100.00% | ||
285 | fido_credman_rk_existing 1 0 100.00% 3 0 100.00% | ||
286 | fido_credman_rk_remaining 1 0 100.00% 3 0 100.00% | ||
287 | fido_credman_rp_new 1 0 100.00% 3 0 100.00% | ||
288 | fido_credman_rp_free 6 1 83.33% 10 0 100.00% | ||
289 | fido_credman_rp_count 1 0 100.00% 3 0 100.00% | ||
290 | fido_credman_rp_id 4 0 100.00% 6 0 100.00% | ||
291 | fido_credman_rp_name 4 0 100.00% 6 0 100.00% | ||
292 | fido_credman_rp_id_hash_len 4 0 100.00% 6 0 100.00% | ||
293 | fido_credman_rp_id_hash_ptr 4 0 100.00% 6 0 100.00% | ||
294 | credman.c:credman_get_metadata_wait 11 0 100.00% 9 0 100.00% | ||
295 | credman.c:credman_tx 30 0 100.00% 53 0 100.00% | ||
296 | credman.c:credman_prepare_hmac 21 1 95.24% 43 2 95.35% | ||
297 | credman.c:credman_rx_metadata 12 0 100.00% 21 0 100.00% | ||
298 | credman.c:credman_parse_metadata 9 0 100.00% 19 0 100.00% | ||
299 | credman.c:credman_get_rk_wait 27 0 100.00% 26 0 100.00% | ||
300 | credman.c:credman_rx_rk 20 0 100.00% 36 0 100.00% | ||
301 | credman.c:credman_parse_rk_count 16 0 100.00% 25 0 100.00% | ||
302 | credman.c:credman_grow_array 17 2 88.24% 28 5 82.14% | ||
303 | credman.c:credman_parse_rk 13 0 100.00% 25 0 100.00% | ||
304 | credman.c:credman_rx_next_rk 16 2 87.50% 26 4 84.62% | ||
305 | credman.c:credman_del_rk_wait 16 0 100.00% 19 0 100.00% | ||
306 | credman.c:credman_get_rp_wait 23 0 100.00% 16 0 100.00% | ||
307 | credman.c:credman_rx_rp 20 0 100.00% 36 0 100.00% | ||
308 | credman.c:credman_parse_rp_count 16 0 100.00% 25 0 100.00% | ||
309 | credman.c:credman_parse_rp 9 0 100.00% 19 0 100.00% | ||
310 | credman.c:credman_rx_next_rp 16 2 87.50% 26 4 84.62% | ||
311 | credman.c:credman_reset_rk 4 0 100.00% 10 0 100.00% | ||
312 | credman.c:credman_reset_rp 4 0 100.00% 15 0 100.00% | ||
313 | --------------------------------------------------------------------------------------- | ||
314 | TOTAL 381 18 95.28% 589 15 97.45% | ||
315 | |||
316 | File '/home/pedro/projects/libfido2/src/dev.c': | ||
317 | Name Regions Miss Cover Lines Miss Cover | ||
318 | --------------------------------------------------------------------------------------- | ||
319 | fido_dev_open 1 0 100.00% 3 0 100.00% | ||
320 | fido_dev_close 8 2 75.00% 9 0 100.00% | ||
321 | fido_dev_cancel 8 2 75.00% 6 3 50.00% | ||
322 | fido_dev_set_io_functions 18 4 77.78% 19 6 68.42% | ||
323 | fido_init 7 1 85.71% 4 0 100.00% | ||
324 | fido_dev_new 9 1 88.89% 22 4 81.82% | ||
325 | fido_dev_free 6 0 100.00% 10 0 100.00% | ||
326 | fido_dev_protocol 1 0 100.00% 3 0 100.00% | ||
327 | fido_dev_major 1 0 100.00% 3 0 100.00% | ||
328 | fido_dev_minor 1 0 100.00% 3 0 100.00% | ||
329 | fido_dev_build 1 0 100.00% 3 0 100.00% | ||
330 | fido_dev_flags 1 0 100.00% 3 0 100.00% | ||
331 | fido_dev_is_fido2 2 0 100.00% 3 0 100.00% | ||
332 | fido_dev_force_u2f 2 0 100.00% 3 0 100.00% | ||
333 | fido_dev_force_fido2 2 2 0.00% 3 3 0.00% | ||
334 | dev.c:fido_dev_open_wait 10 0 100.00% 9 0 100.00% | ||
335 | dev.c:fido_dev_open_tx 26 8 69.23% 32 12 62.50% | ||
336 | dev.c:obtain_nonce 13 2 84.62% 18 2 88.89% | ||
337 | dev.c:fido_dev_open_rx 14 0 100.00% 27 0 100.00% | ||
338 | --------------------------------------------------------------------------------------- | ||
339 | TOTAL 131 22 83.21% 183 30 83.61% | ||
340 | |||
341 | File '/home/pedro/projects/libfido2/src/ecdh.c': | ||
342 | Name Regions Miss Cover Lines Miss Cover | ||
343 | --------------------------------------------------------------------------------------- | ||
344 | fido_do_ecdh 29 0 100.00% 44 0 100.00% | ||
345 | ecdh.c:do_ecdh 39 0 100.00% 60 0 100.00% | ||
346 | --------------------------------------------------------------------------------------- | ||
347 | TOTAL 68 0 100.00% 104 0 100.00% | ||
348 | |||
349 | File '/home/pedro/projects/libfido2/src/eddsa.c': | ||
350 | Name Regions Miss Cover Lines Miss Cover | ||
351 | --------------------------------------------------------------------------------------- | ||
352 | eddsa_pk_decode 8 0 100.00% 10 0 100.00% | ||
353 | eddsa_pk_new 1 0 100.00% 3 0 100.00% | ||
354 | eddsa_pk_free 6 0 100.00% 11 0 100.00% | ||
355 | eddsa_pk_from_ptr 6 0 100.00% 8 0 100.00% | ||
356 | eddsa_pk_to_EVP_PKEY 3 0 100.00% 9 0 100.00% | ||
357 | eddsa_pk_from_EVP_PKEY 14 4 71.43% 12 2 83.33% | ||
358 | eddsa.c:decode_pubkey_point 8 0 100.00% 14 0 100.00% | ||
359 | eddsa.c:decode_coord 8 0 100.00% 12 0 100.00% | ||
360 | --------------------------------------------------------------------------------------- | ||
361 | TOTAL 54 4 92.59% 79 2 97.47% | ||
362 | |||
363 | File '/home/pedro/projects/libfido2/src/err.c': | ||
364 | Name Regions Miss Cover Lines Miss Cover | ||
365 | --------------------------------------------------------------------------------------- | ||
366 | fido_strerr 108 108 0.00% 112 112 0.00% | ||
367 | --------------------------------------------------------------------------------------- | ||
368 | TOTAL 108 108 0.00% 112 112 0.00% | ||
369 | |||
370 | File '/home/pedro/projects/libfido2/src/es256.c': | ||
371 | Name Regions Miss Cover Lines Miss Cover | ||
372 | --------------------------------------------------------------------------------------- | ||
373 | es256_pk_decode 8 0 100.00% 10 0 100.00% | ||
374 | es256_pk_encode 56 0 100.00% 70 0 100.00% | ||
375 | es256_sk_new 1 0 100.00% 3 0 100.00% | ||
376 | es256_sk_free 6 0 100.00% 11 0 100.00% | ||
377 | es256_pk_new 1 0 100.00% 3 0 100.00% | ||
378 | es256_pk_free 6 0 100.00% 11 0 100.00% | ||
379 | es256_pk_from_ptr 6 0 100.00% 8 0 100.00% | ||
380 | es256_pk_set_x 1 0 100.00% 5 0 100.00% | ||
381 | es256_pk_set_y 1 0 100.00% 5 0 100.00% | ||
382 | es256_sk_create 39 2 94.87% 46 6 86.96% | ||
383 | es256_pk_to_EVP_PKEY 41 0 100.00% 58 0 100.00% | ||
384 | es256_pk_from_EC_KEY 38 2 94.74% 39 7 82.05% | ||
385 | es256_sk_to_EVP_PKEY 27 0 100.00% 41 0 100.00% | ||
386 | es256_derive_pk 25 0 100.00% 34 0 100.00% | ||
387 | es256.c:decode_pubkey_point 9 0 100.00% 16 0 100.00% | ||
388 | es256.c:decode_coord 8 0 100.00% 12 0 100.00% | ||
389 | --------------------------------------------------------------------------------------- | ||
390 | TOTAL 273 4 98.53% 372 13 96.51% | ||
391 | |||
392 | File '/home/pedro/projects/libfido2/src/extern.h': | ||
393 | Name Regions Miss Cover Lines Miss Cover | ||
394 | --------------------------------------------------------------------------------------- | ||
395 | |||
396 | File '/home/pedro/projects/libfido2/src/fido.h': | ||
397 | Name Regions Miss Cover Lines Miss Cover | ||
398 | --------------------------------------------------------------------------------------- | ||
399 | |||
400 | File '/home/pedro/projects/libfido2/src/hid.c': | ||
401 | Name Regions Miss Cover Lines Miss Cover | ||
402 | --------------------------------------------------------------------------------------- | ||
403 | fido_dev_info_new 1 1 0.00% 3 3 0.00% | ||
404 | fido_dev_info_free 9 9 0.00% 17 17 0.00% | ||
405 | fido_dev_info_ptr 1 1 0.00% 3 3 0.00% | ||
406 | fido_dev_info_path 1 1 0.00% 3 3 0.00% | ||
407 | fido_dev_info_vendor 1 1 0.00% 3 3 0.00% | ||
408 | fido_dev_info_product 1 1 0.00% 3 3 0.00% | ||
409 | fido_dev_info_manufacturer_string 1 1 0.00% 3 3 0.00% | ||
410 | fido_dev_info_product_string 1 1 0.00% 3 3 0.00% | ||
411 | --------------------------------------------------------------------------------------- | ||
412 | TOTAL 16 16 0.00% 38 38 0.00% | ||
413 | |||
414 | File '/home/pedro/projects/libfido2/src/hid_linux.c': | ||
415 | Name Regions Miss Cover Lines Miss Cover | ||
416 | --------------------------------------------------------------------------------------- | ||
417 | fido_dev_info_manifest 33 33 0.00% 40 40 0.00% | ||
418 | fido_hid_open 6 6 0.00% 11 11 0.00% | ||
419 | fido_hid_close 1 1 0.00% 6 6 0.00% | ||
420 | fido_hid_read 12 12 0.00% 16 16 0.00% | ||
421 | fido_hid_write 12 12 0.00% 16 16 0.00% | ||
422 | hid_linux.c:copy_info 35 35 0.00% 56 56 0.00% | ||
423 | hid_linux.c:is_fido 6 6 0.00% 14 14 0.00% | ||
424 | hid_linux.c:get_report_descriptor 17 17 0.00% 31 31 0.00% | ||
425 | hid_linux.c:get_usage_info 16 16 0.00% 33 33 0.00% | ||
426 | hid_linux.c:get_key_len 6 6 0.00% 14 14 0.00% | ||
427 | hid_linux.c:get_key_val 6 6 0.00% 20 20 0.00% | ||
428 | hid_linux.c:parse_uevent 16 16 0.00% 30 30 0.00% | ||
429 | --------------------------------------------------------------------------------------- | ||
430 | TOTAL 166 166 0.00% 287 287 0.00% | ||
431 | |||
432 | File '/home/pedro/projects/libfido2/src/info.c': | ||
433 | Name Regions Miss Cover Lines Miss Cover | ||
434 | --------------------------------------------------------------------------------------- | ||
435 | fido_dev_get_cbor_info 1 0 100.00% 3 0 100.00% | ||
436 | fido_cbor_info_new 1 0 100.00% 3 0 100.00% | ||
437 | fido_cbor_info_free 6 1 83.33% 14 0 100.00% | ||
438 | fido_cbor_info_versions_ptr 1 0 100.00% 3 0 100.00% | ||
439 | fido_cbor_info_versions_len 1 0 100.00% 3 0 100.00% | ||
440 | fido_cbor_info_extensions_ptr 1 0 100.00% 3 0 100.00% | ||
441 | fido_cbor_info_extensions_len 1 0 100.00% 3 0 100.00% | ||
442 | fido_cbor_info_aaguid_ptr 1 0 100.00% 3 0 100.00% | ||
443 | fido_cbor_info_aaguid_len 1 0 100.00% 3 0 100.00% | ||
444 | fido_cbor_info_options_name_ptr 1 0 100.00% 3 0 100.00% | ||
445 | fido_cbor_info_options_value_ptr 1 0 100.00% 3 0 100.00% | ||
446 | fido_cbor_info_options_len 1 0 100.00% 3 0 100.00% | ||
447 | fido_cbor_info_maxmsgsiz 1 0 100.00% 3 0 100.00% | ||
448 | fido_cbor_info_protocols_ptr 1 0 100.00% 3 0 100.00% | ||
449 | fido_cbor_info_protocols_len 1 0 100.00% 3 0 100.00% | ||
450 | info.c:fido_dev_get_cbor_info_wait 10 0 100.00% 9 0 100.00% | ||
451 | info.c:fido_dev_get_cbor_info_tx 9 0 100.00% 13 0 100.00% | ||
452 | info.c:fido_dev_get_cbor_info_rx 7 0 100.00% 18 0 100.00% | ||
453 | info.c:parse_reply_element 13 0 100.00% 27 0 100.00% | ||
454 | info.c:decode_versions 12 0 100.00% 21 0 100.00% | ||
455 | info.c:decode_version 4 0 100.00% 14 0 100.00% | ||
456 | info.c:decode_extensions 12 0 100.00% 21 0 100.00% | ||
457 | info.c:decode_extension 4 0 100.00% 14 0 100.00% | ||
458 | info.c:decode_aaguid 8 0 100.00% 12 0 100.00% | ||
459 | info.c:decode_options 11 0 100.00% 18 0 100.00% | ||
460 | info.c:decode_option 11 0 100.00% 22 0 100.00% | ||
461 | info.c:decode_protocols 12 0 100.00% 21 0 100.00% | ||
462 | info.c:decode_protocol 6 0 100.00% 16 0 100.00% | ||
463 | info.c:free_str_array 4 0 100.00% 8 0 100.00% | ||
464 | info.c:free_opt_array 4 0 100.00% 9 0 100.00% | ||
465 | info.c:free_byte_array 1 0 100.00% 6 0 100.00% | ||
466 | --------------------------------------------------------------------------------------- | ||
467 | TOTAL 148 1 99.32% 305 0 100.00% | ||
468 | |||
469 | File '/home/pedro/projects/libfido2/src/io.c': | ||
470 | Name Regions Miss Cover Lines Miss Cover | ||
471 | --------------------------------------------------------------------------------------- | ||
472 | fido_tx 18 0 100.00% 35 0 100.00% | ||
473 | fido_rx 34 3 91.18% 84 12 85.71% | ||
474 | fido_rx_cbor_status 9 0 100.00% 13 0 100.00% | ||
475 | io.c:tx_preamble 16 1 93.75% 24 1 95.83% | ||
476 | io.c:tx_frame 16 1 93.75% 21 0 100.00% | ||
477 | io.c:rx_preamble 11 0 100.00% 12 0 100.00% | ||
478 | io.c:rx_frame 9 1 88.89% 12 0 100.00% | ||
479 | --------------------------------------------------------------------------------------- | ||
480 | TOTAL 113 6 94.69% 201 13 93.53% | ||
481 | |||
482 | File '/home/pedro/projects/libfido2/src/iso7816.c': | ||
483 | Name Regions Miss Cover Lines Miss Cover | ||
484 | --------------------------------------------------------------------------------------- | ||
485 | iso7816_new 4 0 100.00% 19 0 100.00% | ||
486 | iso7816_free 6 0 100.00% 11 0 100.00% | ||
487 | iso7816_add 6 1 83.33% 10 0 100.00% | ||
488 | iso7816_ptr 1 0 100.00% 3 0 100.00% | ||
489 | iso7816_len 1 0 100.00% 4 0 100.00% | ||
490 | --------------------------------------------------------------------------------------- | ||
491 | TOTAL 18 1 94.44% 47 0 100.00% | ||
492 | |||
493 | File '/home/pedro/projects/libfido2/src/log.c': | ||
494 | Name Regions Miss Cover Lines Miss Cover | ||
495 | --------------------------------------------------------------------------------------- | ||
496 | fido_log_init 1 1 0.00% 3 3 0.00% | ||
497 | fido_log_xxd 11 8 27.27% 18 12 33.33% | ||
498 | fido_log_debug 4 1 75.00% 13 8 38.46% | ||
499 | --------------------------------------------------------------------------------------- | ||
500 | TOTAL 16 10 37.50% 34 23 32.35% | ||
501 | |||
502 | File '/home/pedro/projects/libfido2/src/pin.c': | ||
503 | Name Regions Miss Cover Lines Miss Cover | ||
504 | --------------------------------------------------------------------------------------- | ||
505 | fido_dev_get_pin_token 1 0 100.00% 3 0 100.00% | ||
506 | fido_dev_set_pin 1 0 100.00% 3 0 100.00% | ||
507 | fido_dev_get_retry_count 1 0 100.00% 3 0 100.00% | ||
508 | cbor_add_pin_params 17 0 100.00% 27 0 100.00% | ||
509 | pin.c:fido_dev_get_pin_token_wait 10 0 100.00% 9 0 100.00% | ||
510 | pin.c:fido_dev_get_pin_token_tx 29 0 100.00% 40 0 100.00% | ||
511 | pin.c:fido_dev_get_pin_token_rx 21 0 100.00% 36 0 100.00% | ||
512 | pin.c:parse_pintoken 8 0 100.00% 12 0 100.00% | ||
513 | pin.c:fido_dev_set_pin_wait 16 0 100.00% 22 0 100.00% | ||
514 | pin.c:fido_dev_change_pin_tx 41 0 100.00% 59 0 100.00% | ||
515 | pin.c:pad64 18 0 100.00% 24 0 100.00% | ||
516 | pin.c:fido_dev_set_pin_tx 33 0 100.00% 48 0 100.00% | ||
517 | pin.c:fido_dev_get_retry_count_wait 10 0 100.00% 9 0 100.00% | ||
518 | pin.c:fido_dev_get_retry_count_tx 19 0 100.00% 28 0 100.00% | ||
519 | pin.c:fido_dev_get_retry_count_rx 12 0 100.00% 21 0 100.00% | ||
520 | pin.c:parse_retry_count 13 0 100.00% 20 0 100.00% | ||
521 | --------------------------------------------------------------------------------------- | ||
522 | TOTAL 250 0 100.00% 364 0 100.00% | ||
523 | |||
524 | File '/home/pedro/projects/libfido2/src/reset.c': | ||
525 | Name Regions Miss Cover Lines Miss Cover | ||
526 | --------------------------------------------------------------------------------------- | ||
527 | fido_dev_reset 1 0 100.00% 3 0 100.00% | ||
528 | reset.c:fido_dev_reset_wait 10 0 100.00% 9 0 100.00% | ||
529 | reset.c:fido_dev_reset_tx 9 0 100.00% 11 0 100.00% | ||
530 | --------------------------------------------------------------------------------------- | ||
531 | TOTAL 20 0 100.00% 23 0 100.00% | ||
532 | |||
533 | File '/home/pedro/projects/libfido2/src/rs256.c': | ||
534 | Name Regions Miss Cover Lines Miss Cover | ||
535 | --------------------------------------------------------------------------------------- | ||
536 | rs256_pk_decode 8 0 100.00% 10 0 100.00% | ||
537 | rs256_pk_new 1 0 100.00% 3 0 100.00% | ||
538 | rs256_pk_free 6 0 100.00% 11 0 100.00% | ||
539 | rs256_pk_from_ptr 6 0 100.00% 8 0 100.00% | ||
540 | rs256_pk_to_EVP_PKEY 32 0 100.00% 48 0 100.00% | ||
541 | rs256_pk_from_RSA 32 6 81.25% 32 9 71.88% | ||
542 | rs256.c:decode_rsa_pubkey 9 0 100.00% 16 0 100.00% | ||
543 | rs256.c:decode_bignum 8 0 100.00% 12 0 100.00% | ||
544 | --------------------------------------------------------------------------------------- | ||
545 | TOTAL 102 6 94.12% 140 9 93.57% | ||
546 | |||
547 | File '/home/pedro/projects/libfido2/src/u2f.c': | ||
548 | Name Regions Miss Cover Lines Miss Cover | ||
549 | --------------------------------------------------------------------------------------- | ||
550 | u2f_register 70 1 98.57% 89 0 100.00% | ||
551 | u2f_authenticate 27 0 100.00% 33 0 100.00% | ||
552 | u2f.c:key_lookup 44 0 100.00% 69 0 100.00% | ||
553 | u2f.c:send_dummy_register 31 1 96.77% 50 0 100.00% | ||
554 | u2f.c:parse_register_reply 57 0 100.00% 83 0 100.00% | ||
555 | u2f.c:x5c_get 21 1 95.24% 37 3 91.89% | ||
556 | u2f.c:sig_get 8 1 87.50% 16 6 62.50% | ||
557 | u2f.c:encode_cred_authdata 37 2 94.59% 82 6 92.68% | ||
558 | u2f.c:cbor_blob_from_ec_point 22 0 100.00% 39 0 100.00% | ||
559 | u2f.c:u2f_authenticate_single 34 2 94.12% 53 4 92.45% | ||
560 | u2f.c:do_auth 50 1 98.00% 72 0 100.00% | ||
561 | u2f.c:parse_auth_reply 23 2 91.30% 29 3 89.66% | ||
562 | u2f.c:authdata_fake 12 0 100.00% 34 0 100.00% | ||
563 | --------------------------------------------------------------------------------------- | ||
564 | TOTAL 436 11 97.48% 686 22 96.79% | ||
diff --git a/fuzz/fuzz_assert.c b/fuzz/fuzz_assert.c new file mode 100644 index 0000000..0395345 --- /dev/null +++ b/fuzz/fuzz_assert.c | |||
@@ -0,0 +1,664 @@ | |||
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 <assert.h> | ||
8 | #include <stdbool.h> | ||
9 | #include <stdint.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <string.h> | ||
12 | #include <stdio.h> | ||
13 | |||
14 | #include "mutator_aux.h" | ||
15 | #include "fido.h" | ||
16 | #include "fido/es256.h" | ||
17 | #include "fido/rs256.h" | ||
18 | #include "fido/eddsa.h" | ||
19 | |||
20 | #include "../openbsd-compat/openbsd-compat.h" | ||
21 | |||
22 | #define TAG_U2F 0x01 | ||
23 | #define TAG_TYPE 0x02 | ||
24 | #define TAG_CDH 0x03 | ||
25 | #define TAG_RP_ID 0x04 | ||
26 | #define TAG_EXT 0x05 | ||
27 | #define TAG_SEED 0x06 | ||
28 | #define TAG_UP 0x07 | ||
29 | #define TAG_UV 0x08 | ||
30 | #define TAG_WIRE_DATA 0x09 | ||
31 | #define TAG_CRED_COUNT 0x0a | ||
32 | #define TAG_CRED 0x0b | ||
33 | #define TAG_ES256 0x0c | ||
34 | #define TAG_RS256 0x0d | ||
35 | #define TAG_PIN 0x0e | ||
36 | #define TAG_EDDSA 0x0f | ||
37 | |||
38 | /* Parameter set defining a FIDO2 get assertion operation. */ | ||
39 | struct param { | ||
40 | char pin[MAXSTR]; | ||
41 | char rp_id[MAXSTR]; | ||
42 | int ext; | ||
43 | int seed; | ||
44 | struct blob cdh; | ||
45 | struct blob cred; | ||
46 | struct blob es256; | ||
47 | struct blob rs256; | ||
48 | struct blob eddsa; | ||
49 | struct blob wire_data; | ||
50 | uint8_t cred_count; | ||
51 | uint8_t type; | ||
52 | uint8_t u2f; | ||
53 | uint8_t up; | ||
54 | uint8_t uv; | ||
55 | }; | ||
56 | |||
57 | /* Example parameters. */ | ||
58 | static const char dummy_rp_id[] = "localhost"; | ||
59 | static const char dummy_pin[] = "9}4gT:8d=A37Dh}U"; | ||
60 | |||
61 | static const uint8_t dummy_cdh[] = { | ||
62 | 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7, | ||
63 | 0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56, | ||
64 | 0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52, | ||
65 | 0x35, 0x2d, 0xa2, 0x62, 0x4a, 0xbe, 0x89, 0x76, | ||
66 | }; | ||
67 | |||
68 | static const uint8_t dummy_es256[] = { | ||
69 | 0xcc, 0x1b, 0x50, 0xac, 0xc4, 0x19, 0xf8, 0x3a, | ||
70 | 0xee, 0x0a, 0x77, 0xd6, 0xf3, 0x53, 0xdb, 0xef, | ||
71 | 0xf2, 0xb9, 0x5c, 0x2d, 0x8b, 0x1e, 0x52, 0x58, | ||
72 | 0x88, 0xf4, 0x0b, 0x85, 0x1f, 0x40, 0x6d, 0x18, | ||
73 | 0x15, 0xb3, 0xcc, 0x25, 0x7c, 0x38, 0x3d, 0xec, | ||
74 | 0xdf, 0xad, 0xbd, 0x46, 0x91, 0xc3, 0xac, 0x30, | ||
75 | 0x94, 0x2a, 0xf7, 0x78, 0x35, 0x70, 0x59, 0x6f, | ||
76 | 0x28, 0xcb, 0x8e, 0x07, 0x85, 0xb5, 0x91, 0x96, | ||
77 | }; | ||
78 | |||
79 | static const uint8_t dummy_rs256[] = { | ||
80 | 0xd2, 0xa8, 0xc0, 0x11, 0x82, 0x9e, 0x57, 0x2e, | ||
81 | 0x60, 0xae, 0x8c, 0xb0, 0x09, 0xe1, 0x58, 0x2b, | ||
82 | 0x99, 0xec, 0xc3, 0x11, 0x1b, 0xef, 0x81, 0x49, | ||
83 | 0x34, 0x53, 0x6a, 0x01, 0x65, 0x2c, 0x24, 0x09, | ||
84 | 0x30, 0x87, 0x98, 0x51, 0x6e, 0x30, 0x4f, 0x60, | ||
85 | 0xbd, 0x54, 0xd2, 0x54, 0xbd, 0x94, 0x42, 0xdd, | ||
86 | 0x63, 0xe5, 0x2c, 0xc6, 0x04, 0x32, 0xc0, 0x8f, | ||
87 | 0x72, 0xd5, 0xb4, 0xf0, 0x4f, 0x42, 0xe5, 0xb0, | ||
88 | 0xa2, 0x95, 0x11, 0xfe, 0xd8, 0xb0, 0x65, 0x34, | ||
89 | 0xff, 0xfb, 0x44, 0x97, 0x52, 0xfc, 0x67, 0x23, | ||
90 | 0x0b, 0xad, 0xf3, 0x3a, 0x82, 0xd4, 0x96, 0x10, | ||
91 | 0x87, 0x6b, 0xfa, 0xd6, 0x51, 0x60, 0x3e, 0x1c, | ||
92 | 0xae, 0x19, 0xb8, 0xce, 0x08, 0xae, 0x9a, 0xee, | ||
93 | 0x78, 0x16, 0x22, 0xcc, 0x92, 0xcb, 0xa8, 0x95, | ||
94 | 0x34, 0xe5, 0xb9, 0x42, 0x6a, 0xf0, 0x2e, 0x82, | ||
95 | 0x1f, 0x4c, 0x7d, 0x84, 0x94, 0x68, 0x7b, 0x97, | ||
96 | 0x2b, 0xf7, 0x7d, 0x67, 0x83, 0xbb, 0xc7, 0x8a, | ||
97 | 0x31, 0x5a, 0xf3, 0x2a, 0x95, 0xdf, 0x63, 0xe7, | ||
98 | 0x4e, 0xee, 0x26, 0xda, 0x87, 0x00, 0xe2, 0x23, | ||
99 | 0x4a, 0x33, 0x9a, 0xa0, 0x1b, 0xce, 0x60, 0x1f, | ||
100 | 0x98, 0xa1, 0xb0, 0xdb, 0xbf, 0x20, 0x59, 0x27, | ||
101 | 0xf2, 0x06, 0xd9, 0xbe, 0x37, 0xa4, 0x03, 0x6b, | ||
102 | 0x6a, 0x4e, 0xaf, 0x22, 0x68, 0xf3, 0xff, 0x28, | ||
103 | 0x59, 0x05, 0xc9, 0xf1, 0x28, 0xf4, 0xbb, 0x35, | ||
104 | 0xe0, 0xc2, 0x68, 0xc2, 0xaa, 0x54, 0xac, 0x8c, | ||
105 | 0xc1, 0x69, 0x9e, 0x4b, 0x32, 0xfc, 0x53, 0x58, | ||
106 | 0x85, 0x7d, 0x3f, 0x51, 0xd1, 0xc9, 0x03, 0x02, | ||
107 | 0x13, 0x61, 0x62, 0xda, 0xf8, 0xfe, 0x3e, 0xc8, | ||
108 | 0x95, 0x12, 0xfb, 0x0c, 0xdf, 0x06, 0x65, 0x6f, | ||
109 | 0x23, 0xc7, 0x83, 0x7c, 0x50, 0x2d, 0x27, 0x25, | ||
110 | 0x4d, 0xbf, 0x94, 0xf0, 0x89, 0x04, 0xb9, 0x2d, | ||
111 | 0xc4, 0xa5, 0x32, 0xa9, 0x25, 0x0a, 0x99, 0x59, | ||
112 | 0x01, 0x00, 0x01, | ||
113 | }; | ||
114 | |||
115 | static const uint8_t dummy_eddsa[] = { | ||
116 | 0xfe, 0x8b, 0x61, 0x50, 0x31, 0x7a, 0xe6, 0xdf, | ||
117 | 0xb1, 0x04, 0x9d, 0x4d, 0xb5, 0x7a, 0x5e, 0x96, | ||
118 | 0x4c, 0xb2, 0xf9, 0x5f, 0x72, 0x47, 0xb5, 0x18, | ||
119 | 0xe2, 0x39, 0xdf, 0x2f, 0x87, 0x19, 0xb3, 0x02, | ||
120 | }; | ||
121 | |||
122 | /* | ||
123 | * Collection of HID reports from an authenticator issued with a FIDO2 | ||
124 | * get assertion using the example parameters above. | ||
125 | */ | ||
126 | static const uint8_t dummy_wire_data_fido[] = { | ||
127 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0xf7, | ||
128 | 0x6f, 0xda, 0x52, 0xfd, 0xcb, 0xb6, 0x24, 0x00, | ||
129 | 0x92, 0x00, 0x0e, 0x02, 0x05, 0x00, 0x02, 0x05, | ||
130 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
131 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
132 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
133 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
134 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
135 | 0x00, 0x92, 0x00, 0x0e, 0x90, 0x00, 0x51, 0x00, | ||
136 | 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, | ||
137 | 0x20, 0x01, 0x21, 0x58, 0x20, 0xe9, 0x1d, 0x9b, | ||
138 | 0xac, 0x14, 0x25, 0x5f, 0xda, 0x1e, 0x11, 0xdb, | ||
139 | 0xae, 0xc2, 0x90, 0x22, 0xca, 0x32, 0xec, 0x32, | ||
140 | 0xe6, 0x05, 0x15, 0x44, 0xe5, 0xe8, 0xbc, 0x4f, | ||
141 | 0x0a, 0xb6, 0x1a, 0xeb, 0x11, 0x22, 0x58, 0x20, | ||
142 | 0xcc, 0x72, 0xf0, 0x22, 0xe8, 0x28, 0x82, 0xc5, | ||
143 | 0x00, 0x92, 0x00, 0x0e, 0x00, 0xa6, 0x65, 0x6e, | ||
144 | 0xff, 0x1e, 0xe3, 0x7f, 0x27, 0x44, 0x2d, 0xfb, | ||
145 | 0x8d, 0x41, 0xfa, 0x85, 0x0e, 0xcb, 0xda, 0x95, | ||
146 | 0x64, 0x64, 0x9b, 0x1f, 0x34, 0x00, 0x00, 0x00, | ||
147 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
148 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
149 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
150 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
151 | 0x00, 0x92, 0x00, 0x0e, 0x90, 0x00, 0x14, 0x00, | ||
152 | 0xa1, 0x02, 0x50, 0xee, 0x40, 0x4c, 0x85, 0xd7, | ||
153 | 0xa1, 0x2f, 0x56, 0xc4, 0x4e, 0xc5, 0x93, 0x41, | ||
154 | 0xd0, 0x3b, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
155 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
156 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
157 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
158 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
159 | 0x00, 0x92, 0x00, 0x0e, 0x90, 0x00, 0xcb, 0x00, | ||
160 | 0xa3, 0x01, 0xa2, 0x62, 0x69, 0x64, 0x58, 0x40, | ||
161 | 0x4a, 0x4c, 0x9e, 0xcc, 0x81, 0x7d, 0x42, 0x03, | ||
162 | 0x2b, 0x41, 0xd1, 0x38, 0xd3, 0x49, 0xb4, 0xfc, | ||
163 | 0xfb, 0xe4, 0x4e, 0xe4, 0xff, 0x76, 0x34, 0x16, | ||
164 | 0x68, 0x06, 0x9d, 0xa6, 0x01, 0x32, 0xb9, 0xff, | ||
165 | 0xc2, 0x35, 0x0d, 0x89, 0x43, 0x66, 0x12, 0xf8, | ||
166 | 0x8e, 0x5b, 0xde, 0xf4, 0xcc, 0xec, 0x9d, 0x03, | ||
167 | 0x00, 0x92, 0x00, 0x0e, 0x00, 0x85, 0xc2, 0xf5, | ||
168 | 0xe6, 0x8e, 0xeb, 0x3f, 0x3a, 0xec, 0xc3, 0x1d, | ||
169 | 0x04, 0x6e, 0xf3, 0x5b, 0x88, 0x64, 0x74, 0x79, | ||
170 | 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, | ||
171 | 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x02, 0x58, 0x25, | ||
172 | 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, 0x8c, 0x68, | ||
173 | 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, 0x60, 0x5b, | ||
174 | 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, 0x32, 0xc7, | ||
175 | 0x00, 0x92, 0x00, 0x0e, 0x01, 0x99, 0x5c, 0xf3, | ||
176 | 0xba, 0x83, 0x1d, 0x97, 0x63, 0x04, 0x00, 0x00, | ||
177 | 0x00, 0x09, 0x03, 0x58, 0x47, 0x30, 0x45, 0x02, | ||
178 | 0x21, 0x00, 0xcf, 0x3f, 0x36, 0x0e, 0x1f, 0x6f, | ||
179 | 0xd6, 0xa0, 0x9d, 0x13, 0xcf, 0x55, 0xf7, 0x49, | ||
180 | 0x8f, 0xc8, 0xc9, 0x03, 0x12, 0x76, 0x41, 0x75, | ||
181 | 0x7b, 0xb5, 0x0a, 0x90, 0xa5, 0x82, 0x26, 0xf1, | ||
182 | 0x6b, 0x80, 0x02, 0x20, 0x34, 0x9b, 0x7a, 0x82, | ||
183 | 0x00, 0x92, 0x00, 0x0e, 0x02, 0xd3, 0xe1, 0x79, | ||
184 | 0x49, 0x55, 0x41, 0x9f, 0xa4, 0x06, 0x06, 0xbd, | ||
185 | 0xc8, 0xb9, 0x2b, 0x5f, 0xe1, 0xa7, 0x99, 0x1c, | ||
186 | 0xa1, 0xfc, 0x7e, 0x3e, 0xd5, 0x85, 0x2e, 0x11, | ||
187 | 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
188 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
189 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
190 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
191 | }; | ||
192 | |||
193 | /* | ||
194 | * Collection of HID reports from an authenticator issued with a U2F | ||
195 | * authentication using the example parameters above. | ||
196 | */ | ||
197 | static const uint8_t dummy_wire_data_u2f[] = { | ||
198 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x0f, | ||
199 | 0x26, 0x9c, 0xd3, 0x87, 0x0d, 0x7b, 0xf6, 0x00, | ||
200 | 0x00, 0x99, 0x01, 0x02, 0x01, 0x01, 0x00, 0x01, | ||
201 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
202 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
203 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
204 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
205 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
206 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
207 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
208 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
209 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
210 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
211 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
212 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
213 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
214 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
215 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
216 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
217 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
218 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
219 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
220 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
221 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
222 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
223 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
224 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
225 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
226 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
227 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
228 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
229 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
230 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
231 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
232 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
233 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
234 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
235 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
236 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
237 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
238 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
239 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
240 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
241 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
242 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
243 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
244 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
245 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
246 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
247 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
248 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
249 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
250 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
251 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
252 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
253 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
254 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
255 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
256 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
257 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
258 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
259 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
260 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
261 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
262 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
263 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
264 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
265 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
266 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
267 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
268 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
269 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
270 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
271 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
272 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
273 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
274 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
275 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
276 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
277 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
278 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x4e, 0x01, | ||
279 | 0x00, 0x00, 0x00, 0x2c, 0x30, 0x45, 0x02, 0x20, | ||
280 | 0x1c, 0xf5, 0x7c, 0xf6, 0xde, 0xbe, 0xe9, 0x86, | ||
281 | 0xee, 0x97, 0xb7, 0x64, 0xa3, 0x4e, 0x7a, 0x70, | ||
282 | 0x85, 0xd0, 0x66, 0xf9, 0xf0, 0xcd, 0x04, 0x5d, | ||
283 | 0x97, 0xf2, 0x3c, 0x22, 0xe3, 0x0e, 0x61, 0xc8, | ||
284 | 0x02, 0x21, 0x00, 0x97, 0xef, 0xae, 0x36, 0xe6, | ||
285 | 0x17, 0x9f, 0x5e, 0x2d, 0xd7, 0x8c, 0x34, 0xa7, | ||
286 | 0x00, 0x00, 0x99, 0x01, 0x00, 0xa1, 0xe9, 0xfb, | ||
287 | 0x8f, 0x86, 0x8c, 0xe3, 0x1e, 0xde, 0x3f, 0x4e, | ||
288 | 0x1b, 0xe1, 0x2f, 0x8f, 0x2f, 0xca, 0x42, 0x26, | ||
289 | 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
290 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
291 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
292 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
293 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
294 | }; | ||
295 | |||
296 | int LLVMFuzzerTestOneInput(const uint8_t *, size_t); | ||
297 | size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); | ||
298 | |||
299 | static int | ||
300 | unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN | ||
301 | { | ||
302 | uint8_t **pp = (void *)&ptr; | ||
303 | |||
304 | if (unpack_byte(TAG_UV, pp, &len, &p->uv) < 0 || | ||
305 | unpack_byte(TAG_UP, pp, &len, &p->up) < 0 || | ||
306 | unpack_byte(TAG_U2F, pp, &len, &p->u2f) < 0 || | ||
307 | unpack_byte(TAG_TYPE, pp, &len, &p->type) < 0 || | ||
308 | unpack_byte(TAG_CRED_COUNT, pp, &len, &p->cred_count) < 0 || | ||
309 | unpack_int(TAG_EXT, pp, &len, &p->ext) < 0 || | ||
310 | unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || | ||
311 | unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || | ||
312 | unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || | ||
313 | unpack_blob(TAG_WIRE_DATA, pp, &len, &p->wire_data) < 0 || | ||
314 | unpack_blob(TAG_RS256, pp, &len, &p->rs256) < 0 || | ||
315 | unpack_blob(TAG_ES256, pp, &len, &p->es256) < 0 || | ||
316 | unpack_blob(TAG_EDDSA, pp, &len, &p->eddsa) < 0 || | ||
317 | unpack_blob(TAG_CRED, pp, &len, &p->cred) < 0 || | ||
318 | unpack_blob(TAG_CDH, pp, &len, &p->cdh) < 0) | ||
319 | return (-1); | ||
320 | |||
321 | return (0); | ||
322 | } | ||
323 | |||
324 | static size_t | ||
325 | pack(uint8_t *ptr, size_t len, const struct param *p) | ||
326 | { | ||
327 | const size_t max = len; | ||
328 | |||
329 | if (pack_byte(TAG_UV, &ptr, &len, p->uv) < 0 || | ||
330 | pack_byte(TAG_UP, &ptr, &len, p->up) < 0 || | ||
331 | pack_byte(TAG_U2F, &ptr, &len, p->u2f) < 0 || | ||
332 | pack_byte(TAG_TYPE, &ptr, &len, p->type) < 0 || | ||
333 | pack_byte(TAG_CRED_COUNT, &ptr, &len, p->cred_count) < 0 || | ||
334 | pack_int(TAG_EXT, &ptr, &len, p->ext) < 0 || | ||
335 | pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || | ||
336 | pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || | ||
337 | pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || | ||
338 | pack_blob(TAG_WIRE_DATA, &ptr, &len, &p->wire_data) < 0 || | ||
339 | pack_blob(TAG_RS256, &ptr, &len, &p->rs256) < 0 || | ||
340 | pack_blob(TAG_ES256, &ptr, &len, &p->es256) < 0 || | ||
341 | pack_blob(TAG_EDDSA, &ptr, &len, &p->eddsa) < 0 || | ||
342 | pack_blob(TAG_CRED, &ptr, &len, &p->cred) < 0 || | ||
343 | pack_blob(TAG_CDH, &ptr, &len, &p->cdh) < 0) | ||
344 | return (0); | ||
345 | |||
346 | return (max - len); | ||
347 | } | ||
348 | |||
349 | static void | ||
350 | get_assert(fido_assert_t *assert, uint8_t u2f, const struct blob *cdh, | ||
351 | const char *rp_id, int ext, uint8_t up, uint8_t uv, const char *pin, | ||
352 | uint8_t cred_count, struct blob *cred) | ||
353 | { | ||
354 | fido_dev_t *dev; | ||
355 | fido_dev_io_t io; | ||
356 | |||
357 | io.open = dev_open; | ||
358 | io.close = dev_close; | ||
359 | io.read = dev_read; | ||
360 | io.write = dev_write; | ||
361 | |||
362 | if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, | ||
363 | &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { | ||
364 | fido_dev_free(&dev); | ||
365 | return; | ||
366 | } | ||
367 | |||
368 | if (u2f & 1) | ||
369 | fido_dev_force_u2f(dev); | ||
370 | |||
371 | for (uint8_t i = 0; i < cred_count; i++) | ||
372 | fido_assert_allow_cred(assert, cred->body, cred->len); | ||
373 | |||
374 | fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len); | ||
375 | fido_assert_set_rp(assert, rp_id); | ||
376 | if (ext & 1) | ||
377 | fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET); | ||
378 | if (up & 1) | ||
379 | fido_assert_set_up(assert, FIDO_OPT_TRUE); | ||
380 | if (uv & 1) | ||
381 | fido_assert_set_uv(assert, FIDO_OPT_TRUE); | ||
382 | /* XXX reuse cred as hmac salt to keep struct param small */ | ||
383 | fido_assert_set_hmac_salt(assert, cred->body, cred->len); | ||
384 | |||
385 | fido_dev_get_assert(dev, assert, u2f & 1 ? NULL : pin); | ||
386 | |||
387 | fido_dev_cancel(dev); | ||
388 | fido_dev_close(dev); | ||
389 | fido_dev_free(&dev); | ||
390 | } | ||
391 | |||
392 | static void | ||
393 | verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len, | ||
394 | const char *rp_id, const unsigned char *authdata_ptr, size_t authdata_len, | ||
395 | const unsigned char *sig_ptr, size_t sig_len, uint8_t up, uint8_t uv, | ||
396 | int ext, void *pk) | ||
397 | { | ||
398 | fido_assert_t *assert = NULL; | ||
399 | |||
400 | if ((assert = fido_assert_new()) == NULL) | ||
401 | return; | ||
402 | |||
403 | fido_assert_set_clientdata_hash(assert, cdh_ptr, cdh_len); | ||
404 | fido_assert_set_rp(assert, rp_id); | ||
405 | fido_assert_set_count(assert, 1); | ||
406 | if (fido_assert_set_authdata(assert, 0, authdata_ptr, | ||
407 | authdata_len) != FIDO_OK) { | ||
408 | fido_assert_set_authdata_raw(assert, 0, authdata_ptr, | ||
409 | authdata_len); | ||
410 | } | ||
411 | fido_assert_set_extensions(assert, ext); | ||
412 | if (up & 1) fido_assert_set_up(assert, FIDO_OPT_TRUE); | ||
413 | if (uv & 1) fido_assert_set_uv(assert, FIDO_OPT_TRUE); | ||
414 | fido_assert_set_sig(assert, 0, sig_ptr, sig_len); | ||
415 | fido_assert_verify(assert, 0, type, pk); | ||
416 | |||
417 | fido_assert_free(&assert); | ||
418 | } | ||
419 | |||
420 | /* | ||
421 | * Do a dummy conversion to exercise rs256_pk_from_RSA(). | ||
422 | */ | ||
423 | static void | ||
424 | rs256_convert(const rs256_pk_t *k) | ||
425 | { | ||
426 | EVP_PKEY *pkey = NULL; | ||
427 | rs256_pk_t *pk = NULL; | ||
428 | RSA *rsa = NULL; | ||
429 | volatile int r; | ||
430 | |||
431 | if ((pkey = rs256_pk_to_EVP_PKEY(k)) == NULL || | ||
432 | (pk = rs256_pk_new()) == NULL || | ||
433 | (rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) | ||
434 | goto out; | ||
435 | |||
436 | r = rs256_pk_from_RSA(pk, rsa); | ||
437 | out: | ||
438 | if (pk) | ||
439 | rs256_pk_free(&pk); | ||
440 | if (pkey) | ||
441 | EVP_PKEY_free(pkey); | ||
442 | } | ||
443 | |||
444 | /* | ||
445 | * Do a dummy conversion to exercise eddsa_pk_from_EVP_PKEY(). | ||
446 | */ | ||
447 | static void | ||
448 | eddsa_convert(const eddsa_pk_t *k) | ||
449 | { | ||
450 | EVP_PKEY *pkey = NULL; | ||
451 | eddsa_pk_t *pk = NULL; | ||
452 | volatile int r; | ||
453 | |||
454 | if ((pkey = eddsa_pk_to_EVP_PKEY(k)) == NULL || | ||
455 | (pk = eddsa_pk_new()) == NULL) | ||
456 | goto out; | ||
457 | |||
458 | r = eddsa_pk_from_EVP_PKEY(pk, pkey); | ||
459 | out: | ||
460 | if (pk) | ||
461 | eddsa_pk_free(&pk); | ||
462 | if (pkey) | ||
463 | EVP_PKEY_free(pkey); | ||
464 | } | ||
465 | |||
466 | int | ||
467 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) | ||
468 | { | ||
469 | struct param p; | ||
470 | fido_assert_t *assert = NULL; | ||
471 | es256_pk_t *es256_pk = NULL; | ||
472 | rs256_pk_t *rs256_pk = NULL; | ||
473 | eddsa_pk_t *eddsa_pk = NULL; | ||
474 | uint8_t flags; | ||
475 | uint32_t sigcount; | ||
476 | int cose_alg = 0; | ||
477 | void *pk; | ||
478 | |||
479 | memset(&p, 0, sizeof(p)); | ||
480 | |||
481 | if (unpack(data, size, &p) < 0) | ||
482 | return (0); | ||
483 | |||
484 | srandom((unsigned int)p.seed); | ||
485 | |||
486 | fido_init(0); | ||
487 | |||
488 | switch (p.type & 3) { | ||
489 | case 0: | ||
490 | cose_alg = COSE_ES256; | ||
491 | |||
492 | if ((es256_pk = es256_pk_new()) == NULL) | ||
493 | return (0); | ||
494 | |||
495 | es256_pk_from_ptr(es256_pk, p.es256.body, p.es256.len); | ||
496 | pk = es256_pk; | ||
497 | |||
498 | break; | ||
499 | case 1: | ||
500 | cose_alg = COSE_RS256; | ||
501 | |||
502 | if ((rs256_pk = rs256_pk_new()) == NULL) | ||
503 | return (0); | ||
504 | |||
505 | rs256_pk_from_ptr(rs256_pk, p.rs256.body, p.rs256.len); | ||
506 | pk = rs256_pk; | ||
507 | |||
508 | rs256_convert(pk); | ||
509 | |||
510 | break; | ||
511 | default: | ||
512 | cose_alg = COSE_EDDSA; | ||
513 | |||
514 | if ((eddsa_pk = eddsa_pk_new()) == NULL) | ||
515 | return (0); | ||
516 | |||
517 | eddsa_pk_from_ptr(eddsa_pk, p.eddsa.body, p.eddsa.len); | ||
518 | pk = eddsa_pk; | ||
519 | |||
520 | eddsa_convert(pk); | ||
521 | |||
522 | break; | ||
523 | } | ||
524 | |||
525 | if ((assert = fido_assert_new()) == NULL) | ||
526 | goto out; | ||
527 | |||
528 | set_wire_data(p.wire_data.body, p.wire_data.len); | ||
529 | |||
530 | get_assert(assert, p.u2f, &p.cdh, p.rp_id, p.ext, p.up, p.uv, p.pin, | ||
531 | p.cred_count, &p.cred); | ||
532 | |||
533 | /* XXX +1 on purpose */ | ||
534 | for (size_t i = 0; i <= fido_assert_count(assert); i++) { | ||
535 | verify_assert(cose_alg, | ||
536 | fido_assert_clientdata_hash_ptr(assert), | ||
537 | fido_assert_clientdata_hash_len(assert), | ||
538 | fido_assert_rp_id(assert), | ||
539 | fido_assert_authdata_ptr(assert, i), | ||
540 | fido_assert_authdata_len(assert, i), | ||
541 | fido_assert_sig_ptr(assert, i), | ||
542 | fido_assert_sig_len(assert, i), p.up, p.uv, p.ext, pk); | ||
543 | consume(fido_assert_id_ptr(assert, i), | ||
544 | fido_assert_id_len(assert, i)); | ||
545 | consume(fido_assert_user_id_ptr(assert, i), | ||
546 | fido_assert_user_id_len(assert, i)); | ||
547 | consume(fido_assert_hmac_secret_ptr(assert, i), | ||
548 | fido_assert_hmac_secret_len(assert, i)); | ||
549 | consume(fido_assert_user_icon(assert, i), | ||
550 | xstrlen(fido_assert_user_icon(assert, i))); | ||
551 | consume(fido_assert_user_name(assert, i), | ||
552 | xstrlen(fido_assert_user_name(assert, i))); | ||
553 | consume(fido_assert_user_display_name(assert, i), | ||
554 | xstrlen(fido_assert_user_display_name(assert, i))); | ||
555 | flags = fido_assert_flags(assert, i); | ||
556 | consume(&flags, sizeof(flags)); | ||
557 | sigcount = fido_assert_sigcount(assert, i); | ||
558 | consume(&sigcount, sizeof(sigcount)); | ||
559 | } | ||
560 | |||
561 | out: | ||
562 | es256_pk_free(&es256_pk); | ||
563 | rs256_pk_free(&rs256_pk); | ||
564 | eddsa_pk_free(&eddsa_pk); | ||
565 | |||
566 | fido_assert_free(&assert); | ||
567 | |||
568 | return (0); | ||
569 | } | ||
570 | |||
571 | static size_t | ||
572 | pack_dummy(uint8_t *ptr, size_t len) | ||
573 | { | ||
574 | struct param dummy; | ||
575 | uint8_t blob[16384]; | ||
576 | size_t blob_len; | ||
577 | |||
578 | memset(&dummy, 0, sizeof(dummy)); | ||
579 | |||
580 | dummy.type = 1; | ||
581 | dummy.ext = FIDO_EXT_HMAC_SECRET; | ||
582 | |||
583 | strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); | ||
584 | strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); | ||
585 | |||
586 | dummy.cdh.len = sizeof(dummy_cdh); | ||
587 | dummy.es256.len = sizeof(dummy_es256); | ||
588 | dummy.rs256.len = sizeof(dummy_rs256); | ||
589 | dummy.eddsa.len = sizeof(dummy_eddsa); | ||
590 | dummy.wire_data.len = sizeof(dummy_wire_data_fido); | ||
591 | |||
592 | memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); | ||
593 | memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, | ||
594 | dummy.wire_data.len); | ||
595 | memcpy(&dummy.es256.body, &dummy_es256, dummy.es256.len); | ||
596 | memcpy(&dummy.rs256.body, &dummy_rs256, dummy.rs256.len); | ||
597 | memcpy(&dummy.eddsa.body, &dummy_eddsa, dummy.eddsa.len); | ||
598 | |||
599 | blob_len = pack(blob, sizeof(blob), &dummy); | ||
600 | assert(blob_len != 0); | ||
601 | |||
602 | if (blob_len > len) { | ||
603 | memcpy(ptr, blob, len); | ||
604 | return (len); | ||
605 | } | ||
606 | |||
607 | memcpy(ptr, blob, blob_len); | ||
608 | |||
609 | return (blob_len); | ||
610 | } | ||
611 | |||
612 | size_t | ||
613 | LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, | ||
614 | unsigned int seed) NO_MSAN | ||
615 | { | ||
616 | struct param p; | ||
617 | uint8_t blob[16384]; | ||
618 | size_t blob_len; | ||
619 | |||
620 | (void)seed; | ||
621 | |||
622 | memset(&p, 0, sizeof(p)); | ||
623 | |||
624 | if (unpack(data, size, &p) < 0) | ||
625 | return (pack_dummy(data, maxsize)); | ||
626 | |||
627 | mutate_byte(&p.uv); | ||
628 | mutate_byte(&p.up); | ||
629 | mutate_byte(&p.u2f); | ||
630 | mutate_byte(&p.type); | ||
631 | mutate_byte(&p.cred_count); | ||
632 | |||
633 | mutate_int(&p.ext); | ||
634 | p.seed = (int)seed; | ||
635 | |||
636 | if (p.u2f & 1) { | ||
637 | p.wire_data.len = sizeof(dummy_wire_data_u2f); | ||
638 | memcpy(&p.wire_data.body, &dummy_wire_data_u2f, | ||
639 | p.wire_data.len); | ||
640 | } else { | ||
641 | p.wire_data.len = sizeof(dummy_wire_data_fido); | ||
642 | memcpy(&p.wire_data.body, &dummy_wire_data_fido, | ||
643 | p.wire_data.len); | ||
644 | } | ||
645 | |||
646 | mutate_blob(&p.wire_data); | ||
647 | mutate_blob(&p.rs256); | ||
648 | mutate_blob(&p.es256); | ||
649 | mutate_blob(&p.eddsa); | ||
650 | mutate_blob(&p.cred); | ||
651 | mutate_blob(&p.cdh); | ||
652 | |||
653 | mutate_string(p.rp_id); | ||
654 | mutate_string(p.pin); | ||
655 | |||
656 | blob_len = pack(blob, sizeof(blob), &p); | ||
657 | |||
658 | if (blob_len == 0 || blob_len > maxsize) | ||
659 | return (0); | ||
660 | |||
661 | memcpy(data, blob, blob_len); | ||
662 | |||
663 | return (blob_len); | ||
664 | } | ||
diff --git a/fuzz/fuzz_bio.c b/fuzz/fuzz_bio.c new file mode 100644 index 0000000..f1596a7 --- /dev/null +++ b/fuzz/fuzz_bio.c | |||
@@ -0,0 +1,755 @@ | |||
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 <assert.h> | ||
8 | #include <stdint.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | #include <stdio.h> | ||
12 | |||
13 | #include "mutator_aux.h" | ||
14 | #include "fido.h" | ||
15 | #include "fido/bio.h" | ||
16 | |||
17 | #include "../openbsd-compat/openbsd-compat.h" | ||
18 | |||
19 | #define TAG_PIN 0x01 | ||
20 | #define TAG_NAME 0x02 | ||
21 | #define TAG_SEED 0x03 | ||
22 | #define TAG_ID 0x04 | ||
23 | #define TAG_INFO_WIRE_DATA 0x05 | ||
24 | #define TAG_ENROLL_WIRE_DATA 0x06 | ||
25 | #define TAG_LIST_WIRE_DATA 0x07 | ||
26 | #define TAG_SET_NAME_WIRE_DATA 0x08 | ||
27 | #define TAG_REMOVE_WIRE_DATA 0x09 | ||
28 | |||
29 | /* Parameter set defining a FIDO2 credential management operation. */ | ||
30 | struct param { | ||
31 | char pin[MAXSTR]; | ||
32 | char name[MAXSTR]; | ||
33 | int seed; | ||
34 | struct blob id; | ||
35 | struct blob info_wire_data; | ||
36 | struct blob enroll_wire_data; | ||
37 | struct blob list_wire_data; | ||
38 | struct blob set_name_wire_data; | ||
39 | struct blob remove_wire_data; | ||
40 | }; | ||
41 | |||
42 | /* Example parameters. */ | ||
43 | static const uint8_t dummy_id[] = { 0x5e, 0xd2, }; | ||
44 | static const char dummy_pin[] = "3Q;I){TAx"; | ||
45 | static const char dummy_name[] = "finger1"; | ||
46 | |||
47 | /* | ||
48 | * Collection of HID reports from an authenticator issued with a FIDO2 | ||
49 | * 'getFingerprintSensorInfo' bio enrollment command. | ||
50 | */ | ||
51 | static const uint8_t dummy_info_wire_data[] = { | ||
52 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0xf0, | ||
53 | 0x08, 0xc1, 0x8f, 0x76, 0x4b, 0x8f, 0xa9, 0x00, | ||
54 | 0x10, 0x00, 0x04, 0x02, 0x00, 0x04, 0x06, 0x05, | ||
55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
58 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
60 | 0x00, 0x10, 0x00, 0x04, 0x90, 0x00, 0x06, 0x00, | ||
61 | 0xa2, 0x02, 0x01, 0x03, 0x04, 0x00, 0x00, 0x00, | ||
62 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
63 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
64 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
65 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
66 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
67 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
68 | }; | ||
69 | |||
70 | /* | ||
71 | * Collection of HID reports from an authenticator issued with FIDO2 | ||
72 | * 'enrollBegin' + 'enrollCaptureNextSample' bio enrollment commands. | ||
73 | */ | ||
74 | static const uint8_t dummy_enroll_wire_data[] = { | ||
75 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x06, | ||
76 | 0xb4, 0xba, 0x2e, 0xb3, 0x88, 0x24, 0x38, 0x00, | ||
77 | 0x0a, 0x00, 0x05, 0x02, 0x00, 0x04, 0x06, 0x05, | ||
78 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
79 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
80 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
81 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
82 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
83 | 0x00, 0x0a, 0x00, 0x05, 0x90, 0x00, 0x51, 0x00, | ||
84 | 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, | ||
85 | 0x20, 0x01, 0x21, 0x58, 0x20, 0xc9, 0x12, 0x01, | ||
86 | 0xab, 0x88, 0xd7, 0x0a, 0x24, 0xdd, 0xdc, 0xde, | ||
87 | 0x16, 0x27, 0x50, 0x77, 0x37, 0x06, 0xd3, 0x48, | ||
88 | 0xe6, 0xf9, 0xdb, 0xaa, 0x10, 0x83, 0x81, 0xac, | ||
89 | 0x13, 0x3c, 0xf9, 0x77, 0x2d, 0x22, 0x58, 0x20, | ||
90 | 0xda, 0x20, 0x71, 0x03, 0x01, 0x40, 0xac, 0xd0, | ||
91 | 0x00, 0x0a, 0x00, 0x05, 0x00, 0xb8, 0xdf, 0x2a, | ||
92 | 0x95, 0xd3, 0x88, 0x1c, 0x06, 0x34, 0x30, 0xf1, | ||
93 | 0xf3, 0xcd, 0x27, 0x40, 0x90, 0x5c, 0xc6, 0x74, | ||
94 | 0x66, 0xff, 0x10, 0xde, 0xb6, 0x00, 0x00, 0x00, | ||
95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
96 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
97 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
98 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
99 | 0x00, 0x0a, 0x00, 0x05, 0x90, 0x00, 0x14, 0x00, | ||
100 | 0xa1, 0x02, 0x50, 0x18, 0x81, 0xff, 0xf2, 0xf5, | ||
101 | 0xde, 0x74, 0x43, 0xd5, 0xe0, 0x77, 0x37, 0x6b, | ||
102 | 0x6c, 0x18, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
103 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
105 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
106 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
107 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
108 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
109 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
110 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
111 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
112 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
113 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
114 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
115 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
116 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
117 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
118 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
119 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
120 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
121 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
122 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
123 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
124 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
125 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
126 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
127 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
128 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
129 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
130 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
131 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
132 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
133 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
134 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
135 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
136 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
137 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
138 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
139 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
140 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
141 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
142 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
143 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
144 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
145 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
146 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
147 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
148 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
149 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
150 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
151 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
152 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
153 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
154 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
155 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
156 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
157 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
158 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
159 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
160 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
161 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
162 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
163 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
164 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
165 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
166 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
167 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
168 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
169 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
170 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
171 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
172 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
173 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
174 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
175 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
176 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
177 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
178 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
179 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
181 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
182 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
183 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
184 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
185 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
186 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
187 | 0x00, 0x0a, 0x00, 0x05, 0x90, 0x00, 0x0a, 0x00, | ||
188 | 0xa3, 0x04, 0x42, 0x68, 0x96, 0x05, 0x00, 0x06, | ||
189 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
190 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
191 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
192 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
193 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
194 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
195 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
196 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
197 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
198 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
199 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
200 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
201 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
202 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
203 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
204 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
205 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
206 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
207 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
208 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
209 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
210 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
211 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
212 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
213 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
214 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
215 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
216 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
217 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
218 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
219 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
220 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
221 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
222 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
223 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
224 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
225 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
226 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
227 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
228 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
229 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
230 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
231 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
232 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
233 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
234 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
235 | 0x00, 0x0a, 0x00, 0x05, 0x90, 0x00, 0x06, 0x00, | ||
236 | 0xa2, 0x05, 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, | ||
237 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
238 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
239 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
240 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
241 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
242 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
243 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
244 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
245 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
246 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
247 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
248 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
249 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
250 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
251 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
252 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
253 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
254 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
255 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
256 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
257 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
258 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
259 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
260 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
261 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
262 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
263 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
264 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
265 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
266 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
267 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
268 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
269 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
270 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
271 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
272 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
273 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
274 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
275 | 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, | ||
276 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
277 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
278 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
279 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
280 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
281 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
282 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
283 | 0x00, 0x0a, 0x00, 0x05, 0x90, 0x00, 0x06, 0x00, | ||
284 | 0xa2, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, | ||
285 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
286 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
287 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
288 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
289 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
290 | }; | ||
291 | |||
292 | /* | ||
293 | * Collection of HID reports from an authenticator issued with a FIDO2 | ||
294 | * 'enumerateEnrollments' bio enrollment command. | ||
295 | */ | ||
296 | static const uint8_t dummy_list_wire_data[] = { | ||
297 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0xae, | ||
298 | 0x21, 0x88, 0x51, 0x09, 0x6f, 0xd7, 0xbb, 0x00, | ||
299 | 0x10, 0x00, 0x0f, 0x02, 0x00, 0x04, 0x06, 0x05, | ||
300 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
301 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
302 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
303 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
304 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
305 | 0x00, 0x10, 0x00, 0x0f, 0x90, 0x00, 0x51, 0x00, | ||
306 | 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, | ||
307 | 0x20, 0x01, 0x21, 0x58, 0x20, 0x5a, 0x70, 0x63, | ||
308 | 0x11, 0x5b, 0xa6, 0xe1, 0x8e, 0x4a, 0xb0, 0x75, | ||
309 | 0xe7, 0xfd, 0x39, 0x26, 0x29, 0xed, 0x69, 0xb0, | ||
310 | 0xc1, 0x1f, 0xa5, 0x7d, 0xcb, 0x64, 0x1e, 0x7c, | ||
311 | 0x9f, 0x60, 0x5e, 0xb2, 0xf8, 0x22, 0x58, 0x20, | ||
312 | 0xec, 0xe9, 0x1b, 0x11, 0xac, 0x2a, 0x0d, 0xd5, | ||
313 | 0x00, 0x10, 0x00, 0x0f, 0x00, 0x3b, 0x9f, 0xba, | ||
314 | 0x0f, 0x25, 0xd5, 0x24, 0x33, 0x4c, 0x5d, 0x0f, | ||
315 | 0x63, 0xbf, 0xf1, 0xf3, 0x64, 0x55, 0x78, 0x1a, | ||
316 | 0x59, 0x6e, 0x65, 0x59, 0xfc, 0x00, 0x00, 0x00, | ||
317 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
318 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
319 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
320 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
321 | 0x00, 0x10, 0x00, 0x0f, 0x90, 0x00, 0x14, 0x00, | ||
322 | 0xa1, 0x02, 0x50, 0xb9, 0x31, 0x34, 0xe2, 0x71, | ||
323 | 0x6a, 0x8e, 0xa3, 0x60, 0xec, 0x5e, 0xd2, 0x13, | ||
324 | 0x2e, 0x19, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
325 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
326 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
327 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
328 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
329 | 0x00, 0x10, 0x00, 0x0f, 0x90, 0x00, 0x2e, 0x00, | ||
330 | 0xa1, 0x07, 0x83, 0xa2, 0x01, 0x42, 0xce, 0xa3, | ||
331 | 0x02, 0x67, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, | ||
332 | 0x31, 0xa2, 0x01, 0x42, 0xbf, 0x5e, 0x02, 0x67, | ||
333 | 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x32, 0xa2, | ||
334 | 0x01, 0x42, 0x5e, 0xd2, 0x02, 0x67, 0x66, 0x69, | ||
335 | 0x6e, 0x67, 0x65, 0x72, 0x33, 0x00, 0x00, 0x00, | ||
336 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
337 | }; | ||
338 | |||
339 | /* | ||
340 | * Collection of HID reports from an authenticator issued with a FIDO2 | ||
341 | * 'setFriendlyName' bio enrollment command. | ||
342 | */ | ||
343 | static const uint8_t dummy_set_name_wire_data[] = { | ||
344 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0xac, | ||
345 | 0x48, 0xfd, 0xbd, 0xdd, 0x36, 0x24, 0x4d, 0x00, | ||
346 | 0x10, 0x00, 0x10, 0x02, 0x00, 0x04, 0x06, 0x05, | ||
347 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
348 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
349 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
350 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
351 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
352 | 0x00, 0x10, 0x00, 0x10, 0x90, 0x00, 0x51, 0x00, | ||
353 | 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, | ||
354 | 0x20, 0x01, 0x21, 0x58, 0x20, 0x5a, 0x70, 0x63, | ||
355 | 0x11, 0x5b, 0xa6, 0xe1, 0x8e, 0x4a, 0xb0, 0x75, | ||
356 | 0xe7, 0xfd, 0x39, 0x26, 0x29, 0xed, 0x69, 0xb0, | ||
357 | 0xc1, 0x1f, 0xa5, 0x7d, 0xcb, 0x64, 0x1e, 0x7c, | ||
358 | 0x9f, 0x60, 0x5e, 0xb2, 0xf8, 0x22, 0x58, 0x20, | ||
359 | 0xec, 0xe9, 0x1b, 0x11, 0xac, 0x2a, 0x0d, 0xd5, | ||
360 | 0x00, 0x10, 0x00, 0x10, 0x00, 0x3b, 0x9f, 0xba, | ||
361 | 0x0f, 0x25, 0xd5, 0x24, 0x33, 0x4c, 0x5d, 0x0f, | ||
362 | 0x63, 0xbf, 0xf1, 0xf3, 0x64, 0x55, 0x78, 0x1a, | ||
363 | 0x59, 0x6e, 0x65, 0x59, 0xfc, 0x00, 0x00, 0x00, | ||
364 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
365 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
366 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
367 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
368 | 0x00, 0x10, 0x00, 0x10, 0x90, 0x00, 0x14, 0x00, | ||
369 | 0xa1, 0x02, 0x50, 0x40, 0x95, 0xf3, 0xcb, 0xae, | ||
370 | 0xf2, 0x8d, 0xd9, 0xe0, 0xe0, 0x8a, 0xbd, 0xc3, | ||
371 | 0x03, 0x58, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
372 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
373 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
374 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
375 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
376 | 0x00, 0x10, 0x00, 0x10, 0x90, 0x00, 0x01, 0x00, | ||
377 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
378 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
379 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
380 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
381 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
382 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
383 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
384 | }; | ||
385 | |||
386 | /* | ||
387 | * Collection of HID reports from an authenticator issued with a FIDO2 | ||
388 | * 'removeEnrollment' bio enrollment command. | ||
389 | */ | ||
390 | static const uint8_t dummy_remove_wire_data[] = { | ||
391 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x4b, | ||
392 | 0x24, 0xde, 0xd9, 0x06, 0x57, 0x1a, 0xbd, 0x00, | ||
393 | 0x10, 0x00, 0x15, 0x02, 0x00, 0x04, 0x06, 0x05, | ||
394 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
395 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
396 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
397 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
398 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
399 | 0x00, 0x10, 0x00, 0x15, 0x90, 0x00, 0x51, 0x00, | ||
400 | 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, | ||
401 | 0x20, 0x01, 0x21, 0x58, 0x20, 0x5a, 0x70, 0x63, | ||
402 | 0x11, 0x5b, 0xa6, 0xe1, 0x8e, 0x4a, 0xb0, 0x75, | ||
403 | 0xe7, 0xfd, 0x39, 0x26, 0x29, 0xed, 0x69, 0xb0, | ||
404 | 0xc1, 0x1f, 0xa5, 0x7d, 0xcb, 0x64, 0x1e, 0x7c, | ||
405 | 0x9f, 0x60, 0x5e, 0xb2, 0xf8, 0x22, 0x58, 0x20, | ||
406 | 0xec, 0xe9, 0x1b, 0x11, 0xac, 0x2a, 0x0d, 0xd5, | ||
407 | 0x00, 0x10, 0x00, 0x15, 0x00, 0x3b, 0x9f, 0xba, | ||
408 | 0x0f, 0x25, 0xd5, 0x24, 0x33, 0x4c, 0x5d, 0x0f, | ||
409 | 0x63, 0xbf, 0xf1, 0xf3, 0x64, 0x55, 0x78, 0x1a, | ||
410 | 0x59, 0x6e, 0x65, 0x59, 0xfc, 0x00, 0x00, 0x00, | ||
411 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
412 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
413 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
414 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
415 | 0x00, 0x10, 0x00, 0x15, 0x90, 0x00, 0x14, 0x00, | ||
416 | 0xa1, 0x02, 0x50, 0xb0, 0xd0, 0x71, 0x2f, 0xa7, | ||
417 | 0x8b, 0x89, 0xbd, 0xca, 0xa4, 0x1e, 0x6c, 0x43, | ||
418 | 0xa1, 0x71, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
419 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
420 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
421 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
422 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
423 | 0x00, 0x10, 0x00, 0x15, 0x90, 0x00, 0x01, 0x00, | ||
424 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
425 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
426 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
427 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
428 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
429 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
430 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
431 | }; | ||
432 | |||
433 | int LLVMFuzzerTestOneInput(const uint8_t *, size_t); | ||
434 | size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); | ||
435 | |||
436 | static int | ||
437 | unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN | ||
438 | { | ||
439 | uint8_t **pp = (void *)&ptr; | ||
440 | |||
441 | if (unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || | ||
442 | unpack_string(TAG_NAME, pp, &len, p->name) < 0 || | ||
443 | unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || | ||
444 | unpack_blob(TAG_ID, pp, &len, &p->id) < 0 || | ||
445 | unpack_blob(TAG_INFO_WIRE_DATA, pp, &len, &p->info_wire_data) < 0 || | ||
446 | unpack_blob(TAG_ENROLL_WIRE_DATA, pp, &len, &p->enroll_wire_data) < 0 || | ||
447 | unpack_blob(TAG_LIST_WIRE_DATA, pp, &len, &p->list_wire_data) < 0 || | ||
448 | unpack_blob(TAG_SET_NAME_WIRE_DATA, pp, &len, &p->set_name_wire_data) < 0 || | ||
449 | unpack_blob(TAG_REMOVE_WIRE_DATA, pp, &len, &p->remove_wire_data) < 0) | ||
450 | return (-1); | ||
451 | |||
452 | return (0); | ||
453 | } | ||
454 | |||
455 | static size_t | ||
456 | pack(uint8_t *ptr, size_t len, const struct param *p) | ||
457 | { | ||
458 | const size_t max = len; | ||
459 | |||
460 | if (pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || | ||
461 | pack_string(TAG_NAME, &ptr, &len, p->name) < 0 || | ||
462 | pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || | ||
463 | pack_blob(TAG_ID, &ptr, &len, &p->id) < 0 || | ||
464 | pack_blob(TAG_INFO_WIRE_DATA, &ptr, &len, &p->info_wire_data) < 0 || | ||
465 | pack_blob(TAG_ENROLL_WIRE_DATA, &ptr, &len, &p->enroll_wire_data) < 0 || | ||
466 | pack_blob(TAG_LIST_WIRE_DATA, &ptr, &len, &p->list_wire_data) < 0 || | ||
467 | pack_blob(TAG_SET_NAME_WIRE_DATA, &ptr, &len, &p->set_name_wire_data) < 0 || | ||
468 | pack_blob(TAG_REMOVE_WIRE_DATA, &ptr, &len, &p->remove_wire_data) < 0) | ||
469 | return (0); | ||
470 | |||
471 | return (max - len); | ||
472 | } | ||
473 | |||
474 | static fido_dev_t * | ||
475 | prepare_dev() | ||
476 | { | ||
477 | fido_dev_t *dev; | ||
478 | fido_dev_io_t io; | ||
479 | |||
480 | io.open = dev_open; | ||
481 | io.close = dev_close; | ||
482 | io.read = dev_read; | ||
483 | io.write = dev_write; | ||
484 | |||
485 | if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, | ||
486 | &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { | ||
487 | fido_dev_free(&dev); | ||
488 | return (NULL); | ||
489 | } | ||
490 | |||
491 | return (dev); | ||
492 | } | ||
493 | |||
494 | static void | ||
495 | get_info(struct param *p) | ||
496 | { | ||
497 | fido_dev_t *dev = NULL; | ||
498 | fido_bio_info_t *i = NULL; | ||
499 | uint8_t type; | ||
500 | uint8_t max_samples; | ||
501 | |||
502 | set_wire_data(p->info_wire_data.body, p->info_wire_data.len); | ||
503 | |||
504 | if ((dev = prepare_dev()) == NULL || (i = fido_bio_info_new()) == NULL) | ||
505 | goto done; | ||
506 | |||
507 | fido_bio_dev_get_info(dev, i); | ||
508 | |||
509 | type = fido_bio_info_type(i); | ||
510 | max_samples = fido_bio_info_max_samples(i); | ||
511 | consume(&type, sizeof(type)); | ||
512 | consume(&max_samples, sizeof(max_samples)); | ||
513 | |||
514 | done: | ||
515 | if (dev) | ||
516 | fido_dev_close(dev); | ||
517 | |||
518 | fido_dev_free(&dev); | ||
519 | fido_bio_info_free(&i); | ||
520 | } | ||
521 | |||
522 | static void | ||
523 | consume_template(const fido_bio_template_t *t) | ||
524 | { | ||
525 | consume(fido_bio_template_name(t), xstrlen(fido_bio_template_name(t))); | ||
526 | consume(fido_bio_template_id_ptr(t), fido_bio_template_id_len(t)); | ||
527 | } | ||
528 | |||
529 | static void | ||
530 | consume_enroll(fido_bio_enroll_t *e) | ||
531 | { | ||
532 | uint8_t last_status; | ||
533 | uint8_t remaining_samples; | ||
534 | |||
535 | last_status = fido_bio_enroll_last_status(e); | ||
536 | remaining_samples = fido_bio_enroll_remaining_samples(e); | ||
537 | consume(&last_status, sizeof(last_status)); | ||
538 | consume(&remaining_samples, sizeof(remaining_samples)); | ||
539 | } | ||
540 | |||
541 | static void | ||
542 | enroll(struct param *p) | ||
543 | { | ||
544 | fido_dev_t *dev = NULL; | ||
545 | fido_bio_template_t *t = NULL; | ||
546 | fido_bio_enroll_t *e = NULL; | ||
547 | size_t cnt = 0; | ||
548 | |||
549 | set_wire_data(p->enroll_wire_data.body, p->enroll_wire_data.len); | ||
550 | |||
551 | if ((dev = prepare_dev()) == NULL || | ||
552 | (t = fido_bio_template_new()) == NULL || | ||
553 | (e = fido_bio_enroll_new()) == NULL) | ||
554 | goto done; | ||
555 | |||
556 | fido_bio_dev_enroll_begin(dev, t, e, p->seed, p->pin); | ||
557 | |||
558 | consume_template(t); | ||
559 | consume_enroll(e); | ||
560 | |||
561 | while (fido_bio_enroll_remaining_samples(e) > 0 && cnt++ < 5) { | ||
562 | fido_bio_dev_enroll_continue(dev, t, e, p->seed); | ||
563 | consume_template(t); | ||
564 | consume_enroll(e); | ||
565 | } | ||
566 | |||
567 | done: | ||
568 | if (dev) | ||
569 | fido_dev_close(dev); | ||
570 | |||
571 | fido_dev_free(&dev); | ||
572 | fido_bio_template_free(&t); | ||
573 | fido_bio_enroll_free(&e); | ||
574 | } | ||
575 | |||
576 | static void | ||
577 | list(struct param *p) | ||
578 | { | ||
579 | fido_dev_t *dev = NULL; | ||
580 | fido_bio_template_array_t *ta = NULL; | ||
581 | const fido_bio_template_t *t = NULL; | ||
582 | |||
583 | set_wire_data(p->list_wire_data.body, p->list_wire_data.len); | ||
584 | |||
585 | if ((dev = prepare_dev()) == NULL || | ||
586 | (ta = fido_bio_template_array_new()) == NULL) | ||
587 | goto done; | ||
588 | |||
589 | fido_bio_dev_get_template_array(dev, ta, p->pin); | ||
590 | |||
591 | /* +1 on purpose */ | ||
592 | for (size_t i = 0; i < fido_bio_template_array_count(ta) + 1; i++) | ||
593 | if ((t = fido_bio_template(ta, i)) != NULL) | ||
594 | consume_template(t); | ||
595 | |||
596 | done: | ||
597 | if (dev) | ||
598 | fido_dev_close(dev); | ||
599 | |||
600 | fido_dev_free(&dev); | ||
601 | fido_bio_template_array_free(&ta); | ||
602 | } | ||
603 | |||
604 | static void | ||
605 | set_name(struct param *p) | ||
606 | { | ||
607 | fido_dev_t *dev = NULL; | ||
608 | fido_bio_template_t *t = NULL; | ||
609 | |||
610 | set_wire_data(p->set_name_wire_data.body, p->set_name_wire_data.len); | ||
611 | |||
612 | if ((dev = prepare_dev()) == NULL || | ||
613 | (t = fido_bio_template_new()) == NULL) | ||
614 | goto done; | ||
615 | |||
616 | fido_bio_template_set_name(t, p->name); | ||
617 | fido_bio_template_set_id(t, p->id.body, p->id.len); | ||
618 | consume_template(t); | ||
619 | |||
620 | fido_bio_dev_set_template_name(dev, t, p->pin); | ||
621 | |||
622 | done: | ||
623 | if (dev) | ||
624 | fido_dev_close(dev); | ||
625 | |||
626 | fido_dev_free(&dev); | ||
627 | fido_bio_template_free(&t); | ||
628 | } | ||
629 | |||
630 | static void | ||
631 | del(struct param *p) | ||
632 | { | ||
633 | fido_dev_t *dev = NULL; | ||
634 | fido_bio_template_t *t = NULL; | ||
635 | |||
636 | set_wire_data(p->remove_wire_data.body, p->remove_wire_data.len); | ||
637 | |||
638 | if ((dev = prepare_dev()) == NULL || | ||
639 | (t = fido_bio_template_new()) == NULL) | ||
640 | goto done; | ||
641 | |||
642 | fido_bio_template_set_id(t, p->id.body, p->id.len); | ||
643 | consume_template(t); | ||
644 | |||
645 | fido_bio_dev_enroll_remove(dev, t, p->pin); | ||
646 | |||
647 | done: | ||
648 | if (dev) | ||
649 | fido_dev_close(dev); | ||
650 | |||
651 | fido_dev_free(&dev); | ||
652 | fido_bio_template_free(&t); | ||
653 | } | ||
654 | |||
655 | int | ||
656 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) | ||
657 | { | ||
658 | struct param p; | ||
659 | |||
660 | memset(&p, 0, sizeof(p)); | ||
661 | |||
662 | if (unpack(data, size, &p) < 0) | ||
663 | return (0); | ||
664 | |||
665 | srandom((unsigned int)p.seed); | ||
666 | |||
667 | fido_init(0); | ||
668 | |||
669 | get_info(&p); | ||
670 | enroll(&p); | ||
671 | list(&p); | ||
672 | set_name(&p); | ||
673 | del(&p); | ||
674 | |||
675 | return (0); | ||
676 | } | ||
677 | |||
678 | static size_t | ||
679 | pack_dummy(uint8_t *ptr, size_t len) | ||
680 | { | ||
681 | struct param dummy; | ||
682 | uint8_t blob[32768]; | ||
683 | size_t blob_len; | ||
684 | |||
685 | memset(&dummy, 0, sizeof(dummy)); | ||
686 | |||
687 | strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); | ||
688 | strlcpy(dummy.name, dummy_name, sizeof(dummy.name)); | ||
689 | |||
690 | dummy.info_wire_data.len = sizeof(dummy_info_wire_data); | ||
691 | dummy.enroll_wire_data.len = sizeof(dummy_enroll_wire_data); | ||
692 | dummy.list_wire_data.len = sizeof(dummy_list_wire_data); | ||
693 | dummy.set_name_wire_data.len = sizeof(dummy_set_name_wire_data); | ||
694 | dummy.remove_wire_data.len = sizeof(dummy_remove_wire_data); | ||
695 | dummy.id.len = sizeof(dummy_id); | ||
696 | |||
697 | memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data, | ||
698 | dummy.info_wire_data.len); | ||
699 | memcpy(&dummy.enroll_wire_data.body, &dummy_enroll_wire_data, | ||
700 | dummy.enroll_wire_data.len); | ||
701 | memcpy(&dummy.list_wire_data.body, &dummy_list_wire_data, | ||
702 | dummy.list_wire_data.len); | ||
703 | memcpy(&dummy.set_name_wire_data.body, &dummy_set_name_wire_data, | ||
704 | dummy.set_name_wire_data.len); | ||
705 | memcpy(&dummy.remove_wire_data.body, &dummy_remove_wire_data, | ||
706 | dummy.remove_wire_data.len); | ||
707 | memcpy(&dummy.id.body, &dummy_id, dummy.id.len); | ||
708 | |||
709 | blob_len = pack(blob, sizeof(blob), &dummy); | ||
710 | assert(blob_len != 0); | ||
711 | |||
712 | if (blob_len > len) { | ||
713 | memcpy(ptr, blob, len); | ||
714 | return (len); | ||
715 | } | ||
716 | |||
717 | memcpy(ptr, blob, blob_len); | ||
718 | |||
719 | return (blob_len); | ||
720 | } | ||
721 | |||
722 | size_t | ||
723 | LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, | ||
724 | unsigned int seed) NO_MSAN | ||
725 | { | ||
726 | struct param p; | ||
727 | uint8_t blob[16384]; | ||
728 | size_t blob_len; | ||
729 | |||
730 | memset(&p, 0, sizeof(p)); | ||
731 | |||
732 | if (unpack(data, size, &p) < 0) | ||
733 | return (pack_dummy(data, maxsize)); | ||
734 | |||
735 | p.seed = (int)seed; | ||
736 | |||
737 | mutate_blob(&p.id); | ||
738 | mutate_blob(&p.info_wire_data); | ||
739 | mutate_blob(&p.enroll_wire_data); | ||
740 | mutate_blob(&p.list_wire_data); | ||
741 | mutate_blob(&p.set_name_wire_data); | ||
742 | mutate_blob(&p.remove_wire_data); | ||
743 | |||
744 | mutate_string(p.pin); | ||
745 | mutate_string(p.name); | ||
746 | |||
747 | blob_len = pack(blob, sizeof(blob), &p); | ||
748 | |||
749 | if (blob_len == 0 || blob_len > maxsize) | ||
750 | return (0); | ||
751 | |||
752 | memcpy(data, blob, blob_len); | ||
753 | |||
754 | return (blob_len); | ||
755 | } | ||
diff --git a/fuzz/fuzz_cred.c b/fuzz/fuzz_cred.c new file mode 100644 index 0000000..7bd1d3c --- /dev/null +++ b/fuzz/fuzz_cred.c | |||
@@ -0,0 +1,925 @@ | |||
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 <assert.h> | ||
8 | #include <stdint.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | #include <stdio.h> | ||
12 | |||
13 | #include "mutator_aux.h" | ||
14 | #include "fido.h" | ||
15 | |||
16 | #include "../openbsd-compat/openbsd-compat.h" | ||
17 | |||
18 | #define TAG_U2F 0x01 | ||
19 | #define TAG_TYPE 0x02 | ||
20 | #define TAG_CDH 0x03 | ||
21 | #define TAG_RP_ID 0x04 | ||
22 | #define TAG_RP_NAME 0x05 | ||
23 | #define TAG_USER_ID 0x06 | ||
24 | #define TAG_USER_NAME 0x07 | ||
25 | #define TAG_USER_NICK 0x08 | ||
26 | #define TAG_USER_ICON 0x09 | ||
27 | #define TAG_EXT 0x0a | ||
28 | #define TAG_SEED 0x0b | ||
29 | #define TAG_RK 0x0c | ||
30 | #define TAG_UV 0x0d | ||
31 | #define TAG_PIN 0x0e | ||
32 | #define TAG_WIRE_DATA 0x0f | ||
33 | #define TAG_EXCL_COUNT 0x10 | ||
34 | #define TAG_EXCL_CRED 0x11 | ||
35 | |||
36 | /* Parameter set defining a FIDO2 make credential operation. */ | ||
37 | struct param { | ||
38 | char pin[MAXSTR]; | ||
39 | char rp_id[MAXSTR]; | ||
40 | char rp_name[MAXSTR]; | ||
41 | char user_icon[MAXSTR]; | ||
42 | char user_name[MAXSTR]; | ||
43 | char user_nick[MAXSTR]; | ||
44 | int ext; | ||
45 | int seed; | ||
46 | struct blob cdh; | ||
47 | struct blob excl_cred; | ||
48 | struct blob user_id; | ||
49 | struct blob wire_data; | ||
50 | uint8_t excl_count; | ||
51 | uint8_t rk; | ||
52 | uint8_t type; | ||
53 | uint8_t u2f; | ||
54 | uint8_t uv; | ||
55 | }; | ||
56 | |||
57 | /* Example parameters. */ | ||
58 | static const char dummy_rp_id[] = "localhost"; | ||
59 | static const char dummy_rp_name[] = "sweet home localhost"; | ||
60 | static const char dummy_pin[] = "9}4gT:8d=A37Dh}U"; | ||
61 | static const char dummy_user_icon[] = "an icon"; | ||
62 | static const char dummy_user_name[] = "john smith"; | ||
63 | static const char dummy_user_nick[] = "jsmith"; | ||
64 | |||
65 | static const uint8_t dummy_cdh[] = { | ||
66 | 0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb, | ||
67 | 0xdd, 0xd7, 0xfb, 0x06, 0x37, 0x62, 0xea, 0x26, | ||
68 | 0x20, 0x44, 0x8e, 0x69, 0x7c, 0x03, 0xf2, 0x31, | ||
69 | 0x2f, 0x99, 0xdc, 0xaf, 0x3e, 0x8a, 0x91, 0x6b, | ||
70 | }; | ||
71 | |||
72 | static const uint8_t dummy_user_id[] = { | ||
73 | 0x78, 0x1c, 0x78, 0x60, 0xad, 0x88, 0xd2, 0x63, | ||
74 | 0x32, 0x62, 0x2a, 0xf1, 0x74, 0x5d, 0xed, 0xb2, | ||
75 | 0xe7, 0xa4, 0x2b, 0x44, 0x89, 0x29, 0x39, 0xc5, | ||
76 | 0x56, 0x64, 0x01, 0x27, 0x0d, 0xbb, 0xc4, 0x49, | ||
77 | }; | ||
78 | |||
79 | /* | ||
80 | * Collection of HID reports from an authenticator issued with a FIDO2 | ||
81 | * make credential using the example parameters above. | ||
82 | */ | ||
83 | static const uint8_t dummy_wire_data_fido[] = { | ||
84 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0xb0, | ||
85 | 0x84, 0xeb, 0xec, 0x4d, 0x97, 0x72, 0x09, 0x00, | ||
86 | 0x91, 0x00, 0x03, 0x02, 0x05, 0x00, 0x02, 0x05, | ||
87 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
88 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
89 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
90 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
91 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
92 | 0x00, 0x91, 0x00, 0x03, 0x90, 0x00, 0x51, 0x00, | ||
93 | 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, | ||
94 | 0x20, 0x01, 0x21, 0x58, 0x20, 0x69, 0xf2, 0x7d, | ||
95 | 0x37, 0x57, 0xda, 0x11, 0xba, 0x42, 0xde, 0x79, | ||
96 | 0xe4, 0xab, 0x8d, 0x73, 0x63, 0xee, 0x66, 0x9e, | ||
97 | 0x8a, 0x70, 0xa9, 0xb5, 0xf6, 0x38, 0x4f, 0x5b, | ||
98 | 0xdf, 0xe1, 0xa0, 0xa4, 0xff, 0x22, 0x58, 0x20, | ||
99 | 0x8a, 0xcb, 0x23, 0x2e, 0x93, 0xdb, 0xe0, 0xa4, | ||
100 | 0x00, 0x91, 0x00, 0x03, 0x00, 0xbb, 0xb5, 0x60, | ||
101 | 0x19, 0x18, 0x8b, 0x4d, 0xb8, 0x88, 0x6e, 0x13, | ||
102 | 0x75, 0xac, 0x00, 0x19, 0x27, 0x80, 0xcc, 0x63, | ||
103 | 0xc4, 0xbf, 0xfe, 0x4b, 0x4a, 0x00, 0x00, 0x00, | ||
104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
105 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
106 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
107 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
108 | 0x00, 0x91, 0x00, 0x03, 0x90, 0x00, 0x14, 0x00, | ||
109 | 0xa1, 0x02, 0x50, 0x10, 0x89, 0x77, 0x43, 0x3a, | ||
110 | 0x58, 0xa2, 0xc9, 0x98, 0x18, 0x1a, 0xb1, 0xcc, | ||
111 | 0x09, 0x6b, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
112 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
113 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
114 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
115 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
116 | 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, | ||
117 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
118 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
119 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
120 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
121 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
122 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
123 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
124 | 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, | ||
125 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
126 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
127 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
128 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
129 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
130 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
131 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
132 | 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, | ||
133 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
134 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
135 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
136 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
137 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
138 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
139 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
140 | 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, | ||
141 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
142 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
143 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
144 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
145 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
146 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
147 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
148 | 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, | ||
149 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
150 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
151 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
152 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
153 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
154 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
155 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
156 | 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, | ||
157 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
158 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
159 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
160 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
161 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
162 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
163 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
164 | 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, | ||
165 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
166 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
167 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
168 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
169 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
170 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
171 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
172 | 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, | ||
173 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
174 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
175 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
176 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
177 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
178 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
179 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
180 | 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, | ||
181 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
182 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
183 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
184 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
185 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
186 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
187 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
188 | 0x00, 0x91, 0x00, 0x03, 0xbb, 0x00, 0x01, 0x02, | ||
189 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
190 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
191 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
192 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
193 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
194 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
195 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
196 | 0x00, 0x91, 0x00, 0x03, 0x90, 0x03, 0xe1, 0x00, | ||
197 | 0xa3, 0x01, 0x66, 0x70, 0x61, 0x63, 0x6b, 0x65, | ||
198 | 0x64, 0x02, 0x58, 0xc4, 0x49, 0x96, 0x0d, 0xe5, | ||
199 | 0x88, 0x0e, 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, | ||
200 | 0x64, 0x76, 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, | ||
201 | 0xa2, 0x86, 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, | ||
202 | 0x83, 0x1d, 0x97, 0x63, 0x45, 0x00, 0x00, 0x00, | ||
203 | 0x00, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, | ||
204 | 0x00, 0x91, 0x00, 0x03, 0x00, 0x15, 0x80, 0x06, | ||
205 | 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, 0x40, | ||
206 | 0xed, 0x88, 0x48, 0xa1, 0xdb, 0x56, 0x4d, 0x0f, | ||
207 | 0x0d, 0xc8, 0x8f, 0x0f, 0xe9, 0x16, 0xb1, 0x78, | ||
208 | 0xa9, 0x40, 0x98, 0x71, 0xa0, 0xb3, 0xf2, 0xcf, | ||
209 | 0x05, 0x73, 0x6c, 0x12, 0xbf, 0x00, 0x96, 0xf3, | ||
210 | 0x7b, 0x93, 0xba, 0x49, 0xee, 0x23, 0xb4, 0x78, | ||
211 | 0x2e, 0xfb, 0xce, 0x27, 0xa8, 0xc2, 0x26, 0x78, | ||
212 | 0x00, 0x91, 0x00, 0x03, 0x01, 0xcc, 0x95, 0x2d, | ||
213 | 0x40, 0xdb, 0xd1, 0x40, 0x3d, 0x2b, 0xa3, 0x31, | ||
214 | 0xa0, 0x75, 0x82, 0x63, 0xf0, 0xa5, 0x01, 0x02, | ||
215 | 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x9d, | ||
216 | 0x95, 0xa1, 0xb5, 0xd6, 0x11, 0xbf, 0xe2, 0x28, | ||
217 | 0xa0, 0x7f, 0xca, 0x1e, 0xd9, 0x09, 0x0f, 0x0d, | ||
218 | 0xe7, 0x8e, 0x29, 0xe8, 0x2e, 0x11, 0xdb, 0x55, | ||
219 | 0x62, 0x13, 0xd7, 0x26, 0xc2, 0x7e, 0x2b, 0x22, | ||
220 | 0x00, 0x91, 0x00, 0x03, 0x02, 0x58, 0x20, 0xbe, | ||
221 | 0x74, 0x2a, 0xac, 0xde, 0x11, 0x40, 0x76, 0x31, | ||
222 | 0x0b, 0xed, 0x55, 0xde, 0xf3, 0x03, 0xe4, 0x1c, | ||
223 | 0xac, 0x42, 0x63, 0x8f, 0xe8, 0x30, 0x63, 0xb7, | ||
224 | 0x07, 0x4e, 0x5d, 0xfb, 0x17, 0x5e, 0x9b, 0x03, | ||
225 | 0xa3, 0x63, 0x61, 0x6c, 0x67, 0x26, 0x63, 0x73, | ||
226 | 0x69, 0x67, 0x58, 0x48, 0x30, 0x46, 0x02, 0x21, | ||
227 | 0x00, 0xfb, 0xd1, 0x26, 0x76, 0x34, 0x74, 0xac, | ||
228 | 0x00, 0x91, 0x00, 0x03, 0x03, 0xf6, 0xd8, 0x5c, | ||
229 | 0x5d, 0xbc, 0xda, 0xe0, 0x43, 0xe0, 0xa5, 0x42, | ||
230 | 0x9f, 0xc7, 0xe2, 0x18, 0x3e, 0xe2, 0x2c, 0x94, | ||
231 | 0x78, 0xbf, 0x9c, 0xeb, 0x3e, 0x9d, 0x02, 0x21, | ||
232 | 0x00, 0xab, 0x21, 0x1b, 0xc4, 0x30, 0x69, 0xee, | ||
233 | 0x7f, 0x09, 0xe6, 0x6b, 0x99, 0x98, 0x34, 0x07, | ||
234 | 0x7b, 0x9a, 0x58, 0xb2, 0xe8, 0x77, 0xe0, 0xba, | ||
235 | 0x7d, 0xab, 0x65, 0xf8, 0xba, 0x2a, 0xcb, 0x9a, | ||
236 | 0x00, 0x91, 0x00, 0x03, 0x04, 0x41, 0x63, 0x78, | ||
237 | 0x35, 0x63, 0x81, 0x59, 0x02, 0xb3, 0x30, 0x82, | ||
238 | 0x02, 0xaf, 0x30, 0x82, 0x01, 0x97, 0xa0, 0x03, | ||
239 | 0x02, 0x01, 0x02, 0x02, 0x04, 0x48, 0x5b, 0x3d, | ||
240 | 0xb6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, | ||
241 | 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, | ||
242 | 0x30, 0x21, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, | ||
243 | 0x55, 0x04, 0x03, 0x0c, 0x16, 0x59, 0x75, 0x62, | ||
244 | 0x00, 0x91, 0x00, 0x03, 0x05, 0x69, 0x63, 0x6f, | ||
245 | 0x20, 0x46, 0x49, 0x44, 0x4f, 0x20, 0x50, 0x72, | ||
246 | 0x65, 0x76, 0x69, 0x65, 0x77, 0x20, 0x43, 0x41, | ||
247 | 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x34, | ||
248 | 0x31, 0x32, 0x31, 0x30, 0x35, 0x37, 0x31, 0x30, | ||
249 | 0x5a, 0x17, 0x0d, 0x31, 0x38, 0x31, 0x32, 0x33, | ||
250 | 0x31, 0x31, 0x30, 0x35, 0x37, 0x31, 0x30, 0x5a, | ||
251 | 0x30, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, | ||
252 | 0x00, 0x91, 0x00, 0x03, 0x06, 0x55, 0x04, 0x06, | ||
253 | 0x13, 0x02, 0x53, 0x45, 0x31, 0x12, 0x30, 0x10, | ||
254 | 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x59, | ||
255 | 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x41, 0x42, | ||
256 | 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, | ||
257 | 0x0b, 0x0c, 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, | ||
258 | 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, | ||
259 | 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, | ||
260 | 0x00, 0x91, 0x00, 0x03, 0x07, 0x74, 0x69, 0x6f, | ||
261 | 0x6e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, | ||
262 | 0x04, 0x03, 0x0c, 0x1f, 0x59, 0x75, 0x62, 0x69, | ||
263 | 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20, 0x45, | ||
264 | 0x45, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, | ||
265 | 0x20, 0x31, 0x32, 0x31, 0x33, 0x39, 0x33, 0x39, | ||
266 | 0x31, 0x32, 0x36, 0x30, 0x59, 0x30, 0x13, 0x06, | ||
267 | 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, | ||
268 | 0x00, 0x91, 0x00, 0x03, 0x08, 0x06, 0x08, 0x2a, | ||
269 | 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, | ||
270 | 0x42, 0x00, 0x04, 0xfb, 0x2c, 0xdd, 0x30, 0x43, | ||
271 | 0x28, 0xc5, 0x72, 0x4a, 0x50, 0xcc, 0xe6, 0xf6, | ||
272 | 0x0b, 0xad, 0x7d, 0x27, 0xa9, 0x1b, 0x59, 0xe1, | ||
273 | 0xe6, 0x6f, 0x29, 0x7b, 0x89, 0xc9, 0xd4, 0x3d, | ||
274 | 0xc2, 0xb2, 0xc7, 0x78, 0x89, 0xb4, 0xf0, 0xff, | ||
275 | 0x9d, 0x02, 0x28, 0xcb, 0x94, 0x6d, 0xfc, 0xe0, | ||
276 | 0x00, 0x91, 0x00, 0x03, 0x09, 0x1b, 0x19, 0x58, | ||
277 | 0x9b, 0x67, 0x80, 0x4a, 0xac, 0x97, 0x7f, 0x28, | ||
278 | 0x18, 0x9c, 0xcd, 0xb3, 0x25, 0x74, 0xca, 0x28, | ||
279 | 0xa3, 0x6c, 0x30, 0x6a, 0x30, 0x22, 0x06, 0x09, | ||
280 | 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xc4, 0x0a, | ||
281 | 0x02, 0x04, 0x15, 0x31, 0x2e, 0x33, 0x2e, 0x36, | ||
282 | 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, | ||
283 | 0x31, 0x34, 0x38, 0x32, 0x2e, 0x31, 0x2e, 0x36, | ||
284 | 0x00, 0x91, 0x00, 0x03, 0x0a, 0x30, 0x13, 0x06, | ||
285 | 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xe5, | ||
286 | 0x1c, 0x02, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, | ||
287 | 0x04, 0x30, 0x30, 0x21, 0x06, 0x0b, 0x2b, 0x06, | ||
288 | 0x01, 0x04, 0x01, 0x82, 0xe5, 0x1c, 0x01, 0x01, | ||
289 | 0x04, 0x04, 0x12, 0x04, 0x10, 0xf8, 0xa0, 0x11, | ||
290 | 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, | ||
291 | 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x30, 0x0c, 0x06, | ||
292 | 0x00, 0x91, 0x00, 0x03, 0x0b, 0x03, 0x55, 0x1d, | ||
293 | 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, | ||
294 | 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, | ||
295 | 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, | ||
296 | 0x82, 0x01, 0x01, 0x00, 0x32, 0xf3, 0xe4, 0xbd, | ||
297 | 0x58, 0xd7, 0x42, 0x2b, 0xaf, 0x49, 0x99, 0x86, | ||
298 | 0x08, 0x1f, 0x0d, 0xa9, 0x3b, 0xc6, 0xaa, 0x1c, | ||
299 | 0x72, 0x11, 0xf9, 0x28, 0x53, 0xeb, 0xf3, 0xeb, | ||
300 | 0x00, 0x91, 0x00, 0x03, 0x0c, 0x73, 0xda, 0x69, | ||
301 | 0x3b, 0x06, 0xde, 0x31, 0x33, 0x8e, 0x5d, 0x02, | ||
302 | 0xec, 0xf6, 0x76, 0xe9, 0x5c, 0x42, 0xbe, 0xa5, | ||
303 | 0x8f, 0x25, 0xd3, 0x37, 0x3f, 0x77, 0xbb, 0x2a, | ||
304 | 0x9d, 0x7c, 0xb2, 0x3e, 0x11, 0x8c, 0x41, 0xd4, | ||
305 | 0x9a, 0x4c, 0x9a, 0xd8, 0xf3, 0xe2, 0xa4, 0xec, | ||
306 | 0x01, 0x77, 0x7a, 0x74, 0xa8, 0xc4, 0x12, 0x43, | ||
307 | 0xc3, 0x1e, 0xce, 0x20, 0x8f, 0x2d, 0x0f, 0x6e, | ||
308 | 0x00, 0x91, 0x00, 0x03, 0x0d, 0xbc, 0x61, 0x9b, | ||
309 | 0xe1, 0x84, 0xa1, 0x72, 0xf6, 0xa9, 0xac, 0xcb, | ||
310 | 0xf8, 0x73, 0x6d, 0x5b, 0xe2, 0x98, 0xb3, 0x6b, | ||
311 | 0xec, 0xe7, 0x1e, 0x77, 0x8d, 0x0a, 0x69, 0xaa, | ||
312 | 0xf9, 0x94, 0xb8, 0x63, 0x6d, 0xe8, 0xfa, 0xf6, | ||
313 | 0x2f, 0xd3, 0xce, 0x7f, 0x04, 0x4c, 0x32, 0x2c, | ||
314 | 0xf7, 0x26, 0x3e, 0x34, 0x99, 0xe6, 0xa5, 0xb2, | ||
315 | 0xb0, 0x2a, 0xbb, 0xad, 0x5b, 0xd9, 0xec, 0xe5, | ||
316 | 0x00, 0x91, 0x00, 0x03, 0x0e, 0xb0, 0x71, 0x4d, | ||
317 | 0x73, 0xbb, 0x94, 0x61, 0x49, 0x9c, 0x94, 0x2a, | ||
318 | 0x5f, 0x1d, 0xcc, 0xaf, 0x65, 0x03, 0x3b, 0x39, | ||
319 | 0x39, 0xd4, 0x47, 0xd9, 0xfc, 0xc4, 0x7b, 0x0b, | ||
320 | 0x16, 0xd8, 0xe9, 0x01, 0xfc, 0xec, 0x3f, 0x8c, | ||
321 | 0x1b, 0xc0, 0xc6, 0xac, 0x0b, 0x5d, 0x74, 0xc7, | ||
322 | 0xbb, 0x03, 0x05, 0x69, 0x17, 0xe9, 0x98, 0x1a, | ||
323 | 0x19, 0xb9, 0x09, 0x5c, 0xa1, 0xf4, 0xab, 0x9f, | ||
324 | 0x00, 0x91, 0x00, 0x03, 0x0f, 0x02, 0x7c, 0x28, | ||
325 | 0x0f, 0x8a, 0xf9, 0xed, 0x1d, 0x29, 0x3c, 0xf6, | ||
326 | 0xcc, 0x2f, 0x04, 0x6d, 0x9a, 0xd6, 0x62, 0xb4, | ||
327 | 0xa9, 0x6e, 0xb1, 0xca, 0xca, 0xac, 0x5e, 0x05, | ||
328 | 0x3e, 0x83, 0x91, 0x47, 0x7c, 0x1f, 0x8b, 0x60, | ||
329 | 0x01, 0xde, 0x65, 0x3a, 0xbf, 0xf2, 0xaa, 0xbb, | ||
330 | 0x55, 0x98, 0x86, 0x91, 0x7e, 0xad, 0x3b, 0x36, | ||
331 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
332 | }; | ||
333 | |||
334 | /* | ||
335 | * Collection of HID reports from an authenticator issued with a U2F | ||
336 | * registration using the example parameters above. | ||
337 | */ | ||
338 | static const uint8_t dummy_wire_data_u2f[] = { | ||
339 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x8e, | ||
340 | 0x80, 0xd0, 0xe2, 0x3b, 0x24, 0x93, 0xea, 0x00, | ||
341 | 0x00, 0x99, 0x01, 0x02, 0x01, 0x01, 0x00, 0x01, | ||
342 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
343 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
344 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
345 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
346 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
347 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
348 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
349 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
350 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
351 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
352 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
353 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
354 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
355 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
356 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
357 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
358 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
359 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
360 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
361 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
362 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
363 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
364 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
365 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
366 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
367 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
368 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
369 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
370 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
371 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
372 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
373 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
374 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
375 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
376 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
377 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
378 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
379 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
380 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
381 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
382 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
383 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
384 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
385 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
386 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
387 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
388 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
389 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
390 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
391 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
392 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
393 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
394 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
395 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
396 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
397 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
398 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
399 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
400 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
401 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
402 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
403 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
404 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
405 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
406 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
407 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
408 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
409 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
410 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
411 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
412 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
413 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
414 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
415 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
416 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
417 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
418 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
419 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
420 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
421 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
422 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
423 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
424 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
425 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
426 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
427 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
428 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
429 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
430 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
431 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
432 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
433 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
434 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
435 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
436 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
437 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
438 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
439 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
440 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
441 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
442 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
443 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
444 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
445 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
446 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
447 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
448 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
449 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
450 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
451 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
452 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
453 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
454 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
455 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
456 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
457 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
458 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
459 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
460 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
461 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
462 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
463 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
464 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
465 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
466 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
467 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
468 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
469 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
470 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
471 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
472 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
473 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
474 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
475 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
476 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
477 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
478 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
479 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
480 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
481 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
482 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
483 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
484 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
485 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
486 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
487 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
488 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
489 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
490 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
491 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
492 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
493 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
494 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
495 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
496 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
497 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
498 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
499 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
500 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
501 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
502 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
503 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
504 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
505 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
506 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
507 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, | ||
508 | 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
509 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
510 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
511 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
512 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
513 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
514 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
515 | 0x00, 0x00, 0x99, 0x01, 0x83, 0x03, 0x1e, 0x05, | ||
516 | 0x04, 0x9f, 0xa0, 0xf9, 0x0d, 0x4c, 0xf4, 0xae, | ||
517 | 0x96, 0x3c, 0xb7, 0x46, 0xb7, 0x5c, 0x9d, 0x8b, | ||
518 | 0x48, 0x19, 0xdf, 0xc4, 0xad, 0xea, 0xb2, 0x70, | ||
519 | 0x58, 0x72, 0xd9, 0xce, 0x75, 0xf5, 0xe6, 0x8e, | ||
520 | 0x0f, 0x9c, 0x0e, 0x2e, 0x62, 0x3e, 0x91, 0xd3, | ||
521 | 0x7b, 0x97, 0x46, 0x60, 0xb9, 0x57, 0x13, 0x97, | ||
522 | 0x26, 0xae, 0x0f, 0xb3, 0x8f, 0x2e, 0x9b, 0x3f, | ||
523 | 0x00, 0x00, 0x99, 0x01, 0x00, 0xa5, 0x55, 0xec, | ||
524 | 0x8c, 0x25, 0x7c, 0x65, 0xb7, 0x09, 0x40, 0x48, | ||
525 | 0xae, 0xa8, 0xcb, 0xa1, 0x91, 0xac, 0x40, 0x24, | ||
526 | 0xf2, 0x34, 0x6e, 0x3a, 0x8f, 0xa5, 0xb7, 0x48, | ||
527 | 0x54, 0x6e, 0xfb, 0xf4, 0x37, 0x88, 0x69, 0x79, | ||
528 | 0x6f, 0x12, 0xc1, 0x32, 0xdf, 0x15, 0x5d, 0x6e, | ||
529 | 0x82, 0x54, 0xc0, 0x6e, 0x56, 0x4f, 0x3a, 0x9c, | ||
530 | 0xc3, 0x96, 0x7a, 0xde, 0xa5, 0xfe, 0xec, 0xd1, | ||
531 | 0x00, 0x00, 0x99, 0x01, 0x01, 0x5a, 0x21, 0x85, | ||
532 | 0x0e, 0x25, 0x7b, 0x8d, 0x6e, 0x1d, 0x32, 0x29, | ||
533 | 0xdb, 0x21, 0xb0, 0xa3, 0x30, 0x82, 0x02, 0x4f, | ||
534 | 0x30, 0x82, 0x01, 0x37, 0xa0, 0x03, 0x02, 0x01, | ||
535 | 0x02, 0x02, 0x04, 0x2a, 0xd9, 0x6a, 0xf3, 0x30, | ||
536 | 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, | ||
537 | 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x2e, | ||
538 | 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, | ||
539 | 0x00, 0x00, 0x99, 0x01, 0x02, 0x03, 0x13, 0x23, | ||
540 | 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, | ||
541 | 0x32, 0x46, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, | ||
542 | 0x43, 0x41, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, | ||
543 | 0x6c, 0x20, 0x34, 0x35, 0x37, 0x32, 0x30, 0x30, | ||
544 | 0x36, 0x33, 0x31, 0x30, 0x20, 0x17, 0x0d, 0x31, | ||
545 | 0x34, 0x30, 0x38, 0x30, 0x31, 0x30, 0x30, 0x30, | ||
546 | 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, | ||
547 | 0x00, 0x00, 0x99, 0x01, 0x03, 0x35, 0x30, 0x30, | ||
548 | 0x39, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, | ||
549 | 0x30, 0x5a, 0x30, 0x31, 0x31, 0x2f, 0x30, 0x2d, | ||
550 | 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x26, 0x59, | ||
551 | 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, 0x32, | ||
552 | 0x46, 0x20, 0x45, 0x45, 0x20, 0x53, 0x65, 0x72, | ||
553 | 0x69, 0x61, 0x6c, 0x20, 0x32, 0x33, 0x39, 0x32, | ||
554 | 0x35, 0x37, 0x33, 0x34, 0x35, 0x31, 0x36, 0x35, | ||
555 | 0x00, 0x00, 0x99, 0x01, 0x04, 0x35, 0x30, 0x33, | ||
556 | 0x38, 0x37, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, | ||
557 | 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, | ||
558 | 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, | ||
559 | 0x07, 0x03, 0x42, 0x00, 0x04, 0x2f, 0xe1, 0xa2, | ||
560 | 0x3e, 0xbf, 0xa5, 0x5b, 0x3e, 0x46, 0x1d, 0x59, | ||
561 | 0xa4, 0x35, 0x22, 0xd7, 0x97, 0x48, 0x98, 0x1c, | ||
562 | 0xba, 0x6d, 0x28, 0x9a, 0x98, 0xf1, 0xbd, 0x7d, | ||
563 | 0x00, 0x00, 0x99, 0x01, 0x05, 0xff, 0x65, 0x66, | ||
564 | 0x80, 0xdb, 0xbb, 0xed, 0xbc, 0x2b, 0xae, 0x60, | ||
565 | 0x7e, 0x6e, 0xf7, 0x72, 0xf5, 0x76, 0xb0, 0x4d, | ||
566 | 0x54, 0xc4, 0xe5, 0xf3, 0x2f, 0x59, 0x6f, 0x26, | ||
567 | 0xe6, 0x11, 0x15, 0xc7, 0x27, 0x2c, 0xf6, 0xca, | ||
568 | 0x75, 0x94, 0xa3, 0x3b, 0x30, 0x39, 0x30, 0x22, | ||
569 | 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, | ||
570 | 0xc4, 0x0a, 0x02, 0x04, 0x15, 0x31, 0x2e, 0x33, | ||
571 | 0x00, 0x00, 0x99, 0x01, 0x06, 0x2e, 0x36, 0x2e, | ||
572 | 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x31, | ||
573 | 0x34, 0x38, 0x32, 0x2e, 0x31, 0x2e, 0x32, 0x30, | ||
574 | 0x13, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, | ||
575 | 0x82, 0xe5, 0x1c, 0x02, 0x01, 0x01, 0x04, 0x04, | ||
576 | 0x03, 0x02, 0x04, 0x30, 0x30, 0x0d, 0x06, 0x09, | ||
577 | 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, | ||
578 | 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, | ||
579 | 0x00, 0x00, 0x99, 0x01, 0x07, 0x85, 0x6a, 0xfa, | ||
580 | 0x8b, 0xcf, 0x4f, 0x3f, 0x62, 0x5f, 0x29, 0x1b, | ||
581 | 0xc1, 0x15, 0x8e, 0x3c, 0x7e, 0xbd, 0x25, 0x52, | ||
582 | 0xbc, 0xf7, 0x57, 0x07, 0x53, 0xf5, 0x12, 0x1d, | ||
583 | 0xa6, 0xa5, 0x4d, 0x24, 0xcc, 0xcf, 0xae, 0x27, | ||
584 | 0xce, 0xd6, 0xab, 0x31, 0x12, 0x8c, 0x29, 0x7e, | ||
585 | 0x5b, 0x5b, 0x89, 0x05, 0xdd, 0xa0, 0x20, 0x17, | ||
586 | 0x93, 0x1f, 0x1f, 0x5f, 0x59, 0x25, 0x93, 0x59, | ||
587 | 0x00, 0x00, 0x99, 0x01, 0x08, 0x51, 0xfc, 0x00, | ||
588 | 0x4b, 0xcb, 0xe2, 0x0a, 0xdd, 0x7d, 0x8d, 0x05, | ||
589 | 0x2f, 0x95, 0x43, 0xb3, 0x49, 0x6c, 0x15, 0xb8, | ||
590 | 0x31, 0x0e, 0x10, 0xcb, 0xd9, 0xbb, 0x05, 0x38, | ||
591 | 0x27, 0x4f, 0x58, 0x3e, 0xad, 0x1f, 0x45, 0x12, | ||
592 | 0x88, 0xc3, 0xea, 0x76, 0xd0, 0x70, 0xad, 0x44, | ||
593 | 0xe5, 0x3a, 0xfe, 0xa8, 0xf2, 0x2d, 0x1f, 0x73, | ||
594 | 0x62, 0x5f, 0xf2, 0xd5, 0x89, 0xfe, 0x30, 0xdf, | ||
595 | 0x00, 0x00, 0x99, 0x01, 0x09, 0x26, 0x62, 0xcb, | ||
596 | 0x7c, 0xbb, 0x7c, 0x99, 0x61, 0x80, 0xad, 0xcf, | ||
597 | 0xa9, 0x8a, 0x4d, 0x01, 0x2c, 0xf3, 0x13, 0x46, | ||
598 | 0xcd, 0x11, 0x74, 0x6a, 0x58, 0x48, 0xe8, 0xbe, | ||
599 | 0xed, 0xf3, 0xe3, 0x0c, 0xcb, 0xd9, 0xc1, 0xdd, | ||
600 | 0x22, 0x16, 0x71, 0xb2, 0x83, 0x88, 0x61, 0xf6, | ||
601 | 0x5a, 0x45, 0x36, 0x23, 0xb5, 0x18, 0xd5, 0x56, | ||
602 | 0x7f, 0xa8, 0xf0, 0xa3, 0xce, 0x10, 0x5d, 0xf4, | ||
603 | 0x00, 0x00, 0x99, 0x01, 0x0a, 0xf1, 0x39, 0x53, | ||
604 | 0xe1, 0x14, 0xea, 0x59, 0xe0, 0xa7, 0xf2, 0xfe, | ||
605 | 0x66, 0x88, 0x67, 0x43, 0x2e, 0x52, 0xfd, 0x6a, | ||
606 | 0x2f, 0x64, 0xf7, 0x3c, 0x48, 0xcd, 0x9b, 0x38, | ||
607 | 0xf2, 0xdf, 0xba, 0x2c, 0x7a, 0x4b, 0x3b, 0x11, | ||
608 | 0x28, 0xdf, 0x26, 0xd6, 0x6a, 0x24, 0xf8, 0x95, | ||
609 | 0xdd, 0xa0, 0xb6, 0x11, 0x80, 0xf4, 0x14, 0x4f, | ||
610 | 0x6b, 0x70, 0x75, 0xc3, 0x18, 0xa4, 0x9a, 0xe0, | ||
611 | 0x00, 0x00, 0x99, 0x01, 0x0b, 0x8b, 0x58, 0xd3, | ||
612 | 0x6a, 0xdb, 0x1e, 0x30, 0x53, 0x67, 0x2b, 0x17, | ||
613 | 0xc5, 0xa1, 0x9f, 0x7f, 0x0a, 0x22, 0xf1, 0x0e, | ||
614 | 0x94, 0x30, 0x44, 0x02, 0x20, 0x07, 0x5c, 0x4f, | ||
615 | 0xd2, 0x83, 0xb6, 0x9f, 0x0a, 0x4a, 0x4d, 0x4b, | ||
616 | 0x08, 0x35, 0xeb, 0xc0, 0x7e, 0x4a, 0x14, 0x2e, | ||
617 | 0xc7, 0x8c, 0xd6, 0x64, 0x2f, 0xd3, 0x1e, 0xcc, | ||
618 | 0xb5, 0xe8, 0x42, 0xea, 0xf6, 0x02, 0x20, 0x6b, | ||
619 | 0x00, 0x00, 0x99, 0x01, 0x0c, 0x5a, 0xba, 0x4a, | ||
620 | 0xc8, 0xd7, 0x89, 0xcc, 0x77, 0xe6, 0xb9, 0xa3, | ||
621 | 0x34, 0xea, 0x06, 0x85, 0x72, 0xc6, 0x28, 0xa8, | ||
622 | 0x7a, 0xaa, 0x19, 0x88, 0x34, 0xbb, 0xdc, 0x64, | ||
623 | 0x90, 0x0a, 0xdb, 0x39, 0x90, 0x00, 0x00, 0x00, | ||
624 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
625 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
626 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
627 | }; | ||
628 | |||
629 | int LLVMFuzzerTestOneInput(const uint8_t *, size_t); | ||
630 | size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); | ||
631 | |||
632 | static int | ||
633 | unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN | ||
634 | { | ||
635 | uint8_t **pp = (void *)&ptr; | ||
636 | |||
637 | if (unpack_byte(TAG_RK, pp, &len, &p->rk) < 0 || | ||
638 | unpack_byte(TAG_TYPE, pp, &len, &p->type) < 0 || | ||
639 | unpack_byte(TAG_U2F, pp, &len, &p->u2f) < 0 || | ||
640 | unpack_byte(TAG_UV, pp, &len, &p->uv) < 0 || | ||
641 | unpack_byte(TAG_EXCL_COUNT, pp, &len, &p->excl_count) < 0 || | ||
642 | unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || | ||
643 | unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || | ||
644 | unpack_string(TAG_RP_NAME, pp, &len, p->rp_name) < 0 || | ||
645 | unpack_string(TAG_USER_ICON, pp, &len, p->user_icon) < 0 || | ||
646 | unpack_string(TAG_USER_NAME, pp, &len, p->user_name) < 0 || | ||
647 | unpack_string(TAG_USER_NICK, pp, &len, p->user_nick) < 0 || | ||
648 | unpack_int(TAG_EXT, pp, &len, &p->ext) < 0 || | ||
649 | unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || | ||
650 | unpack_blob(TAG_CDH, pp, &len, &p->cdh) < 0 || | ||
651 | unpack_blob(TAG_USER_ID, pp, &len, &p->user_id) < 0 || | ||
652 | unpack_blob(TAG_WIRE_DATA, pp, &len, &p->wire_data) < 0 || | ||
653 | unpack_blob(TAG_EXCL_CRED, pp, &len, &p->excl_cred) < 0) | ||
654 | return (-1); | ||
655 | |||
656 | return (0); | ||
657 | } | ||
658 | |||
659 | static size_t | ||
660 | pack(uint8_t *ptr, size_t len, const struct param *p) | ||
661 | { | ||
662 | const size_t max = len; | ||
663 | |||
664 | if (pack_byte(TAG_RK, &ptr, &len, p->rk) < 0 || | ||
665 | pack_byte(TAG_TYPE, &ptr, &len, p->type) < 0 || | ||
666 | pack_byte(TAG_U2F, &ptr, &len, p->u2f) < 0 || | ||
667 | pack_byte(TAG_UV, &ptr, &len, p->uv) < 0 || | ||
668 | pack_byte(TAG_EXCL_COUNT, &ptr, &len, p->excl_count) < 0 || | ||
669 | pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || | ||
670 | pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || | ||
671 | pack_string(TAG_RP_NAME, &ptr, &len, p->rp_name) < 0 || | ||
672 | pack_string(TAG_USER_ICON, &ptr, &len, p->user_icon) < 0 || | ||
673 | pack_string(TAG_USER_NAME, &ptr, &len, p->user_name) < 0 || | ||
674 | pack_string(TAG_USER_NICK, &ptr, &len, p->user_nick) < 0 || | ||
675 | pack_int(TAG_EXT, &ptr, &len, p->ext) < 0 || | ||
676 | pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || | ||
677 | pack_blob(TAG_CDH, &ptr, &len, &p->cdh) < 0 || | ||
678 | pack_blob(TAG_USER_ID, &ptr, &len, &p->user_id) < 0 || | ||
679 | pack_blob(TAG_WIRE_DATA, &ptr, &len, &p->wire_data) < 0 || | ||
680 | pack_blob(TAG_EXCL_CRED, &ptr, &len, &p->excl_cred) < 0) | ||
681 | return (0); | ||
682 | |||
683 | return (max - len); | ||
684 | } | ||
685 | |||
686 | static void | ||
687 | make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh, | ||
688 | const char *rp_id, const char *rp_name, struct blob *user_id, | ||
689 | const char *user_name, const char *user_nick, const char *user_icon, | ||
690 | int ext, uint8_t rk, uint8_t uv, const char *pin, uint8_t excl_count, | ||
691 | struct blob *excl_cred) | ||
692 | { | ||
693 | fido_dev_t *dev; | ||
694 | fido_dev_io_t io; | ||
695 | |||
696 | io.open = dev_open; | ||
697 | io.close = dev_close; | ||
698 | io.read = dev_read; | ||
699 | io.write = dev_write; | ||
700 | |||
701 | if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, | ||
702 | &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { | ||
703 | fido_dev_free(&dev); | ||
704 | return; | ||
705 | } | ||
706 | |||
707 | if (u2f & 1) | ||
708 | fido_dev_force_u2f(dev); | ||
709 | |||
710 | for (uint8_t i = 0; i < excl_count; i++) | ||
711 | fido_cred_exclude(cred, excl_cred->body, excl_cred->len); | ||
712 | |||
713 | fido_cred_set_type(cred, type); | ||
714 | fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len); | ||
715 | fido_cred_set_rp(cred, rp_id, rp_name); | ||
716 | fido_cred_set_user(cred, user_id->body, user_id->len, user_name, | ||
717 | user_nick, user_icon); | ||
718 | fido_cred_set_extensions(cred, ext); | ||
719 | if (rk & 1) | ||
720 | fido_cred_set_rk(cred, FIDO_OPT_TRUE); | ||
721 | if (uv & 1) | ||
722 | fido_cred_set_uv(cred, FIDO_OPT_TRUE); | ||
723 | |||
724 | fido_dev_make_cred(dev, cred, u2f & 1 ? NULL : pin); | ||
725 | |||
726 | fido_dev_cancel(dev); | ||
727 | fido_dev_close(dev); | ||
728 | fido_dev_free(&dev); | ||
729 | } | ||
730 | |||
731 | static void | ||
732 | verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len, | ||
733 | const char *rp_id, const char *rp_name, const unsigned char *authdata_ptr, | ||
734 | size_t authdata_len, int ext, uint8_t rk, uint8_t uv, | ||
735 | const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr, | ||
736 | size_t sig_len, const char *fmt) | ||
737 | { | ||
738 | fido_cred_t *cred; | ||
739 | uint8_t flags; | ||
740 | |||
741 | if ((cred = fido_cred_new()) == NULL) { | ||
742 | warnx("%s: fido_cred_new", __func__); | ||
743 | return; | ||
744 | } | ||
745 | |||
746 | fido_cred_set_type(cred, type); | ||
747 | fido_cred_set_clientdata_hash(cred, cdh_ptr, cdh_len); | ||
748 | fido_cred_set_rp(cred, rp_id, rp_name); | ||
749 | if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK) | ||
750 | fido_cred_set_authdata_raw(cred, authdata_ptr, authdata_len); | ||
751 | fido_cred_set_extensions(cred, ext); | ||
752 | fido_cred_set_x509(cred, x5c_ptr, x5c_len); | ||
753 | fido_cred_set_sig(cred, sig_ptr, sig_len); | ||
754 | |||
755 | if (rk & 1) | ||
756 | fido_cred_set_rk(cred, FIDO_OPT_TRUE); | ||
757 | if (uv & 1) | ||
758 | fido_cred_set_uv(cred, FIDO_OPT_TRUE); | ||
759 | if (fmt) | ||
760 | fido_cred_set_fmt(cred, fmt); | ||
761 | |||
762 | fido_cred_verify(cred); | ||
763 | fido_cred_verify_self(cred); | ||
764 | |||
765 | consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); | ||
766 | consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); | ||
767 | consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred)); | ||
768 | consume(fido_cred_user_name(cred), xstrlen(fido_cred_user_name(cred))); | ||
769 | consume(fido_cred_display_name(cred), | ||
770 | xstrlen(fido_cred_display_name(cred))); | ||
771 | |||
772 | flags = fido_cred_flags(cred); | ||
773 | consume(&flags, sizeof(flags)); | ||
774 | type = fido_cred_type(cred); | ||
775 | consume(&type, sizeof(type)); | ||
776 | |||
777 | fido_cred_free(&cred); | ||
778 | } | ||
779 | |||
780 | int | ||
781 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) | ||
782 | { | ||
783 | struct param p; | ||
784 | fido_cred_t *cred = NULL; | ||
785 | int cose_alg = 0; | ||
786 | |||
787 | memset(&p, 0, sizeof(p)); | ||
788 | |||
789 | if (unpack(data, size, &p) < 0) | ||
790 | return (0); | ||
791 | |||
792 | srandom((unsigned int)p.seed); | ||
793 | |||
794 | fido_init(0); | ||
795 | |||
796 | if ((cred = fido_cred_new()) == NULL) | ||
797 | return (0); | ||
798 | |||
799 | set_wire_data(p.wire_data.body, p.wire_data.len); | ||
800 | |||
801 | switch (p.type & 3) { | ||
802 | case 0: | ||
803 | cose_alg = COSE_ES256; | ||
804 | break; | ||
805 | case 1: | ||
806 | cose_alg = COSE_RS256; | ||
807 | break; | ||
808 | default: | ||
809 | cose_alg = COSE_EDDSA; | ||
810 | break; | ||
811 | } | ||
812 | |||
813 | make_cred(cred, p.u2f, cose_alg, &p.cdh, p.rp_id, p.rp_name, | ||
814 | &p.user_id, p.user_name, p.user_nick, p.user_icon, p.ext, p.rk, | ||
815 | p.uv, p.pin, p.excl_count, &p.excl_cred); | ||
816 | |||
817 | verify_cred(cose_alg, | ||
818 | fido_cred_clientdata_hash_ptr(cred), | ||
819 | fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred), | ||
820 | fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred), | ||
821 | fido_cred_authdata_len(cred), p.ext, p.rk, p.uv, | ||
822 | fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred), | ||
823 | fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), | ||
824 | fido_cred_fmt(cred)); | ||
825 | |||
826 | fido_cred_free(&cred); | ||
827 | |||
828 | return (0); | ||
829 | } | ||
830 | |||
831 | static size_t | ||
832 | pack_dummy(uint8_t *ptr, size_t len) | ||
833 | { | ||
834 | struct param dummy; | ||
835 | uint8_t blob[16384]; | ||
836 | size_t blob_len; | ||
837 | |||
838 | memset(&dummy, 0, sizeof(dummy)); | ||
839 | |||
840 | dummy.type = 1; | ||
841 | dummy.ext = FIDO_EXT_HMAC_SECRET; | ||
842 | |||
843 | strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); | ||
844 | strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); | ||
845 | strlcpy(dummy.rp_name, dummy_rp_name, sizeof(dummy.rp_name)); | ||
846 | strlcpy(dummy.user_icon, dummy_user_icon, sizeof(dummy.user_icon)); | ||
847 | strlcpy(dummy.user_name, dummy_user_name, sizeof(dummy.user_name)); | ||
848 | strlcpy(dummy.user_nick, dummy_user_nick, sizeof(dummy.user_nick)); | ||
849 | |||
850 | dummy.cdh.len = sizeof(dummy_cdh); | ||
851 | dummy.user_id.len = sizeof(dummy_user_id); | ||
852 | dummy.wire_data.len = sizeof(dummy_wire_data_fido); | ||
853 | |||
854 | memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); | ||
855 | memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len); | ||
856 | memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, | ||
857 | dummy.wire_data.len); | ||
858 | |||
859 | blob_len = pack(blob, sizeof(blob), &dummy); | ||
860 | assert(blob_len != 0); | ||
861 | |||
862 | if (blob_len > len) { | ||
863 | memcpy(ptr, blob, len); | ||
864 | return (len); | ||
865 | } | ||
866 | |||
867 | memcpy(ptr, blob, blob_len); | ||
868 | |||
869 | return (blob_len); | ||
870 | } | ||
871 | |||
872 | size_t | ||
873 | LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, | ||
874 | unsigned int seed) NO_MSAN | ||
875 | { | ||
876 | struct param p; | ||
877 | uint8_t blob[16384]; | ||
878 | size_t blob_len; | ||
879 | |||
880 | memset(&p, 0, sizeof(p)); | ||
881 | |||
882 | if (unpack(data, size, &p) < 0) | ||
883 | return (pack_dummy(data, maxsize)); | ||
884 | |||
885 | mutate_byte(&p.rk); | ||
886 | mutate_byte(&p.type); | ||
887 | mutate_byte(&p.u2f); | ||
888 | mutate_byte(&p.uv); | ||
889 | mutate_byte(&p.excl_count); | ||
890 | |||
891 | mutate_int(&p.ext); | ||
892 | p.seed = (int)seed; | ||
893 | |||
894 | mutate_blob(&p.cdh); | ||
895 | mutate_blob(&p.user_id); | ||
896 | |||
897 | if (p.u2f & 1) { | ||
898 | p.wire_data.len = sizeof(dummy_wire_data_u2f); | ||
899 | memcpy(&p.wire_data.body, &dummy_wire_data_u2f, | ||
900 | p.wire_data.len); | ||
901 | } else { | ||
902 | p.wire_data.len = sizeof(dummy_wire_data_fido); | ||
903 | memcpy(&p.wire_data.body, &dummy_wire_data_fido, | ||
904 | p.wire_data.len); | ||
905 | } | ||
906 | |||
907 | mutate_blob(&p.wire_data); | ||
908 | mutate_blob(&p.excl_cred); | ||
909 | |||
910 | mutate_string(p.pin); | ||
911 | mutate_string(p.user_icon); | ||
912 | mutate_string(p.user_name); | ||
913 | mutate_string(p.user_nick); | ||
914 | mutate_string(p.rp_id); | ||
915 | mutate_string(p.rp_name); | ||
916 | |||
917 | blob_len = pack(blob, sizeof(blob), &p); | ||
918 | |||
919 | if (blob_len == 0 || blob_len > maxsize) | ||
920 | return (0); | ||
921 | |||
922 | memcpy(data, blob, blob_len); | ||
923 | |||
924 | return (blob_len); | ||
925 | } | ||
diff --git a/fuzz/fuzz_credman.c b/fuzz/fuzz_credman.c new file mode 100644 index 0000000..4359938 --- /dev/null +++ b/fuzz/fuzz_credman.c | |||
@@ -0,0 +1,667 @@ | |||
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 <assert.h> | ||
8 | #include <stdint.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | #include <stdio.h> | ||
12 | |||
13 | #include "mutator_aux.h" | ||
14 | #include "fido.h" | ||
15 | #include "fido/credman.h" | ||
16 | |||
17 | #include "../openbsd-compat/openbsd-compat.h" | ||
18 | |||
19 | #define TAG_META_WIRE_DATA 0x01 | ||
20 | #define TAG_RP_WIRE_DATA 0x02 | ||
21 | #define TAG_RK_WIRE_DATA 0x03 | ||
22 | #define TAG_DEL_WIRE_DATA 0x04 | ||
23 | #define TAG_CRED_ID 0x05 | ||
24 | #define TAG_PIN 0x06 | ||
25 | #define TAG_RP_ID 0x07 | ||
26 | #define TAG_SEED 0x08 | ||
27 | |||
28 | /* Parameter set defining a FIDO2 credential management operation. */ | ||
29 | struct param { | ||
30 | char pin[MAXSTR]; | ||
31 | char rp_id[MAXSTR]; | ||
32 | int seed; | ||
33 | struct blob cred_id; | ||
34 | struct blob del_wire_data; | ||
35 | struct blob meta_wire_data; | ||
36 | struct blob rk_wire_data; | ||
37 | struct blob rp_wire_data; | ||
38 | }; | ||
39 | |||
40 | /* Example parameters. */ | ||
41 | static const uint8_t dummy_cred_id[] = { | ||
42 | 0x4f, 0x72, 0x98, 0x42, 0x4a, 0xe1, 0x17, 0xa5, | ||
43 | 0x85, 0xa0, 0xef, 0x3b, 0x11, 0x24, 0x4a, 0x3d, | ||
44 | }; | ||
45 | static const char dummy_pin[] = "[n#899:~m"; | ||
46 | static const char dummy_rp_id[] = "yubico.com"; | ||
47 | |||
48 | /* | ||
49 | * Collection of HID reports from an authenticator issued with a FIDO2 | ||
50 | * 'getCredsMetadata' credential management command. | ||
51 | */ | ||
52 | static const uint8_t dummy_meta_wire_data[] = { | ||
53 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0xc5, | ||
54 | 0xb7, 0x89, 0xba, 0x8d, 0x5f, 0x94, 0x1b, 0x00, | ||
55 | 0x12, 0x00, 0x04, 0x02, 0x00, 0x04, 0x05, 0x05, | ||
56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
58 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
59 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
60 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
61 | 0x00, 0x12, 0x00, 0x04, 0x90, 0x00, 0x51, 0x00, | ||
62 | 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, | ||
63 | 0x20, 0x01, 0x21, 0x58, 0x20, 0x93, 0xc5, 0x64, | ||
64 | 0x71, 0xe9, 0xd1, 0xb8, 0xed, 0xf6, 0xd5, 0xf3, | ||
65 | 0xa7, 0xd5, 0x96, 0x70, 0xbb, 0xd5, 0x20, 0xa1, | ||
66 | 0xa3, 0xd3, 0x93, 0x4c, 0x5c, 0x20, 0x5c, 0x22, | ||
67 | 0xeb, 0xb0, 0x6a, 0x27, 0x59, 0x22, 0x58, 0x20, | ||
68 | 0x63, 0x02, 0x33, 0xa8, 0xed, 0x3c, 0xbc, 0xe9, | ||
69 | 0x00, 0x12, 0x00, 0x04, 0x00, 0xda, 0x44, 0xf5, | ||
70 | 0xed, 0xda, 0xe6, 0xa4, 0xad, 0x3f, 0x9e, 0xf8, | ||
71 | 0x50, 0x8d, 0x01, 0x47, 0x6c, 0x4e, 0x72, 0xa4, | ||
72 | 0x04, 0x13, 0xa8, 0x65, 0x97, 0x00, 0x00, 0x00, | ||
73 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
74 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
75 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
76 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
77 | 0x00, 0x12, 0x00, 0x04, 0x90, 0x00, 0x14, 0x00, | ||
78 | 0xa1, 0x02, 0x50, 0x6f, 0x11, 0x96, 0x21, 0x92, | ||
79 | 0x52, 0xf1, 0x6b, 0xd4, 0x2c, 0xe3, 0xf8, 0xc9, | ||
80 | 0x8c, 0x47, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
81 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
82 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
83 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
84 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
85 | 0x00, 0x12, 0x00, 0x04, 0x90, 0x00, 0x07, 0x00, | ||
86 | 0xa2, 0x01, 0x00, 0x02, 0x18, 0x19, 0x00, 0x00, | ||
87 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
88 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
89 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
90 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
91 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
92 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
93 | }; | ||
94 | |||
95 | /* | ||
96 | * Collection of HID reports from an authenticator issued with a FIDO2 | ||
97 | * 'enumerateRPsBegin' credential management command. | ||
98 | */ | ||
99 | static const uint8_t dummy_rp_wire_data[] = { | ||
100 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x87, | ||
101 | 0xbf, 0xc6, 0x7f, 0x36, 0xf5, 0xe2, 0x49, 0x00, | ||
102 | 0x15, 0x00, 0x02, 0x02, 0x00, 0x04, 0x05, 0x05, | ||
103 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
105 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
106 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
107 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
108 | 0x00, 0x15, 0x00, 0x02, 0x90, 0x00, 0x51, 0x00, | ||
109 | 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, | ||
110 | 0x20, 0x01, 0x21, 0x58, 0x20, 0x12, 0xc1, 0x81, | ||
111 | 0x6b, 0x92, 0x6a, 0x56, 0x05, 0xfe, 0xdb, 0xab, | ||
112 | 0x90, 0x2f, 0x57, 0x0b, 0x3d, 0x85, 0x3e, 0x3f, | ||
113 | 0xbc, 0xe5, 0xd3, 0xb6, 0x86, 0xdf, 0x10, 0x43, | ||
114 | 0xc2, 0xaf, 0x87, 0x34, 0x0e, 0x22, 0x58, 0x20, | ||
115 | 0xd3, 0x0f, 0x7e, 0x5d, 0x10, 0x33, 0x57, 0x24, | ||
116 | 0x00, 0x15, 0x00, 0x02, 0x00, 0x6e, 0x90, 0x58, | ||
117 | 0x61, 0x2a, 0xd2, 0xc2, 0x1e, 0x08, 0xea, 0x91, | ||
118 | 0xcb, 0x44, 0x66, 0x73, 0x29, 0x92, 0x29, 0x59, | ||
119 | 0x91, 0xa3, 0x4d, 0x2c, 0xbb, 0x00, 0x00, 0x00, | ||
120 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
121 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
122 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
123 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
124 | 0x00, 0x15, 0x00, 0x02, 0x90, 0x00, 0x14, 0x00, | ||
125 | 0xa1, 0x02, 0x50, 0x6d, 0x95, 0x0e, 0x73, 0x78, | ||
126 | 0x46, 0x13, 0x2e, 0x07, 0xbf, 0xeb, 0x61, 0x31, | ||
127 | 0x37, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
128 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
129 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
130 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
131 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
132 | 0x00, 0x15, 0x00, 0x02, 0x90, 0x00, 0x37, 0x00, | ||
133 | 0xa3, 0x03, 0xa1, 0x62, 0x69, 0x64, 0x6a, 0x79, | ||
134 | 0x75, 0x62, 0x69, 0x63, 0x6f, 0x2e, 0x63, 0x6f, | ||
135 | 0x6d, 0x04, 0x58, 0x20, 0x37, 0x82, 0x09, 0xb7, | ||
136 | 0x2d, 0xef, 0xcb, 0xa9, 0x1d, 0xcb, 0xf8, 0x54, | ||
137 | 0xed, 0xb4, 0xda, 0xa6, 0x48, 0x82, 0x8a, 0x2c, | ||
138 | 0xbd, 0x18, 0x0a, 0xfc, 0x77, 0xa7, 0x44, 0x34, | ||
139 | 0x65, 0x5a, 0x1c, 0x7d, 0x05, 0x03, 0x00, 0x00, | ||
140 | 0x00, 0x15, 0x00, 0x02, 0x90, 0x00, 0x36, 0x00, | ||
141 | 0xa2, 0x03, 0xa1, 0x62, 0x69, 0x64, 0x6b, 0x79, | ||
142 | 0x75, 0x62, 0x69, 0x6b, 0x65, 0x79, 0x2e, 0x6f, | ||
143 | 0x72, 0x67, 0x04, 0x58, 0x20, 0x12, 0x6b, 0xba, | ||
144 | 0x6a, 0x2d, 0x7a, 0x81, 0x84, 0x25, 0x7b, 0x74, | ||
145 | 0xdd, 0x1d, 0xdd, 0x46, 0xb6, 0x2a, 0x8c, 0xa2, | ||
146 | 0xa7, 0x83, 0xfe, 0xdb, 0x5b, 0x19, 0x48, 0x73, | ||
147 | 0x55, 0xb7, 0xe3, 0x46, 0x09, 0x00, 0x00, 0x00, | ||
148 | 0x00, 0x15, 0x00, 0x02, 0x90, 0x00, 0x37, 0x00, | ||
149 | 0xa2, 0x03, 0xa1, 0x62, 0x69, 0x64, 0x6c, 0x77, | ||
150 | 0x65, 0x62, 0x61, 0x75, 0x74, 0x68, 0x6e, 0x2e, | ||
151 | 0x64, 0x65, 0x76, 0x04, 0x58, 0x20, 0xd6, 0x32, | ||
152 | 0x7d, 0x8c, 0x6a, 0x5d, 0xe6, 0xae, 0x0e, 0x33, | ||
153 | 0xd0, 0xa3, 0x31, 0xfb, 0x67, 0x77, 0xb9, 0x4e, | ||
154 | 0xf4, 0x73, 0x19, 0xfe, 0x7e, 0xfd, 0xfa, 0x82, | ||
155 | 0x70, 0x8e, 0x1f, 0xbb, 0xa2, 0x55, 0x00, 0x00, | ||
156 | }; | ||
157 | |||
158 | /* | ||
159 | * Collection of HID reports from an authenticator issued with a FIDO2 | ||
160 | * 'enumerateCredentialsBegin' credential management command. | ||
161 | */ | ||
162 | static const uint8_t dummy_rk_wire_data[] = { | ||
163 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x35, | ||
164 | 0x3b, 0x34, 0xb9, 0xcb, 0xeb, 0x40, 0x55, 0x00, | ||
165 | 0x15, 0x00, 0x04, 0x02, 0x00, 0x04, 0x05, 0x05, | ||
166 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
167 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
168 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
169 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
170 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
171 | 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0x51, 0x00, | ||
172 | 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, | ||
173 | 0x20, 0x01, 0x21, 0x58, 0x20, 0x12, 0xc1, 0x81, | ||
174 | 0x6b, 0x92, 0x6a, 0x56, 0x05, 0xfe, 0xdb, 0xab, | ||
175 | 0x90, 0x2f, 0x57, 0x0b, 0x3d, 0x85, 0x3e, 0x3f, | ||
176 | 0xbc, 0xe5, 0xd3, 0xb6, 0x86, 0xdf, 0x10, 0x43, | ||
177 | 0xc2, 0xaf, 0x87, 0x34, 0x0e, 0x22, 0x58, 0x20, | ||
178 | 0xd3, 0x0f, 0x7e, 0x5d, 0x10, 0x33, 0x57, 0x24, | ||
179 | 0x00, 0x15, 0x00, 0x04, 0x00, 0x6e, 0x90, 0x58, | ||
180 | 0x61, 0x2a, 0xd2, 0xc2, 0x1e, 0x08, 0xea, 0x91, | ||
181 | 0xcb, 0x44, 0x66, 0x73, 0x29, 0x92, 0x29, 0x59, | ||
182 | 0x91, 0xa3, 0x4d, 0x2c, 0xbb, 0x00, 0x00, 0x00, | ||
183 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
184 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
185 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
186 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
187 | 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0x14, 0x00, | ||
188 | 0xa1, 0x02, 0x50, 0x1b, 0xf0, 0x01, 0x0d, 0x32, | ||
189 | 0xee, 0x28, 0xa4, 0x5a, 0x7f, 0x56, 0x5b, 0x28, | ||
190 | 0xfd, 0x1f, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
191 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
192 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
193 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
194 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
195 | 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xc5, 0x00, | ||
196 | 0xa5, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, | ||
197 | 0xe4, 0xe1, 0x06, 0x31, 0xde, 0x00, 0x0f, 0x4f, | ||
198 | 0x12, 0x6e, 0xc9, 0x68, 0x2d, 0x43, 0x3f, 0xf1, | ||
199 | 0x02, 0x2c, 0x6e, 0xe6, 0x96, 0x10, 0xbf, 0x73, | ||
200 | 0x35, 0xc9, 0x20, 0x27, 0x06, 0xba, 0x39, 0x09, | ||
201 | 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, | ||
202 | 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, | ||
203 | 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, | ||
204 | 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, | ||
205 | 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, | ||
206 | 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0x19, | ||
207 | 0xf7, 0x78, 0x0c, 0xa0, 0xbc, 0xb9, 0xa6, 0xd5, | ||
208 | 0x1e, 0xd7, 0x87, 0xfb, 0x6c, 0x80, 0x03, 0x64, | ||
209 | 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, | ||
210 | 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, | ||
211 | 0x00, 0x15, 0x00, 0x04, 0x01, 0xa5, 0x01, 0x02, | ||
212 | 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x81, | ||
213 | 0x6c, 0xdd, 0x8c, 0x8f, 0x8c, 0xc8, 0x43, 0xa7, | ||
214 | 0xbb, 0x79, 0x51, 0x09, 0xb1, 0xdf, 0xbe, 0xc4, | ||
215 | 0xa5, 0x54, 0x16, 0x9e, 0x58, 0x56, 0xb3, 0x0b, | ||
216 | 0x34, 0x4f, 0xa5, 0x6c, 0x05, 0xa2, 0x21, 0x22, | ||
217 | 0x58, 0x20, 0xcd, 0xc2, 0x0c, 0x99, 0x83, 0x5a, | ||
218 | 0x61, 0x73, 0xd8, 0xe0, 0x74, 0x23, 0x46, 0x64, | ||
219 | 0x00, 0x15, 0x00, 0x04, 0x02, 0x39, 0x4c, 0xb0, | ||
220 | 0xf4, 0x6c, 0x0a, 0x37, 0x72, 0xaa, 0xa8, 0xea, | ||
221 | 0x58, 0xd3, 0xd4, 0xe0, 0x51, 0xb2, 0x28, 0x09, | ||
222 | 0x05, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
223 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
224 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
225 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
226 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
227 | 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xa0, 0x00, | ||
228 | 0xa4, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, | ||
229 | 0x56, 0xa1, 0x3c, 0x06, 0x2b, 0xad, 0xa2, 0x21, | ||
230 | 0x7d, 0xcd, 0x91, 0x08, 0x47, 0xa8, 0x8a, 0x06, | ||
231 | 0x06, 0xf6, 0x66, 0x91, 0xf6, 0xeb, 0x89, 0xe4, | ||
232 | 0xdf, 0x26, 0xbc, 0x46, 0x59, 0xc3, 0x7d, 0xc0, | ||
233 | 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, | ||
234 | 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, | ||
235 | 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, | ||
236 | 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, | ||
237 | 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, | ||
238 | 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0xd8, | ||
239 | 0x27, 0x4b, 0x25, 0xed, 0x19, 0xef, 0x11, 0xaf, | ||
240 | 0xa6, 0x89, 0x7b, 0x84, 0x50, 0xe7, 0x62, 0x64, | ||
241 | 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, | ||
242 | 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, | ||
243 | 0x00, 0x15, 0x00, 0x04, 0x01, 0xa4, 0x01, 0x01, | ||
244 | 0x03, 0x27, 0x20, 0x06, 0x21, 0x58, 0x20, 0x8d, | ||
245 | 0xfe, 0x45, 0xd5, 0x7d, 0xb6, 0x17, 0xab, 0x86, | ||
246 | 0x2d, 0x32, 0xf6, 0x85, 0xf0, 0x92, 0x76, 0xb7, | ||
247 | 0xce, 0x73, 0xca, 0x4e, 0x0e, 0xfd, 0xd5, 0xdb, | ||
248 | 0x2a, 0x1d, 0x55, 0x90, 0x96, 0x52, 0xc2, 0x0a, | ||
249 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
250 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
251 | 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xa0, 0x00, | ||
252 | 0xa4, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, | ||
253 | 0x04, 0x0e, 0x0f, 0xa0, 0xcd, 0x60, 0x35, 0x9a, | ||
254 | 0xba, 0x47, 0x0c, 0x10, 0xb6, 0x82, 0x6e, 0x2f, | ||
255 | 0x66, 0xb9, 0xa7, 0xcf, 0xd8, 0x47, 0xb4, 0x3d, | ||
256 | 0xfd, 0x77, 0x1a, 0x38, 0x22, 0xa1, 0xda, 0xa5, | ||
257 | 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, | ||
258 | 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, | ||
259 | 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, | ||
260 | 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, | ||
261 | 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, | ||
262 | 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0x00, | ||
263 | 0x5d, 0xdf, 0xef, 0xe2, 0xf3, 0x06, 0xb2, 0xa5, | ||
264 | 0x46, 0x4d, 0x98, 0xbc, 0x14, 0x65, 0xc1, 0x64, | ||
265 | 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, | ||
266 | 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, | ||
267 | 0x00, 0x15, 0x00, 0x04, 0x01, 0xa4, 0x01, 0x01, | ||
268 | 0x03, 0x27, 0x20, 0x06, 0x21, 0x58, 0x20, 0x72, | ||
269 | 0x79, 0x14, 0x69, 0xdf, 0xcb, 0x64, 0x75, 0xee, | ||
270 | 0xd4, 0x45, 0x94, 0xbc, 0x48, 0x4d, 0x2a, 0x9f, | ||
271 | 0xc9, 0xf4, 0xb5, 0x1b, 0x05, 0xa6, 0x5b, 0x54, | ||
272 | 0x9a, 0xac, 0x6c, 0x2e, 0xc6, 0x90, 0x62, 0x0a, | ||
273 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
274 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
275 | 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xc3, 0x00, | ||
276 | 0xa4, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, | ||
277 | 0xce, 0x32, 0xd8, 0x79, 0xdd, 0x86, 0xa2, 0x42, | ||
278 | 0x7c, 0xc3, 0xe1, 0x95, 0x12, 0x93, 0x1a, 0x03, | ||
279 | 0xe6, 0x70, 0xb8, 0xff, 0xcd, 0xa5, 0xdf, 0x15, | ||
280 | 0xfc, 0x88, 0x2a, 0xf5, 0x44, 0xf1, 0x33, 0x9c, | ||
281 | 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, | ||
282 | 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, | ||
283 | 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, | ||
284 | 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, | ||
285 | 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, | ||
286 | 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0x0a, | ||
287 | 0x26, 0x5b, 0x7e, 0x1a, 0x2a, 0xba, 0x70, 0x5f, | ||
288 | 0x18, 0x26, 0x14, 0xb2, 0x71, 0xca, 0x98, 0x64, | ||
289 | 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, | ||
290 | 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, | ||
291 | 0x00, 0x15, 0x00, 0x04, 0x01, 0xa5, 0x01, 0x02, | ||
292 | 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x8b, | ||
293 | 0x48, 0xf0, 0x69, 0xfb, 0x22, 0xfb, 0xf3, 0x86, | ||
294 | 0x57, 0x7c, 0xdd, 0x82, 0x2c, 0x1c, 0x0c, 0xdc, | ||
295 | 0x27, 0xe2, 0x6a, 0x4c, 0x1a, 0x10, 0x04, 0x27, | ||
296 | 0x51, 0x3e, 0x2a, 0x9d, 0x3a, 0xb6, 0xb5, 0x22, | ||
297 | 0x58, 0x20, 0x70, 0xfe, 0x91, 0x67, 0x64, 0x53, | ||
298 | 0x63, 0x83, 0x72, 0x31, 0xe9, 0xe5, 0x20, 0xb7, | ||
299 | 0x00, 0x15, 0x00, 0x04, 0x02, 0xee, 0xc9, 0xfb, | ||
300 | 0x63, 0xd7, 0xe4, 0x76, 0x39, 0x80, 0x82, 0x74, | ||
301 | 0xb8, 0xfa, 0x67, 0xf5, 0x1b, 0x8f, 0xe0, 0x0a, | ||
302 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
303 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
304 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
305 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
306 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
307 | 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xc3, 0x00, | ||
308 | 0xa4, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, | ||
309 | 0xf9, 0xa3, 0x67, 0xbf, 0x5e, 0x80, 0x95, 0xdb, | ||
310 | 0x4c, 0xc5, 0x8f, 0x65, 0x36, 0xc5, 0xaf, 0xdd, | ||
311 | 0x90, 0x2e, 0x62, 0x68, 0x67, 0x9c, 0xa2, 0x26, | ||
312 | 0x2f, 0x2a, 0xf9, 0x3a, 0xda, 0x15, 0xf2, 0x27, | ||
313 | 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, | ||
314 | 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, | ||
315 | 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, | ||
316 | 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, | ||
317 | 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, | ||
318 | 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0xfb, | ||
319 | 0xa6, 0xbe, 0xc1, 0x01, 0xf6, 0x7a, 0x81, 0xf9, | ||
320 | 0xcd, 0x6d, 0x20, 0x41, 0x7a, 0x1c, 0x40, 0x64, | ||
321 | 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, | ||
322 | 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, | ||
323 | 0x00, 0x15, 0x00, 0x04, 0x01, 0xa5, 0x01, 0x02, | ||
324 | 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xda, | ||
325 | 0x2b, 0x53, 0xc3, 0xbe, 0x48, 0xf8, 0xab, 0xbd, | ||
326 | 0x06, 0x28, 0x46, 0xfa, 0x35, 0xab, 0xf9, 0xc5, | ||
327 | 0x2e, 0xfd, 0x3c, 0x38, 0x88, 0xb3, 0xe1, 0xa7, | ||
328 | 0xc5, 0xc6, 0xed, 0x72, 0x54, 0x37, 0x93, 0x22, | ||
329 | 0x58, 0x20, 0x12, 0x82, 0x32, 0x2d, 0xab, 0xbc, | ||
330 | 0x64, 0xb3, 0xed, 0xcc, 0xd5, 0x22, 0xec, 0x79, | ||
331 | 0x00, 0x15, 0x00, 0x04, 0x02, 0x4b, 0xe2, 0x4d, | ||
332 | 0x0c, 0x4b, 0x8d, 0x31, 0x4c, 0xb4, 0x0f, 0xd4, | ||
333 | 0xa9, 0xbe, 0x0c, 0xab, 0x9e, 0x0a, 0xc9, 0x0a, | ||
334 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
335 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
336 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
337 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
338 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
339 | }; | ||
340 | |||
341 | /* | ||
342 | * Collection of HID reports from an authenticator issued with a FIDO2 | ||
343 | * 'deleteCredential' credential management command. | ||
344 | */ | ||
345 | static const uint8_t dummy_del_wire_data[] = { | ||
346 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x8b, | ||
347 | 0xe1, 0xf0, 0x3a, 0x18, 0xa5, 0xda, 0x59, 0x00, | ||
348 | 0x15, 0x00, 0x05, 0x02, 0x00, 0x04, 0x05, 0x05, | ||
349 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
350 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
351 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
352 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
353 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
354 | 0x00, 0x15, 0x00, 0x05, 0x90, 0x00, 0x51, 0x00, | ||
355 | 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, | ||
356 | 0x20, 0x01, 0x21, 0x58, 0x20, 0x12, 0xc1, 0x81, | ||
357 | 0x6b, 0x92, 0x6a, 0x56, 0x05, 0xfe, 0xdb, 0xab, | ||
358 | 0x90, 0x2f, 0x57, 0x0b, 0x3d, 0x85, 0x3e, 0x3f, | ||
359 | 0xbc, 0xe5, 0xd3, 0xb6, 0x86, 0xdf, 0x10, 0x43, | ||
360 | 0xc2, 0xaf, 0x87, 0x34, 0x0e, 0x22, 0x58, 0x20, | ||
361 | 0xd3, 0x0f, 0x7e, 0x5d, 0x10, 0x33, 0x57, 0x24, | ||
362 | 0x00, 0x15, 0x00, 0x05, 0x00, 0x6e, 0x90, 0x58, | ||
363 | 0x61, 0x2a, 0xd2, 0xc2, 0x1e, 0x08, 0xea, 0x91, | ||
364 | 0xcb, 0x44, 0x66, 0x73, 0x29, 0x92, 0x29, 0x59, | ||
365 | 0x91, 0xa3, 0x4d, 0x2c, 0xbb, 0x00, 0x00, 0x00, | ||
366 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
367 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
368 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
369 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
370 | 0x00, 0x15, 0x00, 0x05, 0x90, 0x00, 0x14, 0x00, | ||
371 | 0xa1, 0x02, 0x50, 0x33, 0xf1, 0x3b, 0xde, 0x1e, | ||
372 | 0xa5, 0xd1, 0xbf, 0xf6, 0x5d, 0x63, 0xb6, 0xfc, | ||
373 | 0xd2, 0x24, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
374 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
375 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
376 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
377 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
378 | 0x00, 0x15, 0x00, 0x05, 0x90, 0x00, 0x01, 0x00, | ||
379 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
380 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
381 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
382 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
383 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
384 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
385 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
386 | }; | ||
387 | |||
388 | int LLVMFuzzerTestOneInput(const uint8_t *, size_t); | ||
389 | size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); | ||
390 | |||
391 | static int | ||
392 | unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN | ||
393 | { | ||
394 | uint8_t **pp = (void *)&ptr; | ||
395 | |||
396 | if (unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || | ||
397 | unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || | ||
398 | unpack_blob(TAG_CRED_ID, pp, &len, &p->cred_id) < 0 || | ||
399 | unpack_blob(TAG_META_WIRE_DATA, pp, &len, &p->meta_wire_data) < 0 || | ||
400 | unpack_blob(TAG_RP_WIRE_DATA, pp, &len, &p->rp_wire_data) < 0 || | ||
401 | unpack_blob(TAG_RK_WIRE_DATA, pp, &len, &p->rk_wire_data) < 0 || | ||
402 | unpack_blob(TAG_DEL_WIRE_DATA, pp, &len, &p->del_wire_data) < 0 || | ||
403 | unpack_int(TAG_SEED, pp, &len, &p->seed) < 0) | ||
404 | return (-1); | ||
405 | |||
406 | return (0); | ||
407 | } | ||
408 | |||
409 | static size_t | ||
410 | pack(uint8_t *ptr, size_t len, const struct param *p) | ||
411 | { | ||
412 | const size_t max = len; | ||
413 | |||
414 | if (pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || | ||
415 | pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || | ||
416 | pack_blob(TAG_CRED_ID, &ptr, &len, &p->cred_id) < 0 || | ||
417 | pack_blob(TAG_META_WIRE_DATA, &ptr, &len, &p->meta_wire_data) < 0 || | ||
418 | pack_blob(TAG_RP_WIRE_DATA, &ptr, &len, &p->rp_wire_data) < 0 || | ||
419 | pack_blob(TAG_RK_WIRE_DATA, &ptr, &len, &p->rk_wire_data) < 0 || | ||
420 | pack_blob(TAG_DEL_WIRE_DATA, &ptr, &len, &p->del_wire_data) < 0 || | ||
421 | pack_int(TAG_SEED, &ptr, &len, p->seed) < 0) | ||
422 | return (0); | ||
423 | |||
424 | return (max - len); | ||
425 | } | ||
426 | |||
427 | static fido_dev_t * | ||
428 | prepare_dev() | ||
429 | { | ||
430 | fido_dev_t *dev; | ||
431 | fido_dev_io_t io; | ||
432 | |||
433 | io.open = dev_open; | ||
434 | io.close = dev_close; | ||
435 | io.read = dev_read; | ||
436 | io.write = dev_write; | ||
437 | |||
438 | if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, | ||
439 | &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { | ||
440 | fido_dev_free(&dev); | ||
441 | return (NULL); | ||
442 | } | ||
443 | |||
444 | return (dev); | ||
445 | } | ||
446 | |||
447 | static void | ||
448 | get_metadata(struct param *p) | ||
449 | { | ||
450 | fido_dev_t *dev; | ||
451 | fido_credman_metadata_t *metadata; | ||
452 | uint64_t existing; | ||
453 | uint64_t remaining; | ||
454 | |||
455 | set_wire_data(p->meta_wire_data.body, p->meta_wire_data.len); | ||
456 | |||
457 | if ((dev = prepare_dev()) == NULL) { | ||
458 | return; | ||
459 | } | ||
460 | if ((metadata = fido_credman_metadata_new()) == NULL) { | ||
461 | fido_dev_close(dev); | ||
462 | fido_dev_free(&dev); | ||
463 | return; | ||
464 | } | ||
465 | |||
466 | fido_credman_get_dev_metadata(dev, metadata, p->pin); | ||
467 | |||
468 | existing = fido_credman_rk_existing(metadata); | ||
469 | remaining = fido_credman_rk_remaining(metadata); | ||
470 | consume(&existing, sizeof(existing)); | ||
471 | consume(&remaining, sizeof(remaining)); | ||
472 | |||
473 | fido_credman_metadata_free(&metadata); | ||
474 | fido_dev_close(dev); | ||
475 | fido_dev_free(&dev); | ||
476 | } | ||
477 | |||
478 | static void | ||
479 | get_rp_list(struct param *p) | ||
480 | { | ||
481 | fido_dev_t *dev; | ||
482 | fido_credman_rp_t *rp; | ||
483 | |||
484 | set_wire_data(p->rp_wire_data.body, p->rp_wire_data.len); | ||
485 | |||
486 | if ((dev = prepare_dev()) == NULL) { | ||
487 | return; | ||
488 | } | ||
489 | if ((rp = fido_credman_rp_new()) == NULL) { | ||
490 | fido_dev_close(dev); | ||
491 | fido_dev_free(&dev); | ||
492 | return; | ||
493 | } | ||
494 | |||
495 | fido_credman_get_dev_rp(dev, rp, p->pin); | ||
496 | |||
497 | /* +1 on purpose */ | ||
498 | for (size_t i = 0; i < fido_credman_rp_count(rp) + 1; i++) { | ||
499 | consume(fido_credman_rp_id_hash_ptr(rp, i), | ||
500 | fido_credman_rp_id_hash_len(rp, i)); | ||
501 | consume(fido_credman_rp_id(rp, i), | ||
502 | xstrlen(fido_credman_rp_id(rp, i))); | ||
503 | consume(fido_credman_rp_name(rp, i), | ||
504 | xstrlen(fido_credman_rp_name(rp, i))); | ||
505 | } | ||
506 | |||
507 | fido_credman_rp_free(&rp); | ||
508 | fido_dev_close(dev); | ||
509 | fido_dev_free(&dev); | ||
510 | } | ||
511 | |||
512 | static void | ||
513 | get_rk_list(struct param *p) | ||
514 | { | ||
515 | fido_dev_t *dev; | ||
516 | fido_credman_rk_t *rk; | ||
517 | const fido_cred_t *cred; | ||
518 | int type; | ||
519 | |||
520 | set_wire_data(p->rk_wire_data.body, p->rk_wire_data.len); | ||
521 | |||
522 | if ((dev = prepare_dev()) == NULL) { | ||
523 | return; | ||
524 | } | ||
525 | if ((rk = fido_credman_rk_new()) == NULL) { | ||
526 | fido_dev_close(dev); | ||
527 | fido_dev_free(&dev); | ||
528 | return; | ||
529 | } | ||
530 | |||
531 | fido_credman_get_dev_rk(dev, p->rp_id, rk, p->pin); | ||
532 | |||
533 | /* +1 on purpose */ | ||
534 | for (size_t i = 0; i < fido_credman_rk_count(rk) + 1; i++) { | ||
535 | if ((cred = fido_credman_rk(rk, i)) == NULL) { | ||
536 | assert(i >= fido_credman_rk_count(rk)); | ||
537 | continue; | ||
538 | } | ||
539 | type = fido_cred_type(cred); | ||
540 | consume(&type, sizeof(type)); | ||
541 | consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); | ||
542 | consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); | ||
543 | consume(fido_cred_user_id_ptr(cred), | ||
544 | fido_cred_user_id_len(cred)); | ||
545 | consume(fido_cred_user_name(cred), | ||
546 | xstrlen(fido_cred_user_name(cred))); | ||
547 | consume(fido_cred_display_name(cred), | ||
548 | xstrlen(fido_cred_display_name(cred))); | ||
549 | } | ||
550 | |||
551 | fido_credman_rk_free(&rk); | ||
552 | fido_dev_close(dev); | ||
553 | fido_dev_free(&dev); | ||
554 | } | ||
555 | |||
556 | static void | ||
557 | del_rk(struct param *p) | ||
558 | { | ||
559 | fido_dev_t *dev; | ||
560 | |||
561 | set_wire_data(p->del_wire_data.body, p->del_wire_data.len); | ||
562 | |||
563 | if ((dev = prepare_dev()) == NULL) { | ||
564 | return; | ||
565 | } | ||
566 | |||
567 | fido_credman_del_dev_rk(dev, p->cred_id.body, p->cred_id.len, p->pin); | ||
568 | fido_dev_close(dev); | ||
569 | fido_dev_free(&dev); | ||
570 | } | ||
571 | |||
572 | int | ||
573 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) | ||
574 | { | ||
575 | struct param p; | ||
576 | |||
577 | memset(&p, 0, sizeof(p)); | ||
578 | |||
579 | if (unpack(data, size, &p) < 0) | ||
580 | return (0); | ||
581 | |||
582 | srandom((unsigned int)p.seed); | ||
583 | |||
584 | fido_init(0); | ||
585 | |||
586 | get_metadata(&p); | ||
587 | get_rp_list(&p); | ||
588 | get_rk_list(&p); | ||
589 | del_rk(&p); | ||
590 | |||
591 | return (0); | ||
592 | } | ||
593 | |||
594 | static size_t | ||
595 | pack_dummy(uint8_t *ptr, size_t len) | ||
596 | { | ||
597 | struct param dummy; | ||
598 | uint8_t blob[32768]; | ||
599 | size_t blob_len; | ||
600 | |||
601 | memset(&dummy, 0, sizeof(dummy)); | ||
602 | |||
603 | strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); | ||
604 | strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); | ||
605 | |||
606 | dummy.meta_wire_data.len = sizeof(dummy_meta_wire_data); | ||
607 | dummy.rp_wire_data.len = sizeof(dummy_rp_wire_data); | ||
608 | dummy.rk_wire_data.len = sizeof(dummy_rk_wire_data); | ||
609 | dummy.del_wire_data.len = sizeof(dummy_del_wire_data); | ||
610 | dummy.cred_id.len = sizeof(dummy_cred_id); | ||
611 | |||
612 | memcpy(&dummy.meta_wire_data.body, &dummy_meta_wire_data, | ||
613 | dummy.meta_wire_data.len); | ||
614 | memcpy(&dummy.rp_wire_data.body, &dummy_rp_wire_data, | ||
615 | dummy.rp_wire_data.len); | ||
616 | memcpy(&dummy.rk_wire_data.body, &dummy_rk_wire_data, | ||
617 | dummy.rk_wire_data.len); | ||
618 | memcpy(&dummy.del_wire_data.body, &dummy_del_wire_data, | ||
619 | dummy.del_wire_data.len); | ||
620 | memcpy(&dummy.cred_id.body, &dummy_cred_id, dummy.cred_id.len); | ||
621 | |||
622 | blob_len = pack(blob, sizeof(blob), &dummy); | ||
623 | assert(blob_len != 0); | ||
624 | |||
625 | if (blob_len > len) { | ||
626 | memcpy(ptr, blob, len); | ||
627 | return (len); | ||
628 | } | ||
629 | |||
630 | memcpy(ptr, blob, blob_len); | ||
631 | |||
632 | return (blob_len); | ||
633 | } | ||
634 | |||
635 | size_t | ||
636 | LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, | ||
637 | unsigned int seed) NO_MSAN | ||
638 | { | ||
639 | struct param p; | ||
640 | uint8_t blob[16384]; | ||
641 | size_t blob_len; | ||
642 | |||
643 | memset(&p, 0, sizeof(p)); | ||
644 | |||
645 | if (unpack(data, size, &p) < 0) | ||
646 | return (pack_dummy(data, maxsize)); | ||
647 | |||
648 | p.seed = (int)seed; | ||
649 | |||
650 | mutate_blob(&p.cred_id); | ||
651 | mutate_blob(&p.meta_wire_data); | ||
652 | mutate_blob(&p.rp_wire_data); | ||
653 | mutate_blob(&p.rk_wire_data); | ||
654 | mutate_blob(&p.del_wire_data); | ||
655 | |||
656 | mutate_string(p.pin); | ||
657 | mutate_string(p.rp_id); | ||
658 | |||
659 | blob_len = pack(blob, sizeof(blob), &p); | ||
660 | |||
661 | if (blob_len == 0 || blob_len > maxsize) | ||
662 | return (0); | ||
663 | |||
664 | memcpy(data, blob, blob_len); | ||
665 | |||
666 | return (blob_len); | ||
667 | } | ||
diff --git a/fuzz/fuzz_mgmt.c b/fuzz/fuzz_mgmt.c new file mode 100644 index 0000000..741b375 --- /dev/null +++ b/fuzz/fuzz_mgmt.c | |||
@@ -0,0 +1,529 @@ | |||
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 <assert.h> | ||
8 | #include <stdint.h> | ||
9 | #include <stdio.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <string.h> | ||
12 | |||
13 | #include "mutator_aux.h" | ||
14 | #include "fido.h" | ||
15 | |||
16 | #include "../openbsd-compat/openbsd-compat.h" | ||
17 | |||
18 | #define TAG_PIN1 0x01 | ||
19 | #define TAG_PIN2 0x02 | ||
20 | #define TAG_RESET_WIRE_DATA 0x03 | ||
21 | #define TAG_INFO_WIRE_DATA 0x04 | ||
22 | #define TAG_SET_PIN_WIRE_DATA 0x05 | ||
23 | #define TAG_CHANGE_PIN_WIRE_DATA 0x06 | ||
24 | #define TAG_RETRY_WIRE_DATA 0x07 | ||
25 | #define TAG_SEED 0x08 | ||
26 | |||
27 | struct param { | ||
28 | char pin1[MAXSTR]; | ||
29 | char pin2[MAXSTR]; | ||
30 | struct blob reset_wire_data; | ||
31 | struct blob info_wire_data; | ||
32 | struct blob set_pin_wire_data; | ||
33 | struct blob change_pin_wire_data; | ||
34 | struct blob retry_wire_data; | ||
35 | int seed; | ||
36 | }; | ||
37 | |||
38 | /* Example parameters. */ | ||
39 | static const char dummy_pin1[] = "skepp cg0u3;Y.."; | ||
40 | static const char dummy_pin2[] = "bastilha 6rJrfQZI."; | ||
41 | |||
42 | static const uint8_t dummy_reset_wire_data[] = { | ||
43 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x91, | ||
44 | 0xef, 0xbe, 0x74, 0x39, 0x1a, 0x1c, 0x4a, 0x00, | ||
45 | 0x22, 0x00, 0x01, 0x02, 0x05, 0x02, 0x01, 0x05, | ||
46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
51 | 0x00, 0x22, 0x00, 0x01, 0xbb, 0x00, 0x01, 0x02, | ||
52 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
53 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
54 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
56 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
57 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
58 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
59 | 0x00, 0x22, 0x00, 0x01, 0xbb, 0x00, 0x01, 0x02, | ||
60 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
62 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
63 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
64 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
65 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
66 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
67 | 0x00, 0x22, 0x00, 0x01, 0xbb, 0x00, 0x01, 0x02, | ||
68 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
69 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
70 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
71 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
72 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
73 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
74 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
75 | 0x00, 0x22, 0x00, 0x01, 0xbb, 0x00, 0x01, 0x02, | ||
76 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
77 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
78 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
79 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
80 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
81 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
82 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
83 | 0x00, 0x22, 0x00, 0x01, 0xbb, 0x00, 0x01, 0x02, | ||
84 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
85 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
86 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
87 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
88 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
89 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
90 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
91 | 0x00, 0x22, 0x00, 0x01, 0xbb, 0x00, 0x01, 0x01, | ||
92 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
93 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
94 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
96 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
97 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
98 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
99 | 0x00, 0x22, 0x00, 0x01, 0x90, 0x00, 0x01, 0x00, | ||
100 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
101 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
102 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
103 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
104 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
105 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
106 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
107 | }; | ||
108 | |||
109 | static const uint8_t dummy_info_wire_data[] = { | ||
110 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x80, | ||
111 | 0x43, 0x56, 0x40, 0xb1, 0x4e, 0xd9, 0x2d, 0x00, | ||
112 | 0x22, 0x00, 0x02, 0x02, 0x05, 0x02, 0x01, 0x05, | ||
113 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
114 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
115 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
116 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
117 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
118 | 0x00, 0x22, 0x00, 0x02, 0x90, 0x00, 0xb9, 0x00, | ||
119 | 0xa9, 0x01, 0x83, 0x66, 0x55, 0x32, 0x46, 0x5f, | ||
120 | 0x56, 0x32, 0x68, 0x46, 0x49, 0x44, 0x4f, 0x5f, | ||
121 | 0x32, 0x5f, 0x30, 0x6c, 0x46, 0x49, 0x44, 0x4f, | ||
122 | 0x5f, 0x32, 0x5f, 0x31, 0x5f, 0x50, 0x52, 0x45, | ||
123 | 0x02, 0x82, 0x6b, 0x63, 0x72, 0x65, 0x64, 0x50, | ||
124 | 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x6b, 0x68, | ||
125 | 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x65, 0x63, 0x72, | ||
126 | 0x00, 0x22, 0x00, 0x02, 0x00, 0x65, 0x74, 0x03, | ||
127 | 0x50, 0x19, 0x56, 0xe5, 0xbd, 0xa3, 0x74, 0x45, | ||
128 | 0xf1, 0xa8, 0x14, 0x35, 0x64, 0x03, 0xfd, 0xbc, | ||
129 | 0x18, 0x04, 0xa5, 0x62, 0x72, 0x6b, 0xf5, 0x62, | ||
130 | 0x75, 0x70, 0xf5, 0x64, 0x70, 0x6c, 0x61, 0x74, | ||
131 | 0xf4, 0x69, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, | ||
132 | 0x50, 0x69, 0x6e, 0xf4, 0x75, 0x63, 0x72, 0x65, | ||
133 | 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4d, | ||
134 | 0x00, 0x22, 0x00, 0x02, 0x01, 0x67, 0x6d, 0x74, | ||
135 | 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0xf5, | ||
136 | 0x05, 0x19, 0x04, 0xb0, 0x06, 0x81, 0x01, 0x07, | ||
137 | 0x08, 0x08, 0x18, 0x80, 0x0a, 0x82, 0xa2, 0x63, | ||
138 | 0x61, 0x6c, 0x67, 0x26, 0x64, 0x74, 0x79, 0x70, | ||
139 | 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, | ||
140 | 0x2d, 0x6b, 0x65, 0x79, 0xa2, 0x63, 0x61, 0x6c, | ||
141 | 0x67, 0x27, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, | ||
142 | 0x00, 0x22, 0x00, 0x02, 0x02, 0x70, 0x75, 0x62, | ||
143 | 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x00, | ||
144 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
145 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
146 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
147 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
148 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
149 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
150 | }; | ||
151 | |||
152 | static const uint8_t dummy_set_pin_wire_data[] = { | ||
153 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x59, | ||
154 | 0x50, 0x8c, 0x27, 0x14, 0x83, 0x43, 0xd5, 0x00, | ||
155 | 0x22, 0x00, 0x03, 0x02, 0x05, 0x02, 0x01, 0x05, | ||
156 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
157 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
158 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
159 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
160 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
161 | 0x00, 0x22, 0x00, 0x03, 0x90, 0x00, 0x51, 0x00, | ||
162 | 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, | ||
163 | 0x20, 0x01, 0x21, 0x58, 0x20, 0x2a, 0xb8, 0x2d, | ||
164 | 0x36, 0x69, 0xab, 0x30, 0x9d, 0xe3, 0x5e, 0x9b, | ||
165 | 0xfb, 0x94, 0xfc, 0x1d, 0x92, 0x95, 0xaf, 0x01, | ||
166 | 0x47, 0xfe, 0x4b, 0x87, 0xe5, 0xcf, 0x3f, 0x05, | ||
167 | 0x0b, 0x39, 0xda, 0x17, 0x49, 0x22, 0x58, 0x20, | ||
168 | 0x15, 0x1b, 0xbe, 0x08, 0x78, 0x60, 0x4d, 0x3c, | ||
169 | 0x00, 0x22, 0x00, 0x03, 0x00, 0x3f, 0xf1, 0x60, | ||
170 | 0xa6, 0xd8, 0xf8, 0xed, 0xce, 0x4a, 0x30, 0x5d, | ||
171 | 0x1a, 0xaf, 0x80, 0xc4, 0x0a, 0xd2, 0x6f, 0x77, | ||
172 | 0x38, 0x12, 0x97, 0xaa, 0xbd, 0x00, 0x00, 0x00, | ||
173 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
174 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
175 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
176 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
177 | 0x00, 0x22, 0x00, 0x03, 0x90, 0x00, 0x01, 0x00, | ||
178 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
179 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
180 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
181 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
182 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
183 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
184 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
185 | }; | ||
186 | |||
187 | static const uint8_t dummy_change_pin_wire_data[] = { | ||
188 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x48, | ||
189 | 0xfd, 0xf9, 0xde, 0x28, 0x21, 0x99, 0xd5, 0x00, | ||
190 | 0x22, 0x00, 0x04, 0x02, 0x05, 0x02, 0x01, 0x05, | ||
191 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
192 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
193 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
194 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
195 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
196 | 0x00, 0x22, 0x00, 0x04, 0x90, 0x00, 0x51, 0x00, | ||
197 | 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, | ||
198 | 0x20, 0x01, 0x21, 0x58, 0x20, 0x2a, 0xb8, 0x2d, | ||
199 | 0x36, 0x69, 0xab, 0x30, 0x9d, 0xe3, 0x5e, 0x9b, | ||
200 | 0xfb, 0x94, 0xfc, 0x1d, 0x92, 0x95, 0xaf, 0x01, | ||
201 | 0x47, 0xfe, 0x4b, 0x87, 0xe5, 0xcf, 0x3f, 0x05, | ||
202 | 0x0b, 0x39, 0xda, 0x17, 0x49, 0x22, 0x58, 0x20, | ||
203 | 0x15, 0x1b, 0xbe, 0x08, 0x78, 0x60, 0x4d, 0x3c, | ||
204 | 0x00, 0x22, 0x00, 0x04, 0x00, 0x3f, 0xf1, 0x60, | ||
205 | 0xa6, 0xd8, 0xf8, 0xed, 0xce, 0x4a, 0x30, 0x5d, | ||
206 | 0x1a, 0xaf, 0x80, 0xc4, 0x0a, 0xd2, 0x6f, 0x77, | ||
207 | 0x38, 0x12, 0x97, 0xaa, 0xbd, 0x00, 0x00, 0x00, | ||
208 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
209 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
210 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
211 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
212 | 0x00, 0x22, 0x00, 0x04, 0x90, 0x00, 0x01, 0x00, | ||
213 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
214 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
215 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
216 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
217 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
218 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
219 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
220 | }; | ||
221 | |||
222 | static const uint8_t dummy_retry_wire_data[] = { | ||
223 | 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x7f, | ||
224 | 0xaa, 0x73, 0x3e, 0x95, 0x98, 0xa8, 0x60, 0x00, | ||
225 | 0x22, 0x00, 0x05, 0x02, 0x05, 0x02, 0x01, 0x05, | ||
226 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
227 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
228 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
229 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
230 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
231 | 0x00, 0x22, 0x00, 0x05, 0x90, 0x00, 0x04, 0x00, | ||
232 | 0xa1, 0x03, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
233 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
234 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
235 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
236 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
237 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
238 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
239 | }; | ||
240 | |||
241 | int LLVMFuzzerTestOneInput(const uint8_t *, size_t); | ||
242 | size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); | ||
243 | |||
244 | static int | ||
245 | unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN | ||
246 | { | ||
247 | uint8_t **pp = (void *)&ptr; | ||
248 | |||
249 | if (unpack_string(TAG_PIN1, pp, &len, p->pin1) < 0 || | ||
250 | unpack_string(TAG_PIN2, pp, &len, p->pin2) < 0 || | ||
251 | unpack_blob(TAG_RESET_WIRE_DATA, pp, &len, &p->reset_wire_data) < 0 || | ||
252 | unpack_blob(TAG_INFO_WIRE_DATA, pp, &len, &p->info_wire_data) < 0 || | ||
253 | unpack_blob(TAG_SET_PIN_WIRE_DATA, pp, &len, &p->set_pin_wire_data) < 0 || | ||
254 | unpack_blob(TAG_CHANGE_PIN_WIRE_DATA, pp, &len, &p->change_pin_wire_data) < 0 || | ||
255 | unpack_blob(TAG_RETRY_WIRE_DATA, pp, &len, &p->retry_wire_data) < 0 || | ||
256 | unpack_int(TAG_SEED, pp, &len, &p->seed) < 0) | ||
257 | return (-1); | ||
258 | |||
259 | return (0); | ||
260 | } | ||
261 | |||
262 | static size_t | ||
263 | pack(uint8_t *ptr, size_t len, const struct param *p) | ||
264 | { | ||
265 | const size_t max = len; | ||
266 | |||
267 | if (pack_string(TAG_PIN1, &ptr, &len, p->pin1) < 0 || | ||
268 | pack_string(TAG_PIN2, &ptr, &len, p->pin2) < 0 || | ||
269 | pack_blob(TAG_RESET_WIRE_DATA, &ptr, &len, &p->reset_wire_data) < 0 || | ||
270 | pack_blob(TAG_INFO_WIRE_DATA, &ptr, &len, &p->info_wire_data) < 0 || | ||
271 | pack_blob(TAG_SET_PIN_WIRE_DATA, &ptr, &len, &p->set_pin_wire_data) < 0 || | ||
272 | pack_blob(TAG_CHANGE_PIN_WIRE_DATA, &ptr, &len, &p->change_pin_wire_data) < 0 || | ||
273 | pack_blob(TAG_RETRY_WIRE_DATA, &ptr, &len, &p->retry_wire_data) < 0 || | ||
274 | pack_int(TAG_SEED, &ptr, &len, p->seed) < 0) | ||
275 | return (0); | ||
276 | |||
277 | return (max - len); | ||
278 | } | ||
279 | |||
280 | static fido_dev_t * | ||
281 | prepare_dev() | ||
282 | { | ||
283 | fido_dev_t *dev; | ||
284 | fido_dev_io_t io; | ||
285 | |||
286 | io.open = dev_open; | ||
287 | io.close = dev_close; | ||
288 | io.read = dev_read; | ||
289 | io.write = dev_write; | ||
290 | |||
291 | if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, | ||
292 | &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { | ||
293 | fido_dev_free(&dev); | ||
294 | return (NULL); | ||
295 | } | ||
296 | |||
297 | return (dev); | ||
298 | } | ||
299 | |||
300 | static void | ||
301 | dev_reset(struct param *p) | ||
302 | { | ||
303 | fido_dev_t *dev; | ||
304 | |||
305 | set_wire_data(p->reset_wire_data.body, p->reset_wire_data.len); | ||
306 | |||
307 | if ((dev = prepare_dev()) == NULL) { | ||
308 | return; | ||
309 | } | ||
310 | |||
311 | fido_dev_reset(dev); | ||
312 | fido_dev_close(dev); | ||
313 | fido_dev_free(&dev); | ||
314 | } | ||
315 | |||
316 | static void | ||
317 | dev_get_cbor_info(struct param *p) | ||
318 | { | ||
319 | fido_dev_t *dev; | ||
320 | fido_cbor_info_t *ci; | ||
321 | uint64_t n; | ||
322 | uint8_t proto; | ||
323 | uint8_t major; | ||
324 | uint8_t minor; | ||
325 | uint8_t build; | ||
326 | uint8_t flags; | ||
327 | |||
328 | set_wire_data(p->info_wire_data.body, p->info_wire_data.len); | ||
329 | |||
330 | if ((dev = prepare_dev()) == NULL) { | ||
331 | return; | ||
332 | } | ||
333 | |||
334 | proto = fido_dev_protocol(dev); | ||
335 | major = fido_dev_major(dev); | ||
336 | minor = fido_dev_minor(dev); | ||
337 | build = fido_dev_build(dev); | ||
338 | flags = fido_dev_flags(dev); | ||
339 | |||
340 | consume(&proto, sizeof(proto)); | ||
341 | consume(&major, sizeof(major)); | ||
342 | consume(&minor, sizeof(minor)); | ||
343 | consume(&build, sizeof(build)); | ||
344 | consume(&flags, sizeof(flags)); | ||
345 | |||
346 | if ((ci = fido_cbor_info_new()) == NULL) { | ||
347 | fido_dev_close(dev); | ||
348 | fido_dev_free(&dev); | ||
349 | return; | ||
350 | } | ||
351 | |||
352 | fido_dev_get_cbor_info(dev, ci); | ||
353 | fido_dev_close(dev); | ||
354 | fido_dev_free(&dev); | ||
355 | |||
356 | for (size_t i = 0; i < fido_cbor_info_versions_len(ci); i++) { | ||
357 | char * const *sa = fido_cbor_info_versions_ptr(ci); | ||
358 | consume(sa[i], strlen(sa[i])); | ||
359 | } | ||
360 | for (size_t i = 0; i < fido_cbor_info_extensions_len(ci); i++) { | ||
361 | char * const *sa = fido_cbor_info_extensions_ptr(ci); | ||
362 | consume(sa[i], strlen(sa[i])); | ||
363 | } | ||
364 | |||
365 | for (size_t i = 0; i < fido_cbor_info_options_len(ci); i++) { | ||
366 | char * const *sa = fido_cbor_info_options_name_ptr(ci); | ||
367 | const bool *va = fido_cbor_info_options_value_ptr(ci); | ||
368 | consume(sa[i], strlen(sa[i])); | ||
369 | consume(&va[i], sizeof(va[i])); | ||
370 | } | ||
371 | |||
372 | n = fido_cbor_info_maxmsgsiz(ci); | ||
373 | consume(&n, sizeof(n)); | ||
374 | |||
375 | consume(fido_cbor_info_aaguid_ptr(ci), fido_cbor_info_aaguid_len(ci)); | ||
376 | consume(fido_cbor_info_protocols_ptr(ci), | ||
377 | fido_cbor_info_protocols_len(ci)); | ||
378 | |||
379 | fido_cbor_info_free(&ci); | ||
380 | } | ||
381 | |||
382 | static void | ||
383 | dev_set_pin(struct param *p) | ||
384 | { | ||
385 | fido_dev_t *dev; | ||
386 | |||
387 | set_wire_data(p->set_pin_wire_data.body, p->set_pin_wire_data.len); | ||
388 | |||
389 | if ((dev = prepare_dev()) == NULL) { | ||
390 | return; | ||
391 | } | ||
392 | |||
393 | fido_dev_set_pin(dev, p->pin1, NULL); | ||
394 | fido_dev_close(dev); | ||
395 | fido_dev_free(&dev); | ||
396 | } | ||
397 | |||
398 | static void | ||
399 | dev_change_pin(struct param *p) | ||
400 | { | ||
401 | fido_dev_t *dev; | ||
402 | |||
403 | set_wire_data(p->change_pin_wire_data.body, p->change_pin_wire_data.len); | ||
404 | |||
405 | if ((dev = prepare_dev()) == NULL) { | ||
406 | return; | ||
407 | } | ||
408 | |||
409 | fido_dev_set_pin(dev, p->pin2, p->pin1); | ||
410 | fido_dev_close(dev); | ||
411 | fido_dev_free(&dev); | ||
412 | } | ||
413 | |||
414 | static void | ||
415 | dev_get_retry_count(struct param *p) | ||
416 | { | ||
417 | fido_dev_t *dev; | ||
418 | int n; | ||
419 | |||
420 | set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len); | ||
421 | |||
422 | if ((dev = prepare_dev()) == NULL) { | ||
423 | return; | ||
424 | } | ||
425 | |||
426 | fido_dev_get_retry_count(dev, &n); | ||
427 | consume(&n, sizeof(n)); | ||
428 | fido_dev_close(dev); | ||
429 | fido_dev_free(&dev); | ||
430 | } | ||
431 | |||
432 | int | ||
433 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) | ||
434 | { | ||
435 | struct param p; | ||
436 | |||
437 | memset(&p, 0, sizeof(p)); | ||
438 | |||
439 | if (unpack(data, size, &p) < 0) | ||
440 | return (0); | ||
441 | |||
442 | srandom((unsigned int)p.seed); | ||
443 | |||
444 | fido_init(0); | ||
445 | |||
446 | dev_reset(&p); | ||
447 | dev_get_cbor_info(&p); | ||
448 | dev_set_pin(&p); | ||
449 | dev_change_pin(&p); | ||
450 | dev_get_retry_count(&p); | ||
451 | |||
452 | return (0); | ||
453 | } | ||
454 | |||
455 | static size_t | ||
456 | pack_dummy(uint8_t *ptr, size_t len) | ||
457 | { | ||
458 | struct param dummy; | ||
459 | uint8_t blob[16384]; | ||
460 | size_t blob_len; | ||
461 | |||
462 | memset(&dummy, 0, sizeof(dummy)); | ||
463 | |||
464 | strlcpy(dummy.pin1, dummy_pin1, sizeof(dummy.pin1)); | ||
465 | strlcpy(dummy.pin2, dummy_pin2, sizeof(dummy.pin2)); | ||
466 | |||
467 | dummy.reset_wire_data.len = sizeof(dummy_reset_wire_data); | ||
468 | dummy.info_wire_data.len = sizeof(dummy_info_wire_data); | ||
469 | dummy.set_pin_wire_data.len = sizeof(dummy_set_pin_wire_data); | ||
470 | dummy.change_pin_wire_data.len = sizeof(dummy_change_pin_wire_data); | ||
471 | dummy.retry_wire_data.len = sizeof(dummy_retry_wire_data); | ||
472 | |||
473 | memcpy(&dummy.reset_wire_data.body, &dummy_reset_wire_data, | ||
474 | dummy.reset_wire_data.len); | ||
475 | memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data, | ||
476 | dummy.info_wire_data.len); | ||
477 | memcpy(&dummy.set_pin_wire_data.body, &dummy_set_pin_wire_data, | ||
478 | dummy.set_pin_wire_data.len); | ||
479 | memcpy(&dummy.change_pin_wire_data.body, &dummy_change_pin_wire_data, | ||
480 | dummy.change_pin_wire_data.len); | ||
481 | memcpy(&dummy.retry_wire_data.body, &dummy_retry_wire_data, | ||
482 | dummy.retry_wire_data.len); | ||
483 | |||
484 | blob_len = pack(blob, sizeof(blob), &dummy); | ||
485 | assert(blob_len != 0); | ||
486 | |||
487 | if (blob_len > len) { | ||
488 | memcpy(ptr, blob, len); | ||
489 | return (len); | ||
490 | } | ||
491 | |||
492 | memcpy(ptr, blob, blob_len); | ||
493 | |||
494 | return (blob_len); | ||
495 | } | ||
496 | |||
497 | size_t | ||
498 | LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, | ||
499 | unsigned int seed) | ||
500 | { | ||
501 | struct param p; | ||
502 | uint8_t blob[16384]; | ||
503 | size_t blob_len; | ||
504 | |||
505 | memset(&p, 0, sizeof(p)); | ||
506 | |||
507 | if (unpack(data, size, &p) < 0) | ||
508 | return (pack_dummy(data, maxsize)); | ||
509 | |||
510 | p.seed = (int)seed; | ||
511 | |||
512 | mutate_string(p.pin1); | ||
513 | mutate_string(p.pin2); | ||
514 | |||
515 | mutate_blob(&p.reset_wire_data); | ||
516 | mutate_blob(&p.info_wire_data); | ||
517 | mutate_blob(&p.set_pin_wire_data); | ||
518 | mutate_blob(&p.change_pin_wire_data); | ||
519 | mutate_blob(&p.retry_wire_data); | ||
520 | |||
521 | blob_len = pack(blob, sizeof(blob), &p); | ||
522 | |||
523 | if (blob_len == 0 || blob_len > maxsize) | ||
524 | return (0); | ||
525 | |||
526 | memcpy(data, blob, blob_len); | ||
527 | |||
528 | return (blob_len); | ||
529 | } | ||
diff --git a/fuzz/harnesses/assert b/fuzz/harnesses/assert new file mode 100755 index 0000000..55cd889 --- /dev/null +++ b/fuzz/harnesses/assert | |||
@@ -0,0 +1,32 @@ | |||
1 | #!/bin/bash -u | ||
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 | T=assert | ||
7 | |||
8 | sync() { | ||
9 | mkdir ${T} | ||
10 | ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue ../pubkey" | \ | ||
11 | tar -C ${T} -xf- | ||
12 | } | ||
13 | |||
14 | run() { | ||
15 | find ${T}/queue -type f | while read f; do | ||
16 | cat "${f}" | LD_PRELOAD=${PRELOAD} build/examples/assert \ | ||
17 | ${T}/pubkey nodev 2>/dev/null 1>&2 | ||
18 | done | ||
19 | } | ||
20 | |||
21 | case "$1" in | ||
22 | sync) | ||
23 | sync | ||
24 | ;; | ||
25 | run) | ||
26 | run | ||
27 | exit 0 | ||
28 | ;; | ||
29 | *) | ||
30 | echo unknown command "$1" | ||
31 | exit 1 | ||
32 | esac | ||
diff --git a/fuzz/harnesses/assert-rsa-h-p b/fuzz/harnesses/assert-rsa-h-p new file mode 100755 index 0000000..8eb9ea6 --- /dev/null +++ b/fuzz/harnesses/assert-rsa-h-p | |||
@@ -0,0 +1,33 @@ | |||
1 | #!/bin/bash -u | ||
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 | T=assert-rsa-h-p | ||
7 | |||
8 | sync() { | ||
9 | mkdir ${T} | ||
10 | ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue ../pubkey ../hmac-salt" | \ | ||
11 | tar -C ${T} -xf- | ||
12 | } | ||
13 | |||
14 | run() { | ||
15 | find ${T}/queue -type f | while read f; do | ||
16 | cat "${f}" | LD_PRELOAD=${PRELOAD} build/examples/assert \ | ||
17 | -t rsa -h ${T}/hmac-out -s ${T}/hmac-salt \ | ||
18 | -p ${T}/pubkey nodev 2>/dev/null 1>&2 | ||
19 | done | ||
20 | } | ||
21 | |||
22 | case "$1" in | ||
23 | sync) | ||
24 | sync | ||
25 | ;; | ||
26 | run) | ||
27 | run | ||
28 | exit 0 | ||
29 | ;; | ||
30 | *) | ||
31 | echo unknown command "$1" | ||
32 | exit 1 | ||
33 | esac | ||
diff --git a/fuzz/harnesses/assert-u2f b/fuzz/harnesses/assert-u2f new file mode 100755 index 0000000..257d1d6 --- /dev/null +++ b/fuzz/harnesses/assert-u2f | |||
@@ -0,0 +1,32 @@ | |||
1 | #!/bin/bash -u | ||
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 | T=assert-u2f | ||
7 | |||
8 | sync() { | ||
9 | mkdir ${T} | ||
10 | ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue ../cred_id ../pubkey" | \ | ||
11 | tar -C ${T} -xf- | ||
12 | } | ||
13 | |||
14 | run() { | ||
15 | find ${T}/queue -type f | while read f; do | ||
16 | cat "${f}" | LD_PRELOAD=${PRELOAD} build/examples/assert -up \ | ||
17 | -a ${T}/cred_id ${T}/pubkey nodev 2>/dev/null 1>&2 | ||
18 | done | ||
19 | } | ||
20 | |||
21 | case "$1" in | ||
22 | sync) | ||
23 | sync | ||
24 | ;; | ||
25 | run) | ||
26 | run | ||
27 | exit 0 | ||
28 | ;; | ||
29 | *) | ||
30 | echo unknown command "$1" | ||
31 | exit 1 | ||
32 | esac | ||
diff --git a/fuzz/harnesses/cred b/fuzz/harnesses/cred new file mode 100755 index 0000000..71ee845 --- /dev/null +++ b/fuzz/harnesses/cred | |||
@@ -0,0 +1,31 @@ | |||
1 | #!/bin/bash -u | ||
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 | T=cred | ||
7 | |||
8 | sync() { | ||
9 | mkdir ${T} | ||
10 | ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue" | tar -C ${T} -xf- | ||
11 | } | ||
12 | |||
13 | run() { | ||
14 | find ${T}/queue -type f | while read f; do | ||
15 | cat "${f}" | LD_PRELOAD=${PRELOAD} build/examples/cred \ | ||
16 | -k ${T}/pubkey -i ${T}/cred_id nodev 2>/dev/null 1>&2 | ||
17 | done | ||
18 | } | ||
19 | |||
20 | case "$1" in | ||
21 | sync) | ||
22 | sync | ||
23 | ;; | ||
24 | run) | ||
25 | run | ||
26 | exit 0 | ||
27 | ;; | ||
28 | *) | ||
29 | echo unknown command "$1" | ||
30 | exit 1 | ||
31 | esac | ||
diff --git a/fuzz/harnesses/cred-rsa-h-p b/fuzz/harnesses/cred-rsa-h-p new file mode 100755 index 0000000..bb14c23 --- /dev/null +++ b/fuzz/harnesses/cred-rsa-h-p | |||
@@ -0,0 +1,32 @@ | |||
1 | #!/bin/bash -u | ||
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 | T=cred-rsa-h-p | ||
7 | |||
8 | sync() { | ||
9 | mkdir ${T} | ||
10 | ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue" | tar -C ${T} -xf- | ||
11 | } | ||
12 | |||
13 | run() { | ||
14 | find ${T}/queue -type f | while read f; do | ||
15 | cat "${f}" | LD_PRELOAD=${PRELOAD} build/examples/cred \ | ||
16 | -t rsa -r -k ${T}/pubkey -i ${T}/cred_id -h nodev \ | ||
17 | 2>/dev/null 1>&2 | ||
18 | done | ||
19 | } | ||
20 | |||
21 | case "$1" in | ||
22 | sync) | ||
23 | sync | ||
24 | ;; | ||
25 | run) | ||
26 | run | ||
27 | exit 0 | ||
28 | ;; | ||
29 | *) | ||
30 | echo unknown command "$1" | ||
31 | exit 1 | ||
32 | esac | ||
diff --git a/fuzz/harnesses/cred-u2f b/fuzz/harnesses/cred-u2f new file mode 100755 index 0000000..3af4393 --- /dev/null +++ b/fuzz/harnesses/cred-u2f | |||
@@ -0,0 +1,31 @@ | |||
1 | #!/bin/bash -u | ||
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 | T=cred-u2f | ||
7 | |||
8 | sync() { | ||
9 | mkdir ${T} | ||
10 | ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue" | tar -C ${T} -xf- | ||
11 | } | ||
12 | |||
13 | run() { | ||
14 | find ${T}/queue -type f | while read f; do | ||
15 | cat "${f}" | LD_PRELOAD=${PRELOAD} build/examples/cred \ | ||
16 | -k ${T}/pubkey -i ${T}/cred_id -u nodev 2>/dev/null 1>&2 | ||
17 | done | ||
18 | } | ||
19 | |||
20 | case "$1" in | ||
21 | sync) | ||
22 | sync | ||
23 | ;; | ||
24 | run) | ||
25 | run | ||
26 | exit 0 | ||
27 | ;; | ||
28 | *) | ||
29 | echo unknown command "$1" | ||
30 | exit 1 | ||
31 | esac | ||
diff --git a/fuzz/harnesses/cred-u2f-exclude b/fuzz/harnesses/cred-u2f-exclude new file mode 100755 index 0000000..3777134 --- /dev/null +++ b/fuzz/harnesses/cred-u2f-exclude | |||
@@ -0,0 +1,33 @@ | |||
1 | #!/bin/bash -u | ||
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 | T=cred-u2f-exclude | ||
7 | |||
8 | sync() { | ||
9 | mkdir ${T} | ||
10 | ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue ../excl_id" | \ | ||
11 | tar -C ${T} -xf- | ||
12 | } | ||
13 | |||
14 | run() { | ||
15 | find ${T}/queue -type f | while read f; do | ||
16 | cat "${f}" | LD_PRELOAD=${PRELOAD} build/examples/cred \ | ||
17 | -k ${T}/pubkey -i ${T}/cred_id -e ${T}/excl_id \ | ||
18 | -u nodev 2>/dev/null 1>&2 | ||
19 | done | ||
20 | } | ||
21 | |||
22 | case "$1" in | ||
23 | sync) | ||
24 | sync | ||
25 | ;; | ||
26 | run) | ||
27 | run | ||
28 | exit 0 | ||
29 | ;; | ||
30 | *) | ||
31 | echo unknown command "$1" | ||
32 | exit 1 | ||
33 | esac | ||
diff --git a/fuzz/harnesses/fido2-assert-G b/fuzz/harnesses/fido2-assert-G new file mode 100755 index 0000000..6671449 --- /dev/null +++ b/fuzz/harnesses/fido2-assert-G | |||
@@ -0,0 +1,31 @@ | |||
1 | #!/bin/bash -u | ||
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 | T=fido2-assert-G | ||
7 | |||
8 | sync() { | ||
9 | mkdir ${T} | ||
10 | ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue" | tar -C ${T} -xf- | ||
11 | } | ||
12 | |||
13 | run() { | ||
14 | find ${T}/queue -type f | while read f; do | ||
15 | cat "${f}" | LD_PRELOAD=${PRELOAD} build/tools/fido2-assert \ | ||
16 | -G -i - nodev 2>/dev/null 1>&2 | ||
17 | done | ||
18 | } | ||
19 | |||
20 | case "$1" in | ||
21 | sync) | ||
22 | sync | ||
23 | ;; | ||
24 | run) | ||
25 | run | ||
26 | exit 0 | ||
27 | ;; | ||
28 | *) | ||
29 | echo unknown command "$1" | ||
30 | exit 1 | ||
31 | esac | ||
diff --git a/fuzz/harnesses/fido2-assert-V b/fuzz/harnesses/fido2-assert-V new file mode 100755 index 0000000..898cb0f --- /dev/null +++ b/fuzz/harnesses/fido2-assert-V | |||
@@ -0,0 +1,32 @@ | |||
1 | #!/bin/bash -u | ||
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 | T=fido2-assert-V | ||
7 | |||
8 | sync() { | ||
9 | mkdir ${T} | ||
10 | ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue ../pubkey" | \ | ||
11 | tar -C ${T} -xf- | ||
12 | } | ||
13 | |||
14 | run() { | ||
15 | find ${T}/queue -type f | while read f; do | ||
16 | cat "${f}" | LD_PRELOAD=${PRELOAD} build/tools/fido2-assert -V \ | ||
17 | pubkey es256 2>/dev/null 1>&2 | ||
18 | done | ||
19 | } | ||
20 | |||
21 | case "$1" in | ||
22 | sync) | ||
23 | sync | ||
24 | ;; | ||
25 | run) | ||
26 | run | ||
27 | exit 0 | ||
28 | ;; | ||
29 | *) | ||
30 | echo unknown command "$1" | ||
31 | exit 1 | ||
32 | esac | ||
diff --git a/fuzz/harnesses/fido2-cred-M b/fuzz/harnesses/fido2-cred-M new file mode 100755 index 0000000..f82fbf7 --- /dev/null +++ b/fuzz/harnesses/fido2-cred-M | |||
@@ -0,0 +1,31 @@ | |||
1 | #!/bin/bash -u | ||
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 | T=fido2-cred-M | ||
7 | |||
8 | sync() { | ||
9 | mkdir ${T} | ||
10 | ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue" | tar -C ${T} -xf- | ||
11 | } | ||
12 | |||
13 | run() { | ||
14 | find ${T}/queue -type f | while read f; do | ||
15 | cat "${f}" | LD_PRELOAD=${PRELOAD} build/tools/fido2-cred -M \ | ||
16 | -q -i - nodev 2>/dev/null 1>&2 | ||
17 | done | ||
18 | } | ||
19 | |||
20 | case "$1" in | ||
21 | sync) | ||
22 | sync | ||
23 | ;; | ||
24 | run) | ||
25 | run | ||
26 | exit 0 | ||
27 | ;; | ||
28 | *) | ||
29 | echo unknown command "$1" | ||
30 | exit 1 | ||
31 | esac | ||
diff --git a/fuzz/harnesses/fido2-cred-V b/fuzz/harnesses/fido2-cred-V new file mode 100755 index 0000000..13a648f --- /dev/null +++ b/fuzz/harnesses/fido2-cred-V | |||
@@ -0,0 +1,31 @@ | |||
1 | #!/bin/bash -u | ||
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 | T=fido2-cred-V | ||
7 | |||
8 | sync() { | ||
9 | mkdir ${T} | ||
10 | ssh "${REMOTE}" "cd ${T}/afl-out && tar -cf- queue" | tar -C ${T} -xf- | ||
11 | } | ||
12 | |||
13 | run() { | ||
14 | find ${T}/queue -type f | while read f; do | ||
15 | cat "${f}" | LD_PRELOAD=${PRELOAD} build/tools/fido2-cred -V \ | ||
16 | -o cred 2>/dev/null 1>&2 | ||
17 | done | ||
18 | } | ||
19 | |||
20 | case "$1" in | ||
21 | sync) | ||
22 | sync | ||
23 | ;; | ||
24 | run) | ||
25 | run | ||
26 | exit 0 | ||
27 | ;; | ||
28 | *) | ||
29 | echo unknown command "$1" | ||
30 | exit 1 | ||
31 | esac | ||
diff --git a/fuzz/harnesses/fuzz_assert b/fuzz/harnesses/fuzz_assert new file mode 100755 index 0000000..6a0baa9 --- /dev/null +++ b/fuzz/harnesses/fuzz_assert | |||
@@ -0,0 +1,29 @@ | |||
1 | #!/bin/bash -u | ||
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 | T=fuzz_assert | ||
7 | |||
8 | sync() { | ||
9 | mkdir ${T} | ||
10 | ssh "${REMOTE}" "cd ${T} && tar -cf- corpus" | tar -C ${T} -xf- | ||
11 | } | ||
12 | |||
13 | run() { | ||
14 | build/fuzz/fuzz_assert -max_len=17408 -runs=1 ${T}/corpus \ | ||
15 | 2>/dev/null 1>&2 | ||
16 | } | ||
17 | |||
18 | case "$1" in | ||
19 | sync) | ||
20 | sync | ||
21 | ;; | ||
22 | run) | ||
23 | run | ||
24 | exit 0 | ||
25 | ;; | ||
26 | *) | ||
27 | echo unknown command "$1" | ||
28 | exit 1 | ||
29 | esac | ||
diff --git a/fuzz/harnesses/fuzz_bio b/fuzz/harnesses/fuzz_bio new file mode 100755 index 0000000..f4bab19 --- /dev/null +++ b/fuzz/harnesses/fuzz_bio | |||
@@ -0,0 +1,29 @@ | |||
1 | #!/bin/bash -u | ||
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 | T=fuzz_bio | ||
7 | |||
8 | sync() { | ||
9 | mkdir ${T} | ||
10 | ssh "${REMOTE}" "cd ${T} && tar -cf- corpus" | tar -C ${T} -xf- | ||
11 | } | ||
12 | |||
13 | run() { | ||
14 | build/fuzz/fuzz_bio -max_len=17408 -runs=1 ${T}/corpus \ | ||
15 | 2>/dev/null 1>&2 | ||
16 | } | ||
17 | |||
18 | case "$1" in | ||
19 | sync) | ||
20 | sync | ||
21 | ;; | ||
22 | run) | ||
23 | run | ||
24 | exit 0 | ||
25 | ;; | ||
26 | *) | ||
27 | echo unknown command "$1" | ||
28 | exit 1 | ||
29 | esac | ||
diff --git a/fuzz/harnesses/fuzz_cred b/fuzz/harnesses/fuzz_cred new file mode 100755 index 0000000..8dfb168 --- /dev/null +++ b/fuzz/harnesses/fuzz_cred | |||
@@ -0,0 +1,28 @@ | |||
1 | #!/bin/bash -u | ||
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 | T=fuzz_cred | ||
7 | |||
8 | sync() { | ||
9 | mkdir ${T} | ||
10 | ssh "${REMOTE}" "cd ${T} && tar -cf- corpus" | tar -C ${T} -xf- | ||
11 | } | ||
12 | |||
13 | run() { | ||
14 | build/fuzz/fuzz_cred -max_len=17408 -runs=1 ${T}/corpus 2>/dev/null 1>&2 | ||
15 | } | ||
16 | |||
17 | case "$1" in | ||
18 | sync) | ||
19 | sync | ||
20 | ;; | ||
21 | run) | ||
22 | run | ||
23 | exit 0 | ||
24 | ;; | ||
25 | *) | ||
26 | echo unknown command "$1" | ||
27 | exit 1 | ||
28 | esac | ||
diff --git a/fuzz/harnesses/fuzz_credman b/fuzz/harnesses/fuzz_credman new file mode 100755 index 0000000..7721a58 --- /dev/null +++ b/fuzz/harnesses/fuzz_credman | |||
@@ -0,0 +1,28 @@ | |||
1 | #!/bin/bash -u | ||
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 | T=fuzz_credman | ||
7 | |||
8 | sync() { | ||
9 | mkdir ${T} | ||
10 | ssh "${REMOTE}" "cd ${T} && tar -cf- corpus" | tar -C ${T} -xf- | ||
11 | } | ||
12 | |||
13 | run() { | ||
14 | build/fuzz/fuzz_credman -max_len=17408 -runs=1 ${T}/corpus 2>/dev/null 1>&2 | ||
15 | } | ||
16 | |||
17 | case "$1" in | ||
18 | sync) | ||
19 | sync | ||
20 | ;; | ||
21 | run) | ||
22 | run | ||
23 | exit 0 | ||
24 | ;; | ||
25 | *) | ||
26 | echo unknown command "$1" | ||
27 | exit 1 | ||
28 | esac | ||
diff --git a/fuzz/harnesses/fuzz_mgmt b/fuzz/harnesses/fuzz_mgmt new file mode 100755 index 0000000..9224eea --- /dev/null +++ b/fuzz/harnesses/fuzz_mgmt | |||
@@ -0,0 +1,29 @@ | |||
1 | #!/bin/bash -u | ||
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 | T=fuzz_mgmt | ||
7 | |||
8 | sync() { | ||
9 | mkdir ${T} | ||
10 | ssh "${REMOTE}" "cd ${T} && tar -cf- corpus" | tar -C ${T} -xf- | ||
11 | } | ||
12 | |||
13 | run() { | ||
14 | build/fuzz/fuzz_mgmt -max_len=17408 -runs=1 ${T}/corpus \ | ||
15 | 2>/dev/null 1>&2 | ||
16 | } | ||
17 | |||
18 | case "$1" in | ||
19 | sync) | ||
20 | sync | ||
21 | ;; | ||
22 | run) | ||
23 | run | ||
24 | exit 0 | ||
25 | ;; | ||
26 | *) | ||
27 | echo unknown command "$1" | ||
28 | exit 1 | ||
29 | esac | ||
diff --git a/fuzz/mutator_aux.c b/fuzz/mutator_aux.c new file mode 100644 index 0000000..24aa716 --- /dev/null +++ b/fuzz/mutator_aux.c | |||
@@ -0,0 +1,314 @@ | |||
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 <assert.h> | ||
8 | #include <stddef.h> | ||
9 | #include <stdint.h> | ||
10 | #include <stdio.h> | ||
11 | #include <stdlib.h> | ||
12 | #include <string.h> | ||
13 | |||
14 | #include "mutator_aux.h" | ||
15 | |||
16 | size_t LLVMFuzzerMutate(uint8_t *, size_t, size_t); | ||
17 | |||
18 | static uint8_t *wire_data_ptr = NULL; | ||
19 | static size_t wire_data_len = 0; | ||
20 | |||
21 | size_t | ||
22 | xstrlen(const char *s) | ||
23 | { | ||
24 | if (s == NULL) | ||
25 | return (0); | ||
26 | |||
27 | return (strlen(s)); | ||
28 | } | ||
29 | |||
30 | void | ||
31 | consume(const void *body, size_t len) | ||
32 | { | ||
33 | const volatile uint8_t *ptr = body; | ||
34 | volatile uint8_t x = 0; | ||
35 | |||
36 | while (len--) | ||
37 | x ^= *ptr++; | ||
38 | } | ||
39 | |||
40 | int | ||
41 | unpack_int(uint8_t t, uint8_t **ptr, size_t *len, int *v) NO_MSAN | ||
42 | { | ||
43 | size_t l; | ||
44 | |||
45 | if (*len < sizeof(t) || **ptr != t) | ||
46 | return (-1); | ||
47 | |||
48 | *ptr += sizeof(t); | ||
49 | *len -= sizeof(t); | ||
50 | |||
51 | if (*len < sizeof(l)) | ||
52 | return (-1); | ||
53 | |||
54 | memcpy(&l, *ptr, sizeof(l)); | ||
55 | *ptr += sizeof(l); | ||
56 | *len -= sizeof(l); | ||
57 | |||
58 | if (l != sizeof(*v) || *len < l) | ||
59 | return (-1); | ||
60 | |||
61 | memcpy(v, *ptr, sizeof(*v)); | ||
62 | *ptr += sizeof(*v); | ||
63 | *len -= sizeof(*v); | ||
64 | |||
65 | return (0); | ||
66 | } | ||
67 | |||
68 | int | ||
69 | unpack_string(uint8_t t, uint8_t **ptr, size_t *len, char *v) NO_MSAN | ||
70 | { | ||
71 | size_t l; | ||
72 | |||
73 | if (*len < sizeof(t) || **ptr != t) | ||
74 | return (-1); | ||
75 | |||
76 | *ptr += sizeof(t); | ||
77 | *len -= sizeof(t); | ||
78 | |||
79 | if (*len < sizeof(l)) | ||
80 | return (-1); | ||
81 | |||
82 | memcpy(&l, *ptr, sizeof(l)); | ||
83 | *ptr += sizeof(l); | ||
84 | *len -= sizeof(l); | ||
85 | |||
86 | if (*len < l || l >= MAXSTR) | ||
87 | return (-1); | ||
88 | |||
89 | memcpy(v, *ptr, l); | ||
90 | v[l] = '\0'; | ||
91 | |||
92 | *ptr += l; | ||
93 | *len -= l; | ||
94 | |||
95 | return (0); | ||
96 | } | ||
97 | |||
98 | int | ||
99 | unpack_byte(uint8_t t, uint8_t **ptr, size_t *len, uint8_t *v) NO_MSAN | ||
100 | { | ||
101 | size_t l; | ||
102 | |||
103 | if (*len < sizeof(t) || **ptr != t) | ||
104 | return (-1); | ||
105 | |||
106 | *ptr += sizeof(t); | ||
107 | *len -= sizeof(t); | ||
108 | |||
109 | if (*len < sizeof(l)) | ||
110 | return (-1); | ||
111 | |||
112 | memcpy(&l, *ptr, sizeof(l)); | ||
113 | *ptr += sizeof(l); | ||
114 | *len -= sizeof(l); | ||
115 | |||
116 | if (l != sizeof(*v) || *len < l) | ||
117 | return (-1); | ||
118 | |||
119 | memcpy(v, *ptr, sizeof(*v)); | ||
120 | *ptr += sizeof(*v); | ||
121 | *len -= sizeof(*v); | ||
122 | |||
123 | return (0); | ||
124 | } | ||
125 | |||
126 | int | ||
127 | unpack_blob(uint8_t t, uint8_t **ptr, size_t *len, struct blob *v) NO_MSAN | ||
128 | { | ||
129 | size_t l; | ||
130 | |||
131 | v->len = 0; | ||
132 | |||
133 | if (*len < sizeof(t) || **ptr != t) | ||
134 | return (-1); | ||
135 | |||
136 | *ptr += sizeof(t); | ||
137 | *len -= sizeof(t); | ||
138 | |||
139 | if (*len < sizeof(l)) | ||
140 | return (-1); | ||
141 | |||
142 | memcpy(&l, *ptr, sizeof(l)); | ||
143 | *ptr += sizeof(l); | ||
144 | *len -= sizeof(l); | ||
145 | |||
146 | if (*len < l || l > sizeof(v->body)) | ||
147 | return (-1); | ||
148 | |||
149 | memcpy(v->body, *ptr, l); | ||
150 | *ptr += l; | ||
151 | *len -= l; | ||
152 | |||
153 | v->len = l; | ||
154 | |||
155 | return (0); | ||
156 | } | ||
157 | |||
158 | int | ||
159 | pack_int(uint8_t t, uint8_t **ptr, size_t *len, int v) NO_MSAN | ||
160 | { | ||
161 | const size_t l = sizeof(v); | ||
162 | |||
163 | if (*len < sizeof(t) + sizeof(l) + l) | ||
164 | return (-1); | ||
165 | |||
166 | (*ptr)[0] = t; | ||
167 | memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); | ||
168 | memcpy(&(*ptr)[sizeof(t) + sizeof(l)], &v, l); | ||
169 | |||
170 | *ptr += sizeof(t) + sizeof(l) + l; | ||
171 | *len -= sizeof(t) + sizeof(l) + l; | ||
172 | |||
173 | return (0); | ||
174 | } | ||
175 | |||
176 | int | ||
177 | pack_string(uint8_t t, uint8_t **ptr, size_t *len, const char *v) NO_MSAN | ||
178 | { | ||
179 | const size_t l = strlen(v); | ||
180 | |||
181 | if (*len < sizeof(t) + sizeof(l) + l) | ||
182 | return (-1); | ||
183 | |||
184 | (*ptr)[0] = t; | ||
185 | memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); | ||
186 | memcpy(&(*ptr)[sizeof(t) + sizeof(l)], v, l); | ||
187 | |||
188 | *ptr += sizeof(t) + sizeof(l) + l; | ||
189 | *len -= sizeof(t) + sizeof(l) + l; | ||
190 | |||
191 | return (0); | ||
192 | } | ||
193 | |||
194 | int | ||
195 | pack_byte(uint8_t t, uint8_t **ptr, size_t *len, uint8_t v) NO_MSAN | ||
196 | { | ||
197 | const size_t l = sizeof(v); | ||
198 | |||
199 | if (*len < sizeof(t) + sizeof(l) + l) | ||
200 | return (-1); | ||
201 | |||
202 | (*ptr)[0] = t; | ||
203 | memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); | ||
204 | memcpy(&(*ptr)[sizeof(t) + sizeof(l)], &v, l); | ||
205 | |||
206 | *ptr += sizeof(t) + sizeof(l) + l; | ||
207 | *len -= sizeof(t) + sizeof(l) + l; | ||
208 | |||
209 | return (0); | ||
210 | } | ||
211 | |||
212 | int | ||
213 | pack_blob(uint8_t t, uint8_t **ptr, size_t *len, const struct blob *v) NO_MSAN | ||
214 | { | ||
215 | const size_t l = v->len; | ||
216 | |||
217 | if (*len < sizeof(t) + sizeof(l) + l) | ||
218 | return (-1); | ||
219 | |||
220 | (*ptr)[0] = t; | ||
221 | memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); | ||
222 | memcpy(&(*ptr)[sizeof(t) + sizeof(l)], v->body, l); | ||
223 | |||
224 | *ptr += sizeof(t) + sizeof(l) + l; | ||
225 | *len -= sizeof(t) + sizeof(l) + l; | ||
226 | |||
227 | return (0); | ||
228 | } | ||
229 | |||
230 | void | ||
231 | mutate_byte(uint8_t *b) | ||
232 | { | ||
233 | LLVMFuzzerMutate(b, sizeof(*b), sizeof(*b)); | ||
234 | } | ||
235 | |||
236 | void | ||
237 | mutate_int(int *i) | ||
238 | { | ||
239 | LLVMFuzzerMutate((uint8_t *)i, sizeof(*i), sizeof(*i)); | ||
240 | } | ||
241 | |||
242 | void | ||
243 | mutate_blob(struct blob *blob) | ||
244 | { | ||
245 | blob->len = LLVMFuzzerMutate((uint8_t *)blob->body, blob->len, | ||
246 | sizeof(blob->body)); | ||
247 | } | ||
248 | |||
249 | void | ||
250 | mutate_string(char *s) | ||
251 | { | ||
252 | size_t n; | ||
253 | |||
254 | n = LLVMFuzzerMutate((uint8_t *)s, strlen(s), MAXSTR - 1); | ||
255 | s[n] = '\0'; | ||
256 | } | ||
257 | |||
258 | void * | ||
259 | dev_open(const char *path) | ||
260 | { | ||
261 | (void)path; | ||
262 | |||
263 | return ((void *)0xdeadbeef); | ||
264 | } | ||
265 | |||
266 | void | ||
267 | dev_close(void *handle) | ||
268 | { | ||
269 | assert(handle == (void *)0xdeadbeef); | ||
270 | } | ||
271 | |||
272 | int | ||
273 | dev_read(void *handle, unsigned char *ptr, size_t len, int ms) | ||
274 | { | ||
275 | size_t n; | ||
276 | |||
277 | (void)ms; | ||
278 | |||
279 | assert(handle == (void *)0xdeadbeef); | ||
280 | assert(len == 64); | ||
281 | |||
282 | if (wire_data_len < len) | ||
283 | n = wire_data_len; | ||
284 | else | ||
285 | n = len; | ||
286 | |||
287 | memcpy(ptr, wire_data_ptr, n); | ||
288 | |||
289 | wire_data_ptr += n; | ||
290 | wire_data_len -= n; | ||
291 | |||
292 | return ((int)n); | ||
293 | } | ||
294 | |||
295 | int | ||
296 | dev_write(void *handle, const unsigned char *ptr, size_t len) | ||
297 | { | ||
298 | assert(handle == (void *)0xdeadbeef); | ||
299 | assert(len == 64 + 1); | ||
300 | |||
301 | consume(ptr, len); | ||
302 | |||
303 | if (uniform_random(400) < 1) | ||
304 | return (-1); | ||
305 | |||
306 | return ((int)len); | ||
307 | } | ||
308 | |||
309 | void | ||
310 | set_wire_data(uint8_t *ptr, size_t len) | ||
311 | { | ||
312 | wire_data_ptr = ptr; | ||
313 | wire_data_len = len; | ||
314 | } | ||
diff --git a/fuzz/mutator_aux.h b/fuzz/mutator_aux.h new file mode 100644 index 0000000..687f130 --- /dev/null +++ b/fuzz/mutator_aux.h | |||
@@ -0,0 +1,65 @@ | |||
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 | #ifndef _MUTATOR_AUX_H | ||
8 | #define _MUTATOR_AUX_H | ||
9 | |||
10 | /* | ||
11 | * As of LLVM 7.0.1, MSAN support in libFuzzer was still experimental. | ||
12 | * We therefore have to be careful when using our custom mutator, or | ||
13 | * MSAN will flag uninitialised reads on memory populated by libFuzzer. | ||
14 | * Since there is no way to suppress MSAN without regenerating object | ||
15 | * code (in which case you might as well rebuild libFuzzer with MSAN), | ||
16 | * we adjust our mutator to make it less accurate while allowing | ||
17 | * fuzzing to proceed. | ||
18 | */ | ||
19 | |||
20 | #if defined(__has_feature) | ||
21 | # if __has_feature(memory_sanitizer) | ||
22 | # define NO_MSAN __attribute__((no_sanitize("memory"))) | ||
23 | # define WITH_MSAN 1 | ||
24 | # endif | ||
25 | #endif | ||
26 | |||
27 | #if !defined(WITH_MSAN) | ||
28 | # define NO_MSAN | ||
29 | #endif | ||
30 | |||
31 | #define MAXSTR 1024 | ||
32 | #define MAXBLOB 3072 | ||
33 | |||
34 | struct blob { | ||
35 | uint8_t body[MAXBLOB]; | ||
36 | size_t len; | ||
37 | }; | ||
38 | |||
39 | size_t xstrlen(const char *); | ||
40 | void consume(const void *, size_t); | ||
41 | |||
42 | int unpack_blob(uint8_t, uint8_t **, size_t *, struct blob *); | ||
43 | int unpack_byte(uint8_t, uint8_t **, size_t *, uint8_t *); | ||
44 | int unpack_int(uint8_t, uint8_t **, size_t *, int *); | ||
45 | int unpack_string(uint8_t, uint8_t **, size_t *, char *); | ||
46 | |||
47 | int pack_blob(uint8_t, uint8_t **, size_t *, const struct blob *); | ||
48 | int pack_byte(uint8_t, uint8_t **, size_t *, uint8_t); | ||
49 | int pack_int(uint8_t, uint8_t **, size_t *, int); | ||
50 | int pack_string(uint8_t, uint8_t **, size_t *, const char *); | ||
51 | |||
52 | void mutate_byte(uint8_t *); | ||
53 | void mutate_int(int *); | ||
54 | void mutate_blob(struct blob *); | ||
55 | void mutate_string(char *); | ||
56 | |||
57 | void * dev_open(const char *); | ||
58 | void dev_close(void *); | ||
59 | void set_wire_data(uint8_t *, size_t); | ||
60 | int dev_read(void *, unsigned char *, size_t, int); | ||
61 | int dev_write(void *, const unsigned char *, size_t); | ||
62 | |||
63 | uint32_t uniform_random(uint32_t); | ||
64 | |||
65 | #endif /* !_MUTATOR_AUX_H */ | ||
diff --git a/fuzz/preload-fuzz.c b/fuzz/preload-fuzz.c new file mode 100644 index 0000000..efcb8c6 --- /dev/null +++ b/fuzz/preload-fuzz.c | |||
@@ -0,0 +1,104 @@ | |||
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 | /* | ||
8 | * cc -fPIC -D_GNU_SOURCE -shared -o preload-fuzz.so preload-fuzz.c | ||
9 | * LD_PRELOAD=$(realpath preload-fuzz.so) | ||
10 | */ | ||
11 | |||
12 | #include <sys/types.h> | ||
13 | #include <sys/stat.h> | ||
14 | |||
15 | #include <dlfcn.h> | ||
16 | #include <err.h> | ||
17 | #include <errno.h> | ||
18 | #include <fcntl.h> | ||
19 | #include <limits.h> | ||
20 | #include <stdarg.h> | ||
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <string.h> | ||
24 | #include <unistd.h> | ||
25 | |||
26 | #define FUZZ_DEV_PREFIX "nodev" | ||
27 | |||
28 | static int fd_fuzz = -1; | ||
29 | static int (*open_f)(const char *, int, mode_t); | ||
30 | static int (*close_f)(int); | ||
31 | static ssize_t (*write_f)(int, const void *, size_t); | ||
32 | |||
33 | int | ||
34 | open(const char *path, int flags, ...) | ||
35 | { | ||
36 | va_list ap; | ||
37 | mode_t mode; | ||
38 | |||
39 | va_start(ap, flags); | ||
40 | mode = va_arg(ap, mode_t); | ||
41 | va_end(ap); | ||
42 | |||
43 | if (open_f == NULL) { | ||
44 | open_f = dlsym(RTLD_NEXT, "open"); | ||
45 | if (open_f == NULL) { | ||
46 | warnx("%s: dlsym", __func__); | ||
47 | errno = EACCES; | ||
48 | return (-1); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | if (strncmp(path, FUZZ_DEV_PREFIX, strlen(FUZZ_DEV_PREFIX)) != 0) | ||
53 | return (open_f(path, flags, mode)); | ||
54 | |||
55 | if (fd_fuzz != -1) { | ||
56 | warnx("%s: fd_fuzz != -1", __func__); | ||
57 | errno = EACCES; | ||
58 | return (-1); | ||
59 | } | ||
60 | |||
61 | if ((fd_fuzz = dup(STDIN_FILENO)) < 0) { | ||
62 | warn("%s: dup", __func__); | ||
63 | errno = EACCES; | ||
64 | return (-1); | ||
65 | } | ||
66 | |||
67 | return (fd_fuzz); | ||
68 | } | ||
69 | |||
70 | int | ||
71 | close(int fd) | ||
72 | { | ||
73 | if (close_f == NULL) { | ||
74 | close_f = dlsym(RTLD_NEXT, "close"); | ||
75 | if (close_f == NULL) { | ||
76 | warnx("%s: dlsym", __func__); | ||
77 | errno = EACCES; | ||
78 | return (-1); | ||
79 | } | ||
80 | } | ||
81 | |||
82 | if (fd == fd_fuzz) | ||
83 | fd_fuzz = -1; | ||
84 | |||
85 | return (close_f(fd)); | ||
86 | } | ||
87 | |||
88 | ssize_t | ||
89 | write(int fd, const void *buf, size_t nbytes) | ||
90 | { | ||
91 | if (write_f == NULL) { | ||
92 | write_f = dlsym(RTLD_NEXT, "write"); | ||
93 | if (write_f == NULL) { | ||
94 | warnx("%s: dlsym", __func__); | ||
95 | errno = EBADF; | ||
96 | return (-1); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | if (fd != fd_fuzz) | ||
101 | return (write_f(fd, buf, nbytes)); | ||
102 | |||
103 | return (nbytes); | ||
104 | } | ||
diff --git a/fuzz/preload-snoop.c b/fuzz/preload-snoop.c new file mode 100644 index 0000000..373acc5 --- /dev/null +++ b/fuzz/preload-snoop.c | |||
@@ -0,0 +1,217 @@ | |||
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 | /* | ||
8 | * cc -fPIC -D_GNU_SOURCE -shared -o preload-snoop.so preload-snoop.c | ||
9 | * LD_PRELOAD=$(realpath preload-snoop.so) | ||
10 | */ | ||
11 | |||
12 | #include <sys/types.h> | ||
13 | #include <sys/stat.h> | ||
14 | |||
15 | #include <dlfcn.h> | ||
16 | #include <err.h> | ||
17 | #include <errno.h> | ||
18 | #include <fcntl.h> | ||
19 | #include <limits.h> | ||
20 | #include <stdarg.h> | ||
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <string.h> | ||
24 | #include <unistd.h> | ||
25 | |||
26 | #define SNOOP_DEV_PREFIX "/dev/hidraw" | ||
27 | |||
28 | struct fd_tuple { | ||
29 | int snoop_in; | ||
30 | int snoop_out; | ||
31 | int real_dev; | ||
32 | }; | ||
33 | |||
34 | static struct fd_tuple *fd_tuple; | ||
35 | static int (*open_f)(const char *, int, mode_t); | ||
36 | static int (*close_f)(int); | ||
37 | static ssize_t (*read_f)(int, void *, size_t); | ||
38 | static ssize_t (*write_f)(int, const void *, size_t); | ||
39 | |||
40 | static int | ||
41 | get_fd(const char *hid_path, const char *suffix) | ||
42 | { | ||
43 | char *s = NULL; | ||
44 | char path[PATH_MAX]; | ||
45 | int fd; | ||
46 | int r; | ||
47 | |||
48 | if ((s = strdup(hid_path)) == NULL) { | ||
49 | warnx("%s: strdup", __func__); | ||
50 | return (-1); | ||
51 | } | ||
52 | |||
53 | for (size_t i = 0; i < strlen(s); i++) | ||
54 | if (s[i] == '/') | ||
55 | s[i] = '_'; | ||
56 | |||
57 | if ((r = snprintf(path, sizeof(path), "%s-%s", s, suffix)) < 0 || | ||
58 | (size_t)r >= sizeof(path)) { | ||
59 | warnx("%s: snprintf", __func__); | ||
60 | free(s); | ||
61 | return (-1); | ||
62 | } | ||
63 | |||
64 | free(s); | ||
65 | s = NULL; | ||
66 | |||
67 | if ((fd = open_f(path, O_CREAT | O_WRONLY, 0644)) < 0) { | ||
68 | warn("%s: open", __func__); | ||
69 | return (-1); | ||
70 | } | ||
71 | |||
72 | return (fd); | ||
73 | } | ||
74 | |||
75 | int | ||
76 | open(const char *path, int flags, ...) | ||
77 | { | ||
78 | va_list ap; | ||
79 | mode_t mode; | ||
80 | |||
81 | va_start(ap, flags); | ||
82 | mode = va_arg(ap, mode_t); | ||
83 | va_end(ap); | ||
84 | |||
85 | if (open_f == NULL) { | ||
86 | open_f = dlsym(RTLD_NEXT, "open"); | ||
87 | if (open_f == NULL) { | ||
88 | warnx("%s: dlsym", __func__); | ||
89 | errno = EACCES; | ||
90 | return (-1); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | if (strncmp(path, SNOOP_DEV_PREFIX, strlen(SNOOP_DEV_PREFIX)) != 0) | ||
95 | return (open_f(path, flags, mode)); | ||
96 | |||
97 | if (fd_tuple != NULL) { | ||
98 | warnx("%s: fd_tuple != NULL", __func__); | ||
99 | errno = EACCES; | ||
100 | return (-1); | ||
101 | } | ||
102 | |||
103 | if ((fd_tuple = calloc(1, sizeof(*fd_tuple))) == NULL) { | ||
104 | warn("%s: calloc", __func__); | ||
105 | errno = ENOMEM; | ||
106 | return (-1); | ||
107 | } | ||
108 | |||
109 | fd_tuple->snoop_in = -1; | ||
110 | fd_tuple->snoop_out = -1; | ||
111 | fd_tuple->real_dev = -1; | ||
112 | |||
113 | if ((fd_tuple->snoop_in = get_fd(path, "in")) < 0 || | ||
114 | (fd_tuple->snoop_out = get_fd(path, "out")) < 0 || | ||
115 | (fd_tuple->real_dev = open_f(path, flags, mode)) < 0) { | ||
116 | warn("%s: get_fd/open", __func__); | ||
117 | goto fail; | ||
118 | } | ||
119 | |||
120 | return (fd_tuple->real_dev); | ||
121 | fail: | ||
122 | if (fd_tuple->snoop_in != -1) | ||
123 | close(fd_tuple->snoop_in); | ||
124 | if (fd_tuple->snoop_out != -1) | ||
125 | close(fd_tuple->snoop_out); | ||
126 | if (fd_tuple->real_dev != -1) | ||
127 | close(fd_tuple->real_dev); | ||
128 | |||
129 | free(fd_tuple); | ||
130 | fd_tuple = NULL; | ||
131 | |||
132 | errno = EACCES; | ||
133 | |||
134 | return (-1); | ||
135 | } | ||
136 | |||
137 | int | ||
138 | close(int fd) | ||
139 | { | ||
140 | if (close_f == NULL) { | ||
141 | close_f = dlsym(RTLD_NEXT, "close"); | ||
142 | if (close_f == NULL) { | ||
143 | warnx("%s: dlsym", __func__); | ||
144 | errno = EBADF; | ||
145 | return (-1); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | if (fd_tuple == NULL || fd_tuple->real_dev != fd) | ||
150 | return (close_f(fd)); | ||
151 | |||
152 | close_f(fd_tuple->snoop_in); | ||
153 | close_f(fd_tuple->snoop_out); | ||
154 | close_f(fd_tuple->real_dev); | ||
155 | |||
156 | free(fd_tuple); | ||
157 | fd_tuple = NULL; | ||
158 | |||
159 | return (0); | ||
160 | } | ||
161 | |||
162 | ssize_t | ||
163 | read(int fd, void *buf, size_t nbytes) | ||
164 | { | ||
165 | ssize_t n; | ||
166 | |||
167 | if (read_f == NULL) { | ||
168 | read_f = dlsym(RTLD_NEXT, "read"); | ||
169 | if (read_f == NULL) { | ||
170 | warnx("%s: dlsym", __func__); | ||
171 | errno = EBADF; | ||
172 | return (-1); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | if (write_f == NULL) { | ||
177 | write_f = dlsym(RTLD_NEXT, "write"); | ||
178 | if (write_f == NULL) { | ||
179 | warnx("%s: dlsym", __func__); | ||
180 | errno = EBADF; | ||
181 | return (-1); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | if (fd_tuple == NULL || fd_tuple->real_dev != fd) | ||
186 | return (read_f(fd, buf, nbytes)); | ||
187 | |||
188 | if ((n = read_f(fd, buf, nbytes)) < 0 || | ||
189 | write_f(fd_tuple->snoop_in, buf, n) != n) | ||
190 | return (-1); | ||
191 | |||
192 | return (n); | ||
193 | } | ||
194 | |||
195 | ssize_t | ||
196 | write(int fd, const void *buf, size_t nbytes) | ||
197 | { | ||
198 | ssize_t n; | ||
199 | |||
200 | if (write_f == NULL) { | ||
201 | write_f = dlsym(RTLD_NEXT, "write"); | ||
202 | if (write_f == NULL) { | ||
203 | warnx("%s: dlsym", __func__); | ||
204 | errno = EBADF; | ||
205 | return (-1); | ||
206 | } | ||
207 | } | ||
208 | |||
209 | if (fd_tuple == NULL || fd_tuple->real_dev != fd) | ||
210 | return (write_f(fd, buf, nbytes)); | ||
211 | |||
212 | if ((n = write_f(fd, buf, nbytes)) < 0 || | ||
213 | write_f(fd_tuple->snoop_out, buf, n) != n) | ||
214 | return (-1); | ||
215 | |||
216 | return (n); | ||
217 | } | ||
diff --git a/fuzz/report b/fuzz/report new file mode 100755 index 0000000..bebb0ca --- /dev/null +++ b/fuzz/report | |||
@@ -0,0 +1,80 @@ | |||
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 | # | ||
6 | # XXX This should really be a Makefile. | ||
7 | |||
8 | T="" | ||
9 | #T+=" harnesses/assert" | ||
10 | #T+=" harnesses/assert-rsa-h-p" | ||
11 | #T+=" harnesses/assert-u2f" | ||
12 | #T+=" harnesses/cred" | ||
13 | #T+=" harnesses/cred-rsa-h-p" | ||
14 | #T+=" harnesses/cred-u2f" | ||
15 | #T+=" harnesses/cred-u2f-exclude" | ||
16 | #T+=" harnesses/fido2-assert-G" | ||
17 | #T+=" harnesses/fido2-assert-V" | ||
18 | #T+=" harnesses/fido2-cred-M" | ||
19 | #T+=" harnesses/fido2-cred-V" | ||
20 | T+=" harnesses/fuzz_assert" | ||
21 | T+=" harnesses/fuzz_bio" | ||
22 | T+=" harnesses/fuzz_cred" | ||
23 | T+=" harnesses/fuzz_credman" | ||
24 | T+=" harnesses/fuzz_mgmt" | ||
25 | |||
26 | clean() { | ||
27 | echo cleaning | ||
28 | rm -rf obj | ||
29 | mkdir obj | ||
30 | } | ||
31 | |||
32 | build() { | ||
33 | echo building | ||
34 | mkdir obj/build | ||
35 | (cd obj/build && cmake -DFUZZ=1 -DLIBFUZZER=1 -DCMAKE_C_COMPILER=clang \ | ||
36 | -DCOVERAGE=1 -DCMAKE_BUILD_TYPE=Debug ../../..) 2>/dev/null 1>&2 | ||
37 | make -C obj/build 2>/dev/null 1>&2 | ||
38 | cc -fPIC -D_GNU_SOURCE -shared -o obj/preload-fuzz.so preload-fuzz.c | ||
39 | } | ||
40 | |||
41 | sync() { | ||
42 | if [ -n "${REMOTE}" ]; then | ||
43 | for t in ${T}; do | ||
44 | echo syncing ${t} | ||
45 | (cd obj && REMOTE="${REMOTE}" ../${t} sync) | ||
46 | done | ||
47 | else | ||
48 | tar -C obj -zxf corpus.tgz | ||
49 | fi | ||
50 | } | ||
51 | |||
52 | run() { | ||
53 | export LLVM_PROFILE_FILE="profraw/%h-%p.profraw" | ||
54 | export PRELOAD=$(realpath obj/preload-fuzz.so) | ||
55 | |||
56 | for t in ${T}; do | ||
57 | echo running ${t} | ||
58 | (cd obj && ../${t} run) | ||
59 | done | ||
60 | } | ||
61 | |||
62 | merge() { | ||
63 | echo merging | ||
64 | (cd obj && \ | ||
65 | llvm-profdata merge -sparse profraw/*.profraw \ | ||
66 | -o libfido2.profdata && | ||
67 | llvm-cov show -format=html -tab-size=8 build/src/libfido2.so \ | ||
68 | -instr-profile=libfido2.profdata > report.html && | ||
69 | llvm-cov report -use-color=false build/src/libfido2.so \ | ||
70 | -instr-profile=libfido2.profdata > summary.txt && | ||
71 | llvm-cov report -use-color=false -show-functions \ | ||
72 | -instr-profile=libfido2.profdata build/src/libfido2.so \ | ||
73 | ../../src/*.[ch] > functions.txt) | ||
74 | } | ||
75 | |||
76 | clean | ||
77 | build | ||
78 | sync | ||
79 | run | ||
80 | merge | ||
diff --git a/fuzz/summary.txt b/fuzz/summary.txt new file mode 100644 index 0000000..e494865 --- /dev/null +++ b/fuzz/summary.txt | |||
@@ -0,0 +1,39 @@ | |||
1 | Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover | ||
2 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ||
3 | fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 23 1 95.65% | ||
4 | fuzz/wrap.c 4 0 100.00% 1 0 100.00% 7 0 100.00% | ||
5 | openbsd-compat/explicit_bzero.c 4 0 100.00% 1 0 100.00% 12 0 100.00% | ||
6 | openbsd-compat/recallocarray.c 41 7 82.93% 1 0 100.00% 49 7 85.71% | ||
7 | openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 8 0 100.00% | ||
8 | src/aes256.c 56 0 100.00% 2 0 100.00% 82 0 100.00% | ||
9 | src/assert.c 569 29 94.90% 53 1 98.11% 901 60 93.34% | ||
10 | src/authkey.c 45 0 100.00% 5 0 100.00% 75 0 100.00% | ||
11 | src/bio.c 422 21 95.02% 49 2 95.92% 661 25 96.22% | ||
12 | src/blob.c 39 1 97.44% 7 0 100.00% 73 4 94.52% | ||
13 | src/buf.c 8 1 87.50% 2 0 100.00% 20 1 95.00% | ||
14 | src/cbor.c 844 31 96.33% 51 1 98.04% 1319 47 96.44% | ||
15 | src/cred.c 532 35 93.42% 54 1 98.15% 850 55 93.53% | ||
16 | src/credman.c 381 18 95.28% 38 0 100.00% 589 15 97.45% | ||
17 | src/dev.c 131 22 83.21% 19 1 94.74% 183 30 83.61% | ||
18 | src/ecdh.c 68 0 100.00% 2 0 100.00% 104 0 100.00% | ||
19 | src/eddsa.c 54 4 92.59% 8 0 100.00% 79 2 97.47% | ||
20 | src/err.c 108 108 0.00% 1 1 0.00% 112 112 0.00% | ||
21 | src/es256.c 273 4 98.53% 16 0 100.00% 372 13 96.51% | ||
22 | src/hid.c 16 16 0.00% 8 8 0.00% 38 38 0.00% | ||
23 | src/hid_linux.c 166 166 0.00% 12 12 0.00% 287 287 0.00% | ||
24 | src/info.c 148 1 99.32% 31 0 100.00% 305 0 100.00% | ||
25 | src/io.c 113 6 94.69% 7 0 100.00% 201 13 93.53% | ||
26 | src/iso7816.c 18 1 94.44% 5 0 100.00% 47 0 100.00% | ||
27 | src/log.c 16 10 37.50% 3 1 66.67% 34 23 32.35% | ||
28 | src/pin.c 250 0 100.00% 16 0 100.00% 364 0 100.00% | ||
29 | src/reset.c 20 0 100.00% 3 0 100.00% 23 0 100.00% | ||
30 | src/rs256.c 102 6 94.12% 8 0 100.00% 140 9 93.57% | ||
31 | src/u2f.c 436 11 97.48% 13 0 100.00% 686 22 96.79% | ||
32 | |||
33 | Files which contain no functions: | ||
34 | src/extern.h 0 0 - 0 0 - 0 0 - | ||
35 | src/fido.h 0 0 - 0 0 - 0 0 - | ||
36 | src/fido/err.h 0 0 - 0 0 - 0 0 - | ||
37 | src/fido/param.h 0 0 - 0 0 - 0 0 - | ||
38 | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ||
39 | TOTAL 4875 499 89.76% 418 28 93.30% 7644 764 90.01% | ||
diff --git a/fuzz/uniform_random.c b/fuzz/uniform_random.c new file mode 100644 index 0000000..7711d69 --- /dev/null +++ b/fuzz/uniform_random.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2008, Damien Miller <djm@openbsd.org> | ||
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 <stdint.h> | ||
18 | #include <stdlib.h> | ||
19 | |||
20 | uint32_t uniform_random(uint32_t); | ||
21 | |||
22 | /* | ||
23 | * Calculate a uniformly distributed random number less than upper_bound | ||
24 | * avoiding "modulo bias". | ||
25 | * | ||
26 | * Uniformity is achieved by generating new random numbers until the one | ||
27 | * returned is outside the range [0, 2**32 % upper_bound). This | ||
28 | * guarantees the selected random number will be inside | ||
29 | * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound) | ||
30 | * after reduction modulo upper_bound. | ||
31 | */ | ||
32 | uint32_t | ||
33 | uniform_random(uint32_t upper_bound) | ||
34 | { | ||
35 | uint32_t r, min; | ||
36 | |||
37 | if (upper_bound < 2) | ||
38 | return 0; | ||
39 | |||
40 | /* 2**32 % x == (2**32 - x) % x */ | ||
41 | min = -upper_bound % upper_bound; | ||
42 | |||
43 | /* | ||
44 | * This could theoretically loop forever but each retry has | ||
45 | * p > 0.5 (worst case, usually far better) of selecting a | ||
46 | * number inside the range we need, so it should rarely need | ||
47 | * to re-roll. | ||
48 | */ | ||
49 | for (;;) { | ||
50 | r = (uint32_t)random(); | ||
51 | if (r >= min) | ||
52 | break; | ||
53 | } | ||
54 | |||
55 | return r % upper_bound; | ||
56 | } | ||
diff --git a/fuzz/wrap.c b/fuzz/wrap.c new file mode 100644 index 0000000..8ff7ee7 --- /dev/null +++ b/fuzz/wrap.c | |||
@@ -0,0 +1,419 @@ | |||
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 <openssl/bn.h> | ||
8 | #include <openssl/evp.h> | ||
9 | #include <openssl/sha.h> | ||
10 | |||
11 | #include <cbor.h> | ||
12 | #include <fido.h> | ||
13 | |||
14 | #include <stdbool.h> | ||
15 | #include <stdint.h> | ||
16 | #include <stdio.h> | ||
17 | #include <stdlib.h> | ||
18 | |||
19 | #include "mutator_aux.h" | ||
20 | |||
21 | /* | ||
22 | * Build wrappers around functions of interest, and have them fail | ||
23 | * in a pseudo-random manner. | ||
24 | */ | ||
25 | |||
26 | #define WRAP(type, name, args, retval, param, prob) \ | ||
27 | extern type __wrap_##name args; \ | ||
28 | extern type __real_##name args; \ | ||
29 | type __wrap_##name args { \ | ||
30 | if (uniform_random(400) < (prob)) { \ | ||
31 | return (retval); \ | ||
32 | } \ | ||
33 | \ | ||
34 | return (__real_##name param); \ | ||
35 | } | ||
36 | |||
37 | WRAP(void *, | ||
38 | malloc, | ||
39 | (size_t size), | ||
40 | NULL, | ||
41 | (size), | ||
42 | 1 | ||
43 | ) | ||
44 | |||
45 | WRAP(void *, | ||
46 | calloc, | ||
47 | (size_t nmemb, size_t size), | ||
48 | NULL, | ||
49 | (nmemb, size), | ||
50 | 1 | ||
51 | ) | ||
52 | |||
53 | WRAP(char *, | ||
54 | strdup, | ||
55 | (const char *s), | ||
56 | NULL, | ||
57 | (s), | ||
58 | 1 | ||
59 | ) | ||
60 | |||
61 | WRAP(EVP_CIPHER_CTX *, | ||
62 | EVP_CIPHER_CTX_new, | ||
63 | (void), | ||
64 | NULL, | ||
65 | (), | ||
66 | 1 | ||
67 | ) | ||
68 | |||
69 | WRAP(int, EVP_EncryptInit_ex, | ||
70 | (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl, | ||
71 | const unsigned char *key, const unsigned char *iv), | ||
72 | 0, | ||
73 | (ctx, type, impl, key, iv), | ||
74 | 1 | ||
75 | ) | ||
76 | |||
77 | WRAP(int, | ||
78 | EVP_CIPHER_CTX_set_padding, | ||
79 | (EVP_CIPHER_CTX *x, int padding), | ||
80 | 0, | ||
81 | (x, padding), | ||
82 | 1 | ||
83 | ) | ||
84 | |||
85 | WRAP(int, | ||
86 | EVP_EncryptUpdate, | ||
87 | (EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, | ||
88 | const unsigned char *in, int inl), | ||
89 | 0, | ||
90 | (ctx, out, outl, in, inl), | ||
91 | 1 | ||
92 | ) | ||
93 | |||
94 | WRAP(int, | ||
95 | EVP_DecryptInit_ex, | ||
96 | (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl, | ||
97 | const unsigned char *key, const unsigned char *iv), | ||
98 | 0, | ||
99 | (ctx, type, impl, key, iv), | ||
100 | 1 | ||
101 | ) | ||
102 | |||
103 | WRAP(int, | ||
104 | EVP_DecryptUpdate, | ||
105 | (EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, | ||
106 | const unsigned char *in, int inl), | ||
107 | 0, | ||
108 | (ctx, out, outl, in, inl), | ||
109 | 1 | ||
110 | ) | ||
111 | |||
112 | WRAP(int, | ||
113 | SHA256_Init, | ||
114 | (SHA256_CTX *c), | ||
115 | 0, | ||
116 | (c), | ||
117 | 1 | ||
118 | ) | ||
119 | |||
120 | WRAP(int, | ||
121 | SHA256_Update, | ||
122 | (SHA256_CTX *c, const void *data, size_t len), | ||
123 | 0, | ||
124 | (c, data, len), | ||
125 | 1 | ||
126 | ) | ||
127 | |||
128 | WRAP(int, | ||
129 | SHA256_Final, | ||
130 | (unsigned char *md, SHA256_CTX *c), | ||
131 | 0, | ||
132 | (md, c), | ||
133 | 1 | ||
134 | ) | ||
135 | |||
136 | WRAP(RSA *, | ||
137 | EVP_PKEY_get0_RSA, | ||
138 | (EVP_PKEY *pkey), | ||
139 | NULL, | ||
140 | (pkey), | ||
141 | 1 | ||
142 | ) | ||
143 | |||
144 | WRAP(EVP_MD_CTX *, | ||
145 | EVP_MD_CTX_new, | ||
146 | (void), | ||
147 | NULL, | ||
148 | (), | ||
149 | 1 | ||
150 | ) | ||
151 | |||
152 | WRAP(int, | ||
153 | EVP_DigestVerifyInit, | ||
154 | (EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, | ||
155 | EVP_PKEY *pkey), | ||
156 | 0, | ||
157 | (ctx, pctx, type, e, pkey), | ||
158 | 1 | ||
159 | ) | ||
160 | |||
161 | WRAP(BIGNUM *, | ||
162 | BN_bin2bn, | ||
163 | (const unsigned char *s, int len, BIGNUM *ret), | ||
164 | NULL, | ||
165 | (s, len, ret), | ||
166 | 1 | ||
167 | ) | ||
168 | |||
169 | WRAP(BIGNUM *, | ||
170 | BN_CTX_get, | ||
171 | (BN_CTX *ctx), | ||
172 | NULL, | ||
173 | (ctx), | ||
174 | 1 | ||
175 | ) | ||
176 | |||
177 | WRAP(BN_CTX *, | ||
178 | BN_CTX_new, | ||
179 | (void), | ||
180 | NULL, | ||
181 | (), | ||
182 | 1 | ||
183 | ) | ||
184 | |||
185 | WRAP(BIGNUM *, | ||
186 | BN_new, | ||
187 | (void), | ||
188 | NULL, | ||
189 | (), | ||
190 | 1 | ||
191 | ) | ||
192 | |||
193 | WRAP(int, | ||
194 | RSA_set0_key, | ||
195 | (RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d), | ||
196 | 0, | ||
197 | (r, n, e, d), | ||
198 | 1 | ||
199 | ) | ||
200 | |||
201 | WRAP(EC_KEY *, | ||
202 | EC_KEY_new_by_curve_name, | ||
203 | (int nid), | ||
204 | NULL, | ||
205 | (nid), | ||
206 | 1 | ||
207 | ) | ||
208 | |||
209 | WRAP(const EC_GROUP *, | ||
210 | EC_KEY_get0_group, | ||
211 | (const EC_KEY *key), | ||
212 | NULL, | ||
213 | (key), | ||
214 | 1 | ||
215 | ) | ||
216 | |||
217 | WRAP(EC_POINT *, | ||
218 | EC_POINT_new, | ||
219 | (const EC_GROUP *group), | ||
220 | NULL, | ||
221 | (group), | ||
222 | 1 | ||
223 | ) | ||
224 | |||
225 | WRAP(EVP_PKEY *, | ||
226 | EVP_PKEY_new, | ||
227 | (void), | ||
228 | NULL, | ||
229 | (), | ||
230 | 1 | ||
231 | ) | ||
232 | |||
233 | WRAP(int, | ||
234 | EVP_PKEY_assign, | ||
235 | (EVP_PKEY *pkey, int type, void *key), | ||
236 | 0, | ||
237 | (pkey, type, key), | ||
238 | 1 | ||
239 | ) | ||
240 | |||
241 | WRAP(EVP_PKEY *, | ||
242 | EVP_PKEY_new_raw_public_key, | ||
243 | (int type, ENGINE *e, const unsigned char *key, size_t keylen), | ||
244 | NULL, | ||
245 | (type, e, key, keylen), | ||
246 | 1 | ||
247 | ) | ||
248 | |||
249 | WRAP(EVP_PKEY_CTX *, | ||
250 | EVP_PKEY_CTX_new, | ||
251 | (EVP_PKEY *pkey, ENGINE *e), | ||
252 | NULL, | ||
253 | (pkey, e), | ||
254 | 1 | ||
255 | ) | ||
256 | |||
257 | WRAP(int, | ||
258 | EVP_PKEY_derive_init, | ||
259 | (EVP_PKEY_CTX *ctx), | ||
260 | 0, | ||
261 | (ctx), | ||
262 | 1 | ||
263 | ) | ||
264 | |||
265 | WRAP(int, | ||
266 | EVP_PKEY_derive_set_peer, | ||
267 | (EVP_PKEY_CTX *ctx, EVP_PKEY *peer), | ||
268 | 0, | ||
269 | (ctx, peer), | ||
270 | 1 | ||
271 | ) | ||
272 | |||
273 | WRAP(const EVP_MD *, | ||
274 | EVP_sha256, | ||
275 | (void), | ||
276 | NULL, | ||
277 | (), | ||
278 | 1 | ||
279 | ) | ||
280 | |||
281 | WRAP(unsigned char *, | ||
282 | HMAC, | ||
283 | (const EVP_MD *evp_md, const void *key, int key_len, | ||
284 | const unsigned char *d, int n, unsigned char *md, | ||
285 | unsigned int *md_len), | ||
286 | NULL, | ||
287 | (evp_md, key, key_len, d, n, md, md_len), | ||
288 | 1 | ||
289 | ) | ||
290 | |||
291 | WRAP(HMAC_CTX *, | ||
292 | HMAC_CTX_new, | ||
293 | (void), | ||
294 | NULL, | ||
295 | (), | ||
296 | 1 | ||
297 | ) | ||
298 | |||
299 | WRAP(int, | ||
300 | HMAC_Init_ex, | ||
301 | (HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, | ||
302 | ENGINE *impl), | ||
303 | 0, | ||
304 | (ctx, key, key_len, md, impl), | ||
305 | 1 | ||
306 | ) | ||
307 | |||
308 | WRAP(int, | ||
309 | HMAC_Update, | ||
310 | (HMAC_CTX *ctx, const unsigned char *data, int len), | ||
311 | 0, | ||
312 | (ctx, data, len), | ||
313 | 1 | ||
314 | ) | ||
315 | |||
316 | WRAP(int, | ||
317 | HMAC_Final, | ||
318 | (HMAC_CTX *ctx, unsigned char *md, unsigned int *len), | ||
319 | 0, | ||
320 | (ctx, md, len), | ||
321 | 1 | ||
322 | ) | ||
323 | |||
324 | WRAP(unsigned char *, | ||
325 | SHA256, | ||
326 | (const unsigned char *d, size_t n, unsigned char *md), | ||
327 | NULL, | ||
328 | (d, n, md), | ||
329 | 1 | ||
330 | ) | ||
331 | |||
332 | WRAP(cbor_item_t *, | ||
333 | cbor_build_string, | ||
334 | (const char *val), | ||
335 | NULL, | ||
336 | (val), | ||
337 | 1 | ||
338 | ) | ||
339 | |||
340 | WRAP(cbor_item_t *, | ||
341 | cbor_build_bytestring, | ||
342 | (cbor_data handle, size_t length), | ||
343 | NULL, | ||
344 | (handle, length), | ||
345 | 1 | ||
346 | ) | ||
347 | |||
348 | WRAP(cbor_item_t *, | ||
349 | cbor_load, | ||
350 | (cbor_data source, size_t source_size, struct cbor_load_result *result), | ||
351 | NULL, | ||
352 | (source, source_size, result), | ||
353 | 1 | ||
354 | ) | ||
355 | |||
356 | WRAP(cbor_item_t *, | ||
357 | cbor_build_uint8, | ||
358 | (uint8_t value), | ||
359 | NULL, | ||
360 | (value), | ||
361 | 1 | ||
362 | ) | ||
363 | |||
364 | WRAP(struct cbor_pair *, | ||
365 | cbor_map_handle, | ||
366 | (const cbor_item_t *item), | ||
367 | NULL, | ||
368 | (item), | ||
369 | 1 | ||
370 | ) | ||
371 | |||
372 | WRAP(cbor_item_t **, | ||
373 | cbor_array_handle, | ||
374 | (const cbor_item_t *item), | ||
375 | NULL, | ||
376 | (item), | ||
377 | 1 | ||
378 | ) | ||
379 | |||
380 | WRAP(bool, | ||
381 | cbor_map_add, | ||
382 | (cbor_item_t *item, struct cbor_pair pair), | ||
383 | false, | ||
384 | (item, pair), | ||
385 | 1 | ||
386 | ) | ||
387 | |||
388 | WRAP(cbor_item_t *, | ||
389 | cbor_new_definite_map, | ||
390 | (size_t size), | ||
391 | NULL, | ||
392 | (size), | ||
393 | 1 | ||
394 | ) | ||
395 | |||
396 | WRAP(size_t, | ||
397 | cbor_serialize_alloc, | ||
398 | (const cbor_item_t *item, cbor_mutable_data *buffer, | ||
399 | size_t *buffer_size), | ||
400 | 0, | ||
401 | (item, buffer, buffer_size), | ||
402 | 1 | ||
403 | ) | ||
404 | |||
405 | WRAP(int, | ||
406 | fido_tx, | ||
407 | (fido_dev_t *d, uint8_t cmd, const void *buf, size_t count), | ||
408 | -1, | ||
409 | (d, cmd, buf, count), | ||
410 | 1 | ||
411 | ) | ||
412 | |||
413 | WRAP(int, | ||
414 | usleep, | ||
415 | (unsigned int usec), | ||
416 | -1, | ||
417 | (usec), | ||
418 | 1 | ||
419 | ) | ||
diff --git a/fuzz/wrapped.sym b/fuzz/wrapped.sym new file mode 100644 index 0000000..3679f91 --- /dev/null +++ b/fuzz/wrapped.sym | |||
@@ -0,0 +1,47 @@ | |||
1 | BN_bin2bn | ||
2 | BN_CTX_get | ||
3 | BN_CTX_new | ||
4 | BN_new | ||
5 | calloc | ||
6 | cbor_array_handle | ||
7 | cbor_build_bytestring | ||
8 | cbor_build_string | ||
9 | cbor_build_uint8 | ||
10 | cbor_load | ||
11 | cbor_map_add | ||
12 | cbor_map_handle | ||
13 | cbor_new_definite_map | ||
14 | cbor_serialize_alloc | ||
15 | EC_KEY_get0_group | ||
16 | EC_KEY_new_by_curve_name | ||
17 | EC_POINT_new | ||
18 | EVP_CIPHER_CTX_new | ||
19 | EVP_CIPHER_CTX_set_padding | ||
20 | EVP_DecryptInit_ex | ||
21 | EVP_DecryptUpdate | ||
22 | EVP_DigestVerifyInit | ||
23 | EVP_EncryptInit_ex | ||
24 | EVP_EncryptUpdate | ||
25 | EVP_MD_CTX_new | ||
26 | EVP_PKEY_assign | ||
27 | EVP_PKEY_CTX_new | ||
28 | EVP_PKEY_derive_init | ||
29 | EVP_PKEY_derive_set_peer | ||
30 | EVP_PKEY_get0_RSA | ||
31 | EVP_PKEY_new | ||
32 | EVP_PKEY_new_raw_public_key | ||
33 | EVP_sha256 | ||
34 | fido_tx | ||
35 | HMAC | ||
36 | HMAC_CTX_new | ||
37 | HMAC_Final | ||
38 | HMAC_Init_ex | ||
39 | HMAC_Update | ||
40 | malloc | ||
41 | RSA_set0_key | ||
42 | SHA256 | ||
43 | SHA256_Final | ||
44 | SHA256_Init | ||
45 | SHA256_Update | ||
46 | strdup | ||
47 | usleep | ||
diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt new file mode 100644 index 0000000..c903ab8 --- /dev/null +++ b/man/CMakeLists.txt | |||
@@ -0,0 +1,314 @@ | |||
1 | # Copyright (c) 2018 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 | find_program(MANDOC_PATH mandoc) | ||
6 | message(STATUS "MANDOC_PATH: ${MANDOC_PATH}") | ||
7 | |||
8 | if(CMAKE_SYSTEM_NAME STREQUAL "Linux") | ||
9 | find_program(GZIP_PATH gzip) | ||
10 | message(STATUS "GZIP_PATH: ${GZIP_PATH}") | ||
11 | endif() | ||
12 | |||
13 | list(APPEND MAN_SOURCES | ||
14 | eddsa_pk_new.3 | ||
15 | es256_pk_new.3 | ||
16 | fido2-assert.1 | ||
17 | fido2-cred.1 | ||
18 | fido2-token.1 | ||
19 | fido_init.3 | ||
20 | fido_assert_new.3 | ||
21 | fido_assert_allow_cred.3 | ||
22 | fido_assert_set_authdata.3 | ||
23 | fido_assert_verify.3 | ||
24 | fido_bio_dev_get_info.3 | ||
25 | fido_bio_enroll_new.3 | ||
26 | fido_bio_info_new.3 | ||
27 | fido_bio_template.3 | ||
28 | fido_cbor_info_new.3 | ||
29 | fido_cred_new.3 | ||
30 | fido_cred_exclude.3 | ||
31 | fido_credman_metadata_new.3 | ||
32 | fido_cred_set_authdata.3 | ||
33 | fido_cred_verify.3 | ||
34 | fido_dev_get_assert.3 | ||
35 | fido_dev_info_manifest.3 | ||
36 | fido_dev_make_cred.3 | ||
37 | fido_dev_open.3 | ||
38 | fido_dev_set_io_functions.3 | ||
39 | fido_dev_set_pin.3 | ||
40 | fido_strerr.3 | ||
41 | rs256_pk_new.3 | ||
42 | ) | ||
43 | |||
44 | list(APPEND MAN_ALIAS | ||
45 | eddsa_pk_new eddsa_pk_free | ||
46 | eddsa_pk_new eddsa_pk_from_ptr | ||
47 | eddsa_pk_new eddsa_pk_to_EVP_PKEY | ||
48 | es256_pk_new es256_pk_free | ||
49 | es256_pk_new es256_pk_from_EC_KEY | ||
50 | es256_pk_new es256_pk_from_ptr | ||
51 | es256_pk_new es256_pk_to_EVP_PKEY | ||
52 | fido_assert_new fido_assert_authdata_len | ||
53 | fido_assert_new fido_assert_authdata_ptr | ||
54 | fido_assert_new fido_assert_clientdata_hash_len | ||
55 | fido_assert_new fido_assert_clientdata_hash_ptr | ||
56 | fido_assert_new fido_assert_count | ||
57 | fido_assert_new fido_assert_free | ||
58 | fido_assert_new fido_assert_hmac_secret_len | ||
59 | fido_assert_new fido_assert_hmac_secret_ptr | ||
60 | fido_assert_new fido_assert_sigcount | ||
61 | fido_assert_new fido_assert_sig_len | ||
62 | fido_assert_new fido_assert_sig_ptr | ||
63 | fido_assert_new fido_assert_user_display_name | ||
64 | fido_assert_new fido_assert_user_icon | ||
65 | fido_assert_new fido_assert_user_id_len | ||
66 | fido_assert_new fido_assert_user_id_ptr | ||
67 | fido_assert_new fido_assert_user_name | ||
68 | fido_assert_set_authdata fido_assert_set_clientdata_hash | ||
69 | fido_assert_set_authdata fido_assert_set_count | ||
70 | fido_assert_set_authdata fido_assert_set_extensions | ||
71 | fido_assert_set_authdata fido_assert_set_hmac_salt | ||
72 | fido_assert_set_authdata fido_assert_set_rp | ||
73 | fido_assert_set_authdata fido_assert_set_sig | ||
74 | fido_assert_set_authdata fido_assert_set_up | ||
75 | fido_assert_set_authdata fido_assert_set_uv | ||
76 | fido_bio_dev_get_info fido_bio_dev_enroll_begin | ||
77 | fido_bio_dev_get_info fido_bio_dev_enroll_cancel | ||
78 | fido_bio_dev_get_info fido_bio_dev_enroll_continue | ||
79 | fido_bio_dev_get_info fido_bio_dev_enroll_remove | ||
80 | fido_bio_dev_get_info fido_bio_dev_get_template_array | ||
81 | fido_bio_dev_get_info fido_bio_dev_set_template_name | ||
82 | fido_bio_enroll_new fido_bio_enroll_free | ||
83 | fido_bio_enroll_new fido_bio_enroll_last_status | ||
84 | fido_bio_enroll_new fido_bio_enroll_remaining_samples | ||
85 | fido_bio_info_new fido_bio_info_free | ||
86 | fido_bio_info_new fido_bio_info_max_samples | ||
87 | fido_bio_info_new fido_bio_info_type | ||
88 | fido_bio_template fido_bio_template_array_count | ||
89 | fido_bio_template fido_bio_template_array_free | ||
90 | fido_bio_template fido_bio_template_array_new | ||
91 | fido_bio_template fido_bio_template_free | ||
92 | fido_bio_template fido_bio_template_id_len | ||
93 | fido_bio_template fido_bio_template_id_ptr | ||
94 | fido_bio_template fido_bio_template_name | ||
95 | fido_bio_template fido_bio_template_new | ||
96 | fido_bio_template fido_bio_template_set_id | ||
97 | fido_bio_template fido_bio_template_set_name | ||
98 | fido_cbor_info_new fido_cbor_info_aaguid_len | ||
99 | fido_cbor_info_new fido_cbor_info_aaguid_ptr | ||
100 | fido_cbor_info_new fido_cbor_info_extensions_len | ||
101 | fido_cbor_info_new fido_cbor_info_extensions_ptr | ||
102 | fido_cbor_info_new fido_cbor_info_free | ||
103 | fido_cbor_info_new fido_cbor_info_maxmsgsiz | ||
104 | fido_cbor_info_new fido_cbor_info_options_len | ||
105 | fido_cbor_info_new fido_cbor_info_options_name_ptr | ||
106 | fido_cbor_info_new fido_cbor_info_options_value_ptr | ||
107 | fido_cbor_info_new fido_cbor_info_protocols_len | ||
108 | fido_cbor_info_new fido_cbor_info_protocols_ptr | ||
109 | fido_cbor_info_new fido_cbor_info_versions_len | ||
110 | fido_cbor_info_new fido_cbor_info_versions_ptr | ||
111 | fido_cbor_info_new fido_dev_get_cbor_info | ||
112 | fido_cred_new fido_cred_authdata_len | ||
113 | fido_cred_new fido_cred_authdata_ptr | ||
114 | fido_cred_new fido_cred_clientdata_hash_len | ||
115 | fido_cred_new fido_cred_clientdata_hash_ptr | ||
116 | fido_cred_new fido_cred_fmt | ||
117 | fido_cred_new fido_cred_free | ||
118 | fido_cred_new fido_cred_id_len | ||
119 | fido_cred_new fido_cred_id_ptr | ||
120 | fido_cred_new fido_cred_pubkey_len | ||
121 | fido_cred_new fido_cred_pubkey_ptr | ||
122 | fido_cred_new fido_cred_sig_len | ||
123 | fido_cred_new fido_cred_sig_ptr | ||
124 | fido_cred_new fido_cred_x5c_len | ||
125 | fido_cred_new fido_cred_x5c_ptr | ||
126 | fido_credman_metadata_new fido_credman_del_dev_rk | ||
127 | fido_credman_metadata_new fido_credman_get_dev_metadata | ||
128 | fido_credman_metadata_new fido_credman_get_dev_rk | ||
129 | fido_credman_metadata_new fido_credman_get_dev_rp | ||
130 | fido_credman_metadata_new fido_credman_metadata_free | ||
131 | fido_credman_metadata_new fido_credman_rk | ||
132 | fido_credman_metadata_new fido_credman_rk_count | ||
133 | fido_credman_metadata_new fido_credman_rk_existing | ||
134 | fido_credman_metadata_new fido_credman_rk_free | ||
135 | fido_credman_metadata_new fido_credman_rk_new | ||
136 | fido_credman_metadata_new fido_credman_rk_remaining | ||
137 | fido_credman_metadata_new fido_credman_rp_count | ||
138 | fido_credman_metadata_new fido_credman_rp_free | ||
139 | fido_credman_metadata_new fido_credman_rp_id | ||
140 | fido_credman_metadata_new fido_credman_rp_id_hash_len | ||
141 | fido_credman_metadata_new fido_credman_rp_id_hash_ptr | ||
142 | fido_credman_metadata_new fido_credman_rp_name | ||
143 | fido_credman_metadata_new fido_credman_rp_new | ||
144 | fido_cred_set_authdata fido_cred_set_authdata_raw | ||
145 | fido_cred_set_authdata fido_cred_set_clientdata_hash | ||
146 | fido_cred_set_authdata fido_cred_set_extensions | ||
147 | fido_cred_set_authdata fido_cred_set_fmt | ||
148 | fido_cred_set_authdata fido_cred_set_rk | ||
149 | fido_cred_set_authdata fido_cred_set_rp | ||
150 | fido_cred_set_authdata fido_cred_set_sig | ||
151 | fido_cred_set_authdata fido_cred_set_type | ||
152 | fido_cred_set_authdata fido_cred_set_user | ||
153 | fido_cred_set_authdata fido_cred_set_uv | ||
154 | fido_cred_set_authdata fido_cred_set_x509 | ||
155 | fido_dev_info_manifest fido_dev_info_free | ||
156 | fido_dev_info_manifest fido_dev_info_manufacturer_string | ||
157 | fido_dev_info_manifest fido_dev_info_new | ||
158 | fido_dev_info_manifest fido_dev_info_path | ||
159 | fido_dev_info_manifest fido_dev_info_product | ||
160 | fido_dev_info_manifest fido_dev_info_product_string | ||
161 | fido_dev_info_manifest fido_dev_info_ptr | ||
162 | fido_dev_info_manifest fido_dev_info_vendor | ||
163 | fido_dev_open fido_dev_build | ||
164 | fido_dev_open fido_dev_cancel | ||
165 | fido_dev_open fido_dev_close | ||
166 | fido_dev_open fido_dev_flags | ||
167 | fido_dev_open fido_dev_force_fido2 | ||
168 | fido_dev_open fido_dev_force_u2f | ||
169 | fido_dev_open fido_dev_free | ||
170 | fido_dev_open fido_dev_is_fido2 | ||
171 | fido_dev_open fido_dev_major | ||
172 | fido_dev_open fido_dev_minor | ||
173 | fido_dev_open fido_dev_new | ||
174 | fido_dev_open fido_dev_protocol | ||
175 | fido_dev_set_pin fido_dev_get_retry_count | ||
176 | fido_dev_set_pin fido_dev_reset | ||
177 | rs256_pk_new rs256_pk_free | ||
178 | rs256_pk_new rs256_pk_from_ptr | ||
179 | rs256_pk_new rs256_pk_from_RSA | ||
180 | rs256_pk_new rs256_pk_to_EVP_PKEY | ||
181 | ) | ||
182 | |||
183 | list(LENGTH MAN_ALIAS MAN_ALIAS_LEN) | ||
184 | math(EXPR MAN_ALIAS_MAX "${MAN_ALIAS_LEN} - 2") | ||
185 | |||
186 | # man_copy | ||
187 | foreach(f ${MAN_SOURCES}) | ||
188 | add_custom_command(OUTPUT ${f} | ||
189 | COMMAND cp -f ${CMAKE_SOURCE_DIR}/man/${f} . | ||
190 | DEPENDS ${f}) | ||
191 | list(APPEND COPY_FILES ${f}) | ||
192 | endforeach() | ||
193 | |||
194 | # man_lint | ||
195 | foreach(f ${MAN_SOURCES}) | ||
196 | add_custom_command(OUTPUT ${f}.lint | ||
197 | COMMAND mandoc -T lint -W warning ${f} > ${f}.lint | ||
198 | DEPENDS ${f}) | ||
199 | list(APPEND LINT_FILES ${f}.lint) | ||
200 | endforeach() | ||
201 | |||
202 | # man_html | ||
203 | foreach(f ${MAN_SOURCES}) | ||
204 | string(REGEX REPLACE ".[13]" "" g ${f}) | ||
205 | add_custom_command(OUTPUT ${g}.html | ||
206 | COMMAND mandoc -T html -O man="%N.html",style=style.css -I os="Yubico AB" ${f} > ${g}.html | ||
207 | DEPENDS ${f}) | ||
208 | list(APPEND HTML_FILES ${g}.html) | ||
209 | endforeach() | ||
210 | |||
211 | # man_html_partial | ||
212 | foreach(f ${MAN_SOURCES}) | ||
213 | string(REGEX REPLACE ".[13]" "" g ${f}) | ||
214 | add_custom_command(OUTPUT ${g}.partial | ||
215 | COMMAND cat ${CMAKE_SOURCE_DIR}/man/dyc.css > ${g}.partial | ||
216 | COMMAND mandoc -T html -O man="%N.html",fragment ${f} >> ${g}.partial | ||
217 | DEPENDS ${f}) | ||
218 | list(APPEND HTML_PARTIAL_FILES ${g}.partial) | ||
219 | endforeach() | ||
220 | |||
221 | # man_gzip | ||
222 | foreach(f ${MAN_SOURCES}) | ||
223 | add_custom_command(OUTPUT ${f}.gz | ||
224 | COMMAND gzip -c ${f} > ${f}.gz | ||
225 | DEPENDS ${f}) | ||
226 | list(APPEND GZ_FILES ${f}.gz) | ||
227 | endforeach() | ||
228 | |||
229 | macro(define_symlink_target NAME EXT) | ||
230 | foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2) | ||
231 | math(EXPR j "${i} + 1") | ||
232 | list(GET MAN_ALIAS ${i} SRC) | ||
233 | list(GET MAN_ALIAS ${j} DST) | ||
234 | add_custom_command(OUTPUT ${DST}.${EXT} | ||
235 | COMMAND ln -sf ${SRC}.${EXT} ${DST}.${EXT}) | ||
236 | list(APPEND ${NAME}_LINK_FILES ${DST}.${EXT}) | ||
237 | endforeach() | ||
238 | add_custom_target(${NAME} DEPENDS ${${NAME}_LINK_FILES}) | ||
239 | endmacro() | ||
240 | |||
241 | add_custom_target(man_copy DEPENDS ${COPY_FILES}) | ||
242 | add_custom_target(man_lint DEPENDS ${LINT_FILES}) | ||
243 | add_custom_target(man_html DEPENDS ${HTML_FILES}) | ||
244 | add_custom_target(man_html_partial DEPENDS ${HTML_PARTIAL_FILES}) | ||
245 | add_custom_target(man_gzip DEPENDS ${GZ_FILES}) | ||
246 | |||
247 | define_symlink_target(man_symlink 3) | ||
248 | define_symlink_target(man_symlink_html html) | ||
249 | define_symlink_target(man_symlink_html_partial partial) | ||
250 | define_symlink_target(man_symlink_gzip 3.gz) | ||
251 | |||
252 | add_dependencies(man_symlink man_copy) | ||
253 | add_dependencies(man_lint man_symlink) | ||
254 | add_dependencies(man_html man_lint) | ||
255 | add_dependencies(man_symlink_html man_html) | ||
256 | add_dependencies(man_html_partial man_lint) | ||
257 | add_dependencies(man_symlink_html_partial man_html_partial) | ||
258 | add_custom_target(man ALL) | ||
259 | |||
260 | if(MANDOC_PATH) | ||
261 | add_dependencies(man man_symlink_html) | ||
262 | add_dependencies(man_gzip man_lint) | ||
263 | install(FILES ${CMAKE_SOURCE_DIR}/man/style.css | ||
264 | DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/libfido2) | ||
265 | foreach(f ${MAN_SOURCES}) | ||
266 | string(REGEX REPLACE ".[13]" "" f ${f}) | ||
267 | install(FILES ${CMAKE_BINARY_DIR}/man/${f}.html | ||
268 | DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/libfido2) | ||
269 | endforeach() | ||
270 | foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2) | ||
271 | math(EXPR j "${i} + 1") | ||
272 | list(GET MAN_ALIAS ${j} DST) | ||
273 | install(FILES ${CMAKE_BINARY_DIR}/man/${DST}.html | ||
274 | DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/libfido2) | ||
275 | endforeach() | ||
276 | endif() | ||
277 | |||
278 | if(GZIP_PATH) | ||
279 | add_dependencies(man_gzip man_copy) | ||
280 | add_dependencies(man_symlink_gzip man_gzip) | ||
281 | add_dependencies(man man_symlink_gzip) | ||
282 | foreach(f ${MAN_SOURCES}) | ||
283 | if (${f} MATCHES ".1$") | ||
284 | install(FILES ${CMAKE_BINARY_DIR}/man/${f}.gz | ||
285 | DESTINATION "${CMAKE_INSTALL_PREFIX}/share/man/man1") | ||
286 | elseif(${f} MATCHES ".3$") | ||
287 | install(FILES ${CMAKE_BINARY_DIR}/man/${f}.gz | ||
288 | DESTINATION "${CMAKE_INSTALL_PREFIX}/share/man/man3") | ||
289 | endif() | ||
290 | endforeach() | ||
291 | foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2) | ||
292 | math(EXPR j "${i} + 1") | ||
293 | list(GET MAN_ALIAS ${j} DST) | ||
294 | install(FILES ${CMAKE_BINARY_DIR}/man/${DST}.3.gz | ||
295 | DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man3) | ||
296 | endforeach() | ||
297 | elseif(NOT MSVC) | ||
298 | add_dependencies(man man_symlink) | ||
299 | foreach(f ${MAN_SOURCES}) | ||
300 | if (${f} MATCHES ".1$") | ||
301 | install(FILES ${CMAKE_BINARY_DIR}/man/${f} | ||
302 | DESTINATION "${CMAKE_INSTALL_PREFIX}/man/man1") | ||
303 | elseif(${f} MATCHES ".3$") | ||
304 | install(FILES ${CMAKE_BINARY_DIR}/man/${f} | ||
305 | DESTINATION "${CMAKE_INSTALL_PREFIX}/man/man3") | ||
306 | endif() | ||
307 | endforeach() | ||
308 | foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2) | ||
309 | math(EXPR j "${i} + 1") | ||
310 | list(GET MAN_ALIAS ${j} DST) | ||
311 | install(FILES ${CMAKE_BINARY_DIR}/man/${DST}.3 | ||
312 | DESTINATION ${CMAKE_INSTALL_PREFIX}/man/man3) | ||
313 | endforeach() | ||
314 | endif() | ||
diff --git a/man/NOTES b/man/NOTES new file mode 100644 index 0000000..4a461ff --- /dev/null +++ b/man/NOTES | |||
@@ -0,0 +1,4 @@ | |||
1 | To generate .partial files for https://developers.yubico.com/: | ||
2 | |||
3 | $ make -C build man_symlink_html_partial | ||
4 | $ (cd build/man && pax -p p -r -w *.partial /tmp/partial) | ||
diff --git a/man/dyc.css b/man/dyc.css new file mode 100644 index 0000000..1ff5b59 --- /dev/null +++ b/man/dyc.css | |||
@@ -0,0 +1,14 @@ | |||
1 | <style> | ||
2 | table.head, table.foot { width: 100%; } | ||
3 | td.head-rtitle, td.foot-os { text-align: right; } | ||
4 | td.head-vol { text-align: center; } | ||
5 | div.Pp { margin: 1ex 0ex; } | ||
6 | div.Nd, div.Bf, div.Op { display: inline; } | ||
7 | span.Pa, span.Ad { font-style: italic; } | ||
8 | span.Ms { font-weight: bold; } | ||
9 | dl.Bl-diag > dt { font-weight: bold; } | ||
10 | code.Nm, code.Fl, code.Cm, code.Ic, code.In, code.Fd, code.Fn, | ||
11 | code.Cd { font-weight: bold; font-family: monospace; } | ||
12 | var { font-family: monospace; } | ||
13 | .Sh { font-size: 1.5em; padding-top: 1em; padding-bottom: 1em; } | ||
14 | </style> | ||
diff --git a/man/eddsa_pk_new.3 b/man/eddsa_pk_new.3 new file mode 100644 index 0000000..65bf9a9 --- /dev/null +++ b/man/eddsa_pk_new.3 | |||
@@ -0,0 +1,122 @@ | |||
1 | .\" Copyright (c) 2019 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: May 15 2019 $ | ||
6 | .Dt EDDSA_PK_NEW 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm eddsa_pk_new , | ||
10 | .Nm eddsa_pk_free , | ||
11 | .Nm eddsa_pk_from_EVP_PKEY , | ||
12 | .Nm eddsa_pk_from_ptr , | ||
13 | .Nm eddsa_pk_to_EVP_PKEY | ||
14 | .Nd FIDO 2 COSE EDDSA API | ||
15 | .Sh SYNOPSIS | ||
16 | .In openssl/evp.h | ||
17 | .In fido/eddsa.h | ||
18 | .Ft eddsa_pk_t * | ||
19 | .Fn eddsa_pk_new "void" | ||
20 | .Ft void | ||
21 | .Fn eddsa_pk_free "eddsa_pk_t **pkp" | ||
22 | .Ft int | ||
23 | .Fn eddsa_pk_from_EVP_PKEY "eddsa_pk_t *pk" "const EVP_PKEY *pkey" | ||
24 | .Ft int | ||
25 | .Fn eddsa_pk_from_ptr "eddsa_pk_t *pk" "const void *ptr" "size_t len" | ||
26 | .Ft EVP_PKEY * | ||
27 | .Fn eddsa_pk_to_EVP_PKEY "const eddsa_pk_t *pk" | ||
28 | .Sh DESCRIPTION | ||
29 | EDDSA is the name given in the CBOR Object Signing and Encryption | ||
30 | (COSE) RFC to EDDSA over Curve25519 with SHA-512. | ||
31 | The COSE EDDSA API of | ||
32 | .Em libfido2 | ||
33 | is an auxiliary API with routines to convert between the different | ||
34 | EDDSA public key types used in | ||
35 | .Em libfido2 | ||
36 | and | ||
37 | .Em OpenSSL . | ||
38 | .Pp | ||
39 | In | ||
40 | .Em libfido2 , | ||
41 | EDDSA public keys are abstracted by the | ||
42 | .Vt eddsa_pk_t | ||
43 | type. | ||
44 | .Pp | ||
45 | The | ||
46 | .Fn eddsa_pk_new | ||
47 | function returns a pointer to a newly allocated, empty | ||
48 | .Vt eddsa_pk_t | ||
49 | type. | ||
50 | If memory cannot be allocated, NULL is returned. | ||
51 | .Pp | ||
52 | The | ||
53 | .Fn eddsa_pk_free | ||
54 | function releases the memory backing | ||
55 | .Fa *pkp , | ||
56 | where | ||
57 | .Fa *pkp | ||
58 | must have been previously allocated by | ||
59 | .Fn eddsa_pk_new . | ||
60 | On return, | ||
61 | .Fa *pkp | ||
62 | is set to NULL. | ||
63 | Either | ||
64 | .Fa pkp | ||
65 | or | ||
66 | .Fa *pkp | ||
67 | may be NULL, in which case | ||
68 | .Fn eddsa_pk_free | ||
69 | is a NOP. | ||
70 | .Pp | ||
71 | The | ||
72 | .Fn eddsa_pk_from_EVP_PKEY | ||
73 | function fills | ||
74 | .Fa pk | ||
75 | with the contents of | ||
76 | .Fa pkey . | ||
77 | No references to | ||
78 | .Fa pkey | ||
79 | are kept. | ||
80 | .Pp | ||
81 | The | ||
82 | .Fn eddsa_pk_from_ptr | ||
83 | function fills | ||
84 | .Fa pk | ||
85 | with the contents of | ||
86 | .Fa ptr , | ||
87 | where | ||
88 | .Fa ptr | ||
89 | points to | ||
90 | .Fa len | ||
91 | bytes. | ||
92 | No references to | ||
93 | .Fa ptr | ||
94 | are kept. | ||
95 | .Pp | ||
96 | The | ||
97 | .Fn eddsa_pk_to_EVP_PKEY | ||
98 | function converts | ||
99 | .Fa pk | ||
100 | to a newly allocated | ||
101 | .Fa EVP_PKEY | ||
102 | type with a reference count of 1. | ||
103 | No internal references to the returned pointer are kept. | ||
104 | If an error occurs, | ||
105 | .Fn eddsa_pk_to_EVP_PKEY | ||
106 | returns NULL. | ||
107 | .Sh RETURN VALUES | ||
108 | The | ||
109 | .Fn eddsa_pk_from_EC_KEY | ||
110 | and | ||
111 | .Fn eddsa_pk_from_ptr | ||
112 | functions return | ||
113 | .Dv FIDO_OK | ||
114 | on success. | ||
115 | On error, a different error code defined in | ||
116 | .In fido/err.h | ||
117 | is returned. | ||
118 | .Sh SEE ALSO | ||
119 | .Xr es256_pk_new 3 , | ||
120 | .Xr fido_assert_verify 3 , | ||
121 | .Xr fido_cred_pubkey_ptr 3 , | ||
122 | .Xr rs256_pk_new 3 | ||
diff --git a/man/es256_pk_new.3 b/man/es256_pk_new.3 new file mode 100644 index 0000000..48eda0b --- /dev/null +++ b/man/es256_pk_new.3 | |||
@@ -0,0 +1,122 @@ | |||
1 | .\" Copyright (c) 2018 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: May 24 2018 $ | ||
6 | .Dt ES256_PK_NEW 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm es256_pk_new , | ||
10 | .Nm es256_pk_free , | ||
11 | .Nm es256_pk_from_EC_KEY , | ||
12 | .Nm es256_pk_from_ptr , | ||
13 | .Nm es256_pk_to_EVP_PKEY | ||
14 | .Nd FIDO 2 COSE ES256 API | ||
15 | .Sh SYNOPSIS | ||
16 | .In openssl/ec.h | ||
17 | .In fido/es256.h | ||
18 | .Ft es256_pk_t * | ||
19 | .Fn es256_pk_new "void" | ||
20 | .Ft void | ||
21 | .Fn es256_pk_free "es256_pk_t **pkp" | ||
22 | .Ft int | ||
23 | .Fn es256_pk_from_EC_KEY "es256_pk_t *pk" "const EC_KEY *ec" | ||
24 | .Ft int | ||
25 | .Fn es256_pk_from_ptr "es256_pk_t *pk" "const void *ptr" "size_t len" | ||
26 | .Ft EVP_PKEY * | ||
27 | .Fn es256_pk_to_EVP_PKEY "const es256_pk_t *pk" | ||
28 | .Sh DESCRIPTION | ||
29 | ES256 is the name given in the CBOR Object Signing and Encryption | ||
30 | (COSE) RFC to ECDSA over P-256 with SHA-256. | ||
31 | The COSE ES256 API of | ||
32 | .Em libfido2 | ||
33 | is an auxiliary API with routines to convert between the different | ||
34 | ECDSA public key types used in | ||
35 | .Em libfido2 | ||
36 | and | ||
37 | .Em OpenSSL . | ||
38 | .Pp | ||
39 | In | ||
40 | .Em libfido2 , | ||
41 | ES256 public keys are abstracted by the | ||
42 | .Vt es256_pk_t | ||
43 | type. | ||
44 | .Pp | ||
45 | The | ||
46 | .Fn es256_pk_new | ||
47 | function returns a pointer to a newly allocated, empty | ||
48 | .Vt es256_pk_t | ||
49 | type. | ||
50 | If memory cannot be allocated, NULL is returned. | ||
51 | .Pp | ||
52 | The | ||
53 | .Fn es256_pk_free | ||
54 | function releases the memory backing | ||
55 | .Fa *pkp , | ||
56 | where | ||
57 | .Fa *pkp | ||
58 | must have been previously allocated by | ||
59 | .Fn es256_pk_new . | ||
60 | On return, | ||
61 | .Fa *pkp | ||
62 | is set to NULL. | ||
63 | Either | ||
64 | .Fa pkp | ||
65 | or | ||
66 | .Fa *pkp | ||
67 | may be NULL, in which case | ||
68 | .Fn es256_pk_free | ||
69 | is a NOP. | ||
70 | .Pp | ||
71 | The | ||
72 | .Fn es256_pk_from_EC_KEY | ||
73 | function fills | ||
74 | .Fa pk | ||
75 | with the contents of | ||
76 | .Fa ec . | ||
77 | No references to | ||
78 | .Fa ec | ||
79 | are kept. | ||
80 | .Pp | ||
81 | The | ||
82 | .Fn es256_pk_from_ptr | ||
83 | function fills | ||
84 | .Fa pk | ||
85 | with the contents of | ||
86 | .Fa ptr , | ||
87 | where | ||
88 | .Fa ptr | ||
89 | points to | ||
90 | .Fa len | ||
91 | bytes. | ||
92 | No references to | ||
93 | .Fa ptr | ||
94 | are kept. | ||
95 | .Pp | ||
96 | The | ||
97 | .Fn es256_pk_to_EVP_PKEY | ||
98 | function converts | ||
99 | .Fa pk | ||
100 | to a newly allocated | ||
101 | .Fa EVP_PKEY | ||
102 | type with a reference count of 1. | ||
103 | No internal references to the returned pointer are kept. | ||
104 | If an error occurs, | ||
105 | .Fn es256_pk_to_EVP_PKEY | ||
106 | returns NULL. | ||
107 | .Sh RETURN VALUES | ||
108 | The | ||
109 | .Fn es256_pk_from_EC_KEY | ||
110 | and | ||
111 | .Fn es256_pk_from_ptr | ||
112 | functions return | ||
113 | .Dv FIDO_OK | ||
114 | on success. | ||
115 | On error, a different error code defined in | ||
116 | .In fido/err.h | ||
117 | is returned. | ||
118 | .Sh SEE ALSO | ||
119 | .Xr eddsa_pk_new 3 , | ||
120 | .Xr fido_assert_verify 3 , | ||
121 | .Xr fido_cred_pubkey_ptr 3 , | ||
122 | .Xr rs256_pk_new 3 | ||
diff --git a/man/fido2-assert.1 b/man/fido2-assert.1 new file mode 100644 index 0000000..67883e2 --- /dev/null +++ b/man/fido2-assert.1 | |||
@@ -0,0 +1,220 @@ | |||
1 | .\" Copyright (c) 2018 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: November 5 2019 $ | ||
6 | .Dt FIDO2-ASSERT 1 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido2-assert | ||
10 | .Nd get/verify a FIDO 2 assertion | ||
11 | .Sh SYNOPSIS | ||
12 | .Nm | ||
13 | .Fl G | ||
14 | .Op Fl dhpruv | ||
15 | .Op Fl i Ar input_file | ||
16 | .Op Fl o Ar output_file | ||
17 | .Ar device | ||
18 | .Nm | ||
19 | .Fl V | ||
20 | .Op Fl dhpv | ||
21 | .Op Fl i Ar input_file | ||
22 | .Ar key_file | ||
23 | .Op Ar type | ||
24 | .Sh DESCRIPTION | ||
25 | .Nm | ||
26 | gets or verifies a FIDO 2 assertion. | ||
27 | .Pp | ||
28 | The input of | ||
29 | .Nm | ||
30 | is defined by the parameters of the assertion to be obtained/verified. | ||
31 | See the | ||
32 | .Sx INPUT FORMAT | ||
33 | section for details. | ||
34 | .Pp | ||
35 | The output of | ||
36 | .Nm | ||
37 | is defined by the result of the selected operation. | ||
38 | See the | ||
39 | .Sx OUTPUT FORMAT | ||
40 | section for details. | ||
41 | .Pp | ||
42 | If an assertion is successfully obtained or verified, | ||
43 | .Nm | ||
44 | exits 0. | ||
45 | Otherwise, | ||
46 | .Nm | ||
47 | exits 1. | ||
48 | .Pp | ||
49 | The options are as follows: | ||
50 | .Bl -tag -width Ds | ||
51 | .It Fl G | ||
52 | Tells | ||
53 | .Nm | ||
54 | to obtain a new assertion from | ||
55 | .Ar device . | ||
56 | .It Fl V | ||
57 | Tells | ||
58 | .Nm | ||
59 | to verify an assertion using the PEM-encoded public key in | ||
60 | .Ar key_file | ||
61 | of type | ||
62 | .Ar type , | ||
63 | where | ||
64 | .Ar type | ||
65 | may be | ||
66 | .Em es256 | ||
67 | (denoting ECDSA over NIST P-256 with SHA-256), | ||
68 | .Em rs256 | ||
69 | (denoting 2048-bit RSA with PKCS#1.5 padding and SHA-256), or | ||
70 | .Em eddsa | ||
71 | (denoting EDDSA over Curve25519 with SHA-512). | ||
72 | If | ||
73 | .Ar type | ||
74 | is not specified, | ||
75 | .Em es256 | ||
76 | is assumed. | ||
77 | .It Fl h | ||
78 | If obtaining an assertion, enable the FIDO2 hmac-secret | ||
79 | extension. | ||
80 | If verifying an assertion, check whether the extension data bit was | ||
81 | signed by the authenticator. | ||
82 | .It Fl d | ||
83 | Causes | ||
84 | .Nm | ||
85 | to emit debugging output on | ||
86 | .Em stderr . | ||
87 | .It Fl i Ar input_file | ||
88 | Tells | ||
89 | .Nm | ||
90 | to read the parameters of the assertion from | ||
91 | .Ar input_file | ||
92 | instead of | ||
93 | .Em stdin . | ||
94 | .It Fl o Ar output_file | ||
95 | Tells | ||
96 | .Nm | ||
97 | to write output on | ||
98 | .Ar output_file | ||
99 | instead of | ||
100 | .Em stdout . | ||
101 | .It Fl p | ||
102 | If obtaining an assertion, request user presence. | ||
103 | If verifying an assertion, check whether the user presence bit was | ||
104 | signed by the authenticator. | ||
105 | .It Fl r | ||
106 | Obtain an assertion using a resident credential. | ||
107 | If | ||
108 | .Fl r | ||
109 | is specified, | ||
110 | .Nm | ||
111 | will not expect a credential id in its input, and may output | ||
112 | multiple assertions. | ||
113 | .It Fl u | ||
114 | Obtain an assertion using U2F. | ||
115 | By default, | ||
116 | .Nm | ||
117 | will use FIDO2 if supported by the authenticator, and fallback to | ||
118 | U2F otherwise. | ||
119 | .It Fl v | ||
120 | If obtaining an assertion, prompt the user for a PIN and request | ||
121 | user verification from the authenticator. | ||
122 | If a | ||
123 | .Em tty | ||
124 | is available, | ||
125 | .Nm | ||
126 | will use it to obtain the PIN. | ||
127 | Otherwise, | ||
128 | .Em stdin | ||
129 | is used. | ||
130 | If verifying an assertion, check whether the user verification bit | ||
131 | was signed by the authenticator. | ||
132 | .El | ||
133 | .Sh INPUT FORMAT | ||
134 | The input of | ||
135 | .Nm | ||
136 | consists of base64 blobs and UTF-8 strings separated | ||
137 | by newline characters ('\\n'). | ||
138 | .Pp | ||
139 | When obtaining an assertion, | ||
140 | .Nm | ||
141 | expects its input to consist of: | ||
142 | .Pp | ||
143 | .Bl -enum -offset indent -compact | ||
144 | .It | ||
145 | client data hash (base64 blob); | ||
146 | .It | ||
147 | relying party id (UTF-8 string); | ||
148 | .It | ||
149 | credential id, if credential not resident (base64 blob); | ||
150 | .It | ||
151 | hmac salt, if the FIDO2 hmac-secret extension is enabled | ||
152 | (base64 blob); | ||
153 | .El | ||
154 | .Pp | ||
155 | When verifying an assertion, | ||
156 | .Nm | ||
157 | expects its input to consist of: | ||
158 | .Pp | ||
159 | .Bl -enum -offset indent -compact | ||
160 | .It | ||
161 | client data hash (base64 blob); | ||
162 | .It | ||
163 | relying party id (UTF-8 string); | ||
164 | .It | ||
165 | authenticator data (base64 blob); | ||
166 | .It | ||
167 | assertion signature (base64 blob); | ||
168 | .El | ||
169 | .Pp | ||
170 | UTF-8 strings passed to | ||
171 | .Nm | ||
172 | must not contain embedded newline or NUL characters. | ||
173 | .Sh OUTPUT FORMAT | ||
174 | The output of | ||
175 | .Nm | ||
176 | consists of base64 blobs and UTF-8 strings separated | ||
177 | by newline characters ('\\n'). | ||
178 | .Pp | ||
179 | For each generated assertion, | ||
180 | .Nm | ||
181 | outputs: | ||
182 | .Pp | ||
183 | .Bl -enum -offset indent -compact | ||
184 | .It | ||
185 | client data hash (base64 blob); | ||
186 | .It | ||
187 | relying party id (UTF-8 string); | ||
188 | .It | ||
189 | authenticator data (base64 blob); | ||
190 | .It | ||
191 | assertion signature (base64 blob); | ||
192 | .It | ||
193 | user id, if credential resident (base64 blob); | ||
194 | .It | ||
195 | hmac secret, if the FIDO2 hmac-secret extension is enabled | ||
196 | (base64 blob); | ||
197 | .El | ||
198 | .Pp | ||
199 | When verifying an assertion, | ||
200 | .Nm | ||
201 | produces no output. | ||
202 | .Sh EXAMPLES | ||
203 | Assuming | ||
204 | .Pa cred | ||
205 | contains a | ||
206 | .Em es256 | ||
207 | credential created according to the steps outlined in | ||
208 | .Xr fido2-cred 1 , | ||
209 | obtain an assertion from an authenticator at | ||
210 | .Pa /dev/hidraw5 | ||
211 | and verify it: | ||
212 | .Pp | ||
213 | .Dl $ echo assertion challenge | openssl sha256 -binary | base64 > assert_param | ||
214 | .Dl $ echo relying party >> assert_param | ||
215 | .Dl $ head -1 cred >> assert_param | ||
216 | .Dl $ tail -n +2 cred > pubkey | ||
217 | .Dl $ fido2-assert -G -i assert_param /dev/hidraw5 | fido2-assert -V pubkey es256 | ||
218 | .Sh SEE ALSO | ||
219 | .Xr fido2-cred 1 , | ||
220 | .Xr fido2-token 1 | ||
diff --git a/man/fido2-cred.1 b/man/fido2-cred.1 new file mode 100644 index 0000000..d9bf7d2 --- /dev/null +++ b/man/fido2-cred.1 | |||
@@ -0,0 +1,238 @@ | |||
1 | .\" Copyright (c) 2018 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: November 5 2019 $ | ||
6 | .Dt FIDO2-CRED 1 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido2-cred | ||
10 | .Nd make/verify a FIDO 2 credential | ||
11 | .Sh SYNOPSIS | ||
12 | .Nm | ||
13 | .Fl M | ||
14 | .Op Fl dhqruv | ||
15 | .Op Fl i Ar input_file | ||
16 | .Op Fl o Ar output_file | ||
17 | .Ar device | ||
18 | .Op Ar type | ||
19 | .Nm | ||
20 | .Fl V | ||
21 | .Op Fl dhv | ||
22 | .Op Fl i Ar input_file | ||
23 | .Op Fl o Ar output_file | ||
24 | .Op Ar type | ||
25 | .Sh DESCRIPTION | ||
26 | .Nm | ||
27 | makes or verifies a FIDO 2 credential. | ||
28 | .Pp | ||
29 | A credential | ||
30 | .Ar type | ||
31 | may be | ||
32 | .Em es256 | ||
33 | (denoting ECDSA over NIST P-256 with SHA-256), | ||
34 | .Em rs256 | ||
35 | (denoting 2048-bit RSA with PKCS#1.5 padding and SHA-256), or | ||
36 | .Em eddsa | ||
37 | (denoting EDDSA over Curve25519 with SHA-512). | ||
38 | If | ||
39 | .Ar type | ||
40 | is not specified, | ||
41 | .Em es256 | ||
42 | is assumed. | ||
43 | .Pp | ||
44 | When making a credential, the authenticator may require the user | ||
45 | to authenticate with a PIN. | ||
46 | If the | ||
47 | .Fl q | ||
48 | option is not specified, | ||
49 | .Nm | ||
50 | will prompt the user for the PIN. | ||
51 | If a | ||
52 | .Em tty | ||
53 | is available, | ||
54 | .Nm | ||
55 | will use it to obtain the PIN. | ||
56 | Otherwise, | ||
57 | .Em stdin | ||
58 | is used. | ||
59 | .Pp | ||
60 | The input of | ||
61 | .Nm | ||
62 | is defined by the parameters of the credential to be made/verified. | ||
63 | See the | ||
64 | .Sx INPUT FORMAT | ||
65 | section for details. | ||
66 | .Pp | ||
67 | The output of | ||
68 | .Nm | ||
69 | is defined by the result of the selected operation. | ||
70 | See the | ||
71 | .Sx OUTPUT FORMAT | ||
72 | section for details. | ||
73 | .Pp | ||
74 | If a credential is successfully created or verified, | ||
75 | .Nm | ||
76 | exits 0. | ||
77 | Otherwise, | ||
78 | .Nm | ||
79 | exits 1. | ||
80 | .Pp | ||
81 | The options are as follows: | ||
82 | .Bl -tag -width Ds | ||
83 | .It Fl M | ||
84 | Tells | ||
85 | .Nm | ||
86 | to make a new credential on | ||
87 | .Ar device . | ||
88 | .It Fl V | ||
89 | Tells | ||
90 | .Nm | ||
91 | to verify a credential. | ||
92 | .It Fl d | ||
93 | Causes | ||
94 | .Nm | ||
95 | to emit debugging output on | ||
96 | .Em stderr . | ||
97 | .It Fl h | ||
98 | If making a credential, enable the FIDO2 hmac-secret extension. | ||
99 | If verifying a credential, check whether the extension data bit was | ||
100 | signed by the authenticator. | ||
101 | .It Fl i Ar input_file | ||
102 | Tells | ||
103 | .Nm | ||
104 | to read the parameters of the credential from | ||
105 | .Ar input_file | ||
106 | instead of | ||
107 | .Em stdin . | ||
108 | .It Fl o Ar output_file | ||
109 | Tells | ||
110 | .Nm | ||
111 | to write output on | ||
112 | .Ar output_file | ||
113 | instead of | ||
114 | .Em stdout . | ||
115 | .It Fl q | ||
116 | Tells | ||
117 | .Nm | ||
118 | to be quiet. | ||
119 | If a PIN is required and | ||
120 | .Fl q | ||
121 | is specified, | ||
122 | .Nm | ||
123 | will fail. | ||
124 | .It Fl r | ||
125 | Create a resident credential. | ||
126 | .It Fl u | ||
127 | Create a U2F credential. | ||
128 | By default, | ||
129 | .Nm | ||
130 | will use FIDO2 if supported by the authenticator, and fallback to | ||
131 | U2F otherwise. | ||
132 | .It Fl v | ||
133 | If making a credential, request user verification. | ||
134 | If verifying a credential, check whether the user verification bit | ||
135 | was signed by the authenticator. | ||
136 | .El | ||
137 | .Sh INPUT FORMAT | ||
138 | The input of | ||
139 | .Nm | ||
140 | consists of base64 blobs and UTF-8 strings separated | ||
141 | by newline characters ('\\n'). | ||
142 | .Pp | ||
143 | When making a credential, | ||
144 | .Nm | ||
145 | expects its input to consist of: | ||
146 | .Pp | ||
147 | .Bl -enum -offset indent -compact | ||
148 | .It | ||
149 | client data hash (base64 blob); | ||
150 | .It | ||
151 | relying party id (UTF-8 string); | ||
152 | .It | ||
153 | user name (UTF-8 string); | ||
154 | .It | ||
155 | user id (base64 blob). | ||
156 | .El | ||
157 | .Pp | ||
158 | When verifying a credential, | ||
159 | .Nm | ||
160 | expects its input to consist of: | ||
161 | .Pp | ||
162 | .Bl -enum -offset indent -compact | ||
163 | .It | ||
164 | client data hash (base64 blob); | ||
165 | .It | ||
166 | relying party id (UTF-8 string); | ||
167 | .It | ||
168 | credential format (UTF-8 string); | ||
169 | .It | ||
170 | authenticator data (base64 blob); | ||
171 | .It | ||
172 | credential id (base64 blob); | ||
173 | .It | ||
174 | attestation signature (base64 blob); | ||
175 | .It | ||
176 | attestation certificate (optional, base64 blob). | ||
177 | .El | ||
178 | .Pp | ||
179 | UTF-8 strings passed to | ||
180 | .Nm | ||
181 | must not contain embedded newline or NUL characters. | ||
182 | .Sh OUTPUT FORMAT | ||
183 | The output of | ||
184 | .Nm | ||
185 | consists of base64 blobs, UTF-8 strings, and PEM-encoded public | ||
186 | keys separated by newline characters ('\\n'). | ||
187 | .Pp | ||
188 | Upon the successful generation of a credential, | ||
189 | .Nm | ||
190 | outputs: | ||
191 | .Pp | ||
192 | .Bl -enum -offset indent -compact | ||
193 | .It | ||
194 | client data hash (base64 blob); | ||
195 | .It | ||
196 | relying party id (UTF-8 string); | ||
197 | .It | ||
198 | credential format (UTF-8 string); | ||
199 | .It | ||
200 | authenticator data (base64 blob); | ||
201 | .It | ||
202 | credential id (base64 blob); | ||
203 | .It | ||
204 | attestation signature (base64 blob); | ||
205 | .It | ||
206 | attestation certificate, if present (base64 blob). | ||
207 | .El | ||
208 | .Pp | ||
209 | Upon the successful verification of a credential, | ||
210 | .Nm | ||
211 | outputs: | ||
212 | .Pp | ||
213 | .Bl -enum -offset indent -compact | ||
214 | .It | ||
215 | credential id (base64 blob); | ||
216 | .It | ||
217 | PEM-encoded credential key. | ||
218 | .El | ||
219 | .Sh EXAMPLES | ||
220 | Create a new | ||
221 | .Em es256 | ||
222 | credential on | ||
223 | .Pa /dev/hidraw5 , | ||
224 | verify it, and save the id and the public key of the credential in | ||
225 | .Em cred : | ||
226 | .Pp | ||
227 | .Dl $ echo credential challenge | openssl sha256 -binary | base64 > cred_param | ||
228 | .Dl $ echo relying party >> cred_param | ||
229 | .Dl $ echo user name >> cred_param | ||
230 | .Dl $ dd if=/dev/urandom bs=1 count=32 | base64 >> cred_param | ||
231 | .Dl $ fido2-cred -M -i cred_param /dev/hidraw5 | fido2-cred -V -o cred | ||
232 | .Sh SEE ALSO | ||
233 | .Xr fido2-assert 1 , | ||
234 | .Xr fido2-token 1 | ||
235 | .Sh CAVEATS | ||
236 | Please note that | ||
237 | .Nm | ||
238 | handles Basic Attestation and Self Attestation transparently. | ||
diff --git a/man/fido2-token.1 b/man/fido2-token.1 new file mode 100644 index 0000000..d5a5734 --- /dev/null +++ b/man/fido2-token.1 | |||
@@ -0,0 +1,158 @@ | |||
1 | .\" Copyright (c) 2018 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: September 13 2019 $ | ||
6 | .Dt FIDO2-TOKEN 1 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido2-token | ||
10 | .Nd find and manage a FIDO 2 authenticator | ||
11 | .Sh SYNOPSIS | ||
12 | .Nm | ||
13 | .Op Fl CR | ||
14 | .Op Fl d | ||
15 | .Ar device | ||
16 | .Nm | ||
17 | .Fl D | ||
18 | .Op Fl de | ||
19 | .Fl i | ||
20 | .Ar id | ||
21 | .Ar device | ||
22 | .Nm | ||
23 | .Fl I | ||
24 | .Op Fl cd | ||
25 | .Op Fl k Ar rp_id Fl i Ar cred_id | ||
26 | .Ar device | ||
27 | .Nm | ||
28 | .Fl L | ||
29 | .Op Fl der | ||
30 | .Op Fl k Ar rp_id | ||
31 | .Op device | ||
32 | .Nm | ||
33 | .Fl S | ||
34 | .Op Fl de | ||
35 | .Op Fl i Ar template_id Fl n Ar template_name | ||
36 | .Ar device | ||
37 | .Nm | ||
38 | .Fl V | ||
39 | .Sh DESCRIPTION | ||
40 | .Nm | ||
41 | manages a FIDO 2 authenticator. | ||
42 | .Pp | ||
43 | The options are as follows: | ||
44 | .Bl -tag -width Ds | ||
45 | .It Fl C Ar device | ||
46 | Changes the PIN of | ||
47 | .Ar device . | ||
48 | The user will be prompted for the current and new PINs. | ||
49 | .It Fl D Fl i Ar id Ar device | ||
50 | Deletes the resident credential specified by | ||
51 | .Ar id | ||
52 | from | ||
53 | .Ar device , | ||
54 | where | ||
55 | .Ar id | ||
56 | is the credential's base64-encoded id. | ||
57 | The user will be prompted for the PIN. | ||
58 | .It Fl D Fl e Fl i Ar id Ar device | ||
59 | Deletes the biometric enrollment specified by | ||
60 | .Ar id | ||
61 | from | ||
62 | .Ar device , | ||
63 | where | ||
64 | .Ar id | ||
65 | is the enrollment's template base64-encoded id. | ||
66 | The user will be prompted for the PIN. | ||
67 | .It Fl I Ar device | ||
68 | Retrieves information on | ||
69 | .Ar device . | ||
70 | .It Fl I Fl c Ar device | ||
71 | Retrieves resident credential metadata from | ||
72 | .Ar device . | ||
73 | The user will be prompted for the PIN. | ||
74 | .It Fl I Fl k Ar rp_id Fl i Ar cred_id Ar device | ||
75 | Prints the credential id (base64-encoded) and public key | ||
76 | (PEM encoded) of the resident credential specified by | ||
77 | .Ar rp_id | ||
78 | and | ||
79 | .Ar cred_id , | ||
80 | where | ||
81 | .Ar rp_id | ||
82 | is a UTF-8 relying party id, and | ||
83 | .Ar cred_id | ||
84 | is a base64-encoded credential id. | ||
85 | The user will be prompted for the PIN. | ||
86 | .It Fl L | ||
87 | Produces a list of authenticators found by the operating system. | ||
88 | .It Fl L Fl e Ar device | ||
89 | Produces a list of biometric enrollments on | ||
90 | .Ar device . | ||
91 | The user will be prompted for the PIN. | ||
92 | .It Fl L Fl r Ar device | ||
93 | Produces a list of relying parties with resident credentials on | ||
94 | .Ar device . | ||
95 | The user will be prompted for the PIN. | ||
96 | .It Fl L Fl k Ar rp_id Ar device | ||
97 | Produces a list of resident credentials corresponding to | ||
98 | relying party | ||
99 | .Ar rp_id | ||
100 | on | ||
101 | .Ar device . | ||
102 | The user will be prompted for the PIN. | ||
103 | .It Fl R | ||
104 | Performs a reset on | ||
105 | .Ar device . | ||
106 | .Nm | ||
107 | will NOT prompt for confirmation. | ||
108 | .It Fl S | ||
109 | Sets the PIN of | ||
110 | .Ar device . | ||
111 | The user will be prompted for the PIN. | ||
112 | .It Fl S Fl e Ar device | ||
113 | Performs a new biometric enrollment on | ||
114 | .Ar device . | ||
115 | The user will be prompted for the PIN. | ||
116 | .It Fl S Fl e Fl i Ar template_id Fl n Ar template_name Ar device | ||
117 | Sets the friendly name of the biometric enrollment specified by | ||
118 | .Ar template_id | ||
119 | to | ||
120 | .Ar template_name | ||
121 | on | ||
122 | .Ar device , | ||
123 | where | ||
124 | .Ar template_id | ||
125 | is base64-encoded and | ||
126 | .Ar template_name | ||
127 | is a UTF-8 string. | ||
128 | The user will be prompted for the PIN. | ||
129 | .It Fl V | ||
130 | Prints version information. | ||
131 | .It Fl d | ||
132 | Causes | ||
133 | .Nm | ||
134 | to emit debugging output on | ||
135 | .Em stderr . | ||
136 | .El | ||
137 | .Pp | ||
138 | If a | ||
139 | .Em tty | ||
140 | is available, | ||
141 | .Nm | ||
142 | will use it to prompt for PINs. | ||
143 | Otherwise, | ||
144 | .Em stdin | ||
145 | is used. | ||
146 | .Pp | ||
147 | .Nm | ||
148 | exits 0 on success and 1 on error. | ||
149 | .Sh SEE ALSO | ||
150 | .Xr fido2-assert 1 , | ||
151 | .Xr fido2-cred 1 | ||
152 | .Sh CAVEATS | ||
153 | The actual user-flow to perform a reset is outside the scope of the | ||
154 | FIDO2 specification, and may therefore vary depending on the | ||
155 | authenticator. | ||
156 | Yubico authenticators do not allow resets after 5 seconds from | ||
157 | power-up, and expect a reset to be confirmed by the user through | ||
158 | touch within 30 seconds. | ||
diff --git a/man/fido_assert_allow_cred.3 b/man/fido_assert_allow_cred.3 new file mode 100644 index 0000000..bbe6e4d --- /dev/null +++ b/man/fido_assert_allow_cred.3 | |||
@@ -0,0 +1,47 @@ | |||
1 | .\" Copyright (c) 2018 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: May 23 2018 $ | ||
6 | .Dt FIDO_ASSERT_ALLOW_CRED 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_assert_allow_cred | ||
10 | .Nd appends a credential ID to the list of credentials allowed in an assertion | ||
11 | .Sh SYNOPSIS | ||
12 | .In fido.h | ||
13 | .Ft int | ||
14 | .Fn fido_assert_allow_cred "fido_assert_t *assert" "const unsigned char *ptr" "size_t len" | ||
15 | .Sh DESCRIPTION | ||
16 | The | ||
17 | .Fn fido_assert_allow_cred | ||
18 | function adds | ||
19 | .Fa ptr | ||
20 | to the list of credentials allowed in | ||
21 | .Fa assert , | ||
22 | where | ||
23 | .Fa ptr | ||
24 | points to a credential ID of | ||
25 | .Fa len | ||
26 | bytes. | ||
27 | A copy of | ||
28 | .Fa ptr | ||
29 | is made, and no references to the passed pointer are kept. | ||
30 | If | ||
31 | .Fn fido_assert_allow_cred | ||
32 | fails, the existing list of allowed credentials is preserved. | ||
33 | .Pp | ||
34 | For the format of a FIDO 2 credential ID, please refer to the | ||
35 | Web Authentication (webauthn) standard. | ||
36 | .Sh RETURN VALUES | ||
37 | The error codes returned by | ||
38 | .Fn fido_assert_allow_cred | ||
39 | are defined in | ||
40 | .In fido/err.h . | ||
41 | On success, | ||
42 | .Dv FIDO_OK | ||
43 | is returned. | ||
44 | .Sh SEE ALSO | ||
45 | .Xr fido_assert_new 3 , | ||
46 | .Xr fido_assert_set_authdata 3 , | ||
47 | .Xr fido_dev_get_assert 3 | ||
diff --git a/man/fido_assert_new.3 b/man/fido_assert_new.3 new file mode 100644 index 0000000..0c2f92f --- /dev/null +++ b/man/fido_assert_new.3 | |||
@@ -0,0 +1,190 @@ | |||
1 | .\" Copyright (c) 2018 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: October 22 2019 $ | ||
6 | .Dt FIDO_ASSERT_NEW 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_assert_new , | ||
10 | .Nm fido_assert_free , | ||
11 | .Nm fido_assert_count , | ||
12 | .Nm fido_assert_user_display_name , | ||
13 | .Nm fido_assert_user_icon , | ||
14 | .Nm fido_assert_user_name , | ||
15 | .Nm fido_assert_authdata_ptr , | ||
16 | .Nm fido_assert_clientdata_hash_ptr , | ||
17 | .Nm fido_assert_hmac_secret_ptr , | ||
18 | .Nm fido_assert_user_id_ptr , | ||
19 | .Nm fido_assert_sig_ptr , | ||
20 | .Nm fido_assert_authdata_len , | ||
21 | .Nm fido_assert_clientdata_hash_len , | ||
22 | .Nm fido_assert_hmac_secret_len , | ||
23 | .Nm fido_assert_user_id_len , | ||
24 | .Nm fido_assert_sig_len , | ||
25 | .Nm fido_assert_sigcount | ||
26 | .Nd FIDO 2 assertion API | ||
27 | .Sh SYNOPSIS | ||
28 | .In fido.h | ||
29 | .Ft fido_assert_t * | ||
30 | .Fn fido_assert_new "void" | ||
31 | .Ft void | ||
32 | .Fn fido_assert_free "fido_assert_t **assert_p" | ||
33 | .Ft size_t | ||
34 | .Fn fido_assert_count "const fido_assert_t *assert" | ||
35 | .Ft const char * | ||
36 | .Fn fido_assert_user_display_name "const fido_assert_t *assert" "size_t idx" | ||
37 | .Ft const char * | ||
38 | .Fn fido_assert_user_icon "const fido_assert_t *assert" "size_t idx" | ||
39 | .Ft const char * | ||
40 | .Fn fido_assert_user_name "const fido_assert_t *assert" "size_t idx" | ||
41 | .Ft const unsigned char * | ||
42 | .Fn fido_assert_authdata_ptr "const fido_assert_t *assert" "size_t idx" | ||
43 | .Ft const unsigned char * | ||
44 | .Fn fido_assert_clientdata_hash_ptr "const fido_assert_t *assert" | ||
45 | .Ft const unsigned char * | ||
46 | .Fn fido_assert_hmac_secret_ptr "const fido_assert_t *assert" "size_t idx" | ||
47 | .Ft const unsigned char * | ||
48 | .Fn fido_assert_user_id_ptr "const fido_assert_t *assert" "size_t idx" | ||
49 | .Ft const unsigned char * | ||
50 | .Fn fido_assert_sig_ptr "const fido_assert_t *assert" "size_t idx" | ||
51 | .Ft size_t | ||
52 | .Fn fido_assert_authdata_len "const fido_assert_t *assert" "size_t idx" | ||
53 | .Ft size_t | ||
54 | .Fn fido_assert_clientdata_hash_len "const fido_assert_t *assert" | ||
55 | .Ft size_t | ||
56 | .Fn fido_assert_hmac_secret_len "const fido_assert_t *assert" "size_t idx" | ||
57 | .Ft size_t | ||
58 | .Fn fido_assert_user_id_len "const fido_assert_t *assert" "size_t idx" | ||
59 | .Ft size_t | ||
60 | .Fn fido_assert_sig_len "const fido_assert_t *assert" "size_t idx" | ||
61 | .Ft uint32_t | ||
62 | .Fn fido_assert_sigcount "const fido_assert_t *assert" "size_t idx" | ||
63 | .Sh DESCRIPTION | ||
64 | FIDO 2 assertions are abstracted in | ||
65 | .Em libfido2 | ||
66 | by the | ||
67 | .Vt fido_assert_t | ||
68 | type. | ||
69 | The functions described in this page allow a | ||
70 | .Vt fido_assert_t | ||
71 | type to be allocated, deallocated, and inspected. | ||
72 | For other operations on | ||
73 | .Vt fido_assert_t , | ||
74 | please refer to | ||
75 | .Xr fido_assert_set_authdata 3 , | ||
76 | .Xr fido_assert_allow_cred 3 , | ||
77 | .Xr fido_assert_verify 3 , | ||
78 | and | ||
79 | .Xr fido_dev_get_assert 3 . | ||
80 | .Pp | ||
81 | The | ||
82 | .Fn fido_assert_new | ||
83 | function returns a pointer to a newly allocated, empty | ||
84 | .Vt fido_assert_t | ||
85 | type. | ||
86 | If memory cannot be allocated, NULL is returned. | ||
87 | .Pp | ||
88 | The | ||
89 | .Fn fido_assert_free | ||
90 | function releases the memory backing | ||
91 | .Fa *assert_p , | ||
92 | where | ||
93 | .Fa *assert_p | ||
94 | must have been previously allocated by | ||
95 | .Fn fido_assert_new . | ||
96 | On return, | ||
97 | .Fa *assert_p | ||
98 | is set to NULL. | ||
99 | Either | ||
100 | .Fa assert_p | ||
101 | or | ||
102 | .Fa *assert_p | ||
103 | may be NULL, in which case | ||
104 | .Fn fido_assert_free | ||
105 | is a NOP. | ||
106 | .Pp | ||
107 | The | ||
108 | .Fn fido_assert_count | ||
109 | function returns the number of statements in | ||
110 | .Fa assert . | ||
111 | .Pp | ||
112 | The | ||
113 | .Fn fido_assert_user_display_name , | ||
114 | .Fn fido_assert_user_icon , | ||
115 | and | ||
116 | .Fn fido_assert_user_name , | ||
117 | functions return pointers to the user display name, icon, and | ||
118 | name attributes of statement | ||
119 | .Fa idx | ||
120 | in | ||
121 | .Fa assert . | ||
122 | If not NULL, the values returned by these functions point to | ||
123 | NUL-terminated UTF-8 strings. | ||
124 | .Pp | ||
125 | The | ||
126 | .Fn fido_assert_user_id_ptr , | ||
127 | .Fn fido_assert_authdata_ptr , | ||
128 | .Fn fido_assert_hmac_secret_ptr , | ||
129 | and | ||
130 | .Fn fido_assert_sig_ptr | ||
131 | functions return pointers to the user ID, authenticator data, | ||
132 | hmac-secret, and signature attributes of statement | ||
133 | .Fa idx | ||
134 | in | ||
135 | .Fa assert . | ||
136 | The | ||
137 | .Fn fido_assert_user_id_len , | ||
138 | .Fn fido_assert_authdata_len , | ||
139 | .Fn fido_assert_hmac_secret_len , | ||
140 | and | ||
141 | .Fn fido_assert_sig_len | ||
142 | functions can be used to retrieve the corresponding length of a | ||
143 | specific attribute. | ||
144 | .Pp | ||
145 | The | ||
146 | .Fn fido_assert_sigcount | ||
147 | function can be used to obtain the signature counter of statement | ||
148 | .Fa idx | ||
149 | in | ||
150 | .Fa assert . | ||
151 | .Pp | ||
152 | Please note that the first statement in | ||
153 | .Fa assert | ||
154 | has an | ||
155 | .Fa idx | ||
156 | (index) value of 0. | ||
157 | .Pp | ||
158 | The authenticator data and signature parts of an assertion | ||
159 | statement are typically passed to a FIDO 2 server for verification. | ||
160 | .Pp | ||
161 | The | ||
162 | .Fn fido_assert_clientdata_hash_ptr | ||
163 | function returns a pointer to the client data hash of | ||
164 | .Fa assert . | ||
165 | The corresponding length can be obtained by | ||
166 | .Fn fido_assert_clientdata_hash_len . | ||
167 | .Sh RETURN VALUES | ||
168 | The | ||
169 | .Fn fido_assert_user_display_name , | ||
170 | .Fn fido_assert_user_icon , | ||
171 | .Fn fido_assert_user_name , | ||
172 | .Fn fido_assert_authdata_ptr , | ||
173 | .Fn fido_assert_clientdata_hash_ptr , | ||
174 | .Fn fido_assert_user_id_ptr , | ||
175 | and | ||
176 | .Fn fido_assert_sig_ptr | ||
177 | functions return NULL if the respective field in | ||
178 | .Fa assert | ||
179 | is not set. | ||
180 | If not NULL, returned pointers are guaranteed to exist until any API | ||
181 | function that takes | ||
182 | .Fa assert | ||
183 | without the | ||
184 | .Em const | ||
185 | qualifier is invoked. | ||
186 | .Sh SEE ALSO | ||
187 | .Xr fido_assert_allow_cred 3 , | ||
188 | .Xr fido_assert_set_authdata 3 , | ||
189 | .Xr fido_assert_verify 3 , | ||
190 | .Xr fido_dev_get_assert 3 | ||
diff --git a/man/fido_assert_set_authdata.3 b/man/fido_assert_set_authdata.3 new file mode 100644 index 0000000..29a86c1 --- /dev/null +++ b/man/fido_assert_set_authdata.3 | |||
@@ -0,0 +1,194 @@ | |||
1 | .\" Copyright (c) 2018 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: May 23 2018 $ | ||
6 | .Dt FIDO_ASSERT_SET_AUTHDATA 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_assert_set_authdata , | ||
10 | .Nm fido_assert_set_authdata_raw , | ||
11 | .Nm fido_assert_set_clientdata_hash , | ||
12 | .Nm fido_assert_set_count , | ||
13 | .Nm fido_assert_set_extensions , | ||
14 | .Nm fido_assert_set_hmac_salt , | ||
15 | .Nm fido_assert_set_up , | ||
16 | .Nm fido_assert_set_uv , | ||
17 | .Nm fido_assert_set_rp , | ||
18 | .Nm fido_assert_set_sig | ||
19 | .Nd set parameters of a FIDO 2 assertion | ||
20 | .Sh SYNOPSIS | ||
21 | .In fido.h | ||
22 | .Bd -literal | ||
23 | typedef enum { | ||
24 | FIDO_OPT_OMIT = 0, /* use authenticator's default */ | ||
25 | FIDO_OPT_FALSE, /* explicitly set option to false */ | ||
26 | FIDO_OPT_TRUE, /* explicitly set option to true */ | ||
27 | } fido_opt_t; | ||
28 | .Ed | ||
29 | .Ft int | ||
30 | .Fn fido_assert_set_authdata "fido_assert_t *assert" " size_t idx" "const unsigned char *ptr" "size_t len" | ||
31 | .Ft int | ||
32 | .Fn fido_assert_set_authdata_raw "fido_assert_t *assert" " size_t idx" "const unsigned char *ptr" "size_t len" | ||
33 | .Ft int | ||
34 | .Fn fido_assert_set_clientdata_hash "fido_assert_t *assert" "const unsigned char *ptr" "size_t len" | ||
35 | .Ft int | ||
36 | .Fn fido_assert_set_count "fido_assert_t *assert" "size_t n" | ||
37 | .Ft int | ||
38 | .Fn fido_assert_set_extensions "fido_assert_t *assert" "int flags" | ||
39 | .Ft int | ||
40 | .Fn fido_assert_set_hmac_salt "fido_assert_t *assert" "const unsigned char *ptr" "size_t len" | ||
41 | .Ft int | ||
42 | .Fn fido_assert_set_up "fido_assert_t *assert" "fido_opt_t up" | ||
43 | .Ft int | ||
44 | .Fn fido_assert_set_uv "fido_assert_t *assert" "fido_opt_t uv" | ||
45 | .Ft int | ||
46 | .Fn fido_assert_set_rp "fido_assert_t *assert" "const char *id" | ||
47 | .Ft int | ||
48 | .Fn fido_assert_set_sig "fido_assert_t *assert" "size_t idx" "const unsigned char *ptr" "size_t len" | ||
49 | .Sh DESCRIPTION | ||
50 | The | ||
51 | .Nm | ||
52 | set of functions define the various parameters of a FIDO 2 | ||
53 | assertion, allowing a | ||
54 | .Fa fido_assert_t | ||
55 | type to be prepared for a subsequent call to | ||
56 | .Xr fido_dev_get_assert 3 | ||
57 | or | ||
58 | .Xr fido_assert_verify 3 . | ||
59 | For the complete specification of a FIDO 2 assertion and the format | ||
60 | of its constituent parts, please refer to the Web Authentication | ||
61 | (webauthn) standard. | ||
62 | .Pp | ||
63 | The | ||
64 | .Fn fido_assert_set_count | ||
65 | function sets the number of assertion statements in | ||
66 | .Fa assert | ||
67 | to | ||
68 | .Fa n . | ||
69 | .Pp | ||
70 | The | ||
71 | .Fn fido_assert_set_authdata | ||
72 | and | ||
73 | .Fn fido_assert_set_sig | ||
74 | functions set the authenticator data and signature parts of the | ||
75 | statement with index | ||
76 | .Fa idx | ||
77 | of | ||
78 | .Fa assert | ||
79 | to | ||
80 | .Fa ptr , | ||
81 | where | ||
82 | .Fa ptr | ||
83 | points to | ||
84 | .Fa len | ||
85 | bytes. | ||
86 | A copy of | ||
87 | .Fa ptr | ||
88 | is made, and no references to the passed pointer are kept. | ||
89 | Please note that the first assertion statement of | ||
90 | .Fa assert | ||
91 | has an | ||
92 | .Fa idx | ||
93 | of | ||
94 | .Em 0 . | ||
95 | The authenticator data passed to | ||
96 | .Fn fido_assert_set_authdata | ||
97 | must be a CBOR-encoded byte string, as obtained from | ||
98 | .Fn fido_assert_authdata_ptr . | ||
99 | Alternatively, a raw binary blob may be passed to | ||
100 | .Fn fido_assert_set_authdata_raw . | ||
101 | .Pp | ||
102 | The | ||
103 | .Fn fido_assert_set_clientdata_hash | ||
104 | and | ||
105 | .Fn fido_assert_set_hmac_salt | ||
106 | functions set the client data hash and hmac-salt parts of | ||
107 | .Fa assert | ||
108 | to | ||
109 | .Fa ptr , | ||
110 | where | ||
111 | .Fa ptr | ||
112 | points to | ||
113 | .Fa len | ||
114 | bytes. | ||
115 | A copy of | ||
116 | .Fa ptr | ||
117 | is made, and no references to the passed pointer are kept. | ||
118 | .Pp | ||
119 | The | ||
120 | .Fn fido_assert_set_rp | ||
121 | function sets the relying party | ||
122 | .Fa id | ||
123 | of | ||
124 | .Fa assert , | ||
125 | where | ||
126 | .Fa id | ||
127 | is a NUL-terminated UTF-8 string. | ||
128 | The content of | ||
129 | .Fa id | ||
130 | is copied, and no references to the passed pointer are kept. | ||
131 | .Pp | ||
132 | The | ||
133 | .Fn fido_assert_set_extensions | ||
134 | function sets the extensions of | ||
135 | .Fa assert | ||
136 | to the bitmask | ||
137 | .Fa flags . | ||
138 | At the moment, only the | ||
139 | .Dv FIDO_EXT_HMAC_SECRET | ||
140 | extension is supported. | ||
141 | If | ||
142 | .Fa flags | ||
143 | is zero, the extensions of | ||
144 | .Fa assert | ||
145 | are cleared. | ||
146 | .Pp | ||
147 | The | ||
148 | .Fn fido_assert_set_up | ||
149 | and | ||
150 | .Fn fido_assert_set_uv | ||
151 | functions set the | ||
152 | .Fa up | ||
153 | (user presence) and | ||
154 | .Fa uv | ||
155 | (user verification) | ||
156 | attributes of | ||
157 | .Fa assert . | ||
158 | Both are | ||
159 | .Dv FIDO_OPT_OMIT | ||
160 | by default, allowing the authenticator to use its default settings. | ||
161 | .Pp | ||
162 | Use of the | ||
163 | .Nm | ||
164 | set of functions may happen in two distinct situations: | ||
165 | when asking a FIDO device to produce a series of assertion | ||
166 | statements, prior to | ||
167 | .Xr fido_dev_get_assert 3 | ||
168 | (i.e, in the context of a FIDO client), or when verifying assertion | ||
169 | statements using | ||
170 | .Xr fido_assert_verify 3 | ||
171 | (i.e, in the context of a FIDO server). | ||
172 | .Pp | ||
173 | For a complete description of the generation of a FIDO 2 assertion | ||
174 | and its verification, please refer to the FIDO 2 specification. | ||
175 | An example of how to use the | ||
176 | .Nm | ||
177 | set of functions can be found in the | ||
178 | .Pa examples/assert.c | ||
179 | file shipped with | ||
180 | .Em libfido2 . | ||
181 | .Sh RETURN VALUES | ||
182 | The | ||
183 | .Nm | ||
184 | functions return | ||
185 | .Dv FIDO_OK | ||
186 | on success. | ||
187 | The error codes returned by the | ||
188 | .Nm | ||
189 | set of functions are defined in | ||
190 | .In fido/err.h . | ||
191 | .Sh SEE ALSO | ||
192 | .Xr fido_assert_allow_cred 3 , | ||
193 | .Xr fido_assert_verify 3 , | ||
194 | .Xr fido_dev_get_assert 3 | ||
diff --git a/man/fido_assert_verify.3 b/man/fido_assert_verify.3 new file mode 100644 index 0000000..82e64e1 --- /dev/null +++ b/man/fido_assert_verify.3 | |||
@@ -0,0 +1,79 @@ | |||
1 | .\" Copyright (c) 2018 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: May 24 2018 $ | ||
6 | .Dt FIDO_ASSERT_VERIFY 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_assert_verify | ||
10 | .Nd verifies the signature of a FIDO 2 assertion statement | ||
11 | .Sh SYNOPSIS | ||
12 | .In fido.h | ||
13 | .Ft int | ||
14 | .Fn fido_assert_verify "fido_assert_t *assert" "size_t idx" "int cose_alg" "const void *pk" | ||
15 | .Sh DESCRIPTION | ||
16 | The | ||
17 | .Fn fido_assert_verify | ||
18 | function verifies whether the signature contained in statement index | ||
19 | .Fa idx | ||
20 | of | ||
21 | .Fa assert | ||
22 | matches the parameters of the assertion. | ||
23 | Before using | ||
24 | .Fn fido_assert_verify | ||
25 | in a sensitive context, the reader is strongly encouraged to make | ||
26 | herself familiar with the FIDO 2 assertion statement process | ||
27 | as defined in the Web Authentication (webauthn) standard. | ||
28 | .Pp | ||
29 | A brief description follows: | ||
30 | .Pp | ||
31 | The | ||
32 | .Fn fido_assert_verify | ||
33 | function verifies whether the client data hash, relying party ID, | ||
34 | user presence and user verification attributes of | ||
35 | .Fa assert | ||
36 | have been attested by the holder of the private counterpart of | ||
37 | the public key | ||
38 | .Fa pk | ||
39 | of COSE type | ||
40 | .Fa cose_alg , | ||
41 | where | ||
42 | .Fa cose_alg | ||
43 | is | ||
44 | .Dv COSE_ES256 , | ||
45 | .Dv COSE_RS256 , | ||
46 | or | ||
47 | .Dv COSE_EDDSA , | ||
48 | and | ||
49 | .Fa pk | ||
50 | points to a | ||
51 | .Vt es256_pk_t , | ||
52 | .Vt rs256_pk_t , | ||
53 | or | ||
54 | .Vt eddsa_pk_t | ||
55 | type accordingly. | ||
56 | .Pp | ||
57 | Please note that the first statement in | ||
58 | .Fa assert | ||
59 | has an | ||
60 | .Fa idx | ||
61 | of 0. | ||
62 | .Sh RETURN VALUES | ||
63 | The error codes returned by | ||
64 | .Fn fido_assert_verify | ||
65 | are defined in | ||
66 | .In fido/err.h . | ||
67 | If | ||
68 | statement | ||
69 | .Fa idx | ||
70 | of | ||
71 | .Fa assert | ||
72 | passes verification with | ||
73 | .Fa pk , | ||
74 | then | ||
75 | .Dv FIDO_OK | ||
76 | is returned. | ||
77 | .Sh SEE ALSO | ||
78 | .Xr fido_assert_new 3 , | ||
79 | .Xr fido_assert_set_authdata 3 | ||
diff --git a/man/fido_bio_dev_get_info.3 b/man/fido_bio_dev_get_info.3 new file mode 100644 index 0000000..bde1396 --- /dev/null +++ b/man/fido_bio_dev_get_info.3 | |||
@@ -0,0 +1,120 @@ | |||
1 | .\" Copyright (c) 2019 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: September 13 2019 $ | ||
6 | .Dt FIDO_BIO_DEV_GET_INFO 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_bio_dev_get_info , | ||
10 | .Nm fido_bio_dev_enroll_begin , | ||
11 | .Nm fido_bio_dev_enroll_continue , | ||
12 | .Nm fido_bio_dev_enroll_cancel , | ||
13 | .Nm fido_bio_dev_enroll_remove , | ||
14 | .Nm fido_bio_dev_get_template_array , | ||
15 | .Nm fido_bio_dev_set_template_name | ||
16 | .Nd FIDO 2 biometric authenticator API | ||
17 | .Sh SYNOPSIS | ||
18 | .In fido.h | ||
19 | .In fido/bio.h | ||
20 | .Ft int | ||
21 | .Fn fido_bio_dev_get_info "fido_dev_t *dev" "fido_bio_info_t *info" | ||
22 | .Ft int | ||
23 | .Fn fido_bio_dev_enroll_begin "fido_dev_t *dev" "fido_bio_template_t *template" "fido_bio_enroll_t *enroll" "uint32_t timeout_ms" "const char *pin" | ||
24 | .Ft int | ||
25 | .Fn fido_bio_dev_enroll_continue "fido_dev_t *dev" "const fido_bio_template_t *template" "fido_bio_enroll_t *enroll" "uint32_t timeout_ms" | ||
26 | .Ft int | ||
27 | .Fn fido_bio_dev_enroll_cancel "fido_dev_t *dev" | ||
28 | .Ft int | ||
29 | .Fn fido_bio_dev_enroll_remove "fido_dev_t *dev" "const fido_bio_template_t *template" "const char *pin" | ||
30 | .Ft int | ||
31 | .Fn fido_bio_dev_get_template_array "fido_dev_t *dev" "fido_bio_template_array_t *template_array" "const char *pin" | ||
32 | .Ft int | ||
33 | .Fn fido_bio_dev_set_template_name "fido_dev_t *dev" "const fido_bio_template_t *template" "const char *pin" | ||
34 | .Sh DESCRIPTION | ||
35 | The functions described in this page allow biometric | ||
36 | templates on a FIDO2 authenticator to be listed, created, | ||
37 | removed, and customised. | ||
38 | For a description of the types involved, please refer to | ||
39 | .Xr fido_bio_info_new 3 , | ||
40 | .Xr fido_bio_enroll_new 3 , | ||
41 | and | ||
42 | .Xr fido_bio_template 3 . | ||
43 | .Pp | ||
44 | The | ||
45 | .Fn fido_bio_dev_get_info | ||
46 | function populates | ||
47 | .Fa info | ||
48 | with sensor information from | ||
49 | .Fa dev . | ||
50 | .Pp | ||
51 | The | ||
52 | .Fn fido_bio_dev_enroll_begin | ||
53 | function initiates a biometric enrollment on | ||
54 | .Fa dev , | ||
55 | instructing the authenticator to wait | ||
56 | .Fa timeout_ms | ||
57 | milliseconds. | ||
58 | On success, | ||
59 | .Fa template | ||
60 | and | ||
61 | .Fa enroll | ||
62 | will be populated with the newly created template's | ||
63 | information and enrollment status, respectively. | ||
64 | .Pp | ||
65 | The | ||
66 | .Fn fido_bio_dev_enroll_continue | ||
67 | function continues an ongoing enrollment on | ||
68 | .Fa dev , | ||
69 | instructing the authenticator to wait | ||
70 | .Fa timeout_ms | ||
71 | milliseconds. | ||
72 | On success, | ||
73 | .Fa enroll | ||
74 | will be updated to reflect the status of the biometric | ||
75 | enrollment. | ||
76 | .Pp | ||
77 | The | ||
78 | .Fn fido_bio_dev_enroll_cancel | ||
79 | function cancels an ongoing enrollment on | ||
80 | .Fa dev . | ||
81 | .Pp | ||
82 | The | ||
83 | .Fn fido_bio_dev_enroll_remove | ||
84 | function removes | ||
85 | .Fa template | ||
86 | from | ||
87 | .Fa dev . | ||
88 | .Pp | ||
89 | The | ||
90 | .Fn fido_bio_dev_get_template_array | ||
91 | function populates | ||
92 | .Fa template_array | ||
93 | with the templates currently enrolled on | ||
94 | .Fa dev . | ||
95 | .Pp | ||
96 | The | ||
97 | .Fn fido_bio_dev_set_template_name | ||
98 | function sets the friendly name of | ||
99 | .Fa template | ||
100 | on | ||
101 | .Fa dev . | ||
102 | .Pp | ||
103 | The error codes returned by | ||
104 | .Fn fido_bio_dev_get_info , | ||
105 | .Fn fido_bio_dev_enroll_begin , | ||
106 | .Fn fido_bio_dev_enroll_continue , | ||
107 | .Fn fido_bio_dev_enroll_cancel , | ||
108 | .Fn fido_bio_dev_enroll_remove , | ||
109 | .Fn fido_bio_dev_get_template_array , | ||
110 | and | ||
111 | .Fn fido_bio_dev_set_template_name | ||
112 | are defined in | ||
113 | .In fido/err.h . | ||
114 | On success, | ||
115 | .Dv FIDO_OK | ||
116 | is returned. | ||
117 | .Sh SEE ALSO | ||
118 | .Xr fido_bio_enroll_new 3 , | ||
119 | .Xr fido_bio_info_new 3 , | ||
120 | .Xr fido_bio_template 3 | ||
diff --git a/man/fido_bio_enroll_new.3 b/man/fido_bio_enroll_new.3 new file mode 100644 index 0000000..3db3e7a --- /dev/null +++ b/man/fido_bio_enroll_new.3 | |||
@@ -0,0 +1,95 @@ | |||
1 | .\" Copyright (c) 2019 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: September 13 2019 $ | ||
6 | .Dt FIDO_BIO_ENROLL_NEW 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_bio_enroll_new , | ||
10 | .Nm fido_bio_enroll_free , | ||
11 | .Nm fido_bio_enroll_last_status , | ||
12 | .Nm fido_bio_enroll_remaining_samples | ||
13 | .Nd FIDO 2 biometric enrollment API | ||
14 | .Sh SYNOPSIS | ||
15 | .In fido.h | ||
16 | .In fido/bio.h | ||
17 | .Bd -literal | ||
18 | #define FIDO_BIO_ENROLL_FP_GOOD 0x00 | ||
19 | #define FIDO_BIO_ENROLL_FP_TOO_HIGH 0x01 | ||
20 | #define FIDO_BIO_ENROLL_FP_TOO_LOW 0x02 | ||
21 | #define FIDO_BIO_ENROLL_FP_TOO_LEFT 0x03 | ||
22 | #define FIDO_BIO_ENROLL_FP_TOO_RIGHT 0x04 | ||
23 | #define FIDO_BIO_ENROLL_FP_TOO_FAST 0x05 | ||
24 | #define FIDO_BIO_ENROLL_FP_TOO_SLOW 0x06 | ||
25 | #define FIDO_BIO_ENROLL_FP_POOR_QUALITY 0x07 | ||
26 | #define FIDO_BIO_ENROLL_FP_TOO_SKEWED 0x08 | ||
27 | #define FIDO_BIO_ENROLL_FP_TOO_SHORT 0x09 | ||
28 | #define FIDO_BIO_ENROLL_FP_MERGE_FAILURE 0x0a | ||
29 | #define FIDO_BIO_ENROLL_FP_EXISTS 0x0b | ||
30 | #define FIDO_BIO_ENROLL_FP_DATABASE_FULL 0x0c | ||
31 | #define FIDO_BIO_ENROLL_NO_USER_ACTIVITY 0x0d | ||
32 | #define FIDO_BIO_ENROLL_NO_USER_PRESENCE_TRANSITION 0x0e | ||
33 | .Ed | ||
34 | .Ft fido_bio_enroll_t * | ||
35 | .Fn fido_bio_enroll_new "void" | ||
36 | .Ft void | ||
37 | .Fn fido_bio_enroll_free "fido_bio_enroll_t **enroll_p" | ||
38 | .Ft uint8_t | ||
39 | .Fn fido_bio_enroll_last_status "const fido_bio_enroll_t *enroll" | ||
40 | .Ft uint8_t | ||
41 | .Fn fido_bio_enroll_remaining_samples "const fido_bio_enroll_t *enroll" | ||
42 | .Sh DESCRIPTION | ||
43 | Ongoing FIDO 2 biometric enrollments are abstracted in | ||
44 | .Em libfido2 | ||
45 | by the | ||
46 | .Vt fido_bio_enroll_t | ||
47 | type. | ||
48 | .Pp | ||
49 | The functions described in this page allow a | ||
50 | .Vt fido_bio_enroll_t | ||
51 | type to be allocated, deallocated, and inspected. | ||
52 | For device operations on | ||
53 | .Vt fido_bio_enroll_t , | ||
54 | please refer to | ||
55 | .Xr fido_bio_dev_get_info 3 . | ||
56 | .Pp | ||
57 | The | ||
58 | .Fn fido_bio_enroll_new | ||
59 | function returns a pointer to a newly allocated, empty | ||
60 | .Vt fido_bio_enroll_t | ||
61 | type. | ||
62 | If memory cannot be allocated, NULL is returned. | ||
63 | .Pp | ||
64 | The | ||
65 | .Fn fido_bio_enroll_free | ||
66 | function releases the memory backing | ||
67 | .Fa *enroll_p , | ||
68 | where | ||
69 | .Fa *enroll_p | ||
70 | must have been previously allocated by | ||
71 | .Fn fido_bio_enroll_new . | ||
72 | On return, | ||
73 | .Fa *enroll_p | ||
74 | is set to NULL. | ||
75 | Either | ||
76 | .Fa enroll_p | ||
77 | or | ||
78 | .Fa *enroll_p | ||
79 | may be NULL, in which case | ||
80 | .Fn fido_bio_enroll_free | ||
81 | is a NOP. | ||
82 | .Pp | ||
83 | The | ||
84 | .Fn fido_bio_enroll_last_status | ||
85 | function returns the enrollment status of | ||
86 | .Fa enroll . | ||
87 | .Pp | ||
88 | The | ||
89 | .Fn fido_bio_enroll_remaining_samples | ||
90 | function returns the number of samples left for | ||
91 | .Fa enroll | ||
92 | to complete. | ||
93 | .Sh SEE ALSO | ||
94 | .Xr fido_bio_dev_get_info 3 , | ||
95 | .Xr fido_bio_template 3 | ||
diff --git a/man/fido_bio_info_new.3 b/man/fido_bio_info_new.3 new file mode 100644 index 0000000..c827333 --- /dev/null +++ b/man/fido_bio_info_new.3 | |||
@@ -0,0 +1,81 @@ | |||
1 | .\" Copyright (c) 2019 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: September 13 2019 $ | ||
6 | .Dt FIDO_BIO_INFO_NEW 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_bio_info_new , | ||
10 | .Nm fido_bio_info_free , | ||
11 | .Nm fido_bio_info_type , | ||
12 | .Nm fido_bio_info_max_samples | ||
13 | .Nd FIDO 2 biometric sensor information API | ||
14 | .Sh SYNOPSIS | ||
15 | .In fido.h | ||
16 | .In fido/bio.h | ||
17 | .Ft fido_bio_info_t * | ||
18 | .Fn fido_bio_info_new "void" | ||
19 | .Ft void | ||
20 | .Fn fido_bio_info_free "fido_bio_info_t **info_p" | ||
21 | .Ft uint8_t | ||
22 | .Fn fido_bio_info_type "const fido_bio_info_t *info" | ||
23 | .Ft uint8_t | ||
24 | .Fn fido_bio_info_max_samples "const fido_bio_info_t *info" | ||
25 | .Sh DESCRIPTION | ||
26 | Biometric sensor metadata is abstracted in | ||
27 | .Em libfido2 | ||
28 | by the | ||
29 | .Vt fido_bio_info_t | ||
30 | type. | ||
31 | .Pp | ||
32 | The functions described in this page allow a | ||
33 | .Vt fido_bio_info_t | ||
34 | type to be allocated, deallocated, and inspected. | ||
35 | For device operations on | ||
36 | .Vt fido_bio_info_t , | ||
37 | please refer to | ||
38 | .Xr fido_bio_dev_get_info 3 . | ||
39 | .Pp | ||
40 | The | ||
41 | .Fn fido_bio_info_new | ||
42 | function returns a pointer to a newly allocated, empty | ||
43 | .Vt fido_bio_info_t | ||
44 | type. | ||
45 | If memory cannot be allocated, NULL is returned. | ||
46 | .Pp | ||
47 | The | ||
48 | .Fn fido_bio_info_free | ||
49 | function releases the memory backing | ||
50 | .Fa *info_p , | ||
51 | where | ||
52 | .Fa *info_p | ||
53 | must have been previously allocated by | ||
54 | .Fn fido_bio_info_new . | ||
55 | On return, | ||
56 | .Fa *info_p | ||
57 | is set to NULL. | ||
58 | Either | ||
59 | .Fa info_p | ||
60 | or | ||
61 | .Fa *info_p | ||
62 | may be NULL, in which case | ||
63 | .Fn fido_bio_info_free | ||
64 | is a NOP. | ||
65 | .Pp | ||
66 | The | ||
67 | .Fn fido_bio_info_type | ||
68 | function returns the fingerprint sensor type, which is | ||
69 | .Dv 1 | ||
70 | for touch sensors, and | ||
71 | .Dv 2 | ||
72 | for swipe sensors. | ||
73 | .Pp | ||
74 | The | ||
75 | .Fn fido_bio_info_max_samples | ||
76 | function returns the maximum number of successful samples | ||
77 | required for enrollment. | ||
78 | .Sh SEE ALSO | ||
79 | .Xr fido_bio_dev_get_info 3 , | ||
80 | .Xr fido_bio_enroll_new 3 , | ||
81 | .Xr fido_bio_template 3 | ||
diff --git a/man/fido_bio_template.3 b/man/fido_bio_template.3 new file mode 100644 index 0000000..6140926 --- /dev/null +++ b/man/fido_bio_template.3 | |||
@@ -0,0 +1,169 @@ | |||
1 | .\" Copyright (c) 2019 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: September 13 2019 $ | ||
6 | .Dt FIDO_BIO_TEMPLATE 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_bio_template , | ||
10 | .Nm fido_bio_template_array_count , | ||
11 | .Nm fido_bio_template_array_free , | ||
12 | .Nm fido_bio_template_array_new , | ||
13 | .Nm fido_bio_template_free , | ||
14 | .Nm fido_bio_template_id_len , | ||
15 | .Nm fido_bio_template_id_ptr , | ||
16 | .Nm fido_bio_template_name , | ||
17 | .Nm fido_bio_template_new , | ||
18 | .Nm fido_bio_template_set_id , | ||
19 | .Nm fido_bio_template_set_name | ||
20 | .Nd FIDO 2 biometric template API | ||
21 | .Sh SYNOPSIS | ||
22 | .In fido.h | ||
23 | .In fido/bio.h | ||
24 | .Ft fido_bio_template_t * | ||
25 | .Fn fido_bio_template_new "void" | ||
26 | .Ft void | ||
27 | .Fn fido_bio_template_free "fido_bio_template_t **template_p" | ||
28 | .Ft const char * | ||
29 | .Fn fido_bio_template_name "const fido_bio_template_t *template" | ||
30 | .Ft const unsigned char * | ||
31 | .Fn fido_bio_template_id_ptr "const fido_bio_template_t *template" | ||
32 | .Ft size_t | ||
33 | .Fn fido_bio_template_id_len "const fido_bio_template_t *template" | ||
34 | .Ft int | ||
35 | .Fn fido_bio_template_set_id "fido_bio_template_t *template" "const unsigned char *ptr" "size_t len" | ||
36 | .Ft int | ||
37 | .Fn fido_bio_template_set_name "fido_bio_template_t *template" "const char *name" | ||
38 | .Ft fido_bio_template_array_t * | ||
39 | .Fn fido_bio_template_array_new "void" | ||
40 | .Ft void | ||
41 | .Fn fido_bio_template_array_free "fido_bio_template_array_t **template_array_p" | ||
42 | .Ft size_t | ||
43 | .Fn fido_bio_template_array_count "const fido_bio_template_array_t *template_array" | ||
44 | .Ft const fido_bio_template_t * | ||
45 | .Fn fido_bio_template "const fido_bio_template_array_t *template_array" "size_t idx" | ||
46 | .Sh DESCRIPTION | ||
47 | Existing FIDO 2 biometric enrollments are abstracted in | ||
48 | .Em libfido2 | ||
49 | by the | ||
50 | .Vt fido_bio_template_t | ||
51 | and | ||
52 | .Vt fido_bio_template_array_t | ||
53 | types. | ||
54 | .Pp | ||
55 | The functions described in this page allow a | ||
56 | .Vt fido_bio_template_t | ||
57 | type to be allocated, deallocated, changed, and inspected, | ||
58 | and a | ||
59 | .Vt fido_bio_template_array_t | ||
60 | type to be allocated, deallocated, and inspected. | ||
61 | For device operations on | ||
62 | .Vt fido_bio_template_t | ||
63 | and | ||
64 | .Vt fido_bio_template_array_t , | ||
65 | please refer to | ||
66 | .Xr fido_bio_dev_get_info 3 . | ||
67 | .Pp | ||
68 | The | ||
69 | .Fn fido_bio_template_new | ||
70 | function returns a pointer to a newly allocated, empty | ||
71 | .Vt fido_bio_template_t | ||
72 | type. | ||
73 | If memory cannot be allocated, NULL is returned. | ||
74 | .Pp | ||
75 | The | ||
76 | .Fn fido_bio_template_free | ||
77 | function releases the memory backing | ||
78 | .Fa *template_p , | ||
79 | where | ||
80 | .Fa *template_p | ||
81 | must have been previously allocated by | ||
82 | .Fn fido_bio_template_new . | ||
83 | On return, | ||
84 | .Fa *template_p | ||
85 | is set to NULL. | ||
86 | Either | ||
87 | .Fa template_p | ||
88 | or | ||
89 | .Fa *template_p | ||
90 | may be NULL, in which case | ||
91 | .Fn fido_bio_template_free | ||
92 | is a NOP. | ||
93 | .Pp | ||
94 | The | ||
95 | .Fn fido_bio_template_name | ||
96 | function returns a pointer to a NUL-terminated string containing | ||
97 | the friendly name of | ||
98 | .Fa template , | ||
99 | or NULL if | ||
100 | .Fa template | ||
101 | does not have a friendly name set. | ||
102 | .Pp | ||
103 | The | ||
104 | .Fn fido_bio_template_id_ptr | ||
105 | function returns a pointer to the template id of | ||
106 | .Fa template , | ||
107 | or NULL if | ||
108 | .Fa template | ||
109 | does not have an id. | ||
110 | The corresponding length can be obtained by | ||
111 | .Fn fido_bio_template_id_len . | ||
112 | .Pp | ||
113 | The | ||
114 | .Fn fido_bio_template_set_name | ||
115 | function sets the friendly name of | ||
116 | .Fa template | ||
117 | to | ||
118 | .Fa name . | ||
119 | If | ||
120 | .Fa name | ||
121 | is NULL, the friendly name of | ||
122 | .Fa template | ||
123 | is unset. | ||
124 | .Pp | ||
125 | The | ||
126 | .Fn fido_bio_template_array_new | ||
127 | function returns a pointer to a newly allocated, empty | ||
128 | .Vt fido_bio_template_array_t | ||
129 | type. | ||
130 | If memory cannot be allocated, NULL is returned. | ||
131 | .Pp | ||
132 | The | ||
133 | .Fn fido_bio_template_array_free | ||
134 | function releases the memory backing | ||
135 | .Fa *template_array_p , | ||
136 | where | ||
137 | .Fa *template_array_p | ||
138 | must have been previously allocated by | ||
139 | .Fn fido_bio_template_array_new . | ||
140 | On return, | ||
141 | .Fa *template_array_p | ||
142 | is set to NULL. | ||
143 | Either | ||
144 | .Fa template_array_p | ||
145 | or | ||
146 | .Fa *template_array_p | ||
147 | may be NULL, in which case | ||
148 | .Fn fido_bio_template_array_free | ||
149 | is a NOP. | ||
150 | .Pp | ||
151 | The | ||
152 | .Fn fido_bio_template_array_count | ||
153 | function returns the number of templates in | ||
154 | .Fa template_array . | ||
155 | .Pp | ||
156 | The | ||
157 | .Fn fido_bio_template | ||
158 | function returns a pointer to the template at index | ||
159 | .Fa idx | ||
160 | in | ||
161 | .Fa template_array . | ||
162 | Please note that the first template in | ||
163 | .Fa template_array | ||
164 | has an | ||
165 | .Fa idx | ||
166 | (index) value of 0. | ||
167 | .Sh SEE ALSO | ||
168 | .Xr fido_bio_dev_get_info 3 , | ||
169 | .Xr fido_bio_enroll_new 3 | ||
diff --git a/man/fido_cbor_info_new.3 b/man/fido_cbor_info_new.3 new file mode 100644 index 0000000..d1e4c41 --- /dev/null +++ b/man/fido_cbor_info_new.3 | |||
@@ -0,0 +1,153 @@ | |||
1 | .\" Copyright (c) 2018 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: May 24 2018 $ | ||
6 | .Dt FIDO_CBOR_INFO_NEW 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_cbor_info_new , | ||
10 | .Nm fido_cbor_info_free , | ||
11 | .Nm fido_dev_get_cbor_info , | ||
12 | .Nm fido_cbor_info_aaguid_ptr , | ||
13 | .Nm fido_cbor_info_extensions_ptr , | ||
14 | .Nm fido_cbor_info_protocols_ptr , | ||
15 | .Nm fido_cbor_info_versions_ptr , | ||
16 | .Nm fido_cbor_info_options_name_ptr , | ||
17 | .Nm fido_cbor_info_options_value_ptr , | ||
18 | .Nm fido_cbor_info_aaguid_len , | ||
19 | .Nm fido_cbor_info_extensions_len , | ||
20 | .Nm fido_cbor_info_protocols_len , | ||
21 | .Nm fido_cbor_info_versions_len , | ||
22 | .Nm fido_cbor_info_options_len , | ||
23 | .Nm fido_cbor_info_maxmsgsiz | ||
24 | .Nd FIDO 2 CBOR Info API | ||
25 | .Sh SYNOPSIS | ||
26 | .In fido.h | ||
27 | .Ft fido_cbor_info_t * | ||
28 | .Fn fido_cbor_info_new "void" | ||
29 | .Ft void | ||
30 | .Fn fido_cbor_info_free "fido_cbor_info_t **ci_p" | ||
31 | .Ft int | ||
32 | .Fn fido_dev_get_cbor_info "fido_dev_t *dev" "fido_cbor_info_t *ci" | ||
33 | .Ft const unsigned char * | ||
34 | .Fn fido_cbor_info_aaguid_ptr "const fido_cbor_info_t *ci" | ||
35 | .Ft char ** | ||
36 | .Fn fido_cbor_info_extensions_ptr "const fido_cbor_info_t *ci" | ||
37 | .Ft const uint8_t * | ||
38 | .Fn fido_cbor_info_protocols_ptr "const fido_cbor_info_t *ci" | ||
39 | .Ft char ** | ||
40 | .Fn fido_cbor_info_versions_ptr "const fido_cbor_info_t *ci" | ||
41 | .Ft char ** | ||
42 | .Fn fido_cbor_info_options_name_ptr "const fido_cbor_info_t *ci" | ||
43 | .Ft const bool * | ||
44 | .Fn fido_cbor_info_options_value_ptr "const fido_cbor_info_t *ci" | ||
45 | .Ft size_t | ||
46 | .Fn fido_cbor_info_aaguid_len "const fido_cbor_info_t *ci" | ||
47 | .Ft size_t | ||
48 | .Fn fido_cbor_info_extensions_len "const fido_cbor_info_t *ci" | ||
49 | .Ft size_t | ||
50 | .Fn fido_cbor_info_protocols_len "const fido_cbor_info_t *ci" | ||
51 | .Ft size_t | ||
52 | .Fn fido_cbor_info_versions_len "const fido_cbor_info_t *ci" | ||
53 | .Ft size_t | ||
54 | .Fn fido_cbor_info_options_len "const fido_cbor_info_t *ci" | ||
55 | .Ft uint64_t | ||
56 | .Fn fido_cbor_info_maxmsgsiz "const fido_cbor_info_t *ci" | ||
57 | .Sh DESCRIPTION | ||
58 | The | ||
59 | .Fn fido_cbor_info_new | ||
60 | function returns a pointer to a newly allocated, empty | ||
61 | .Vt fido_cbor_info_t | ||
62 | type. | ||
63 | If memory cannot be allocated, NULL is returned. | ||
64 | .Pp | ||
65 | The | ||
66 | .Fn fido_cbor_info_free | ||
67 | function releases the memory backing | ||
68 | .Fa *ci_p , | ||
69 | where | ||
70 | .Fa *ci_p | ||
71 | must have been previously allocated by | ||
72 | .Fn fido_cbor_info_new . | ||
73 | On return, | ||
74 | .Fa *ci_p | ||
75 | is set to NULL. | ||
76 | Either | ||
77 | .Fa ci_p | ||
78 | or | ||
79 | .Fa *ci_p | ||
80 | may be NULL, in which case | ||
81 | .Fn fido_cbor_info_free | ||
82 | is a NOP. | ||
83 | .Pp | ||
84 | The | ||
85 | .Fn fido_dev_get_cbor_info | ||
86 | function transmits a | ||
87 | .Dv CTAP_CBOR_GETINFO | ||
88 | command to | ||
89 | .Fa dev | ||
90 | and fills | ||
91 | .Fa ci | ||
92 | with attributes retrieved from the command's response. | ||
93 | The | ||
94 | .Fn fido_dev_get_cbor_info | ||
95 | function may block. | ||
96 | .Pp | ||
97 | The | ||
98 | .Fn fido_cbor_info_aaguid_ptr , | ||
99 | .Fn fido_cbor_info_extensions_ptr , | ||
100 | .Fn fido_cbor_info_protocols_ptr , | ||
101 | and | ||
102 | .Fn fido_cbor_info_versions_ptr | ||
103 | functions return pointers to the AAGUID, supported extensions, | ||
104 | PIN protocol and CTAP version strings of | ||
105 | .Fa ci . | ||
106 | The corresponding length of a given attribute can be | ||
107 | obtained by | ||
108 | .Fn fido_cbor_info_aaguid_len , | ||
109 | .Fn fido_cbor_info_extensions_len , | ||
110 | .Fn fido_cbor_info_protocols_len , | ||
111 | or | ||
112 | .Fn fido_cbor_info_versions_len . | ||
113 | .Pp | ||
114 | The | ||
115 | .Fn fido_cbor_info_options_name_ptr | ||
116 | and | ||
117 | .Fn fido_cbor_info_options_value_ptr | ||
118 | functions return pointers to the array of option names and their | ||
119 | respective values | ||
120 | in | ||
121 | .Fa ci . | ||
122 | The length of the options array is returned by | ||
123 | .Fn fido_cbor_info_options_len . | ||
124 | .Pp | ||
125 | The | ||
126 | .Fn fido_cbor_info_maxmsgsiz | ||
127 | function returns the maximum message size of | ||
128 | .Fa ci . | ||
129 | .Pp | ||
130 | A complete example of how to use these functions can be found in the | ||
131 | .Pa example/info.c | ||
132 | file shipped with | ||
133 | .Em libfido2 . | ||
134 | .Sh RETURN VALUES | ||
135 | The | ||
136 | .Fn fido_cbor_info_aaguid_ptr , | ||
137 | .Fn fido_cbor_info_extensions_ptr , | ||
138 | .Fn fido_cbor_info_protocols_ptr , | ||
139 | .Fn fido_cbor_info_versions_ptr , | ||
140 | .Fn fido_cbor_info_options_name_ptr , | ||
141 | and | ||
142 | .Fn fido_cbor_info_options_value_ptr | ||
143 | functions return NULL if the respective field in | ||
144 | .Fa ci | ||
145 | is absent. | ||
146 | If not NULL, returned pointers are guaranteed to exist until any | ||
147 | API function that takes | ||
148 | .Fa ci | ||
149 | without the | ||
150 | .Em const | ||
151 | qualifier is invoked. | ||
152 | .Sh SEE ALSO | ||
153 | .Xr fido_dev_open 3 | ||
diff --git a/man/fido_cred_exclude.3 b/man/fido_cred_exclude.3 new file mode 100644 index 0000000..700d6af --- /dev/null +++ b/man/fido_cred_exclude.3 | |||
@@ -0,0 +1,60 @@ | |||
1 | .\" Copyright (c) 2018 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: May 23 2018 $ | ||
6 | .Dt FIDO_CRED_EXCLUDE 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_cred_exclude | ||
10 | .Nd appends a credential ID to a credential's list of excluded credentials | ||
11 | .Sh SYNOPSIS | ||
12 | .In fido.h | ||
13 | .Ft int | ||
14 | .Fn fido_cred_exclude "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" | ||
15 | .Sh DESCRIPTION | ||
16 | The | ||
17 | .Fn fido_cred_exclude | ||
18 | function adds | ||
19 | .Fa ptr | ||
20 | to the list of credentials excluded by | ||
21 | .Fa cred , | ||
22 | where | ||
23 | .Fa ptr | ||
24 | points to a credential ID of | ||
25 | .Fa len | ||
26 | bytes. | ||
27 | A copy of | ||
28 | .Fa ptr | ||
29 | is made, and no references to the passed pointer are kept. | ||
30 | If | ||
31 | .Fn fido_cred_exclude | ||
32 | fails, the existing list of excluded credentials is preserved. | ||
33 | .Pp | ||
34 | If | ||
35 | .Nm | ||
36 | returns success and | ||
37 | .Fa cred | ||
38 | is later passed to | ||
39 | .Xr fido_dev_make_cred 3 | ||
40 | on a device that contains the credential | ||
41 | denoted by | ||
42 | .Fa ptr , | ||
43 | then | ||
44 | .Xr fido_dev_make_cred 3 | ||
45 | will fail. | ||
46 | .Pp | ||
47 | For the format of a FIDO 2 credential ID, please refer to the | ||
48 | Web Authentication (webauthn) standard. | ||
49 | .Sh RETURN VALUES | ||
50 | The error codes returned by | ||
51 | .Fn fido_cred_exclude | ||
52 | are defined in | ||
53 | .In fido/err.h . | ||
54 | On success, | ||
55 | .Dv FIDO_OK | ||
56 | is returned. | ||
57 | .Sh SEE ALSO | ||
58 | .Xr fido_cred_new 3 , | ||
59 | .Xr fido_cred_set_authdata 3 , | ||
60 | .Xr fido_dev_make_cred 3 | ||
diff --git a/man/fido_cred_new.3 b/man/fido_cred_new.3 new file mode 100644 index 0000000..47eeba8 --- /dev/null +++ b/man/fido_cred_new.3 | |||
@@ -0,0 +1,157 @@ | |||
1 | .\" Copyright (c) 2018 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: May 23 2018 $ | ||
6 | .Dt FIDO_CRED_NEW 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_cred_new , | ||
10 | .Nm fido_cred_free , | ||
11 | .Nm fido_cred_fmt , | ||
12 | .Nm fido_cred_authdata_ptr , | ||
13 | .Nm fido_cred_clientdata_hash_ptr , | ||
14 | .Nm fido_cred_id_ptr , | ||
15 | .Nm fido_cred_pubkey_ptr , | ||
16 | .Nm fido_cred_sig_ptr , | ||
17 | .Nm fido_cred_x5c_ptr , | ||
18 | .Nm fido_cred_authdata_len , | ||
19 | .Nm fido_cred_clientdata_hash_len , | ||
20 | .Nm fido_cred_id_len , | ||
21 | .Nm fido_cred_pubkey_len , | ||
22 | .Nm fido_cred_sig_len , | ||
23 | .Nm fido_cred_x5c_len | ||
24 | .Nd FIDO 2 credential API | ||
25 | .Sh SYNOPSIS | ||
26 | .In fido.h | ||
27 | .Ft fido_cred_t * | ||
28 | .Fn fido_cred_new "void" | ||
29 | .Ft void | ||
30 | .Fn fido_cred_free "fido_cred_t **cred_p" | ||
31 | .Ft const char * | ||
32 | .Fn fido_cred_fmt "const fido_cred_t *cred" | ||
33 | .Ft const unsigned char * | ||
34 | .Fn fido_cred_authdata_ptr "const fido_cred_t *cred" | ||
35 | .Ft const unsigned char * | ||
36 | .Fn fido_cred_clientdata_hash_ptr "const fido_cred_t *cred" | ||
37 | .Ft const unsigned char * | ||
38 | .Fn fido_cred_id_ptr "const fido_cred_t *cred" | ||
39 | .Ft const unsigned char * | ||
40 | .Fn fido_cred_pubkey_ptr "const fido_cred_t *cred" | ||
41 | .Ft const unsigned char * | ||
42 | .Fn fido_cred_sig_ptr "const fido_cred_t *cred" | ||
43 | .Ft const unsigned char * | ||
44 | .Fn fido_cred_x5c_ptr "const fido_cred_t *cred" | ||
45 | .Ft size_t | ||
46 | .Fn fido_cred_authdata_len "const fido_cred_t *cred" | ||
47 | .Ft size_t | ||
48 | .Fn fido_cred_clientdata_hash_len "const fido_cred_t *cred" | ||
49 | .Ft size_t | ||
50 | .Fn fido_cred_id_len "const fido_cred_t *cred" | ||
51 | .Ft size_t | ||
52 | .Fn fido_cred_pubkey_len "const fido_cred_t *cred" | ||
53 | .Ft size_t | ||
54 | .Fn fido_cred_sig_len "const fido_cred_t *cred" | ||
55 | .Ft size_t | ||
56 | .Fn fido_cred_x5c_len "const fido_cred_t *cred" | ||
57 | .Sh DESCRIPTION | ||
58 | FIDO 2 credentials are abstracted in | ||
59 | .Em libfido2 | ||
60 | by the | ||
61 | .Vt fido_cred_t | ||
62 | type. | ||
63 | The functions described in this page allow a | ||
64 | .Vt fido_cred_t | ||
65 | type to be allocated, deallocated, and inspected. | ||
66 | For other operations on | ||
67 | .Vt fido_cred_t , | ||
68 | please refer to | ||
69 | .Xr fido_cred_set_authdata 3 , | ||
70 | .Xr fido_cred_exclude 3 , | ||
71 | .Xr fido_cred_verify 3 , | ||
72 | and | ||
73 | .Xr fido_dev_make_cred 3 . | ||
74 | .Pp | ||
75 | The | ||
76 | .Fn fido_cred_new | ||
77 | function returns a pointer to a newly allocated, empty | ||
78 | .Vt fido_cred_t | ||
79 | type. | ||
80 | If memory cannot be allocated, NULL is returned. | ||
81 | .Pp | ||
82 | The | ||
83 | .Fn fido_cred_free | ||
84 | function releases the memory backing | ||
85 | .Fa *cred_p , | ||
86 | where | ||
87 | .Fa *cred_p | ||
88 | must have been previously allocated by | ||
89 | .Fn fido_cred_new . | ||
90 | On return, | ||
91 | .Fa *cred_p | ||
92 | is set to NULL. | ||
93 | Either | ||
94 | .Fa cred_p | ||
95 | or | ||
96 | .Fa *cred_p | ||
97 | may be NULL, in which case | ||
98 | .Fn fido_cred_free | ||
99 | is a NOP. | ||
100 | .Pp | ||
101 | The | ||
102 | .Fn fido_cred_fmt | ||
103 | function returns a pointer to a NUL-terminated string containing | ||
104 | the format of | ||
105 | .Fa cred , | ||
106 | or NULL if | ||
107 | .Fa cred | ||
108 | does not have a format set. | ||
109 | .Pp | ||
110 | The | ||
111 | .Fn fido_cred_authdata_ptr , | ||
112 | .Fn fido_cred_clientdata_hash_ptr , | ||
113 | .Fn fido_cred_id_ptr , | ||
114 | .Fn fido_cred_pubkey_ptr , | ||
115 | .Fn fido_cred_sig_ptr , | ||
116 | and | ||
117 | .Fn fido_cred_x5c_ptr | ||
118 | functions return pointers to the authenticator data, client data | ||
119 | hash, ID, public key, signature and x509 certificate parts of | ||
120 | .Fa cred , | ||
121 | or NULL if the respective entry is not set. | ||
122 | .Pp | ||
123 | The corresponding length can be obtained by | ||
124 | .Fn fido_cred_authdata_len , | ||
125 | .Fn fido_cred_clientdata_hash_len , | ||
126 | .Fn fido_cred_id_len , | ||
127 | .Fn fido_cred_pubkey_len , | ||
128 | and | ||
129 | .Fn fido_cred_sig_len . | ||
130 | .Pp | ||
131 | The authenticator data, x509 certificate, and signature parts of a | ||
132 | credential are typically passed to a FIDO 2 server for verification. | ||
133 | .Sh RETURN VALUES | ||
134 | The authenticator data returned by | ||
135 | .Fn fido_cred_authdata_ptr | ||
136 | is a CBOR-encoded byte string, as obtained from the authenticator. | ||
137 | .Pp | ||
138 | If not NULL, pointers returned by | ||
139 | .Fn fido_cred_fmt , | ||
140 | .Fn fido_cred_authdata_ptr , | ||
141 | .Fn fido_cred_clientdata_hash_ptr , | ||
142 | .Fn fido_cred_id_ptr , | ||
143 | .Fn fido_cred_pubkey_ptr , | ||
144 | .Fn fido_cred_sig_ptr , | ||
145 | and | ||
146 | .Fn fido_cred_x5c_ptr | ||
147 | are guaranteed to exist until any API function that takes | ||
148 | .Fa cred | ||
149 | without the | ||
150 | .Em const | ||
151 | qualifier is invoked. | ||
152 | .Sh SEE ALSO | ||
153 | .Xr fido_cred_exclude 3 , | ||
154 | .Xr fido_cred_set_authdata 3 , | ||
155 | .Xr fido_cred_verify 3 , | ||
156 | .Xr fido_credman_metadata_new 3 , | ||
157 | .Xr fido_dev_make_cred 3 | ||
diff --git a/man/fido_cred_set_authdata.3 b/man/fido_cred_set_authdata.3 new file mode 100644 index 0000000..8b087fa --- /dev/null +++ b/man/fido_cred_set_authdata.3 | |||
@@ -0,0 +1,240 @@ | |||
1 | .\" Copyright (c) 2018 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: May 23 2018 $ | ||
6 | .Dt FIDO_CRED_SET_AUTHDATA 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_cred_set_authdata , | ||
10 | .Nm fido_cred_set_authdata_raw , | ||
11 | .Nm fido_cred_set_x509 , | ||
12 | .Nm fido_cred_set_sig , | ||
13 | .Nm fido_cred_set_clientdata_hash , | ||
14 | .Nm fido_cred_set_rp , | ||
15 | .Nm fido_cred_set_user , | ||
16 | .Nm fido_cred_set_extensions , | ||
17 | .Nm fido_cred_set_rk , | ||
18 | .Nm fido_cred_set_uv , | ||
19 | .Nm fido_cred_set_fmt , | ||
20 | .Nm fido_cred_set_type | ||
21 | .Nd set parameters of a FIDO 2 credential | ||
22 | .Sh SYNOPSIS | ||
23 | .In fido.h | ||
24 | .Bd -literal | ||
25 | typedef enum { | ||
26 | FIDO_OPT_OMIT = 0, /* use authenticator's default */ | ||
27 | FIDO_OPT_FALSE, /* explicitly set option to false */ | ||
28 | FIDO_OPT_TRUE, /* explicitly set option to true */ | ||
29 | } fido_opt_t; | ||
30 | .Ed | ||
31 | .Ft int | ||
32 | .Fn fido_cred_set_authdata "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" | ||
33 | .Ft int | ||
34 | .Fn fido_cred_set_authdata_raw "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" | ||
35 | .Ft int | ||
36 | .Fn fido_cred_set_x509 "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" | ||
37 | .Ft int | ||
38 | .Fn fido_cred_set_sig "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" | ||
39 | .Ft int | ||
40 | .Fn fido_cred_set_clientdata_hash "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" | ||
41 | .Ft int | ||
42 | .Fn fido_cred_set_rp "fido_cred_t *cred" "const char *id" "const char *name" | ||
43 | .Ft int | ||
44 | .Fn fido_cred_set_user "fido_cred_t *cred" "const unsigned char *user_id" "size_t user_id_len" "const char *name" "const char *display_name" "const char *icon" | ||
45 | .Ft int | ||
46 | .Fn fido_cred_set_extensions "fido_cred_t *cred" "int flags" | ||
47 | .Ft int | ||
48 | .Fn fido_cred_set_rk "fido_cred_t *cred" "fido_opt_t rk" | ||
49 | .Ft int | ||
50 | .Fn fido_cred_set_uv "fido_cred_t *cred" "fido_opt_t uv" | ||
51 | .Ft int | ||
52 | .Fn fido_cred_set_fmt "fido_cred_t *cred" "const char *ptr" | ||
53 | .Ft int | ||
54 | .Fn fido_cred_set_type "fido_cred_t *cred" "int cose_alg" | ||
55 | .Sh DESCRIPTION | ||
56 | The | ||
57 | .Nm | ||
58 | set of functions define the various parameters of a FIDO 2 | ||
59 | credential, allowing a | ||
60 | .Fa fido_cred_t | ||
61 | type to be prepared for a subsequent call to | ||
62 | .Xr fido_dev_make_cred 3 | ||
63 | or | ||
64 | .Xr fido_cred_verify 3 . | ||
65 | For the complete specification of a FIDO 2 credential and the format | ||
66 | of its constituent parts, please refer to the Web Authentication | ||
67 | (webauthn) standard. | ||
68 | .Pp | ||
69 | The | ||
70 | .Fn fido_cred_set_authdata , | ||
71 | .Fn fido_cred_set_x509 , | ||
72 | .Fn fido_cred_set_sig , | ||
73 | and | ||
74 | .Fn fido_cred_set_clientdata_hash | ||
75 | functions set the authenticator data, attestation certificate, | ||
76 | signature and client data hash parts of | ||
77 | .Fa cred | ||
78 | to | ||
79 | .Fa ptr , | ||
80 | where | ||
81 | .Fa ptr | ||
82 | points to | ||
83 | .Fa len | ||
84 | bytes. | ||
85 | A copy of | ||
86 | .Fa ptr | ||
87 | is made, and no references to the passed pointer are kept. | ||
88 | The authenticator data passed to | ||
89 | .Fn fido_cred_set_authdata | ||
90 | must be a CBOR-encoded byte string, as obtained from | ||
91 | .Fn fido_cred_authdata_ptr . | ||
92 | Alternatively, a raw binary blob may be passed to | ||
93 | .Fn fido_cred_set_authdata_raw . | ||
94 | .Pp | ||
95 | The | ||
96 | .Fn fido_cred_set_rp | ||
97 | function sets the relying party | ||
98 | .Fa id | ||
99 | and | ||
100 | .Fa name | ||
101 | parameters of | ||
102 | .Fa cred , | ||
103 | where | ||
104 | .Fa id | ||
105 | and | ||
106 | .Fa name | ||
107 | are NUL-terminated UTF-8 strings. | ||
108 | The contents of | ||
109 | .Fa id | ||
110 | and | ||
111 | .Fa name | ||
112 | are copied, and no references to the passed pointers are kept. | ||
113 | .Pp | ||
114 | The | ||
115 | .Fn fido_cred_set_user | ||
116 | function sets the user attributes of | ||
117 | .Fa cred , | ||
118 | where | ||
119 | .Fa user_id | ||
120 | points to | ||
121 | .Fa user_id_len | ||
122 | bytes and | ||
123 | .Fa name , | ||
124 | .Fa display_name , | ||
125 | and | ||
126 | .Fa icon | ||
127 | are NUL-terminated UTF-8 strings. | ||
128 | The contents of | ||
129 | .Fa user_id , | ||
130 | .Fa name , | ||
131 | .Fa display_name , | ||
132 | and | ||
133 | .Fa icon | ||
134 | are copied, and no references to the passed pointers are kept. | ||
135 | Previously set user attributes are flushed. | ||
136 | The | ||
137 | .Fa user_id , | ||
138 | .Fa name , | ||
139 | .Fa display_name , | ||
140 | and | ||
141 | .Fa icon | ||
142 | parameters may be NULL. | ||
143 | .Pp | ||
144 | The | ||
145 | .Fn fido_cred_set_extensions | ||
146 | function sets the extensions of | ||
147 | .Fa cred | ||
148 | to the bitmask | ||
149 | .Fa flags . | ||
150 | At the moment, only the | ||
151 | .Dv FIDO_EXT_HMAC_SECRET | ||
152 | extension is supported. | ||
153 | If | ||
154 | .Fa flags | ||
155 | is zero, the extensions of | ||
156 | .Fa cred | ||
157 | are cleared. | ||
158 | .Pp | ||
159 | The | ||
160 | .Fn fido_cred_set_rk | ||
161 | and | ||
162 | .Fn fido_cred_set_uv | ||
163 | functions set the | ||
164 | .Em rk | ||
165 | (resident key) | ||
166 | and | ||
167 | .Em uv | ||
168 | (user verification) | ||
169 | attributes of | ||
170 | .Fa cred . | ||
171 | Both are | ||
172 | .Dv FIDO_OPT_OMIT | ||
173 | by default, allowing the authenticator to use its default settings. | ||
174 | .Pp | ||
175 | The | ||
176 | .Fn fido_cred_set_fmt | ||
177 | function sets the format of | ||
178 | .Fa cred | ||
179 | to | ||
180 | .Fa fmt , | ||
181 | where | ||
182 | .Fa fmt | ||
183 | must be either | ||
184 | .Vt "packed" | ||
185 | (the format used in FIDO 2) | ||
186 | or | ||
187 | .Vt "fido-u2f" | ||
188 | (the format used by U2F). | ||
189 | A copy of | ||
190 | .Fa fmt | ||
191 | is made, and no references to the passed pointer are kept. | ||
192 | Note that not all authenticators support FIDO2 and therefore may not | ||
193 | be able to generate | ||
194 | .Vt "packed" . | ||
195 | .Pp | ||
196 | The | ||
197 | .Fn fido_cred_set_type | ||
198 | function sets the type of | ||
199 | .Fa cred to | ||
200 | .Fa cose_alg , | ||
201 | where | ||
202 | .Fa cose_alg | ||
203 | is | ||
204 | .Dv COSE_ES256 , | ||
205 | .Dv COSE_RS256 , | ||
206 | or | ||
207 | .Dv COSE_EDDSA . | ||
208 | The type of a credential may only be set once. | ||
209 | Note that not all authenticators support COSE_RS256 or COSE_EDDSA. | ||
210 | .Pp | ||
211 | Use of the | ||
212 | .Nm | ||
213 | set of functions may happen in two distinct situations: | ||
214 | when generating a new credential on a FIDO device, prior to | ||
215 | .Xr fido_dev_make_cred 3 | ||
216 | (i.e, in the context of a FIDO client), or when validating | ||
217 | a generated credential using | ||
218 | .Xr fido_cred_verify 3 | ||
219 | (i.e, in the context of a FIDO server). | ||
220 | .Pp | ||
221 | For a complete description of the generation of a FIDO 2 credential | ||
222 | and its verification, please refer to the FIDO 2 specification. | ||
223 | A concrete utilisation example of the | ||
224 | .Nm | ||
225 | set of functions can be found in the | ||
226 | .Pa cred.c | ||
227 | example shipped with | ||
228 | .Em libfido2 . | ||
229 | .Sh RETURN VALUES | ||
230 | The error codes returned by the | ||
231 | .Nm | ||
232 | set of functions are defined in | ||
233 | .In fido/err.h . | ||
234 | On success, | ||
235 | .Dv FIDO_OK | ||
236 | is returned. | ||
237 | .Sh SEE ALSO | ||
238 | .Xr fido_cred_exclude 3 , | ||
239 | .Xr fido_cred_verify 3 , | ||
240 | .Xr fido_dev_make_cred 3 | ||
diff --git a/man/fido_cred_verify.3 b/man/fido_cred_verify.3 new file mode 100644 index 0000000..c75b9a1 --- /dev/null +++ b/man/fido_cred_verify.3 | |||
@@ -0,0 +1,64 @@ | |||
1 | .\" Copyright (c) 2018 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: May 23 2018 $ | ||
6 | .Dt FIDO_CRED_VERIFY 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_cred_verify | ||
10 | .Nd verifies the signature of a FIDO 2 credential | ||
11 | .Sh SYNOPSIS | ||
12 | .In fido.h | ||
13 | .Ft int | ||
14 | .Fn fido_cred_verify "const fido_cred_t *cred" | ||
15 | .Sh DESCRIPTION | ||
16 | The | ||
17 | .Fn fido_cred_verify | ||
18 | function verifies whether the signature contained in | ||
19 | .Fa cred | ||
20 | matches the attributes of the credential. | ||
21 | Before using | ||
22 | .Fn fido_cred_verify | ||
23 | in a sensitive context, the reader is strongly encouraged to make | ||
24 | herself familiar with the FIDO 2 credential attestation process | ||
25 | as defined in the Web Authentication (webauthn) standard. | ||
26 | .Pp | ||
27 | A brief description follows: | ||
28 | .Pp | ||
29 | The | ||
30 | .Fn fido_cred_verify | ||
31 | function verifies whether the client data hash, relying party ID, | ||
32 | credential ID, type, and resident key and user verification | ||
33 | attributes of | ||
34 | .Fa cred | ||
35 | have been attested by the holder of the private counterpart of | ||
36 | the public key contained in the credential's x509 certificate. | ||
37 | .Pp | ||
38 | Please note that the x509 certificate itself is not verified. | ||
39 | .Pp | ||
40 | The attestation statement formats supported by | ||
41 | .Fn fido_cred_verify | ||
42 | are | ||
43 | .Em packed | ||
44 | and | ||
45 | .Em fido-u2f . | ||
46 | The attestation type implemented by | ||
47 | .Fn fido_cred_verify | ||
48 | is | ||
49 | .Em Basic Attestation . | ||
50 | The attestation key pair is assumed to be of the type ES256. | ||
51 | Other attestation formats and types are not supported. | ||
52 | .Sh RETURN VALUES | ||
53 | The error codes returned by | ||
54 | .Fn fido_cred_verify | ||
55 | are defined in | ||
56 | .In fido/err.h . | ||
57 | If | ||
58 | .Fa cred | ||
59 | passes verification, then | ||
60 | .Dv FIDO_OK | ||
61 | is returned. | ||
62 | .Sh SEE ALSO | ||
63 | .Xr fido_cred_new 3 , | ||
64 | .Xr fido_cred_set_authdata 3 | ||
diff --git a/man/fido_credman_metadata_new.3 b/man/fido_credman_metadata_new.3 new file mode 100644 index 0000000..16f0192 --- /dev/null +++ b/man/fido_credman_metadata_new.3 | |||
@@ -0,0 +1,299 @@ | |||
1 | .\" Copyright (c) 2019 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: June 28 2019 $ | ||
6 | .Dt FIDO_CREDMAN_METADATA_NEW 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_credman_metadata_new , | ||
10 | .Nm fido_credman_rk_new , | ||
11 | .Nm fido_credman_rp_new , | ||
12 | .Nm fido_credman_metadata_free , | ||
13 | .Nm fido_credman_rk_free , | ||
14 | .Nm fido_credman_rp_free , | ||
15 | .Nm fido_credman_rk_existing , | ||
16 | .Nm fido_credman_rk_remaining , | ||
17 | .Nm fido_credman_rk , | ||
18 | .Nm fido_credman_rk_count , | ||
19 | .Nm fido_credman_rp_id , | ||
20 | .Nm fido_credman_rp_name , | ||
21 | .Nm fido_credman_rp_count , | ||
22 | .Nm fido_credman_rp_id_hash_ptr , | ||
23 | .Nm fido_credman_rp_id_hash_len , | ||
24 | .Nm fido_credman_get_dev_metadata , | ||
25 | .Nm fido_credman_get_dev_rk , | ||
26 | .Nm fido_credman_del_dev_rk , | ||
27 | .Nm fido_credman_get_dev_rp | ||
28 | .Nd FIDO 2 credential management API | ||
29 | .Sh SYNOPSIS | ||
30 | .In fido.h | ||
31 | .In fido/credman.h | ||
32 | .Ft fido_credman_metadata_t * | ||
33 | .Fn fido_credman_metadata_new "void" | ||
34 | .Ft fido_credman_rk_t * | ||
35 | .Fn fido_credman_rk_new "void" | ||
36 | .Ft fido_credman_rp_t * | ||
37 | .Fn fido_credman_rp_new "void" | ||
38 | .Ft void | ||
39 | .Fn fido_credman_metadata_free "fido_credman_metadata_t **metadata_p" | ||
40 | .Ft void | ||
41 | .Fn fido_credman_rk_free "fido_credman_rk_t **rk_p" | ||
42 | .Ft void | ||
43 | .Fn fido_credman_rp_free "fido_credman_rp_t **rp_p" | ||
44 | .Ft uint64_t | ||
45 | .Fn fido_credman_rk_existing "const fido_credman_metadata_t *metadata" | ||
46 | .Ft uint64_t | ||
47 | .Fn fido_credman_rk_remaining "const fido_credman_metadata_t *metadata" | ||
48 | .Ft const fido_cred_t * | ||
49 | .Fn fido_credman_rk "const fido_credman_rk_t *rk" "size_t idx" | ||
50 | .Ft size_t | ||
51 | .Fn fido_credman_rk_count "const fido_credman_rk_t *rk" | ||
52 | .Ft const char * | ||
53 | .Fn fido_credman_rp_id "const fido_credman_rp_t *rp" "size_t idx" | ||
54 | .Ft const char * | ||
55 | .Fn fido_credman_rp_name "const fido_credman_rp_t *rp" "size_t idx" | ||
56 | .Ft size_t | ||
57 | .Fn fido_credman_rp_count "const fido_credman_rp_t *rp" | ||
58 | .Ft const unsigned char * | ||
59 | .Fn fido_credman_rp_id_hash_ptr "const fido_credman_rp_t *rp" "size_t idx" | ||
60 | .Ft size_t | ||
61 | .Fn fido_credman_rp_id_hash_len "const fido_credman_rp_t *" "size_t idx" | ||
62 | .Ft int | ||
63 | .Fn fido_credman_get_dev_metadata "fido_dev_t *dev" "fido_credman_metadata_t *metadata" "const char *pin" | ||
64 | .Ft int | ||
65 | .Fn fido_credman_get_dev_rk "fido_dev_t *dev" "const char *rp_id" "fido_credman_rk_t *rk" "const char *pin" | ||
66 | .Ft int | ||
67 | .Fn fido_credman_del_dev_rk "fido_dev_t *dev" const unsigned char *cred_id" "size_t cred_id_len" "const char *pin" | ||
68 | .Ft int | ||
69 | .Fn fido_credman_get_dev_rp "fido_dev_t *dev" "fido_credman_rp_t *rp" "const char *pin" | ||
70 | .Sh DESCRIPTION | ||
71 | The credential management API of | ||
72 | .Em libfido2 | ||
73 | allows resident credentials on a FIDO2 authenticator to be listed, | ||
74 | inspected, and removed. | ||
75 | Please note that not all authenticators support credential management. | ||
76 | To obtain information on what an authenticator supports, please | ||
77 | refer to | ||
78 | .Xr fido_cbor_info_new 3 . | ||
79 | .Pp | ||
80 | The | ||
81 | .Vt fido_credman_metadata_t | ||
82 | type abstracts credential management metadata. | ||
83 | .Pp | ||
84 | The | ||
85 | .Fn fido_credman_metadata_new | ||
86 | function returns a pointer to a newly allocated, empty | ||
87 | .Vt fido_credman_metadata_t | ||
88 | type. | ||
89 | If memory cannot be allocated, NULL is returned. | ||
90 | .Pp | ||
91 | The | ||
92 | .Fn fido_credman_metadata_free | ||
93 | function releases the memory backing | ||
94 | .Fa *metadata_p , | ||
95 | where | ||
96 | .Fa *metadata_p | ||
97 | must have been previously allocated by | ||
98 | .Fn fido_credman_metadata_new . | ||
99 | On return, | ||
100 | .Fa *metadata_p | ||
101 | is set to NULL. | ||
102 | Either | ||
103 | .Fa metadata_p | ||
104 | or | ||
105 | .Fa *metadata_p | ||
106 | may be NULL, in which case | ||
107 | .Fn fido_credman_metadata_free | ||
108 | is a NOP. | ||
109 | .Pp | ||
110 | The | ||
111 | .Fn fido_credman_get_dev_metadata | ||
112 | function populates | ||
113 | .Fa metadata | ||
114 | with information retrieved from | ||
115 | .Fa dev . | ||
116 | A valid | ||
117 | .Fa pin | ||
118 | must be provided. | ||
119 | .Pp | ||
120 | The | ||
121 | .Fn fido_credman_rk_existing | ||
122 | function inspects | ||
123 | .Fa metadata | ||
124 | and returns the number of resident credentials on the | ||
125 | authenticator. | ||
126 | The | ||
127 | .Fn fido_credman_rk_remaining | ||
128 | function inspects | ||
129 | .Fa metadata | ||
130 | and returns the estimated number of resident credentials that can | ||
131 | be created on the authenticator. | ||
132 | .Pp | ||
133 | The | ||
134 | .Vt fido_credman_rk_t | ||
135 | type abstracts the set of resident credentials belonging to a | ||
136 | given relying party. | ||
137 | .Pp | ||
138 | The | ||
139 | .Fn fido_credman_rk_new | ||
140 | function returns a pointer to a newly allocated, empty | ||
141 | .Vt fido_credman_rk_t | ||
142 | type. | ||
143 | If memory cannot be allocated, NULL is returned. | ||
144 | .Pp | ||
145 | The | ||
146 | .Fn fido_credman_rk_free | ||
147 | function releases the memory backing | ||
148 | .Fa *rk_p , | ||
149 | where | ||
150 | .Fa *rk_p | ||
151 | must have been previously allocated by | ||
152 | .Fn fido_credman_rk_new . | ||
153 | On return, | ||
154 | .Fa *rk_p | ||
155 | is set to NULL. | ||
156 | Either | ||
157 | .Fa rk_p | ||
158 | or | ||
159 | .Fa *rk_p | ||
160 | may be NULL, in which case | ||
161 | .Fn fido_credman_rk_free | ||
162 | is a NOP. | ||
163 | .Pp | ||
164 | The | ||
165 | .Fn fido_credman_get_dev_rk | ||
166 | function populates | ||
167 | .Fa rk | ||
168 | with the set of resident credentials belonging to | ||
169 | .Fa rp_id | ||
170 | in | ||
171 | .Fa dev . | ||
172 | A valid | ||
173 | .Fa pin | ||
174 | must be provided. | ||
175 | .Pp | ||
176 | The | ||
177 | .Fn fido_credman_rk_count | ||
178 | function returns the number of resident credentials in | ||
179 | .Fa rk . | ||
180 | The | ||
181 | .Fn fido_credman_rk | ||
182 | function returns a pointer to the credential at index | ||
183 | .Fa idx | ||
184 | in | ||
185 | .Fa rk . | ||
186 | Please note that the first credential in | ||
187 | .Fa rk | ||
188 | has an | ||
189 | .Fa idx | ||
190 | (index) value of 0. | ||
191 | .Pp | ||
192 | The | ||
193 | .Fn fido_credman_del_dev_rk | ||
194 | function deletes the resident credential identified by | ||
195 | .Fa cred_id | ||
196 | from | ||
197 | .Fa dev , | ||
198 | where | ||
199 | .Fa cred_id | ||
200 | points to | ||
201 | .Fa cred_id_len | ||
202 | bytes. | ||
203 | A valid | ||
204 | .Fa pin | ||
205 | must be provided. | ||
206 | .Pp | ||
207 | The | ||
208 | .Vt fido_credman_rp_t | ||
209 | type abstracts information about a relying party. | ||
210 | .Pp | ||
211 | The | ||
212 | .Fn fido_credman_rp_new | ||
213 | function returns a pointer to a newly allocated, empty | ||
214 | .Vt fido_credman_rp_t | ||
215 | type. | ||
216 | If memory cannot be allocated, NULL is returned. | ||
217 | .Pp | ||
218 | The | ||
219 | .Fn fido_credman_rp_free | ||
220 | function releases the memory backing | ||
221 | .Fa *rp_p , | ||
222 | where | ||
223 | .Fa *rp_p | ||
224 | must have been previously allocated by | ||
225 | .Fn fido_credman_rp_new . | ||
226 | On return, | ||
227 | .Fa *rp_p | ||
228 | is set to NULL. | ||
229 | Either | ||
230 | .Fa rp_p | ||
231 | or | ||
232 | .Fa *rp_p | ||
233 | may be NULL, in which case | ||
234 | .Fn fido_credman_rp_free | ||
235 | is a NOP. | ||
236 | .Pp | ||
237 | The | ||
238 | .Fn fido_credman_get_dev_rp | ||
239 | function populates | ||
240 | .Fa rp | ||
241 | with information about relying parties with resident credentials | ||
242 | in | ||
243 | .Fa dev . | ||
244 | A valid | ||
245 | .Fa pin | ||
246 | must be provided. | ||
247 | .Pp | ||
248 | The | ||
249 | .Fn fido_credman_rp_count | ||
250 | function returns the number of relying parties in | ||
251 | .Fa rp . | ||
252 | .Pp | ||
253 | The | ||
254 | .Fn fido_credman_rp_id | ||
255 | and | ||
256 | .Fn fido_credman_rp_name | ||
257 | functions return pointers to the id and name of relying party | ||
258 | .Fa idx | ||
259 | in | ||
260 | .Fa rp . | ||
261 | If not NULL, the values returned by these functions point to | ||
262 | NUL-terminated UTF-8 strings. | ||
263 | Please note that the first relying party in | ||
264 | .Fa rp | ||
265 | has an | ||
266 | .Fa idx | ||
267 | (index) value of 0. | ||
268 | .Pp | ||
269 | The | ||
270 | .Fn fido_credman_rp_id_hash_ptr | ||
271 | function returns a pointer to the hashed id of relying party | ||
272 | .Fa idx | ||
273 | in | ||
274 | .Fa rp . | ||
275 | The corresponding length can be obtained by | ||
276 | .Fn fido_credman_rp_id_hash_len . | ||
277 | Please note that the first relying party in | ||
278 | .Fa rp | ||
279 | has an | ||
280 | .Fa idx | ||
281 | (index) value of 0. | ||
282 | .Sh RETURN VALUES | ||
283 | The | ||
284 | .Fn fido_credman_get_dev_metadata , | ||
285 | .Fn fido_credman_get_dev_rk , | ||
286 | .Fn fido_credman_del_dev_rk , | ||
287 | and | ||
288 | .Fn fido_credman_get_dev_rp | ||
289 | functions return | ||
290 | .Dv FIDO_OK | ||
291 | on success. | ||
292 | On error, a different error code defined in | ||
293 | .In fido/err.h | ||
294 | is returned. | ||
295 | Functions returning pointers are not guaranteed to succeed, and | ||
296 | should have their return values checked for NULL. | ||
297 | .Sh SEE ALSO | ||
298 | .Xr fido_cbor_info_new 3 , | ||
299 | .Xr fido_cred_new 3 | ||
diff --git a/man/fido_dev_get_assert.3 b/man/fido_dev_get_assert.3 new file mode 100644 index 0000000..2e33fc5 --- /dev/null +++ b/man/fido_dev_get_assert.3 | |||
@@ -0,0 +1,76 @@ | |||
1 | .\" Copyright (c) 2018 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: May 24 2018 $ | ||
6 | .Dt FIDO_DEV_GET_ASSERT 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_dev_get_assert | ||
10 | .Nd obtains an assertion from a FIDO device | ||
11 | .Sh SYNOPSIS | ||
12 | .In fido.h | ||
13 | .Ft int | ||
14 | .Fn fido_dev_get_assert "fido_dev_t *dev" " fido_assert_t *assert" "const char *pin" | ||
15 | .Sh DESCRIPTION | ||
16 | The | ||
17 | .Fn fido_dev_get_assert | ||
18 | function asks the FIDO device represented by | ||
19 | .Fa dev | ||
20 | for an assertion according to the following parameters defined in | ||
21 | .Fa assert : | ||
22 | .Pp | ||
23 | .Bl -dash -compact | ||
24 | .It | ||
25 | .Nm relying party ID ; | ||
26 | .It | ||
27 | .Nm client data hash ; | ||
28 | .It | ||
29 | .Nm list of allowed credential IDs ; | ||
30 | .It | ||
31 | .Nm user presence and user verification attributes . | ||
32 | .El | ||
33 | .Pp | ||
34 | See | ||
35 | .Xr fido_assert_set_authdata 3 | ||
36 | for information on how these values are set. | ||
37 | .Pp | ||
38 | If a PIN is not needed to authenticate the request against | ||
39 | .Fa dev , | ||
40 | then | ||
41 | .Fa pin | ||
42 | may be NULL. | ||
43 | Otherwise | ||
44 | .Fa pin | ||
45 | must point to a NUL-terminated UTF-8 string. | ||
46 | .Pp | ||
47 | After a successful call to | ||
48 | .Fn fido_dev_get_assert , | ||
49 | the | ||
50 | .Xr fido_assert_count 3 , | ||
51 | .Xr fido_assert_user_display_name 3 , | ||
52 | .Xr fido_assert_user_icon 3 , | ||
53 | .Xr fido_assert_user_name 3 , | ||
54 | .Xr fido_assert_authdata_ptr 3 , | ||
55 | .Xr fido_assert_user_id_ptr 3 , | ||
56 | .Xr fido_assert_sig_ptr 3 , | ||
57 | and | ||
58 | .Xr fido_assert_sigcount 3 | ||
59 | functions may be invoked on | ||
60 | .Fa assert | ||
61 | to retrieve the various attributes of the generated assertion. | ||
62 | .Pp | ||
63 | Please note that | ||
64 | .Fn fido_dev_get_assert | ||
65 | is synchronous and will block if necessary. | ||
66 | .Sh RETURN VALUES | ||
67 | The error codes returned by | ||
68 | .Fn fido_dev_get_assert | ||
69 | are defined in | ||
70 | .In fido/err.h . | ||
71 | On success, | ||
72 | .Dv FIDO_OK | ||
73 | is returned. | ||
74 | .Sh SEE ALSO | ||
75 | .Xr fido_assert_new 3 , | ||
76 | .Xr fido_assert_set_authdata 3 | ||
diff --git a/man/fido_dev_info_manifest.3 b/man/fido_dev_info_manifest.3 new file mode 100644 index 0000000..22519e2 --- /dev/null +++ b/man/fido_dev_info_manifest.3 | |||
@@ -0,0 +1,143 @@ | |||
1 | .\" Copyright (c) 2018 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: May 25 2018 $ | ||
6 | .Dt FIDO_DEV_INFO_MANIFEST 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_dev_info_manifest , | ||
10 | .Nm fido_dev_info_new , | ||
11 | .Nm fido_dev_info_free , | ||
12 | .Nm fido_dev_info_ptr , | ||
13 | .Nm fido_dev_info_path , | ||
14 | .Nm fido_dev_info_product , | ||
15 | .Nm fido_dev_info_vendor , | ||
16 | .Nm fido_dev_info_manufacturer_string , | ||
17 | .Nm fido_dev_info_product_string | ||
18 | .Nd FIDO 2 device discovery functions | ||
19 | .Sh SYNOPSIS | ||
20 | .In fido.h | ||
21 | .Ft int | ||
22 | .Fn fido_dev_info_manifest "fido_dev_info_t *devlist" "size_t ilen" "size_t *olen" | ||
23 | .Ft fido_dev_info_t * | ||
24 | .Fn fido_dev_info_new "size_t n" | ||
25 | .Ft void | ||
26 | .Fn fido_dev_info_free "fido_dev_info_t **devlist_p" "size_t n" | ||
27 | .Ft const fido_dev_info_t * | ||
28 | .Fn fido_dev_info_ptr "const fido_dev_info_t *devlist" "size_t i" | ||
29 | .Ft const char * | ||
30 | .Fn fido_dev_info_path "const fido_dev_info_t *di" | ||
31 | .Ft int16_t | ||
32 | .Fn fido_dev_info_product "const fido_dev_info_t *di" | ||
33 | .Ft int16_t | ||
34 | .Fn fido_dev_info_vendor "const fido_dev_info_t *di" | ||
35 | .Ft const char * | ||
36 | .Fn fido_dev_info_manufacturer_string "const fido_dev_info_t *di" | ||
37 | .Ft const char * | ||
38 | .Fn fido_dev_info_product_string "const fido_dev_info_t *di" | ||
39 | .Sh DESCRIPTION | ||
40 | The | ||
41 | .Fn fido_dev_info_manifest | ||
42 | function fills | ||
43 | .Fa devlist | ||
44 | with up to | ||
45 | .Fa ilen | ||
46 | FIDO devices found by the underlying operating system. | ||
47 | Currently only USB HID devices are supported. | ||
48 | The number of discovered devices is returned in | ||
49 | .Fa olen , | ||
50 | where | ||
51 | .Fa olen | ||
52 | is an addressable pointer. | ||
53 | .Pp | ||
54 | The | ||
55 | .Fn fido_dev_info_new | ||
56 | function returns a pointer to a newly allocated, empty device list | ||
57 | with | ||
58 | .Fa n | ||
59 | available slots. | ||
60 | If memory is not available, NULL is returned. | ||
61 | .Pp | ||
62 | The | ||
63 | .Fn fido_dev_info_free | ||
64 | function releases the memory backing | ||
65 | .Fa *devlist_p , | ||
66 | where | ||
67 | .Fa *devlist_p | ||
68 | must have been previously allocated by | ||
69 | .Fn fido_dev_info_new . | ||
70 | The number | ||
71 | .Fa n | ||
72 | of allocated slots must also be provided. | ||
73 | On return, | ||
74 | .Fa *devlist_p | ||
75 | is set to NULL. | ||
76 | Either | ||
77 | .Fa devlist_p | ||
78 | or | ||
79 | .Fa *devlist_p | ||
80 | may be NULL, in which case | ||
81 | .Fn fido_dev_info_free | ||
82 | is a NOP. | ||
83 | .Pp | ||
84 | The | ||
85 | .Fn fido_dev_info_ptr | ||
86 | function returns a pointer to slot number | ||
87 | .Fa i | ||
88 | of | ||
89 | .Fa devlist . | ||
90 | It is the caller's responsibility to ensure that | ||
91 | .Fa i | ||
92 | is bounded. | ||
93 | Please note that the first slot has index 0. | ||
94 | .Pp | ||
95 | The | ||
96 | .Fn fido_dev_info_path | ||
97 | returns the filesystem path or subsystem-specific identification | ||
98 | string of | ||
99 | .Fa di . | ||
100 | .Pp | ||
101 | The | ||
102 | .Fn fido_dev_info_product | ||
103 | function returns the product ID of | ||
104 | .Fa di . | ||
105 | .Pp | ||
106 | The | ||
107 | .Fn fido_dev_info_vendor | ||
108 | function returns the vendor ID of | ||
109 | .Fa di . | ||
110 | .Pp | ||
111 | The | ||
112 | .Fn fido_dev_info_manufacturer_string | ||
113 | function returns the manufacturer string of | ||
114 | .Fa di . | ||
115 | .Pp | ||
116 | The | ||
117 | .Fn fido_dev_info_product_string | ||
118 | function returns the product string of | ||
119 | .Fa di . | ||
120 | .Pp | ||
121 | An example of how to use the functions described in this document | ||
122 | can be found in the | ||
123 | .Pa examples/manifest.c | ||
124 | file shipped with | ||
125 | .Em libfido2 . | ||
126 | .Sh RETURN VALUES | ||
127 | The | ||
128 | .Fn fido_dev_info_manifest | ||
129 | function always returns | ||
130 | .Dv FIDO_OK . | ||
131 | If a discovery error occurs, the | ||
132 | .Fa olen | ||
133 | pointer is set to 0. | ||
134 | .Pp | ||
135 | The pointers returned by | ||
136 | .Fn fido_dev_info_ptr , | ||
137 | .Fn fido_dev_info_path , | ||
138 | .Fn fido_dev_info_manufacturer_string , | ||
139 | and | ||
140 | .Fn fido_dev_info_product_string | ||
141 | are guaranteed to exist until | ||
142 | .Fn fido_dev_info_free | ||
143 | is called on the corresponding device list. | ||
diff --git a/man/fido_dev_make_cred.3 b/man/fido_dev_make_cred.3 new file mode 100644 index 0000000..ccaf788 --- /dev/null +++ b/man/fido_dev_make_cred.3 | |||
@@ -0,0 +1,77 @@ | |||
1 | .\" Copyright (c) 2018 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: May 23 2018 $ | ||
6 | .Dt FIDO_DEV_MAKE_CRED 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_dev_make_cred | ||
10 | .Nd generates a new credential on a FIDO device | ||
11 | .Sh SYNOPSIS | ||
12 | .In fido.h | ||
13 | .Ft int | ||
14 | .Fn fido_dev_make_cred "fido_dev_t *dev" " fido_cred_t *cred" "const char *pin" | ||
15 | .Sh DESCRIPTION | ||
16 | The | ||
17 | .Fn fido_dev_make_cred | ||
18 | function asks the FIDO device represented by | ||
19 | .Fa dev | ||
20 | to generate a new credential according to the following parameters | ||
21 | defined in | ||
22 | .Fa cred : | ||
23 | .Pp | ||
24 | .Bl -dash -compact | ||
25 | .It | ||
26 | .Nm type ; | ||
27 | .It | ||
28 | .Nm client data hash ; | ||
29 | .It | ||
30 | .Nm relying party ; | ||
31 | .It | ||
32 | .Nm user attributes ; | ||
33 | .It | ||
34 | .Nm list of excluded credential IDs ; | ||
35 | .It | ||
36 | .Nm resident key and user verification attributes . | ||
37 | .El | ||
38 | .Pp | ||
39 | See | ||
40 | .Xr fido_cred_set_authdata 3 | ||
41 | for information on how these values are set. | ||
42 | .Pp | ||
43 | If a PIN is not needed to authenticate the request against | ||
44 | .Fa dev , | ||
45 | then | ||
46 | .Fa pin | ||
47 | may be NULL. | ||
48 | Otherwise | ||
49 | .Fa pin | ||
50 | must point to a NUL-terminated UTF-8 string. | ||
51 | .Pp | ||
52 | After a successful call to | ||
53 | .Fn fido_dev_make_cred , | ||
54 | the | ||
55 | .Xr fido_cred_authdata_ptr 3 , | ||
56 | .Xr fido_cred_pubkey_ptr 3 , | ||
57 | .Xr fido_cred_x5c_ptr 3 , | ||
58 | and | ||
59 | .Xr fido_cred_sig_ptr 3 | ||
60 | functions may be invoked on | ||
61 | .Fa cred | ||
62 | to retrieve the various parts of the generated credential. | ||
63 | .Pp | ||
64 | Please note that | ||
65 | .Fn fido_dev_make_cred | ||
66 | is synchronous and will block if necessary. | ||
67 | .Sh RETURN VALUES | ||
68 | The error codes returned by | ||
69 | .Fn fido_dev_make_cred | ||
70 | are defined in | ||
71 | .In fido/err.h . | ||
72 | On success, | ||
73 | .Dv FIDO_OK | ||
74 | is returned. | ||
75 | .Sh SEE ALSO | ||
76 | .Xr fido_cred_new 3 , | ||
77 | .Xr fido_cred_set_authdata 3 | ||
diff --git a/man/fido_dev_open.3 b/man/fido_dev_open.3 new file mode 100644 index 0000000..53e3a12 --- /dev/null +++ b/man/fido_dev_open.3 | |||
@@ -0,0 +1,159 @@ | |||
1 | .\" Copyright (c) 2018 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: May 25 2018 $ | ||
6 | .Dt FIDO_DEV_OPEN 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_dev_open , | ||
10 | .Nm fido_dev_close , | ||
11 | .Nm fido_dev_cancel , | ||
12 | .Nm fido_dev_new , | ||
13 | .Nm fido_dev_free , | ||
14 | .Nm fido_dev_force_fido2 , | ||
15 | .Nm fido_dev_force_u2f , | ||
16 | .Nm fido_dev_is_fido2 , | ||
17 | .Nm fido_dev_protocol , | ||
18 | .Nm fido_dev_build , | ||
19 | .Nm fido_dev_flags , | ||
20 | .Nm fido_dev_major , | ||
21 | .Nm fido_dev_minor | ||
22 | .Nd FIDO 2 device open/close and related functions | ||
23 | .Sh SYNOPSIS | ||
24 | .In fido.h | ||
25 | .Ft int | ||
26 | .Fn fido_dev_open "fido_dev_t *dev" "const char *path" | ||
27 | .Ft int | ||
28 | .Fn fido_dev_close "fido_dev_t *dev" | ||
29 | .Ft int | ||
30 | .Fn fido_dev_cancel "fido_dev_t *dev" | ||
31 | .Ft fido_dev_t * | ||
32 | .Fn fido_dev_new "void" | ||
33 | .Ft void | ||
34 | .Fn fido_dev_free "fido_dev_t **dev_p" | ||
35 | .Ft void | ||
36 | .Fn fido_dev_force_fido2 "fido_dev_t *dev" | ||
37 | .Ft void | ||
38 | .Fn fido_dev_force_u2f "fido_dev_t *dev" | ||
39 | .Ft bool | ||
40 | .Fn fido_dev_is_fido2 "const fido_dev_t *dev" | ||
41 | .Ft uint8_t | ||
42 | .Fn fido_dev_protocol "const fido_dev_t *dev" | ||
43 | .Ft uint8_t | ||
44 | .Fn fido_dev_build "const fido_dev_t *dev" | ||
45 | .Ft uint8_t | ||
46 | .Fn fido_dev_flags "const fido_dev_t *dev" | ||
47 | .Ft uint8_t | ||
48 | .Fn fido_dev_major "const fido_dev_t *dev" | ||
49 | .Ft uint8_t | ||
50 | .Fn fido_dev_minor "const fido_dev_t *dev" | ||
51 | .Sh DESCRIPTION | ||
52 | The | ||
53 | .Fn fido_dev_open | ||
54 | function opens the device pointed to by | ||
55 | .Fa path , | ||
56 | where | ||
57 | .Fa dev | ||
58 | is a freshly allocated or otherwise closed | ||
59 | .Vt fido_dev_t . | ||
60 | .Pp | ||
61 | The | ||
62 | .Fn fido_dev_close | ||
63 | function closes the device represented by | ||
64 | .Fa dev . | ||
65 | If | ||
66 | .Fa dev | ||
67 | is already closed, | ||
68 | .Fn fido_dev_close | ||
69 | is a NOP. | ||
70 | .Pp | ||
71 | The | ||
72 | .Fn fido_dev_cancel | ||
73 | function cancels any pending requests on | ||
74 | .Fa dev . | ||
75 | .Pp | ||
76 | The | ||
77 | .Fn fido_dev_new | ||
78 | function returns a pointer to a newly allocated, empty | ||
79 | .Vt fido_dev_t . | ||
80 | If memory cannot be allocated, NULL is returned. | ||
81 | .Pp | ||
82 | The | ||
83 | .Fn fido_dev_free | ||
84 | function releases the memory backing | ||
85 | .Fa *dev_p , | ||
86 | where | ||
87 | .Fa *dev_p | ||
88 | must have been previously allocated by | ||
89 | .Fn fido_dev_new . | ||
90 | On return, | ||
91 | .Fa *dev_p | ||
92 | is set to NULL. | ||
93 | Either | ||
94 | .Fa dev_p | ||
95 | or | ||
96 | .Fa *dev_p | ||
97 | may be NULL, in which case | ||
98 | .Fn fido_dev_free | ||
99 | is a NOP. | ||
100 | .Pp | ||
101 | The | ||
102 | .Fn fido_dev_force_fido2 | ||
103 | function can be used to force CTAP2 communication with | ||
104 | .Fa dev . | ||
105 | .Pp | ||
106 | The | ||
107 | .Fn fido_dev_force_u2f | ||
108 | function can be used to force CTAP1 (U2F) communication with | ||
109 | .Fa dev . | ||
110 | .Pp | ||
111 | The | ||
112 | .Fn fido_dev_is_fido2 | ||
113 | function returns | ||
114 | .Dv true | ||
115 | if | ||
116 | .Fa dev | ||
117 | is a FIDO 2 device. | ||
118 | .Pp | ||
119 | The | ||
120 | .Fn fido_dev_protocol | ||
121 | function returns the CTAPHID protocol version identifier of | ||
122 | .Fa dev . | ||
123 | .Pp | ||
124 | The | ||
125 | .Fn fido_dev_build | ||
126 | function returns the CTAPHID build version number of | ||
127 | .Fa dev . | ||
128 | .Pp | ||
129 | The | ||
130 | .Fn fido_dev_flags | ||
131 | function returns the CTAPHID capabilities flags of | ||
132 | .Fa dev . | ||
133 | .Pp | ||
134 | The | ||
135 | .Fn fido_dev_major | ||
136 | function returns the CTAPHID major version number of | ||
137 | .Fa dev . | ||
138 | .Pp | ||
139 | The | ||
140 | .Fn fido_dev_minor | ||
141 | function returns the CTAPHID minor version number of | ||
142 | .Fa dev . | ||
143 | .Pp | ||
144 | For the format and meaning of the CTAPHID parameters returned by | ||
145 | functions above, please refer to the FIDO Client to Authenticator | ||
146 | Protocol (CTAP) specification. | ||
147 | .Sh RETURN VALUES | ||
148 | On success, | ||
149 | .Fn fido_dev_open | ||
150 | and | ||
151 | .Fn fido_dev_close | ||
152 | return | ||
153 | .Dv FIDO_OK . | ||
154 | On error, a different error code defined in | ||
155 | .In fido/err.h | ||
156 | is returned. | ||
157 | .Sh SEE ALSO | ||
158 | .Xr fido_dev_info_manifest 3 , | ||
159 | .Xr fido_dev_set_io_functions 3 | ||
diff --git a/man/fido_dev_set_io_functions.3 b/man/fido_dev_set_io_functions.3 new file mode 100644 index 0000000..adc4a9e --- /dev/null +++ b/man/fido_dev_set_io_functions.3 | |||
@@ -0,0 +1,95 @@ | |||
1 | .\" Copyright (c) 2018 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: May 25 2018 $ | ||
6 | .Dt FIDO_DEV_SET_IO_FUNCTIONS 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_dev_set_io_functions | ||
10 | .Nd FIDO 2 device I/O interface | ||
11 | .Sh SYNOPSIS | ||
12 | .In fido.h | ||
13 | .Bd -literal | ||
14 | typedef void *fido_dev_io_open_t(const char *); | ||
15 | typedef void fido_dev_io_close_t(void *); | ||
16 | typedef int fido_dev_io_read_t(void *, unsigned char *, size_t, int); | ||
17 | typedef int fido_dev_io_write_t(void *, const unsigned char *, size_t); | ||
18 | |||
19 | typedef struct fido_dev_io { | ||
20 | fido_dev_io_open_t *open; | ||
21 | fido_dev_io_close_t *close; | ||
22 | fido_dev_io_read_t *read; | ||
23 | fido_dev_io_write_t *write; | ||
24 | } fido_dev_io_t; | ||
25 | .Ed | ||
26 | .Ft int | ||
27 | .Fn fido_dev_set_io_functions "fido_dev_t *dev" "const fido_dev_io_t *io" | ||
28 | .Sh DESCRIPTION | ||
29 | The | ||
30 | .Nm | ||
31 | interface defines the I/O handlers used to talk to | ||
32 | .Fa dev . | ||
33 | Its usage is optional. | ||
34 | By default, | ||
35 | .Em libfido2 | ||
36 | will use the operating system's native HID interface to talk to | ||
37 | a FIDO device. | ||
38 | .Pp | ||
39 | A | ||
40 | .Vt fido_dev_io_open_t | ||
41 | function is expected to return a non-NULL opaque pointer on success, | ||
42 | and NULL on error. | ||
43 | The returned opaque pointer is never dereferenced by | ||
44 | .Em libfido2 . | ||
45 | .Pp | ||
46 | A | ||
47 | .Vt fido_dev_io_close_t | ||
48 | function receives the opaque handle obtained from | ||
49 | .Vt fido_dev_io_open_t . | ||
50 | It is not expected to be idempotent. | ||
51 | .Pp | ||
52 | A | ||
53 | .Vt fido_dev_io_read_t | ||
54 | function reads from | ||
55 | .Fa dev . | ||
56 | The first parameter taken is the opaque handle obtained from | ||
57 | .Vt fido_dev_io_open_t . | ||
58 | The read buffer is pointed to by the second parameter, and the | ||
59 | third parameter holds its size. | ||
60 | Finally, the last argument passed to | ||
61 | .Vt fido_dev_io_read_t | ||
62 | is the number of milliseconds the caller is willing to sleep, | ||
63 | should the call need to block. | ||
64 | If this value holds -1, | ||
65 | .Vt fido_dev_io_read_t | ||
66 | may block indefinitely. | ||
67 | The number of bytes read is returned. | ||
68 | On error, -1 is returned. | ||
69 | .Pp | ||
70 | Conversely, a | ||
71 | .Vt fido_dev_io_write_t | ||
72 | function writes to | ||
73 | .Fa dev . | ||
74 | The first parameter taken is the opaque handle returned by | ||
75 | .Vt fido_dev_io_open_t . | ||
76 | The write buffer is pointed to by the second parameter, and the | ||
77 | third parameter holds its size. | ||
78 | A | ||
79 | .Vt fido_dev_io_write_t | ||
80 | function may block. | ||
81 | The number of bytes written is returned. | ||
82 | On error, -1 is returned. | ||
83 | .Pp | ||
84 | No references to | ||
85 | .Fa io | ||
86 | are held by | ||
87 | .Fn fido_dev_set_io_functions . | ||
88 | .Sh RETURN VALUES | ||
89 | On success, | ||
90 | .Fn fido_dev_set_io_functions | ||
91 | returns | ||
92 | .Dv FIDO_OK . | ||
93 | On error, a different error code defined in | ||
94 | .In fido/err.h | ||
95 | is returned. | ||
diff --git a/man/fido_dev_set_pin.3 b/man/fido_dev_set_pin.3 new file mode 100644 index 0000000..94f841b --- /dev/null +++ b/man/fido_dev_set_pin.3 | |||
@@ -0,0 +1,88 @@ | |||
1 | .\" Copyright (c) 2018 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: May 25 2018 $ | ||
6 | .Dt FIDO_DEV_SET_PIN 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_dev_set_pin , | ||
10 | .Nm fido_dev_get_retry_count , | ||
11 | .Nm fido_dev_reset | ||
12 | .Nd FIDO 2 device management functions | ||
13 | .Sh SYNOPSIS | ||
14 | .In fido.h | ||
15 | .Ft int | ||
16 | .Fn fido_dev_set_pin "fido_dev_t *dev" "const char *pin" "const char *oldpin" | ||
17 | .Ft int | ||
18 | .Fn fido_dev_get_retry_count "fido_dev_t *dev" "int *retries" | ||
19 | .Ft int | ||
20 | .Fn fido_dev_reset "fido_dev_t *dev" | ||
21 | .Sh DESCRIPTION | ||
22 | The | ||
23 | .Fn fido_dev_set_pin | ||
24 | function sets the PIN of device | ||
25 | .Fa dev | ||
26 | to | ||
27 | .Fa pin , | ||
28 | where | ||
29 | .Fa pin | ||
30 | is a NUL-terminated UTF-8 string. | ||
31 | If | ||
32 | .Fa oldpin | ||
33 | is not NULL, the device's PIN is changed from | ||
34 | .Fa oldpin | ||
35 | to | ||
36 | .Fa pin , | ||
37 | where | ||
38 | .Fa pin | ||
39 | and | ||
40 | .Fa oldpin | ||
41 | are NUL-terminated UTF-8 strings. | ||
42 | .Pp | ||
43 | The | ||
44 | .Fn fido_dev_get_retry_count | ||
45 | function fills | ||
46 | .Fa retries | ||
47 | with the number of PIN retries left in | ||
48 | .Fa dev | ||
49 | before lock-out, where | ||
50 | .Fa retries | ||
51 | is an addressable pointer. | ||
52 | .Pp | ||
53 | The | ||
54 | .Fn fido_dev_reset | ||
55 | function performs a reset on | ||
56 | .Fa dev , | ||
57 | resetting the device's PIN and erasing credentials stored on the | ||
58 | device. | ||
59 | .Pp | ||
60 | Please note that | ||
61 | .Fn fido_dev_set_pin , | ||
62 | .Fn fido_dev_get_retry_count , | ||
63 | and | ||
64 | .Fn fido_dev_reset | ||
65 | are synchronous and will block if necessary. | ||
66 | .Sh RETURN VALUES | ||
67 | The error codes returned by | ||
68 | .Fn fido_dev_set_pin , | ||
69 | .Fn fido_dev_get_retry_count , | ||
70 | and | ||
71 | .Fn fido_dev_reset | ||
72 | are defined in | ||
73 | .In fido/err.h . | ||
74 | On success, | ||
75 | .Dv FIDO_OK | ||
76 | is returned. | ||
77 | .Sh CAVEATS | ||
78 | Regarding | ||
79 | .Fn fido_dev_reset , | ||
80 | the actual user-flow to perform a reset is outside the scope of the | ||
81 | FIDO2 specification, and may therefore vary depending on the | ||
82 | authenticator. | ||
83 | Yubico authenticators will return | ||
84 | .Dv FIDO_ERR_NOT_ALLOWED | ||
85 | if a reset is issued later than 5 seconds after power-up, and | ||
86 | .Dv FIDO_ERR_ACTION_TIMEOUT | ||
87 | if the user fails to confirm the reset by touching the key | ||
88 | within 30 seconds. | ||
diff --git a/man/fido_init.3 b/man/fido_init.3 new file mode 100644 index 0000000..7f38948 --- /dev/null +++ b/man/fido_init.3 | |||
@@ -0,0 +1,40 @@ | |||
1 | .\" Copyright (c) 2018 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: May 25 2018 $ | ||
6 | .Dt FIDO_INIT 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_init | ||
10 | .Nd initialise the FIDO 2 library | ||
11 | .Sh SYNOPSIS | ||
12 | .In fido.h | ||
13 | .Ft void | ||
14 | .Fn fido_init "int flags" | ||
15 | .Sh DESCRIPTION | ||
16 | The | ||
17 | .Fn fido_init | ||
18 | function initialises the | ||
19 | .Em libfido2 | ||
20 | library. | ||
21 | Its invocation must precede that of any other | ||
22 | .Em libfido2 | ||
23 | function. | ||
24 | If | ||
25 | .Dv FIDO_DEBUG | ||
26 | is set in | ||
27 | .Fa flags , | ||
28 | then | ||
29 | debug output will be emitted by | ||
30 | .Em libfido2 | ||
31 | on | ||
32 | .Em stderr . | ||
33 | Alternatively, the | ||
34 | .Ev FIDO_DEBUG | ||
35 | environment variable may be set. | ||
36 | .Sh SEE ALSO | ||
37 | .Xr fido_assert_new 3 , | ||
38 | .Xr fido_cred_new 3 , | ||
39 | .Xr fido_dev_info_manifest 3 , | ||
40 | .Xr fido_dev_open 3 | ||
diff --git a/man/fido_strerr.3 b/man/fido_strerr.3 new file mode 100644 index 0000000..05c86b9 --- /dev/null +++ b/man/fido_strerr.3 | |||
@@ -0,0 +1,27 @@ | |||
1 | .\" Copyright (c) 2018 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: May 25 2018 $ | ||
6 | .Dt FIDO_STRERR 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm fido_strerr | ||
10 | .Nd FIDO 2 error codes | ||
11 | .Sh SYNOPSIS | ||
12 | .In fido.h | ||
13 | .Ft const char * | ||
14 | .Fn fido_strerr "int n" | ||
15 | .Sh DESCRIPTION | ||
16 | The | ||
17 | .Fn fido_strerr | ||
18 | function translates the error code | ||
19 | .Fa n | ||
20 | into a readable string, | ||
21 | where | ||
22 | .Fa n | ||
23 | is an error code defined in | ||
24 | .In fido/err.h . | ||
25 | .Fn fido_strerr | ||
26 | never returns NULL. | ||
27 | Returned pointers point to static strings. | ||
diff --git a/man/rs256_pk_new.3 b/man/rs256_pk_new.3 new file mode 100644 index 0000000..4ad0ebe --- /dev/null +++ b/man/rs256_pk_new.3 | |||
@@ -0,0 +1,122 @@ | |||
1 | .\" Copyright (c) 2018 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: May 24 2018 $ | ||
6 | .Dt RS256_PK_NEW 3 | ||
7 | .Os | ||
8 | .Sh NAME | ||
9 | .Nm rs256_pk_new , | ||
10 | .Nm rs256_pk_free , | ||
11 | .Nm rs256_pk_from_RSA , | ||
12 | .Nm rs256_pk_from_ptr , | ||
13 | .Nm rs256_pk_to_EVP_PKEY | ||
14 | .Nd FIDO 2 COSE RS256 API | ||
15 | .Sh SYNOPSIS | ||
16 | .In openssl/rsa.h | ||
17 | .In fido/rs256.h | ||
18 | .Ft rs256_pk_t * | ||
19 | .Fn rs256_pk_new "void" | ||
20 | .Ft void | ||
21 | .Fn rs256_pk_free "rs256_pk_t **pkp" | ||
22 | .Ft int | ||
23 | .Fn rs256_pk_from_RSA "rs256_pk_t *pk" "const RSA *rsa" | ||
24 | .Ft int | ||
25 | .Fn rs256_pk_from_ptr "rs256_pk_t *pk" "const void *ptr" "size_t len" | ||
26 | .Ft EVP_PKEY * | ||
27 | .Fn rs256_pk_to_EVP_PKEY "const rs256_pk_t *pk" | ||
28 | .Sh DESCRIPTION | ||
29 | RS256 is the name given in the CBOR Object Signing and Encryption | ||
30 | (COSE) RFC to PKCS#1.5 2048-bit RSA with SHA-256. | ||
31 | The COSE RS256 API of | ||
32 | .Em libfido2 | ||
33 | is an auxiliary API with routines to convert between the different | ||
34 | RSA public key types used in | ||
35 | .Em libfido2 | ||
36 | and | ||
37 | .Em OpenSSL . | ||
38 | .Pp | ||
39 | In | ||
40 | .Em libfido2 , | ||
41 | RS256 public keys are abstracted by the | ||
42 | .Vt rs256_pk_t | ||
43 | type. | ||
44 | .Pp | ||
45 | The | ||
46 | .Fn rs256_pk_new | ||
47 | function returns a pointer to a newly allocated, empty | ||
48 | .Vt rs256_pk_t | ||
49 | type. | ||
50 | If memory cannot be allocated, NULL is returned. | ||
51 | .Pp | ||
52 | The | ||
53 | .Fn rs256_pk_free | ||
54 | function releases the memory backing | ||
55 | .Fa *pkp , | ||
56 | where | ||
57 | .Fa *pkp | ||
58 | must have been previously allocated by | ||
59 | .Fn rs256_pk_new . | ||
60 | On return, | ||
61 | .Fa *pkp | ||
62 | is set to NULL. | ||
63 | Either | ||
64 | .Fa pkp | ||
65 | or | ||
66 | .Fa *pkp | ||
67 | may be NULL, in which case | ||
68 | .Fn rs256_pk_free | ||
69 | is a NOP. | ||
70 | .Pp | ||
71 | The | ||
72 | .Fn rs256_pk_from_RSA | ||
73 | function fills | ||
74 | .Fa pk | ||
75 | with the contents of | ||
76 | .Fa rsa . | ||
77 | No references to | ||
78 | .Fa rsa | ||
79 | are kept. | ||
80 | .Pp | ||
81 | The | ||
82 | .Fn rs256_pk_from_ptr | ||
83 | function fills | ||
84 | .Fa pk | ||
85 | with the contents of | ||
86 | .Fa ptr , | ||
87 | where | ||
88 | .Fa ptr | ||
89 | points to | ||
90 | .Fa len | ||
91 | bytes. | ||
92 | No references to | ||
93 | .Fa ptr | ||
94 | are kept. | ||
95 | .Pp | ||
96 | The | ||
97 | .Fn rs256_pk_to_EVP_PKEY | ||
98 | function converts | ||
99 | .Fa pk | ||
100 | to a newly allocated | ||
101 | .Fa EVP_PKEY | ||
102 | type with a reference count of 1. | ||
103 | No internal references to the returned pointer are kept. | ||
104 | If an error occurs, | ||
105 | .Fn rs256_pk_to_EVP_PKEY | ||
106 | returns NULL. | ||
107 | .Sh RETURN VALUES | ||
108 | The | ||
109 | .Fn rs256_pk_from_RSA | ||
110 | and | ||
111 | .Fn rs256_pk_from_ptr | ||
112 | functions return | ||
113 | .Dv FIDO_OK | ||
114 | on success. | ||
115 | On error, a different error code defined in | ||
116 | .In fido/err.h | ||
117 | is returned. | ||
118 | .Sh SEE ALSO | ||
119 | .Xr eddsa_pk_new 3 , | ||
120 | .Xr es256_pk_new 3 , | ||
121 | .Xr fido_assert_verify 3 , | ||
122 | .Xr fido_cred_pubkey_ptr 3 | ||
diff --git a/man/style.css b/man/style.css new file mode 100644 index 0000000..8c223fa --- /dev/null +++ b/man/style.css | |||
@@ -0,0 +1,24 @@ | |||
1 | * { margin: 0; padding: 0; } | ||
2 | |||
3 | body { | ||
4 | font-family: monospace; | ||
5 | font-size: 1em; | ||
6 | margin: 2% auto; | ||
7 | max-width: 54em; | ||
8 | } | ||
9 | |||
10 | ul { margin-left: 1em; } | ||
11 | a { color: #009900; } | ||
12 | .Sh { font-size: 1em; padding-top: 1em; padding-bottom: 1em; } | ||
13 | .foot { padding-top: 1em; } | ||
14 | |||
15 | table.head, table.foot { width: 100%; } | ||
16 | td.head-rtitle, td.foot-os { text-align: right; } | ||
17 | td.head-vol { text-align: center; } | ||
18 | div.Pp { margin: 1ex 0ex; } | ||
19 | div.Nd, div.Bf, div.Op { display: inline; } | ||
20 | span.Pa, span.Ad { font-style: italic; } | ||
21 | span.Ms { font-weight: bold; } | ||
22 | dl.Bl-diag > dt { font-weight: bold; } | ||
23 | code.Nm, code.Fl, code.Cm, code.Ic, code.In, code.Fd, code.Fn, | ||
24 | code.Cd { font-weight: bold; font-family: inherit; } | ||
diff --git a/openbsd-compat/bsd-getline.c b/openbsd-compat/bsd-getline.c new file mode 100644 index 0000000..52b44f7 --- /dev/null +++ b/openbsd-compat/bsd-getline.c | |||
@@ -0,0 +1,115 @@ | |||
1 | /* $NetBSD: getline.c,v 1.1.1.6 2015/01/02 20:34:27 christos Exp $ */ | ||
2 | |||
3 | /* NetBSD: getline.c,v 1.2 2014/09/16 17:23:50 christos Exp */ | ||
4 | |||
5 | /*- | ||
6 | * Copyright (c) 2011 The NetBSD Foundation, Inc. | ||
7 | * All rights reserved. | ||
8 | * | ||
9 | * This code is derived from software contributed to The NetBSD Foundation | ||
10 | * by Christos Zoulas. | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions | ||
14 | * are met: | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in the | ||
19 | * documentation and/or other materials provided with the distribution. | ||
20 | * | ||
21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | ||
22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||
23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | ||
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
31 | * POSSIBILITY OF SUCH DAMAGE. | ||
32 | */ | ||
33 | |||
34 | /* NETBSD ORIGINAL: external/bsd/file/dist/src/getline.c */ | ||
35 | |||
36 | #include "openbsd-compat.h" | ||
37 | |||
38 | #if 0 | ||
39 | #include "file.h" | ||
40 | #endif | ||
41 | |||
42 | #if !HAVE_GETLINE | ||
43 | #include <stdlib.h> | ||
44 | #include <stdio.h> | ||
45 | #ifdef HAVE_UNISTD_H | ||
46 | #include <unistd.h> | ||
47 | #endif | ||
48 | #include <errno.h> | ||
49 | #include <string.h> | ||
50 | |||
51 | static ssize_t | ||
52 | getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) | ||
53 | { | ||
54 | char *ptr, *eptr; | ||
55 | |||
56 | |||
57 | if (*buf == NULL || *bufsiz == 0) { | ||
58 | if ((*buf = malloc(BUFSIZ)) == NULL) | ||
59 | return -1; | ||
60 | *bufsiz = BUFSIZ; | ||
61 | } | ||
62 | |||
63 | for (ptr = *buf, eptr = *buf + *bufsiz;;) { | ||
64 | int c = fgetc(fp); | ||
65 | if (c == -1) { | ||
66 | if (feof(fp)) { | ||
67 | ssize_t diff = (ssize_t)(ptr - *buf); | ||
68 | if (diff != 0) { | ||
69 | *ptr = '\0'; | ||
70 | return diff; | ||
71 | } | ||
72 | } | ||
73 | return -1; | ||
74 | } | ||
75 | *ptr++ = (char)c; | ||
76 | if (c == delimiter) { | ||
77 | *ptr = '\0'; | ||
78 | return ptr - *buf; | ||
79 | } | ||
80 | if (ptr + 2 >= eptr) { | ||
81 | char *nbuf; | ||
82 | size_t nbufsiz = *bufsiz * 2; | ||
83 | ssize_t d = ptr - *buf; | ||
84 | if ((nbuf = realloc(*buf, nbufsiz)) == NULL) | ||
85 | return -1; | ||
86 | *buf = nbuf; | ||
87 | *bufsiz = nbufsiz; | ||
88 | eptr = nbuf + nbufsiz; | ||
89 | ptr = nbuf + d; | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | |||
94 | ssize_t | ||
95 | getline(char **buf, size_t *bufsiz, FILE *fp) | ||
96 | { | ||
97 | return getdelim(buf, bufsiz, '\n', fp); | ||
98 | } | ||
99 | |||
100 | #endif | ||
101 | |||
102 | #ifdef TEST | ||
103 | int | ||
104 | main(int argc, char *argv[]) | ||
105 | { | ||
106 | char *p = NULL; | ||
107 | ssize_t len; | ||
108 | size_t n = 0; | ||
109 | |||
110 | while ((len = getline(&p, &n, stdin)) != -1) | ||
111 | (void)printf("%" SIZE_T_FORMAT "d %s", len, p); | ||
112 | free(p); | ||
113 | return 0; | ||
114 | } | ||
115 | #endif | ||
diff --git a/openbsd-compat/bsd-getpagesize.c b/openbsd-compat/bsd-getpagesize.c new file mode 100644 index 0000000..903bfc3 --- /dev/null +++ b/openbsd-compat/bsd-getpagesize.c | |||
@@ -0,0 +1,27 @@ | |||
1 | /* Placed in the public domain */ | ||
2 | |||
3 | #include "openbsd-compat.h" | ||
4 | |||
5 | #if !defined(HAVE_GETPAGESIZE) | ||
6 | |||
7 | #ifdef HAVE_UNISTD_H | ||
8 | #include <unistd.h> | ||
9 | #endif | ||
10 | #include <limits.h> | ||
11 | |||
12 | int | ||
13 | getpagesize(void) | ||
14 | { | ||
15 | #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) | ||
16 | long r = sysconf(_SC_PAGESIZE); | ||
17 | if (r > 0 && r < INT_MAX) | ||
18 | return (int)r; | ||
19 | #endif | ||
20 | /* | ||
21 | * This is at the lower end of common values and appropriate for | ||
22 | * our current use of getpagesize() in recallocarray(). | ||
23 | */ | ||
24 | return 4096; | ||
25 | } | ||
26 | |||
27 | #endif /* !defined(HAVE_GETPAGESIZE) */ | ||
diff --git a/openbsd-compat/diff.sh b/openbsd-compat/diff.sh new file mode 100755 index 0000000..f21e7d8 --- /dev/null +++ b/openbsd-compat/diff.sh | |||
@@ -0,0 +1,24 @@ | |||
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 | |||
7 | OPENSSH=$(realpath ../../openssh) | ||
8 | LIBRESSL=$(realpath ../../libressl-2.8.3) | ||
9 | [[ ! -d "${OPENSSH}" || ! -d "${LIBRESSL}" ]] && exit 1 | ||
10 | |||
11 | diff -pu bsd-getpagesize.c ${OPENSSH}/openbsd-compat/bsd-getpagesize.c | ||
12 | diff -pu err.h ${LIBRESSL}/include/compat/err.h | ||
13 | diff -pu explicit_bzero.c ${OPENSSH}/openbsd-compat/explicit_bzero.c | ||
14 | diff -pu explicit_bzero_win32.c ${LIBRESSL}/crypto/compat/explicit_bzero_win.c | ||
15 | diff -pu getopt.h ${OPENSSH}/openbsd-compat/getopt.h | ||
16 | diff -pu getopt_long.c ${OPENSSH}/openbsd-compat/getopt_long.c | ||
17 | diff -pu posix_win.c ${LIBRESSL}/crypto/compat/posix_win.c | ||
18 | diff -pu readpassphrase.c ${OPENSSH}/openbsd-compat/readpassphrase.c | ||
19 | diff -pu readpassphrase.h ${OPENSSH}/openbsd-compat/readpassphrase.h | ||
20 | diff -pu recallocarray.c ${OPENSSH}/openbsd-compat/recallocarray.c | ||
21 | diff -pu strlcat.c ${OPENSSH}/openbsd-compat/strlcat.c | ||
22 | diff -pu strlcpy.c ${OPENSSH}/openbsd-compat/strlcpy.c | ||
23 | diff -pu timingsafe_bcmp.c ${OPENSSH}/openbsd-compat/timingsafe_bcmp.c | ||
24 | diff -pu types.h ${LIBRESSL}/include/compat/sys/types.h | ||
diff --git a/openbsd-compat/err.h b/openbsd-compat/err.h new file mode 100644 index 0000000..394c7bb --- /dev/null +++ b/openbsd-compat/err.h | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * Public domain | ||
3 | * err.h compatibility shim | ||
4 | */ | ||
5 | |||
6 | #ifndef _COMPAT_ERR_H | ||
7 | #define _COMPAT_ERR_H | ||
8 | |||
9 | #if !defined(HAVE_ERR_H) | ||
10 | |||
11 | #include <errno.h> | ||
12 | #include <stdarg.h> | ||
13 | #include <stdlib.h> | ||
14 | #include <stdio.h> | ||
15 | #include <string.h> | ||
16 | |||
17 | #if defined(_MSC_VER) | ||
18 | __declspec(noreturn) | ||
19 | #else | ||
20 | __attribute__((noreturn)) | ||
21 | #endif | ||
22 | static inline void | ||
23 | err(int eval, const char *fmt, ...) | ||
24 | { | ||
25 | int sverrno = errno; | ||
26 | va_list ap; | ||
27 | |||
28 | va_start(ap, fmt); | ||
29 | if (fmt != NULL) { | ||
30 | vfprintf(stderr, fmt, ap); | ||
31 | fprintf(stderr, ": "); | ||
32 | } | ||
33 | va_end(ap); | ||
34 | fprintf(stderr, "%s\n", strerror(sverrno)); | ||
35 | exit(eval); | ||
36 | } | ||
37 | |||
38 | #if defined(_MSC_VER) | ||
39 | __declspec(noreturn) | ||
40 | #else | ||
41 | __attribute__((noreturn)) | ||
42 | #endif | ||
43 | static inline void | ||
44 | errx(int eval, const char *fmt, ...) | ||
45 | { | ||
46 | va_list ap; | ||
47 | |||
48 | va_start(ap, fmt); | ||
49 | if (fmt != NULL) | ||
50 | vfprintf(stderr, fmt, ap); | ||
51 | va_end(ap); | ||
52 | fprintf(stderr, "\n"); | ||
53 | exit(eval); | ||
54 | } | ||
55 | |||
56 | static inline void | ||
57 | warn(const char *fmt, ...) | ||
58 | { | ||
59 | int sverrno = errno; | ||
60 | va_list ap; | ||
61 | |||
62 | va_start(ap, fmt); | ||
63 | if (fmt != NULL) { | ||
64 | vfprintf(stderr, fmt, ap); | ||
65 | fprintf(stderr, ": "); | ||
66 | } | ||
67 | va_end(ap); | ||
68 | fprintf(stderr, "%s\n", strerror(sverrno)); | ||
69 | } | ||
70 | |||
71 | static inline void | ||
72 | warnx(const char *fmt, ...) | ||
73 | { | ||
74 | va_list ap; | ||
75 | |||
76 | va_start(ap, fmt); | ||
77 | if (fmt != NULL) | ||
78 | vfprintf(stderr, fmt, ap); | ||
79 | va_end(ap); | ||
80 | fprintf(stderr, "\n"); | ||
81 | } | ||
82 | |||
83 | #endif /* !defined(HAVE_ERR_H) */ | ||
84 | |||
85 | #endif /* _COMPAT_ERR_H */ | ||
diff --git a/openbsd-compat/explicit_bzero.c b/openbsd-compat/explicit_bzero.c new file mode 100644 index 0000000..ac64e69 --- /dev/null +++ b/openbsd-compat/explicit_bzero.c | |||
@@ -0,0 +1,57 @@ | |||
1 | /* OPENBSD ORIGINAL: lib/libc/string/explicit_bzero.c */ | ||
2 | /* $OpenBSD: explicit_bzero.c,v 1.1 2014/01/22 21:06:45 tedu Exp $ */ | ||
3 | /* | ||
4 | * Public domain. | ||
5 | * Written by Ted Unangst | ||
6 | */ | ||
7 | |||
8 | #include "openbsd-compat.h" | ||
9 | |||
10 | #if !defined(HAVE_EXPLICIT_BZERO) && !defined(_WIN32) | ||
11 | |||
12 | #include <string.h> | ||
13 | |||
14 | /* | ||
15 | * explicit_bzero - don't let the compiler optimize away bzero | ||
16 | */ | ||
17 | |||
18 | #ifdef HAVE_MEMSET_S | ||
19 | |||
20 | void | ||
21 | explicit_bzero(void *p, size_t n) | ||
22 | { | ||
23 | if (n == 0) | ||
24 | return; | ||
25 | (void)memset_s(p, n, 0, n); | ||
26 | } | ||
27 | |||
28 | #else /* HAVE_MEMSET_S */ | ||
29 | |||
30 | /* | ||
31 | * Indirect bzero through a volatile pointer to hopefully avoid | ||
32 | * dead-store optimisation eliminating the call. | ||
33 | */ | ||
34 | static void (* volatile ssh_bzero)(void *, size_t) = bzero; | ||
35 | |||
36 | void | ||
37 | explicit_bzero(void *p, size_t n) | ||
38 | { | ||
39 | if (n == 0) | ||
40 | return; | ||
41 | /* | ||
42 | * clang -fsanitize=memory needs to intercept memset-like functions | ||
43 | * to correctly detect memory initialisation. Make sure one is called | ||
44 | * directly since our indirection trick above successfully confuses it. | ||
45 | */ | ||
46 | #if defined(__has_feature) | ||
47 | # if __has_feature(memory_sanitizer) | ||
48 | memset(p, 0, n); | ||
49 | # endif | ||
50 | #endif | ||
51 | |||
52 | ssh_bzero(p, n); | ||
53 | } | ||
54 | |||
55 | #endif /* HAVE_MEMSET_S */ | ||
56 | |||
57 | #endif /* !defined(HAVE_EXPLICIT_BZERO) && !defined(_WIN32) */ | ||
diff --git a/openbsd-compat/explicit_bzero_win32.c b/openbsd-compat/explicit_bzero_win32.c new file mode 100644 index 0000000..8017aff --- /dev/null +++ b/openbsd-compat/explicit_bzero_win32.c | |||
@@ -0,0 +1,19 @@ | |||
1 | /* | ||
2 | * Public domain. | ||
3 | * Win32 explicit_bzero compatibility shim. | ||
4 | */ | ||
5 | |||
6 | #include "openbsd-compat.h" | ||
7 | |||
8 | #if !defined(HAVE_EXPLICIT_BZERO) && defined(_WIN32) | ||
9 | |||
10 | #include <windows.h> | ||
11 | #include <string.h> | ||
12 | |||
13 | void | ||
14 | explicit_bzero(void *buf, size_t len) | ||
15 | { | ||
16 | SecureZeroMemory(buf, len); | ||
17 | } | ||
18 | |||
19 | #endif /* !defined(HAVE_EXPLICIT_BZERO) && defined(_WIN32) */ | ||
diff --git a/openbsd-compat/getopt.h b/openbsd-compat/getopt.h new file mode 100644 index 0000000..8eb1244 --- /dev/null +++ b/openbsd-compat/getopt.h | |||
@@ -0,0 +1,74 @@ | |||
1 | /* $OpenBSD: getopt.h,v 1.2 2008/06/26 05:42:04 ray Exp $ */ | ||
2 | /* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ | ||
3 | |||
4 | /*- | ||
5 | * Copyright (c) 2000 The NetBSD Foundation, Inc. | ||
6 | * All rights reserved. | ||
7 | * | ||
8 | * This code is derived from software contributed to The NetBSD Foundation | ||
9 | * by Dieter Baron and Thomas Klausner. | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * 1. Redistributions of source code must retain the above copyright | ||
15 | * notice, this list of conditions and the following disclaimer. | ||
16 | * 2. Redistributions in binary form must reproduce the above copyright | ||
17 | * notice, this list of conditions and the following disclaimer in the | ||
18 | * documentation and/or other materials provided with the distribution. | ||
19 | * | ||
20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | ||
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | ||
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
30 | * POSSIBILITY OF SUCH DAMAGE. | ||
31 | */ | ||
32 | |||
33 | #ifndef _GETOPT_H_ | ||
34 | #define _GETOPT_H_ | ||
35 | |||
36 | /* | ||
37 | * GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions | ||
38 | */ | ||
39 | #define no_argument 0 | ||
40 | #define required_argument 1 | ||
41 | #define optional_argument 2 | ||
42 | |||
43 | struct option { | ||
44 | /* name of long option */ | ||
45 | const char *name; | ||
46 | /* | ||
47 | * one of no_argument, required_argument, and optional_argument: | ||
48 | * whether option takes an argument | ||
49 | */ | ||
50 | int has_arg; | ||
51 | /* if not NULL, set *flag to val when option found */ | ||
52 | int *flag; | ||
53 | /* if flag not NULL, value to set *flag to; else return value */ | ||
54 | int val; | ||
55 | }; | ||
56 | |||
57 | int getopt_long(int, char * const *, const char *, | ||
58 | const struct option *, int *); | ||
59 | int getopt_long_only(int, char * const *, const char *, | ||
60 | const struct option *, int *); | ||
61 | #ifndef _GETOPT_DEFINED_ | ||
62 | #define _GETOPT_DEFINED_ | ||
63 | int getopt(int, char * const *, const char *); | ||
64 | int getsubopt(char **, char * const *, char **); | ||
65 | |||
66 | extern char *optarg; /* getopt(3) external variables */ | ||
67 | extern int opterr; | ||
68 | extern int optind; | ||
69 | extern int optopt; | ||
70 | extern int optreset; | ||
71 | extern char *suboptarg; /* getsubopt(3) external variable */ | ||
72 | #endif | ||
73 | |||
74 | #endif /* !_GETOPT_H_ */ | ||
diff --git a/openbsd-compat/getopt_long.c b/openbsd-compat/getopt_long.c new file mode 100644 index 0000000..dabbb46 --- /dev/null +++ b/openbsd-compat/getopt_long.c | |||
@@ -0,0 +1,523 @@ | |||
1 | /* $OpenBSD: getopt_long.c,v 1.25 2011/03/05 22:10:11 guenther Exp $ */ | ||
2 | /* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ | ||
3 | |||
4 | /* | ||
5 | * Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | * | ||
19 | * Sponsored in part by the Defense Advanced Research Projects | ||
20 | * Agency (DARPA) and Air Force Research Laboratory, Air Force | ||
21 | * Materiel Command, USAF, under agreement number F39502-99-1-0512. | ||
22 | */ | ||
23 | /*- | ||
24 | * Copyright (c) 2000 The NetBSD Foundation, Inc. | ||
25 | * All rights reserved. | ||
26 | * | ||
27 | * This code is derived from software contributed to The NetBSD Foundation | ||
28 | * by Dieter Baron and Thomas Klausner. | ||
29 | * | ||
30 | * Redistribution and use in source and binary forms, with or without | ||
31 | * modification, are permitted provided that the following conditions | ||
32 | * are met: | ||
33 | * 1. Redistributions of source code must retain the above copyright | ||
34 | * notice, this list of conditions and the following disclaimer. | ||
35 | * 2. Redistributions in binary form must reproduce the above copyright | ||
36 | * notice, this list of conditions and the following disclaimer in the | ||
37 | * documentation and/or other materials provided with the distribution. | ||
38 | * | ||
39 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | ||
40 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||
41 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
42 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | ||
43 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
44 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
45 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
46 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
47 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
48 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
49 | * POSSIBILITY OF SUCH DAMAGE. | ||
50 | */ | ||
51 | |||
52 | /* OPENBSD ORIGINAL: lib/libc/stdlib/getopt_long.c */ | ||
53 | #include "openbsd-compat.h" | ||
54 | |||
55 | #if !defined(HAVE_GETOPT) | ||
56 | |||
57 | #if 0 | ||
58 | #include <err.h> | ||
59 | #include <getopt.h> | ||
60 | #endif | ||
61 | #include <errno.h> | ||
62 | #include <stdlib.h> | ||
63 | #include <string.h> | ||
64 | #include <stdarg.h> | ||
65 | |||
66 | int opterr = 1; /* if error message should be printed */ | ||
67 | int optind = 1; /* index into parent argv vector */ | ||
68 | int optopt = '?'; /* character checked for validity */ | ||
69 | int optreset; /* reset getopt */ | ||
70 | char *optarg; /* argument associated with option */ | ||
71 | |||
72 | #define PRINT_ERROR ((opterr) && (*options != ':')) | ||
73 | |||
74 | #define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ | ||
75 | #define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ | ||
76 | #define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ | ||
77 | |||
78 | /* return values */ | ||
79 | #define BADCH (int)'?' | ||
80 | #define BADARG ((*options == ':') ? (int)':' : (int)'?') | ||
81 | #define INORDER (int)1 | ||
82 | |||
83 | #define EMSG "" | ||
84 | |||
85 | static int getopt_internal(int, char * const *, const char *, | ||
86 | const struct option *, int *, int); | ||
87 | static int parse_long_options(char * const *, const char *, | ||
88 | const struct option *, int *, int); | ||
89 | static int gcd(int, int); | ||
90 | static void permute_args(int, int, int, char * const *); | ||
91 | |||
92 | static char *place = EMSG; /* option letter processing */ | ||
93 | |||
94 | /* XXX: set optreset to 1 rather than these two */ | ||
95 | static int nonopt_start = -1; /* first non option argument (for permute) */ | ||
96 | static int nonopt_end = -1; /* first option after non options (for permute) */ | ||
97 | |||
98 | /* Error messages */ | ||
99 | static const char recargchar[] = "option requires an argument -- %c"; | ||
100 | static const char recargstring[] = "option requires an argument -- %s"; | ||
101 | static const char ambig[] = "ambiguous option -- %.*s"; | ||
102 | static const char noarg[] = "option doesn't take an argument -- %.*s"; | ||
103 | static const char illoptchar[] = "unknown option -- %c"; | ||
104 | static const char illoptstring[] = "unknown option -- %s"; | ||
105 | |||
106 | /* | ||
107 | * Compute the greatest common divisor of a and b. | ||
108 | */ | ||
109 | static int | ||
110 | gcd(int a, int b) | ||
111 | { | ||
112 | int c; | ||
113 | |||
114 | c = a % b; | ||
115 | while (c != 0) { | ||
116 | a = b; | ||
117 | b = c; | ||
118 | c = a % b; | ||
119 | } | ||
120 | |||
121 | return (b); | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * Exchange the block from nonopt_start to nonopt_end with the block | ||
126 | * from nonopt_end to opt_end (keeping the same order of arguments | ||
127 | * in each block). | ||
128 | */ | ||
129 | static void | ||
130 | permute_args(int panonopt_start, int panonopt_end, int opt_end, | ||
131 | char * const *nargv) | ||
132 | { | ||
133 | int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; | ||
134 | char *swap; | ||
135 | |||
136 | /* | ||
137 | * compute lengths of blocks and number and size of cycles | ||
138 | */ | ||
139 | nnonopts = panonopt_end - panonopt_start; | ||
140 | nopts = opt_end - panonopt_end; | ||
141 | ncycle = gcd(nnonopts, nopts); | ||
142 | cyclelen = (opt_end - panonopt_start) / ncycle; | ||
143 | |||
144 | for (i = 0; i < ncycle; i++) { | ||
145 | cstart = panonopt_end+i; | ||
146 | pos = cstart; | ||
147 | for (j = 0; j < cyclelen; j++) { | ||
148 | if (pos >= panonopt_end) | ||
149 | pos -= nnonopts; | ||
150 | else | ||
151 | pos += nopts; | ||
152 | swap = nargv[pos]; | ||
153 | /* LINTED const cast */ | ||
154 | ((char **) nargv)[pos] = nargv[cstart]; | ||
155 | /* LINTED const cast */ | ||
156 | ((char **)nargv)[cstart] = swap; | ||
157 | } | ||
158 | } | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * parse_long_options -- | ||
163 | * Parse long options in argc/argv argument vector. | ||
164 | * Returns -1 if short_too is set and the option does not match long_options. | ||
165 | */ | ||
166 | static int | ||
167 | parse_long_options(char * const *nargv, const char *options, | ||
168 | const struct option *long_options, int *idx, int short_too) | ||
169 | { | ||
170 | char *current_argv, *has_equal; | ||
171 | size_t current_argv_len; | ||
172 | int i, match; | ||
173 | |||
174 | current_argv = place; | ||
175 | match = -1; | ||
176 | |||
177 | optind++; | ||
178 | |||
179 | if ((has_equal = strchr(current_argv, '=')) != NULL) { | ||
180 | /* argument found (--option=arg) */ | ||
181 | current_argv_len = has_equal - current_argv; | ||
182 | has_equal++; | ||
183 | } else | ||
184 | current_argv_len = strlen(current_argv); | ||
185 | |||
186 | for (i = 0; long_options[i].name; i++) { | ||
187 | /* find matching long option */ | ||
188 | if (strncmp(current_argv, long_options[i].name, | ||
189 | current_argv_len)) | ||
190 | continue; | ||
191 | |||
192 | if (strlen(long_options[i].name) == current_argv_len) { | ||
193 | /* exact match */ | ||
194 | match = i; | ||
195 | break; | ||
196 | } | ||
197 | /* | ||
198 | * If this is a known short option, don't allow | ||
199 | * a partial match of a single character. | ||
200 | */ | ||
201 | if (short_too && current_argv_len == 1) | ||
202 | continue; | ||
203 | |||
204 | if (match == -1) /* partial match */ | ||
205 | match = i; | ||
206 | else { | ||
207 | /* ambiguous abbreviation */ | ||
208 | if (PRINT_ERROR) | ||
209 | warnx(ambig, (int)current_argv_len, | ||
210 | current_argv); | ||
211 | optopt = 0; | ||
212 | return (BADCH); | ||
213 | } | ||
214 | } | ||
215 | if (match != -1) { /* option found */ | ||
216 | if (long_options[match].has_arg == no_argument | ||
217 | && has_equal) { | ||
218 | if (PRINT_ERROR) | ||
219 | warnx(noarg, (int)current_argv_len, | ||
220 | current_argv); | ||
221 | /* | ||
222 | * XXX: GNU sets optopt to val regardless of flag | ||
223 | */ | ||
224 | if (long_options[match].flag == NULL) | ||
225 | optopt = long_options[match].val; | ||
226 | else | ||
227 | optopt = 0; | ||
228 | return (BADARG); | ||
229 | } | ||
230 | if (long_options[match].has_arg == required_argument || | ||
231 | long_options[match].has_arg == optional_argument) { | ||
232 | if (has_equal) | ||
233 | optarg = has_equal; | ||
234 | else if (long_options[match].has_arg == | ||
235 | required_argument) { | ||
236 | /* | ||
237 | * optional argument doesn't use next nargv | ||
238 | */ | ||
239 | optarg = nargv[optind++]; | ||
240 | } | ||
241 | } | ||
242 | if ((long_options[match].has_arg == required_argument) | ||
243 | && (optarg == NULL)) { | ||
244 | /* | ||
245 | * Missing argument; leading ':' indicates no error | ||
246 | * should be generated. | ||
247 | */ | ||
248 | if (PRINT_ERROR) | ||
249 | warnx(recargstring, | ||
250 | current_argv); | ||
251 | /* | ||
252 | * XXX: GNU sets optopt to val regardless of flag | ||
253 | */ | ||
254 | if (long_options[match].flag == NULL) | ||
255 | optopt = long_options[match].val; | ||
256 | else | ||
257 | optopt = 0; | ||
258 | --optind; | ||
259 | return (BADARG); | ||
260 | } | ||
261 | } else { /* unknown option */ | ||
262 | if (short_too) { | ||
263 | --optind; | ||
264 | return (-1); | ||
265 | } | ||
266 | if (PRINT_ERROR) | ||
267 | warnx(illoptstring, current_argv); | ||
268 | optopt = 0; | ||
269 | return (BADCH); | ||
270 | } | ||
271 | if (idx) | ||
272 | *idx = match; | ||
273 | if (long_options[match].flag) { | ||
274 | *long_options[match].flag = long_options[match].val; | ||
275 | return (0); | ||
276 | } else | ||
277 | return (long_options[match].val); | ||
278 | } | ||
279 | |||
280 | /* | ||
281 | * getopt_internal -- | ||
282 | * Parse argc/argv argument vector. Called by user level routines. | ||
283 | */ | ||
284 | static int | ||
285 | getopt_internal(int nargc, char * const *nargv, const char *options, | ||
286 | const struct option *long_options, int *idx, int flags) | ||
287 | { | ||
288 | char *oli; /* option letter list index */ | ||
289 | int optchar, short_too; | ||
290 | static int posixly_correct = -1; | ||
291 | |||
292 | if (options == NULL) | ||
293 | return (-1); | ||
294 | |||
295 | /* | ||
296 | * XXX Some GNU programs (like cvs) set optind to 0 instead of | ||
297 | * XXX using optreset. Work around this braindamage. | ||
298 | */ | ||
299 | if (optind == 0) | ||
300 | optind = optreset = 1; | ||
301 | |||
302 | /* | ||
303 | * Disable GNU extensions if POSIXLY_CORRECT is set or options | ||
304 | * string begins with a '+'. | ||
305 | */ | ||
306 | if (posixly_correct == -1 || optreset) | ||
307 | posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); | ||
308 | if (*options == '-') | ||
309 | flags |= FLAG_ALLARGS; | ||
310 | else if (posixly_correct || *options == '+') | ||
311 | flags &= ~FLAG_PERMUTE; | ||
312 | if (*options == '+' || *options == '-') | ||
313 | options++; | ||
314 | |||
315 | optarg = NULL; | ||
316 | if (optreset) | ||
317 | nonopt_start = nonopt_end = -1; | ||
318 | start: | ||
319 | if (optreset || !*place) { /* update scanning pointer */ | ||
320 | optreset = 0; | ||
321 | if (optind >= nargc) { /* end of argument vector */ | ||
322 | place = EMSG; | ||
323 | if (nonopt_end != -1) { | ||
324 | /* do permutation, if we have to */ | ||
325 | permute_args(nonopt_start, nonopt_end, | ||
326 | optind, nargv); | ||
327 | optind -= nonopt_end - nonopt_start; | ||
328 | } | ||
329 | else if (nonopt_start != -1) { | ||
330 | /* | ||
331 | * If we skipped non-options, set optind | ||
332 | * to the first of them. | ||
333 | */ | ||
334 | optind = nonopt_start; | ||
335 | } | ||
336 | nonopt_start = nonopt_end = -1; | ||
337 | return (-1); | ||
338 | } | ||
339 | if (*(place = nargv[optind]) != '-' || | ||
340 | (place[1] == '\0' && strchr(options, '-') == NULL)) { | ||
341 | place = EMSG; /* found non-option */ | ||
342 | if (flags & FLAG_ALLARGS) { | ||
343 | /* | ||
344 | * GNU extension: | ||
345 | * return non-option as argument to option 1 | ||
346 | */ | ||
347 | optarg = nargv[optind++]; | ||
348 | return (INORDER); | ||
349 | } | ||
350 | if (!(flags & FLAG_PERMUTE)) { | ||
351 | /* | ||
352 | * If no permutation wanted, stop parsing | ||
353 | * at first non-option. | ||
354 | */ | ||
355 | return (-1); | ||
356 | } | ||
357 | /* do permutation */ | ||
358 | if (nonopt_start == -1) | ||
359 | nonopt_start = optind; | ||
360 | else if (nonopt_end != -1) { | ||
361 | permute_args(nonopt_start, nonopt_end, | ||
362 | optind, nargv); | ||
363 | nonopt_start = optind - | ||
364 | (nonopt_end - nonopt_start); | ||
365 | nonopt_end = -1; | ||
366 | } | ||
367 | optind++; | ||
368 | /* process next argument */ | ||
369 | goto start; | ||
370 | } | ||
371 | if (nonopt_start != -1 && nonopt_end == -1) | ||
372 | nonopt_end = optind; | ||
373 | |||
374 | /* | ||
375 | * If we have "-" do nothing, if "--" we are done. | ||
376 | */ | ||
377 | if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { | ||
378 | optind++; | ||
379 | place = EMSG; | ||
380 | /* | ||
381 | * We found an option (--), so if we skipped | ||
382 | * non-options, we have to permute. | ||
383 | */ | ||
384 | if (nonopt_end != -1) { | ||
385 | permute_args(nonopt_start, nonopt_end, | ||
386 | optind, nargv); | ||
387 | optind -= nonopt_end - nonopt_start; | ||
388 | } | ||
389 | nonopt_start = nonopt_end = -1; | ||
390 | return (-1); | ||
391 | } | ||
392 | } | ||
393 | |||
394 | /* | ||
395 | * Check long options if: | ||
396 | * 1) we were passed some | ||
397 | * 2) the arg is not just "-" | ||
398 | * 3) either the arg starts with -- we are getopt_long_only() | ||
399 | */ | ||
400 | if (long_options != NULL && place != nargv[optind] && | ||
401 | (*place == '-' || (flags & FLAG_LONGONLY))) { | ||
402 | short_too = 0; | ||
403 | if (*place == '-') | ||
404 | place++; /* --foo long option */ | ||
405 | else if (*place != ':' && strchr(options, *place) != NULL) | ||
406 | short_too = 1; /* could be short option too */ | ||
407 | |||
408 | optchar = parse_long_options(nargv, options, long_options, | ||
409 | idx, short_too); | ||
410 | if (optchar != -1) { | ||
411 | place = EMSG; | ||
412 | return (optchar); | ||
413 | } | ||
414 | } | ||
415 | |||
416 | if ((optchar = (int)*place++) == (int)':' || | ||
417 | (optchar == (int)'-' && *place != '\0') || | ||
418 | (oli = strchr(options, optchar)) == NULL) { | ||
419 | /* | ||
420 | * If the user specified "-" and '-' isn't listed in | ||
421 | * options, return -1 (non-option) as per POSIX. | ||
422 | * Otherwise, it is an unknown option character (or ':'). | ||
423 | */ | ||
424 | if (optchar == (int)'-' && *place == '\0') | ||
425 | return (-1); | ||
426 | if (!*place) | ||
427 | ++optind; | ||
428 | if (PRINT_ERROR) | ||
429 | warnx(illoptchar, optchar); | ||
430 | optopt = optchar; | ||
431 | return (BADCH); | ||
432 | } | ||
433 | if (long_options != NULL && optchar == 'W' && oli[1] == ';') { | ||
434 | /* -W long-option */ | ||
435 | if (*place) /* no space */ | ||
436 | /* NOTHING */; | ||
437 | else if (++optind >= nargc) { /* no arg */ | ||
438 | place = EMSG; | ||
439 | if (PRINT_ERROR) | ||
440 | warnx(recargchar, optchar); | ||
441 | optopt = optchar; | ||
442 | return (BADARG); | ||
443 | } else /* white space */ | ||
444 | place = nargv[optind]; | ||
445 | optchar = parse_long_options(nargv, options, long_options, | ||
446 | idx, 0); | ||
447 | place = EMSG; | ||
448 | return (optchar); | ||
449 | } | ||
450 | if (*++oli != ':') { /* doesn't take argument */ | ||
451 | if (!*place) | ||
452 | ++optind; | ||
453 | } else { /* takes (optional) argument */ | ||
454 | optarg = NULL; | ||
455 | if (*place) /* no white space */ | ||
456 | optarg = place; | ||
457 | else if (oli[1] != ':') { /* arg not optional */ | ||
458 | if (++optind >= nargc) { /* no arg */ | ||
459 | place = EMSG; | ||
460 | if (PRINT_ERROR) | ||
461 | warnx(recargchar, optchar); | ||
462 | optopt = optchar; | ||
463 | return (BADARG); | ||
464 | } else | ||
465 | optarg = nargv[optind]; | ||
466 | } | ||
467 | place = EMSG; | ||
468 | ++optind; | ||
469 | } | ||
470 | /* dump back option letter */ | ||
471 | return (optchar); | ||
472 | } | ||
473 | |||
474 | /* | ||
475 | * getopt -- | ||
476 | * Parse argc/argv argument vector. | ||
477 | * | ||
478 | * [eventually this will replace the BSD getopt] | ||
479 | */ | ||
480 | int | ||
481 | getopt(int nargc, char * const *nargv, const char *options) | ||
482 | { | ||
483 | |||
484 | /* | ||
485 | * We don't pass FLAG_PERMUTE to getopt_internal() since | ||
486 | * the BSD getopt(3) (unlike GNU) has never done this. | ||
487 | * | ||
488 | * Furthermore, since many privileged programs call getopt() | ||
489 | * before dropping privileges it makes sense to keep things | ||
490 | * as simple (and bug-free) as possible. | ||
491 | */ | ||
492 | return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); | ||
493 | } | ||
494 | |||
495 | #if 0 | ||
496 | /* | ||
497 | * getopt_long -- | ||
498 | * Parse argc/argv argument vector. | ||
499 | */ | ||
500 | int | ||
501 | getopt_long(int nargc, char * const *nargv, const char *options, | ||
502 | const struct option *long_options, int *idx) | ||
503 | { | ||
504 | |||
505 | return (getopt_internal(nargc, nargv, options, long_options, idx, | ||
506 | FLAG_PERMUTE)); | ||
507 | } | ||
508 | |||
509 | /* | ||
510 | * getopt_long_only -- | ||
511 | * Parse argc/argv argument vector. | ||
512 | */ | ||
513 | int | ||
514 | getopt_long_only(int nargc, char * const *nargv, const char *options, | ||
515 | const struct option *long_options, int *idx) | ||
516 | { | ||
517 | |||
518 | return (getopt_internal(nargc, nargv, options, long_options, idx, | ||
519 | FLAG_PERMUTE|FLAG_LONGONLY)); | ||
520 | } | ||
521 | #endif | ||
522 | |||
523 | #endif /* !defined(HAVE_GETOPT) */ | ||
diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h new file mode 100644 index 0000000..d1d8652 --- /dev/null +++ b/openbsd-compat/openbsd-compat.h | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | #ifndef _OPENBSD_COMPAT_H | ||
8 | #define _OPENBSD_COMPAT_H | ||
9 | |||
10 | #if defined(_MSC_VER) | ||
11 | #include "types.h" | ||
12 | #endif | ||
13 | |||
14 | #if defined(HAVE_ENDIAN_H) | ||
15 | #include <endian.h> | ||
16 | #endif | ||
17 | |||
18 | #if defined(__APPLE__) && !defined(HAVE_ENDIAN_H) | ||
19 | #include <libkern/OSByteOrder.h> | ||
20 | #define be16toh(x) OSSwapBigToHostInt16((x)) | ||
21 | #define be32toh(x) OSSwapBigToHostInt32((x)) | ||
22 | #endif /* __APPLE__ && !HAVE_ENDIAN_H */ | ||
23 | |||
24 | #if defined(_WIN32) && !defined(HAVE_ENDIAN_H) | ||
25 | #include <winsock2.h> | ||
26 | #if !defined(_MSC_VER) | ||
27 | #include <sys/param.h> | ||
28 | #endif | ||
29 | #define be16toh(x) ntohs((x)) | ||
30 | #define be32toh(x) ntohl((x)) | ||
31 | #endif /* _WIN32 && !HAVE_ENDIAN_H */ | ||
32 | |||
33 | #include <stdlib.h> | ||
34 | |||
35 | #if !defined(HAVE_STRLCAT) | ||
36 | size_t strlcat(char *, const char *, size_t); | ||
37 | #endif | ||
38 | |||
39 | #if !defined(HAVE_STRLCPY) | ||
40 | size_t strlcpy(char *, const char *, size_t); | ||
41 | #endif | ||
42 | |||
43 | #if !defined(HAVE_RECALLOCARRAY) | ||
44 | void *recallocarray(void *, size_t, size_t, size_t); | ||
45 | #endif | ||
46 | |||
47 | #if !defined(HAVE_EXPLICIT_BZERO) | ||
48 | void explicit_bzero(void *, size_t); | ||
49 | #endif | ||
50 | |||
51 | #if !defined(HAVE_GETPAGESIZE) | ||
52 | int getpagesize(void); | ||
53 | #endif | ||
54 | |||
55 | #if !defined(HAVE_TIMINGSAFE_BCMP) | ||
56 | int timingsafe_bcmp(const void *, const void *, size_t); | ||
57 | #endif | ||
58 | |||
59 | #if !defined(HAVE_READPASSPHRASE) | ||
60 | #include "readpassphrase.h" | ||
61 | #else | ||
62 | #include <readpassphrase.h> | ||
63 | #endif | ||
64 | |||
65 | #if OPENSSL_VERSION_NUMBER < 0x10100000L | ||
66 | #define EVP_PKEY_get0_EC_KEY(x) ((x)->pkey.ec) | ||
67 | #define EVP_PKEY_get0_RSA(x) ((x)->pkey.rsa) | ||
68 | #endif | ||
69 | |||
70 | #if !defined(HAVE_ERR_H) | ||
71 | #include "err.h" | ||
72 | #else | ||
73 | #include <err.h> | ||
74 | #endif | ||
75 | |||
76 | #if !defined(HAVE_GETOPT) | ||
77 | #include "getopt.h" | ||
78 | #else | ||
79 | #include <unistd.h> | ||
80 | #endif | ||
81 | |||
82 | #if !defined(HAVE_GETLINE) | ||
83 | #include <stdio.h> | ||
84 | ssize_t getline(char **, size_t *, FILE *); | ||
85 | #endif | ||
86 | |||
87 | #endif /* !_OPENBSD_COMPAT_H */ | ||
diff --git a/openbsd-compat/posix_win.c b/openbsd-compat/posix_win.c new file mode 100644 index 0000000..eac67c2 --- /dev/null +++ b/openbsd-compat/posix_win.c | |||
@@ -0,0 +1,61 @@ | |||
1 | /* | ||
2 | * Public domain | ||
3 | * | ||
4 | * File IO compatibility shims | ||
5 | * Brent Cook <bcook@openbsd.org> | ||
6 | */ | ||
7 | |||
8 | #define NO_REDEF_POSIX_FUNCTIONS | ||
9 | |||
10 | #include <windows.h> | ||
11 | |||
12 | #include <errno.h> | ||
13 | #include <io.h> | ||
14 | |||
15 | #include "posix_win.h" | ||
16 | |||
17 | int | ||
18 | posix_open(const char *path, ...) | ||
19 | { | ||
20 | va_list ap; | ||
21 | int mode = 0; | ||
22 | int flags; | ||
23 | |||
24 | va_start(ap, path); | ||
25 | flags = va_arg(ap, int); | ||
26 | if (flags & O_CREAT) | ||
27 | mode = va_arg(ap, int); | ||
28 | va_end(ap); | ||
29 | |||
30 | flags |= O_BINARY | O_NOINHERIT; | ||
31 | |||
32 | return (open(path, flags, mode)); | ||
33 | } | ||
34 | |||
35 | int | ||
36 | posix_close(int fd) | ||
37 | { | ||
38 | return (close(fd)); | ||
39 | } | ||
40 | |||
41 | ssize_t | ||
42 | posix_read(int fd, void *buf, size_t count) | ||
43 | { | ||
44 | if (count > INT_MAX) { | ||
45 | errno = EINVAL; | ||
46 | return (-1); | ||
47 | } | ||
48 | |||
49 | return (read(fd, buf, (unsigned int)count)); | ||
50 | } | ||
51 | |||
52 | ssize_t | ||
53 | posix_write(int fd, const void *buf, size_t count) | ||
54 | { | ||
55 | if (count > INT_MAX) { | ||
56 | errno = EINVAL; | ||
57 | return (-1); | ||
58 | } | ||
59 | |||
60 | return (write(fd, buf, (unsigned int)count)); | ||
61 | } | ||
diff --git a/openbsd-compat/posix_win.h b/openbsd-compat/posix_win.h new file mode 100644 index 0000000..a1e0888 --- /dev/null +++ b/openbsd-compat/posix_win.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * Public domain | ||
3 | * | ||
4 | * BSD socket emulation code for Winsock2 | ||
5 | * Brent Cook <bcook@openbsd.org> | ||
6 | */ | ||
7 | |||
8 | #ifndef _COMPAT_POSIX_WIN_H | ||
9 | #define _COMPAT_POSIX_WIN_H | ||
10 | |||
11 | #ifdef _WIN32 | ||
12 | |||
13 | #include <windows.h> | ||
14 | |||
15 | #include <errno.h> | ||
16 | #include <stdarg.h> | ||
17 | #include <stdint.h> | ||
18 | #include <stdio.h> | ||
19 | #include <stdlib.h> | ||
20 | #include <string.h> | ||
21 | |||
22 | #if _MSC_VER >= 1900 | ||
23 | #include <../ucrt/fcntl.h> | ||
24 | #else | ||
25 | #include <../include/fcntl.h> | ||
26 | #endif | ||
27 | |||
28 | #include "types.h" | ||
29 | |||
30 | int posix_open(const char *path, ...); | ||
31 | |||
32 | int posix_close(int fd); | ||
33 | |||
34 | ssize_t posix_read(int fd, void *buf, size_t count); | ||
35 | |||
36 | ssize_t posix_write(int fd, const void *buf, size_t count); | ||
37 | |||
38 | #ifndef NO_REDEF_POSIX_FUNCTIONS | ||
39 | #define open(path, ...) posix_open(path, __VA_ARGS__) | ||
40 | #define close(fd) posix_close(fd) | ||
41 | #define read(fd, buf, count) posix_read(fd, buf, count) | ||
42 | #define write(fd, buf, count) posix_write(fd, buf, count) | ||
43 | #endif | ||
44 | |||
45 | #endif /* _WIN32 */ | ||
46 | |||
47 | #endif /* !_COMPAT_POSIX_WIN_H */ | ||
diff --git a/openbsd-compat/readpassphrase.c b/openbsd-compat/readpassphrase.c new file mode 100644 index 0000000..dfb3065 --- /dev/null +++ b/openbsd-compat/readpassphrase.c | |||
@@ -0,0 +1,214 @@ | |||
1 | /* $OpenBSD: readpassphrase.c,v 1.26 2016/10/18 12:47:18 millert Exp $ */ | ||
2 | |||
3 | /* | ||
4 | * Copyright (c) 2000-2002, 2007, 2010 | ||
5 | * Todd C. Miller <Todd.Miller@courtesan.com> | ||
6 | * | ||
7 | * Permission to use, copy, modify, and distribute this software for any | ||
8 | * purpose with or without fee is hereby granted, provided that the above | ||
9 | * copyright notice and this permission notice appear in all copies. | ||
10 | * | ||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
18 | * | ||
19 | * Sponsored in part by the Defense Advanced Research Projects | ||
20 | * Agency (DARPA) and Air Force Research Laboratory, Air Force | ||
21 | * Materiel Command, USAF, under agreement number F39502-99-1-0512. | ||
22 | */ | ||
23 | |||
24 | /* OPENBSD ORIGINAL: lib/libc/gen/readpassphrase.c */ | ||
25 | |||
26 | #include "openbsd-compat.h" | ||
27 | |||
28 | #ifndef HAVE_READPASSPHRASE | ||
29 | |||
30 | #include <termios.h> | ||
31 | #include <signal.h> | ||
32 | #include <ctype.h> | ||
33 | #include <fcntl.h> | ||
34 | #include <errno.h> | ||
35 | #include <string.h> | ||
36 | #ifdef HAVE_UNISTD_H | ||
37 | #include <unistd.h> | ||
38 | #endif | ||
39 | #include <paths.h> | ||
40 | |||
41 | #ifndef _PATH_TTY | ||
42 | # define _PATH_TTY "/dev/tty" | ||
43 | #endif | ||
44 | |||
45 | #ifndef TCSASOFT | ||
46 | /* If we don't have TCSASOFT define it so that ORing it it below is a no-op. */ | ||
47 | # define TCSASOFT 0 | ||
48 | #endif | ||
49 | |||
50 | /* SunOS 4.x which lacks _POSIX_VDISABLE, but has VDISABLE */ | ||
51 | #if !defined(_POSIX_VDISABLE) && defined(VDISABLE) | ||
52 | # define _POSIX_VDISABLE VDISABLE | ||
53 | #endif | ||
54 | |||
55 | static volatile sig_atomic_t signo[_NSIG]; | ||
56 | |||
57 | static void handler(int); | ||
58 | |||
59 | char * | ||
60 | readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) | ||
61 | { | ||
62 | ssize_t nr; | ||
63 | int input, output, save_errno, i, need_restart; | ||
64 | char ch, *p, *end; | ||
65 | struct termios term, oterm; | ||
66 | struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; | ||
67 | struct sigaction savetstp, savettin, savettou, savepipe; | ||
68 | |||
69 | /* I suppose we could alloc on demand in this case (XXX). */ | ||
70 | if (bufsiz == 0) { | ||
71 | errno = EINVAL; | ||
72 | return(NULL); | ||
73 | } | ||
74 | |||
75 | restart: | ||
76 | for (i = 0; i < _NSIG; i++) | ||
77 | signo[i] = 0; | ||
78 | need_restart = 0; | ||
79 | /* | ||
80 | * Read and write to /dev/tty if available. If not, read from | ||
81 | * stdin and write to stderr unless a tty is required. | ||
82 | */ | ||
83 | if ((flags & RPP_STDIN) || | ||
84 | (input = output = open(_PATH_TTY, O_RDWR)) == -1) { | ||
85 | if (flags & RPP_REQUIRE_TTY) { | ||
86 | errno = ENOTTY; | ||
87 | return(NULL); | ||
88 | } | ||
89 | input = STDIN_FILENO; | ||
90 | output = STDERR_FILENO; | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * Turn off echo if possible. | ||
95 | * If we are using a tty but are not the foreground pgrp this will | ||
96 | * generate SIGTTOU, so do it *before* installing the signal handlers. | ||
97 | */ | ||
98 | if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) { | ||
99 | memcpy(&term, &oterm, sizeof(term)); | ||
100 | if (!(flags & RPP_ECHO_ON)) | ||
101 | term.c_lflag &= ~(ECHO | ECHONL); | ||
102 | #ifdef VSTATUS | ||
103 | if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) | ||
104 | term.c_cc[VSTATUS] = _POSIX_VDISABLE; | ||
105 | #endif | ||
106 | (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term); | ||
107 | } else { | ||
108 | memset(&term, 0, sizeof(term)); | ||
109 | term.c_lflag |= ECHO; | ||
110 | memset(&oterm, 0, sizeof(oterm)); | ||
111 | oterm.c_lflag |= ECHO; | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * Catch signals that would otherwise cause the user to end | ||
116 | * up with echo turned off in the shell. Don't worry about | ||
117 | * things like SIGXCPU and SIGVTALRM for now. | ||
118 | */ | ||
119 | sigemptyset(&sa.sa_mask); | ||
120 | sa.sa_flags = 0; /* don't restart system calls */ | ||
121 | sa.sa_handler = handler; | ||
122 | (void)sigaction(SIGALRM, &sa, &savealrm); | ||
123 | (void)sigaction(SIGHUP, &sa, &savehup); | ||
124 | (void)sigaction(SIGINT, &sa, &saveint); | ||
125 | (void)sigaction(SIGPIPE, &sa, &savepipe); | ||
126 | (void)sigaction(SIGQUIT, &sa, &savequit); | ||
127 | (void)sigaction(SIGTERM, &sa, &saveterm); | ||
128 | (void)sigaction(SIGTSTP, &sa, &savetstp); | ||
129 | (void)sigaction(SIGTTIN, &sa, &savettin); | ||
130 | (void)sigaction(SIGTTOU, &sa, &savettou); | ||
131 | |||
132 | if (!(flags & RPP_STDIN)) | ||
133 | (void)write(output, prompt, strlen(prompt)); | ||
134 | end = buf + bufsiz - 1; | ||
135 | p = buf; | ||
136 | while ((nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') { | ||
137 | if (p < end) { | ||
138 | if ((flags & RPP_SEVENBIT)) | ||
139 | ch &= 0x7f; | ||
140 | if (isalpha((unsigned char)ch)) { | ||
141 | if ((flags & RPP_FORCELOWER)) | ||
142 | ch = (char)tolower((unsigned char)ch); | ||
143 | if ((flags & RPP_FORCEUPPER)) | ||
144 | ch = (char)toupper((unsigned char)ch); | ||
145 | } | ||
146 | *p++ = ch; | ||
147 | } | ||
148 | } | ||
149 | *p = '\0'; | ||
150 | save_errno = errno; | ||
151 | if (!(term.c_lflag & ECHO)) | ||
152 | (void)write(output, "\n", 1); | ||
153 | |||
154 | /* Restore old terminal settings and signals. */ | ||
155 | if (memcmp(&term, &oterm, sizeof(term)) != 0) { | ||
156 | const int sigttou = signo[SIGTTOU]; | ||
157 | |||
158 | /* Ignore SIGTTOU generated when we are not the fg pgrp. */ | ||
159 | while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 && | ||
160 | errno == EINTR && !signo[SIGTTOU]) | ||
161 | continue; | ||
162 | signo[SIGTTOU] = sigttou; | ||
163 | } | ||
164 | (void)sigaction(SIGALRM, &savealrm, NULL); | ||
165 | (void)sigaction(SIGHUP, &savehup, NULL); | ||
166 | (void)sigaction(SIGINT, &saveint, NULL); | ||
167 | (void)sigaction(SIGQUIT, &savequit, NULL); | ||
168 | (void)sigaction(SIGPIPE, &savepipe, NULL); | ||
169 | (void)sigaction(SIGTERM, &saveterm, NULL); | ||
170 | (void)sigaction(SIGTSTP, &savetstp, NULL); | ||
171 | (void)sigaction(SIGTTIN, &savettin, NULL); | ||
172 | (void)sigaction(SIGTTOU, &savettou, NULL); | ||
173 | if (input != STDIN_FILENO) | ||
174 | (void)close(input); | ||
175 | |||
176 | /* | ||
177 | * If we were interrupted by a signal, resend it to ourselves | ||
178 | * now that we have restored the signal handlers. | ||
179 | */ | ||
180 | for (i = 0; i < _NSIG; i++) { | ||
181 | if (signo[i]) { | ||
182 | kill(getpid(), i); | ||
183 | switch (i) { | ||
184 | case SIGTSTP: | ||
185 | case SIGTTIN: | ||
186 | case SIGTTOU: | ||
187 | need_restart = 1; | ||
188 | } | ||
189 | } | ||
190 | } | ||
191 | if (need_restart) | ||
192 | goto restart; | ||
193 | |||
194 | if (save_errno) | ||
195 | errno = save_errno; | ||
196 | return(nr == -1 ? NULL : buf); | ||
197 | } | ||
198 | |||
199 | #if 0 | ||
200 | char * | ||
201 | getpass(const char *prompt) | ||
202 | { | ||
203 | static char buf[_PASSWORD_LEN + 1]; | ||
204 | |||
205 | return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF)); | ||
206 | } | ||
207 | #endif | ||
208 | |||
209 | static void handler(int s) | ||
210 | { | ||
211 | |||
212 | signo[s] = 1; | ||
213 | } | ||
214 | #endif /* HAVE_READPASSPHRASE */ | ||
diff --git a/openbsd-compat/readpassphrase.h b/openbsd-compat/readpassphrase.h new file mode 100644 index 0000000..0c4a59e --- /dev/null +++ b/openbsd-compat/readpassphrase.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* $OpenBSD: readpassphrase.h,v 1.5 2003/06/17 21:56:23 millert Exp $ */ | ||
2 | |||
3 | /* | ||
4 | * Copyright (c) 2000, 2002 Todd C. Miller <Todd.Miller@courtesan.com> | ||
5 | * | ||
6 | * Permission to use, copy, modify, and distribute this software for any | ||
7 | * purpose with or without fee is hereby granted, provided that the above | ||
8 | * copyright notice and this permission notice appear in all copies. | ||
9 | * | ||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
17 | * | ||
18 | * Sponsored in part by the Defense Advanced Research Projects | ||
19 | * Agency (DARPA) and Air Force Research Laboratory, Air Force | ||
20 | * Materiel Command, USAF, under agreement number F39502-99-1-0512. | ||
21 | */ | ||
22 | |||
23 | /* OPENBSD ORIGINAL: include/readpassphrase.h */ | ||
24 | |||
25 | #ifndef _READPASSPHRASE_H_ | ||
26 | #define _READPASSPHRASE_H_ | ||
27 | |||
28 | #ifndef HAVE_READPASSPHRASE | ||
29 | |||
30 | #define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */ | ||
31 | #define RPP_ECHO_ON 0x01 /* Leave echo on. */ | ||
32 | #define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */ | ||
33 | #define RPP_FORCELOWER 0x04 /* Force input to lower case. */ | ||
34 | #define RPP_FORCEUPPER 0x08 /* Force input to upper case. */ | ||
35 | #define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */ | ||
36 | #define RPP_STDIN 0x20 /* Read from stdin, not /dev/tty */ | ||
37 | |||
38 | char * readpassphrase(const char *, char *, size_t, int); | ||
39 | |||
40 | #endif /* HAVE_READPASSPHRASE */ | ||
41 | |||
42 | #endif /* !_READPASSPHRASE_H_ */ | ||
diff --git a/openbsd-compat/readpassphrase_win32.c b/openbsd-compat/readpassphrase_win32.c new file mode 100644 index 0000000..f3079e4 --- /dev/null +++ b/openbsd-compat/readpassphrase_win32.c | |||
@@ -0,0 +1,131 @@ | |||
1 | /* | ||
2 | * Author: Manoj Ampalam <manoj.ampalam@microsoft.com> | ||
3 | * | ||
4 | * Author: Bryan Berns <berns@uwalumni.com> | ||
5 | * Modified group detection use s4u token information | ||
6 | * | ||
7 | * Copyright(c) 2016 Microsoft Corp. | ||
8 | * All rights reserved | ||
9 | * | ||
10 | * Misc Unix POSIX routine implementations for Windows | ||
11 | * | ||
12 | * Redistribution and use in source and binary forms, with or without | ||
13 | * modification, are permitted provided that the following conditions | ||
14 | * are met : | ||
15 | * | ||
16 | * 1. Redistributions of source code must retain the above copyright | ||
17 | * notice, this list of conditions and the following disclaimer. | ||
18 | * 2. Redistributions in binary form must reproduce the above copyright | ||
19 | * notice, this list of conditions and the following disclaimer in the | ||
20 | * documentation and / or other materials provided with the distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
24 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
25 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT | ||
27 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
28 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
29 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
31 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
32 | */ | ||
33 | |||
34 | #define UMDF_USING_NTSTATUS | ||
35 | #define SECURITY_WIN32 | ||
36 | #include <windows.h> | ||
37 | #include <stdio.h> | ||
38 | #include <time.h> | ||
39 | #include <shlwapi.h> | ||
40 | #include <conio.h> | ||
41 | #include <lm.h> | ||
42 | #include <sddl.h> | ||
43 | #include <aclapi.h> | ||
44 | #include <ntsecapi.h> | ||
45 | #include <security.h> | ||
46 | #include <ntstatus.h> | ||
47 | #include <wchar.h> | ||
48 | |||
49 | #include "openbsd-compat.h" | ||
50 | |||
51 | #ifndef HAVE_READPASSPHRASE | ||
52 | |||
53 | /*on error returns NULL and sets errno*/ | ||
54 | static wchar_t * | ||
55 | utf8_to_utf16(const char *utf8) | ||
56 | { | ||
57 | int needed = 0; | ||
58 | wchar_t* utf16 = NULL; | ||
59 | if ((needed = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0)) == 0 || | ||
60 | (utf16 = malloc(needed * sizeof(wchar_t))) == NULL || | ||
61 | MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, needed) == 0) { | ||
62 | /* debug3("failed to convert utf8 payload:%s error:%d", utf8, GetLastError()); */ | ||
63 | errno = ENOMEM; | ||
64 | return NULL; | ||
65 | } | ||
66 | |||
67 | return utf16; | ||
68 | } | ||
69 | |||
70 | char * | ||
71 | readpassphrase(const char *prompt, char *outBuf, size_t outBufLen, int flags) | ||
72 | { | ||
73 | size_t current_index = 0; | ||
74 | char ch; | ||
75 | wchar_t* wtmp = NULL; | ||
76 | |||
77 | if (outBufLen == 0) { | ||
78 | errno = EINVAL; | ||
79 | return NULL; | ||
80 | } | ||
81 | |||
82 | while (_kbhit()) _getch(); | ||
83 | |||
84 | wtmp = utf8_to_utf16(prompt); | ||
85 | if (wtmp == NULL) | ||
86 | errx(1, "unable to alloc memory"); | ||
87 | |||
88 | _cputws(wtmp); | ||
89 | free(wtmp); | ||
90 | |||
91 | while (current_index < outBufLen - 1) { | ||
92 | ch = (char)_getch(); | ||
93 | |||
94 | if (ch == '\r') { | ||
95 | if (_kbhit()) _getch(); /* read linefeed if its there */ | ||
96 | break; | ||
97 | } else if (ch == '\n') { | ||
98 | break; | ||
99 | } else if (ch == '\b') { /* backspace */ | ||
100 | if (current_index > 0) { | ||
101 | if (flags & RPP_ECHO_ON) | ||
102 | printf_s("%c \b", ch); | ||
103 | |||
104 | current_index--; /* overwrite last character */ | ||
105 | } | ||
106 | } else if (ch == '\003') { /* exit on Ctrl+C */ | ||
107 | errx(1, ""); | ||
108 | } else { | ||
109 | if (flags & RPP_SEVENBIT) | ||
110 | ch &= 0x7f; | ||
111 | |||
112 | if (isalpha((unsigned char)ch)) { | ||
113 | if(flags & RPP_FORCELOWER) | ||
114 | ch = (char)tolower((unsigned char)ch); | ||
115 | if(flags & RPP_FORCEUPPER) | ||
116 | ch = (char)toupper((unsigned char)ch); | ||
117 | } | ||
118 | |||
119 | outBuf[current_index++] = ch; | ||
120 | if(flags & RPP_ECHO_ON) | ||
121 | printf_s("%c", ch); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | outBuf[current_index] = '\0'; | ||
126 | _cputs("\n"); | ||
127 | |||
128 | return outBuf; | ||
129 | } | ||
130 | |||
131 | #endif /* HAVE_READPASSPHRASE */ | ||
diff --git a/openbsd-compat/recallocarray.c b/openbsd-compat/recallocarray.c new file mode 100644 index 0000000..5d2f8d9 --- /dev/null +++ b/openbsd-compat/recallocarray.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net> | ||
4 | * | ||
5 | * Permission to use, copy, modify, and distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | /* OPENBSD ORIGINAL: lib/libc/stdlib/recallocarray.c */ | ||
19 | |||
20 | #include "openbsd-compat.h" | ||
21 | |||
22 | #if !defined(HAVE_RECALLOCARRAY) | ||
23 | |||
24 | #include <errno.h> | ||
25 | #include <stdlib.h> | ||
26 | #include <stdint.h> | ||
27 | #include <string.h> | ||
28 | #ifdef HAVE_UNISTD_H | ||
29 | #include <unistd.h> | ||
30 | #endif | ||
31 | |||
32 | /* | ||
33 | * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX | ||
34 | * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW | ||
35 | */ | ||
36 | #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4)) | ||
37 | |||
38 | void * | ||
39 | recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) | ||
40 | { | ||
41 | size_t oldsize, newsize; | ||
42 | void *newptr; | ||
43 | |||
44 | if (ptr == NULL) | ||
45 | return calloc(newnmemb, size); | ||
46 | |||
47 | if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && | ||
48 | newnmemb > 0 && SIZE_MAX / newnmemb < size) { | ||
49 | errno = ENOMEM; | ||
50 | return NULL; | ||
51 | } | ||
52 | newsize = newnmemb * size; | ||
53 | |||
54 | if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && | ||
55 | oldnmemb > 0 && SIZE_MAX / oldnmemb < size) { | ||
56 | errno = EINVAL; | ||
57 | return NULL; | ||
58 | } | ||
59 | oldsize = oldnmemb * size; | ||
60 | |||
61 | /* | ||
62 | * Don't bother too much if we're shrinking just a bit, | ||
63 | * we do not shrink for series of small steps, oh well. | ||
64 | */ | ||
65 | if (newsize <= oldsize) { | ||
66 | size_t d = oldsize - newsize; | ||
67 | |||
68 | if (d < oldsize / 2 && d < (size_t)getpagesize()) { | ||
69 | memset((char *)ptr + newsize, 0, d); | ||
70 | return ptr; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | newptr = malloc(newsize); | ||
75 | if (newptr == NULL) | ||
76 | return NULL; | ||
77 | |||
78 | if (newsize > oldsize) { | ||
79 | memcpy(newptr, ptr, oldsize); | ||
80 | memset((char *)newptr + oldsize, 0, newsize - oldsize); | ||
81 | } else | ||
82 | memcpy(newptr, ptr, newsize); | ||
83 | |||
84 | explicit_bzero(ptr, oldsize); | ||
85 | free(ptr); | ||
86 | |||
87 | return newptr; | ||
88 | } | ||
89 | /* DEF_WEAK(recallocarray); */ | ||
90 | |||
91 | #endif /* !defined(HAVE_RECALLOCARRAY) */ | ||
diff --git a/openbsd-compat/strlcat.c b/openbsd-compat/strlcat.c new file mode 100644 index 0000000..44470de --- /dev/null +++ b/openbsd-compat/strlcat.c | |||
@@ -0,0 +1,63 @@ | |||
1 | /* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ | ||
2 | |||
3 | /* | ||
4 | * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> | ||
5 | * | ||
6 | * Permission to use, copy, modify, and distribute this software for any | ||
7 | * purpose with or without fee is hereby granted, provided that the above | ||
8 | * copyright notice and this permission notice appear in all copies. | ||
9 | * | ||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
17 | */ | ||
18 | |||
19 | /* OPENBSD ORIGINAL: lib/libc/string/strlcat.c */ | ||
20 | |||
21 | #include "openbsd-compat.h" | ||
22 | |||
23 | #if !defined(HAVE_STRLCAT) | ||
24 | |||
25 | #include <sys/types.h> | ||
26 | #include <string.h> | ||
27 | |||
28 | /* | ||
29 | * Appends src to string dst of size siz (unlike strncat, siz is the | ||
30 | * full size of dst, not space left). At most siz-1 characters | ||
31 | * will be copied. Always NUL terminates (unless siz <= strlen(dst)). | ||
32 | * Returns strlen(src) + MIN(siz, strlen(initial dst)). | ||
33 | * If retval >= siz, truncation occurred. | ||
34 | */ | ||
35 | size_t | ||
36 | strlcat(char *dst, const char *src, size_t siz) | ||
37 | { | ||
38 | char *d = dst; | ||
39 | const char *s = src; | ||
40 | size_t n = siz; | ||
41 | size_t dlen; | ||
42 | |||
43 | /* Find the end of dst and adjust bytes left but don't go past end */ | ||
44 | while (n-- != 0 && *d != '\0') | ||
45 | d++; | ||
46 | dlen = d - dst; | ||
47 | n = siz - dlen; | ||
48 | |||
49 | if (n == 0) | ||
50 | return(dlen + strlen(s)); | ||
51 | while (*s != '\0') { | ||
52 | if (n != 1) { | ||
53 | *d++ = *s; | ||
54 | n--; | ||
55 | } | ||
56 | s++; | ||
57 | } | ||
58 | *d = '\0'; | ||
59 | |||
60 | return(dlen + (s - src)); /* count does not include NUL */ | ||
61 | } | ||
62 | |||
63 | #endif /* !defined(HAVE_STRLCAT) */ | ||
diff --git a/openbsd-compat/strlcpy.c b/openbsd-compat/strlcpy.c new file mode 100644 index 0000000..a8b18ea --- /dev/null +++ b/openbsd-compat/strlcpy.c | |||
@@ -0,0 +1,59 @@ | |||
1 | /* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ | ||
2 | |||
3 | /* | ||
4 | * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> | ||
5 | * | ||
6 | * Permission to use, copy, modify, and distribute this software for any | ||
7 | * purpose with or without fee is hereby granted, provided that the above | ||
8 | * copyright notice and this permission notice appear in all copies. | ||
9 | * | ||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
17 | */ | ||
18 | |||
19 | /* OPENBSD ORIGINAL: lib/libc/string/strlcpy.c */ | ||
20 | |||
21 | #include "openbsd-compat.h" | ||
22 | |||
23 | #if !defined(HAVE_STRLCPY) | ||
24 | |||
25 | #include <sys/types.h> | ||
26 | #include <string.h> | ||
27 | |||
28 | /* | ||
29 | * Copy src to string dst of size siz. At most siz-1 characters | ||
30 | * will be copied. Always NUL terminates (unless siz == 0). | ||
31 | * Returns strlen(src); if retval >= siz, truncation occurred. | ||
32 | */ | ||
33 | size_t | ||
34 | strlcpy(char *dst, const char *src, size_t siz) | ||
35 | { | ||
36 | char *d = dst; | ||
37 | const char *s = src; | ||
38 | size_t n = siz; | ||
39 | |||
40 | /* Copy as many bytes as will fit */ | ||
41 | if (n != 0) { | ||
42 | while (--n != 0) { | ||
43 | if ((*d++ = *s++) == '\0') | ||
44 | break; | ||
45 | } | ||
46 | } | ||
47 | |||
48 | /* Not enough room in dst, add NUL and traverse rest of src */ | ||
49 | if (n == 0) { | ||
50 | if (siz != 0) | ||
51 | *d = '\0'; /* NUL-terminate dst */ | ||
52 | while (*s++) | ||
53 | ; | ||
54 | } | ||
55 | |||
56 | return(s - src - 1); /* count does not include NUL */ | ||
57 | } | ||
58 | |||
59 | #endif /* !defined(HAVE_STRLCPY) */ | ||
diff --git a/openbsd-compat/timingsafe_bcmp.c b/openbsd-compat/timingsafe_bcmp.c new file mode 100644 index 0000000..3f7b9e5 --- /dev/null +++ b/openbsd-compat/timingsafe_bcmp.c | |||
@@ -0,0 +1,35 @@ | |||
1 | /* $OpenBSD: timingsafe_bcmp.c,v 1.1 2010/09/24 13:33:00 matthew Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2010 Damien Miller. All rights reserved. | ||
4 | * | ||
5 | * Permission to use, copy, modify, and distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | /* OPENBSD ORIGINAL: lib/libc/string/timingsafe_bcmp.c */ | ||
19 | |||
20 | #include "openbsd-compat.h" | ||
21 | |||
22 | #if !defined(HAVE_TIMINGSAFE_BCMP) | ||
23 | |||
24 | int | ||
25 | timingsafe_bcmp(const void *b1, const void *b2, size_t n) | ||
26 | { | ||
27 | const unsigned char *p1 = b1, *p2 = b2; | ||
28 | int ret = 0; | ||
29 | |||
30 | for (; n > 0; n--) | ||
31 | ret |= *p1++ ^ *p2++; | ||
32 | return (ret != 0); | ||
33 | } | ||
34 | |||
35 | #endif /* !defined(HAVE_TIMINGSAFE_BCMP) */ | ||
diff --git a/openbsd-compat/types.h b/openbsd-compat/types.h new file mode 100644 index 0000000..cc1da66 --- /dev/null +++ b/openbsd-compat/types.h | |||
@@ -0,0 +1,71 @@ | |||
1 | /* | ||
2 | * Public domain | ||
3 | * sys/types.h compatibility shim | ||
4 | */ | ||
5 | |||
6 | #ifdef _MSC_VER | ||
7 | #if _MSC_VER >= 1900 | ||
8 | #include <../ucrt/sys/types.h> | ||
9 | #else | ||
10 | #include <../include/sys/types.h> | ||
11 | #endif | ||
12 | #endif | ||
13 | |||
14 | #ifndef _COMPAT_TYPES_H | ||
15 | #define _COMPAT_TYPES_H | ||
16 | |||
17 | #include <stdint.h> | ||
18 | |||
19 | #ifdef __MINGW32__ | ||
20 | #include <_bsd_types.h> | ||
21 | typedef uint32_t in_addr_t; | ||
22 | typedef uint32_t uid_t; | ||
23 | #endif | ||
24 | |||
25 | #ifdef _MSC_VER | ||
26 | typedef unsigned char u_char; | ||
27 | typedef unsigned short u_short; | ||
28 | typedef unsigned int u_int; | ||
29 | typedef uint32_t in_addr_t; | ||
30 | typedef uint32_t mode_t; | ||
31 | typedef uint32_t uid_t; | ||
32 | |||
33 | #include <basetsd.h> | ||
34 | typedef SSIZE_T ssize_t; | ||
35 | |||
36 | #ifndef SSIZE_MAX | ||
37 | #ifdef _WIN64 | ||
38 | #define SSIZE_MAX _I64_MAX | ||
39 | #else | ||
40 | #define SSIZE_MAX INT_MAX | ||
41 | #endif | ||
42 | #endif | ||
43 | |||
44 | #endif | ||
45 | |||
46 | #if !defined(HAVE_ATTRIBUTE__BOUNDED__) && !defined(__bounded__) | ||
47 | # define __bounded__(x, y, z) | ||
48 | #endif | ||
49 | |||
50 | #ifdef _WIN32 | ||
51 | #define __warn_references(sym,msg) | ||
52 | #else | ||
53 | |||
54 | #ifndef __warn_references | ||
55 | |||
56 | #ifndef __STRING | ||
57 | #define __STRING(x) #x | ||
58 | #endif | ||
59 | |||
60 | #if defined(__GNUC__) && defined (HAS_GNU_WARNING_LONG) | ||
61 | #define __warn_references(sym,msg) \ | ||
62 | __asm__(".section .gnu.warning." __STRING(sym) \ | ||
63 | "\n\t.ascii \"" msg "\"\n\t.text"); | ||
64 | #else | ||
65 | #define __warn_references(sym,msg) | ||
66 | #endif | ||
67 | |||
68 | #endif /* __warn_references */ | ||
69 | #endif /* _WIN32 */ | ||
70 | |||
71 | #endif /* !_COMPAT_TYPES_H */ | ||
diff --git a/regress/CMakeLists.txt b/regress/CMakeLists.txt new file mode 100644 index 0000000..b8fea64 --- /dev/null +++ b/regress/CMakeLists.txt | |||
@@ -0,0 +1,18 @@ | |||
1 | # Copyright (c) 2018 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 | # cred | ||
6 | add_executable(regress_cred cred.c) | ||
7 | target_link_libraries(regress_cred fido2_shared) | ||
8 | add_custom_command(TARGET regress_cred POST_BUILD COMMAND regress_cred) | ||
9 | |||
10 | # assert | ||
11 | add_executable(regress_assert assert.c) | ||
12 | target_link_libraries(regress_assert fido2_shared) | ||
13 | add_custom_command(TARGET regress_assert POST_BUILD COMMAND regress_assert) | ||
14 | |||
15 | # dev | ||
16 | add_executable(regress_dev dev.c) | ||
17 | target_link_libraries(regress_dev fido2_shared) | ||
18 | add_custom_command(TARGET regress_dev POST_BUILD COMMAND regress_dev) | ||
diff --git a/regress/assert.c b/regress/assert.c new file mode 100644 index 0000000..ebf0652 --- /dev/null +++ b/regress/assert.c | |||
@@ -0,0 +1,511 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <assert.h> | ||
8 | #include <fido.h> | ||
9 | #include <fido/es256.h> | ||
10 | #include <fido/rs256.h> | ||
11 | #include <string.h> | ||
12 | |||
13 | #define FAKE_DEV_HANDLE ((void *)0xdeadbeef) | ||
14 | |||
15 | static const unsigned char es256_pk[64] = { | ||
16 | 0x34, 0xeb, 0x99, 0x77, 0x02, 0x9c, 0x36, 0x38, | ||
17 | 0xbb, 0xc2, 0xae, 0xa0, 0xa0, 0x18, 0xc6, 0x64, | ||
18 | 0xfc, 0xe8, 0x49, 0x92, 0xd7, 0x74, 0x9e, 0x0c, | ||
19 | 0x46, 0x8c, 0x9d, 0xa6, 0xdf, 0x46, 0xf7, 0x84, | ||
20 | 0x60, 0x1e, 0x0f, 0x8b, 0x23, 0x85, 0x4a, 0x9a, | ||
21 | 0xec, 0xc1, 0x08, 0x9f, 0x30, 0xd0, 0x0d, 0xd7, | ||
22 | 0x76, 0x7b, 0x55, 0x48, 0x91, 0x7c, 0x4f, 0x0f, | ||
23 | 0x64, 0x1a, 0x1d, 0xf8, 0xbe, 0x14, 0x90, 0x8a, | ||
24 | }; | ||
25 | |||
26 | static const unsigned char cdh[32] = { | ||
27 | 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7, | ||
28 | 0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56, | ||
29 | 0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52, | ||
30 | 0x35, 0x2d, 0xa2, 0x62, 0x4a, 0xbe, 0x89, 0x76, | ||
31 | }; | ||
32 | |||
33 | static const unsigned char authdata[39] = { | ||
34 | 0x58, 0x25, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, | ||
35 | 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, | ||
36 | 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, | ||
37 | 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d, | ||
38 | 0x97, 0x63, 0x00, 0x00, 0x00, 0x00, 0x03, | ||
39 | }; | ||
40 | |||
41 | static const unsigned char sig[72] = { | ||
42 | 0x30, 0x46, 0x02, 0x21, 0x00, 0xf6, 0xd1, 0xa3, | ||
43 | 0xd5, 0x24, 0x2b, 0xde, 0xee, 0xa0, 0x90, 0x89, | ||
44 | 0xcd, 0xf8, 0x9e, 0xbd, 0x6b, 0x4d, 0x55, 0x79, | ||
45 | 0xe4, 0xc1, 0x42, 0x27, 0xb7, 0x9b, 0x9b, 0xa4, | ||
46 | 0x0a, 0xe2, 0x47, 0x64, 0x0e, 0x02, 0x21, 0x00, | ||
47 | 0xe5, 0xc9, 0xc2, 0x83, 0x47, 0x31, 0xc7, 0x26, | ||
48 | 0xe5, 0x25, 0xb2, 0xb4, 0x39, 0xa7, 0xfc, 0x3d, | ||
49 | 0x70, 0xbe, 0xe9, 0x81, 0x0d, 0x4a, 0x62, 0xa9, | ||
50 | 0xab, 0x4a, 0x91, 0xc0, 0x7d, 0x2d, 0x23, 0x1e, | ||
51 | }; | ||
52 | |||
53 | static void * | ||
54 | dummy_open(const char *path) | ||
55 | { | ||
56 | (void)path; | ||
57 | |||
58 | return (FAKE_DEV_HANDLE); | ||
59 | } | ||
60 | |||
61 | static void | ||
62 | dummy_close(void *handle) | ||
63 | { | ||
64 | assert(handle == FAKE_DEV_HANDLE); | ||
65 | } | ||
66 | |||
67 | static int | ||
68 | dummy_read(void *handle, unsigned char *buf, size_t len, int ms) | ||
69 | { | ||
70 | (void)handle; | ||
71 | (void)buf; | ||
72 | (void)len; | ||
73 | (void)ms; | ||
74 | |||
75 | abort(); | ||
76 | /* NOTREACHED */ | ||
77 | } | ||
78 | |||
79 | static int | ||
80 | dummy_write(void *handle, const unsigned char *buf, size_t len) | ||
81 | { | ||
82 | (void)handle; | ||
83 | (void)buf; | ||
84 | (void)len; | ||
85 | |||
86 | abort(); | ||
87 | /* NOTREACHED */ | ||
88 | } | ||
89 | |||
90 | static fido_assert_t * | ||
91 | alloc_assert(void) | ||
92 | { | ||
93 | fido_assert_t *a; | ||
94 | |||
95 | a = fido_assert_new(); | ||
96 | assert(a != NULL); | ||
97 | |||
98 | return (a); | ||
99 | } | ||
100 | |||
101 | static void | ||
102 | free_assert(fido_assert_t *a) | ||
103 | { | ||
104 | fido_assert_free(&a); | ||
105 | assert(a == NULL); | ||
106 | } | ||
107 | |||
108 | static fido_dev_t * | ||
109 | alloc_dev(void) | ||
110 | { | ||
111 | fido_dev_t *d; | ||
112 | |||
113 | d = fido_dev_new(); | ||
114 | assert(d != NULL); | ||
115 | |||
116 | return (d); | ||
117 | } | ||
118 | |||
119 | static void | ||
120 | free_dev(fido_dev_t *d) | ||
121 | { | ||
122 | fido_dev_free(&d); | ||
123 | assert(d == NULL); | ||
124 | } | ||
125 | |||
126 | static es256_pk_t * | ||
127 | alloc_es256_pk(void) | ||
128 | { | ||
129 | es256_pk_t *pk; | ||
130 | |||
131 | pk = es256_pk_new(); | ||
132 | assert(pk != NULL); | ||
133 | |||
134 | return (pk); | ||
135 | } | ||
136 | |||
137 | static void | ||
138 | free_es256_pk(es256_pk_t *pk) | ||
139 | { | ||
140 | es256_pk_free(&pk); | ||
141 | assert(pk == NULL); | ||
142 | } | ||
143 | |||
144 | static rs256_pk_t * | ||
145 | alloc_rs256_pk(void) | ||
146 | { | ||
147 | rs256_pk_t *pk; | ||
148 | |||
149 | pk = rs256_pk_new(); | ||
150 | assert(pk != NULL); | ||
151 | |||
152 | return (pk); | ||
153 | } | ||
154 | |||
155 | static void | ||
156 | free_rs256_pk(rs256_pk_t *pk) | ||
157 | { | ||
158 | rs256_pk_free(&pk); | ||
159 | assert(pk == NULL); | ||
160 | } | ||
161 | |||
162 | static void | ||
163 | empty_assert(fido_dev_t *d, fido_assert_t *a, int idx) | ||
164 | { | ||
165 | es256_pk_t *es256; | ||
166 | rs256_pk_t *rs256; | ||
167 | |||
168 | assert(fido_assert_flags(a, idx) == 0); | ||
169 | assert(fido_assert_authdata_len(a, idx) == 0); | ||
170 | assert(fido_assert_authdata_ptr(a, idx) == NULL); | ||
171 | assert(fido_assert_clientdata_hash_len(a) == 0); | ||
172 | assert(fido_assert_clientdata_hash_ptr(a) == NULL); | ||
173 | assert(fido_assert_id_len(a, idx) == 0); | ||
174 | assert(fido_assert_id_ptr(a, idx) == NULL); | ||
175 | assert(fido_assert_rp_id(a) == NULL); | ||
176 | assert(fido_assert_sig_len(a, idx) == 0); | ||
177 | assert(fido_assert_sig_ptr(a, idx) == NULL); | ||
178 | assert(fido_assert_user_display_name(a, idx) == NULL); | ||
179 | assert(fido_assert_user_icon(a, idx) == NULL); | ||
180 | assert(fido_assert_user_id_len(a, idx) == 0); | ||
181 | assert(fido_assert_user_id_ptr(a, idx) == NULL); | ||
182 | assert(fido_assert_user_name(a, idx) == NULL); | ||
183 | |||
184 | es256 = alloc_es256_pk(); | ||
185 | rs256 = alloc_rs256_pk(); | ||
186 | |||
187 | fido_dev_force_u2f(d); | ||
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); | ||
190 | assert(fido_assert_verify(a, COSE_ES256, idx, | ||
191 | NULL) == FIDO_ERR_INVALID_ARGUMENT); | ||
192 | assert(fido_assert_verify(a, COSE_ES256, idx, | ||
193 | es256) == FIDO_ERR_INVALID_ARGUMENT); | ||
194 | assert(fido_assert_verify(a, COSE_RS256, idx, | ||
195 | rs256) == FIDO_ERR_INVALID_ARGUMENT); | ||
196 | |||
197 | fido_dev_force_fido2(d); | ||
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); | ||
200 | assert(fido_assert_verify(a, COSE_ES256, idx, | ||
201 | NULL) == FIDO_ERR_INVALID_ARGUMENT); | ||
202 | assert(fido_assert_verify(a, COSE_ES256, idx, | ||
203 | es256) == FIDO_ERR_INVALID_ARGUMENT); | ||
204 | assert(fido_assert_verify(a, COSE_RS256, idx, | ||
205 | rs256) == FIDO_ERR_INVALID_ARGUMENT); | ||
206 | |||
207 | free_es256_pk(es256); | ||
208 | free_rs256_pk(rs256); | ||
209 | } | ||
210 | |||
211 | static void | ||
212 | empty_assert_tests(void) | ||
213 | { | ||
214 | fido_assert_t *a; | ||
215 | fido_dev_t *d; | ||
216 | fido_dev_io_t io_f; | ||
217 | int i; | ||
218 | |||
219 | a = alloc_assert(); | ||
220 | d = alloc_dev(); | ||
221 | io_f.open = dummy_open; | ||
222 | io_f.close = dummy_close; | ||
223 | io_f.read = dummy_read; | ||
224 | io_f.write = dummy_write; | ||
225 | assert(fido_dev_set_io_functions(d, &io_f) == FIDO_OK); | ||
226 | |||
227 | empty_assert(d, a, 0); | ||
228 | assert(fido_assert_count(a) == 0); | ||
229 | assert(fido_assert_set_count(a, 4) == FIDO_OK); | ||
230 | assert(fido_assert_count(a) == 4); | ||
231 | for (i = 0; i < 4; i++) { | ||
232 | empty_assert(d, a, i); | ||
233 | } | ||
234 | empty_assert(d, a, 10); | ||
235 | free_assert(a); | ||
236 | free_dev(d); | ||
237 | } | ||
238 | |||
239 | static void | ||
240 | valid_assert(void) | ||
241 | { | ||
242 | fido_assert_t *a; | ||
243 | es256_pk_t *pk; | ||
244 | |||
245 | a = alloc_assert(); | ||
246 | pk = alloc_es256_pk(); | ||
247 | assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); | ||
248 | assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); | ||
249 | assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); | ||
250 | assert(fido_assert_set_count(a, 1) == FIDO_OK); | ||
251 | assert(fido_assert_set_authdata(a, 0, authdata, | ||
252 | sizeof(authdata)) == FIDO_OK); | ||
253 | assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
254 | assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
255 | assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); | ||
256 | assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_OK); | ||
257 | free_assert(a); | ||
258 | free_es256_pk(pk); | ||
259 | } | ||
260 | |||
261 | static void | ||
262 | no_cdh(void) | ||
263 | { | ||
264 | fido_assert_t *a; | ||
265 | es256_pk_t *pk; | ||
266 | |||
267 | a = alloc_assert(); | ||
268 | pk = alloc_es256_pk(); | ||
269 | assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); | ||
270 | assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); | ||
271 | assert(fido_assert_set_count(a, 1) == FIDO_OK); | ||
272 | assert(fido_assert_set_authdata(a, 0, authdata, | ||
273 | sizeof(authdata)) == FIDO_OK); | ||
274 | assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
275 | assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
276 | assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); | ||
277 | assert(fido_assert_verify(a, 0, COSE_ES256, | ||
278 | pk) == FIDO_ERR_INVALID_ARGUMENT); | ||
279 | free_assert(a); | ||
280 | free_es256_pk(pk); | ||
281 | } | ||
282 | |||
283 | static void | ||
284 | no_rp(void) | ||
285 | { | ||
286 | fido_assert_t *a; | ||
287 | es256_pk_t *pk; | ||
288 | |||
289 | a = alloc_assert(); | ||
290 | pk = alloc_es256_pk(); | ||
291 | assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); | ||
292 | assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); | ||
293 | assert(fido_assert_set_count(a, 1) == FIDO_OK); | ||
294 | assert(fido_assert_set_authdata(a, 0, authdata, | ||
295 | sizeof(authdata)) == FIDO_OK); | ||
296 | assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
297 | assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
298 | assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); | ||
299 | assert(fido_assert_verify(a, 0, COSE_ES256, | ||
300 | pk) == FIDO_ERR_INVALID_ARGUMENT); | ||
301 | free_assert(a); | ||
302 | free_es256_pk(pk); | ||
303 | } | ||
304 | |||
305 | static void | ||
306 | no_authdata(void) | ||
307 | { | ||
308 | fido_assert_t *a; | ||
309 | es256_pk_t *pk; | ||
310 | |||
311 | a = alloc_assert(); | ||
312 | pk = alloc_es256_pk(); | ||
313 | assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); | ||
314 | assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); | ||
315 | assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); | ||
316 | assert(fido_assert_set_count(a, 1) == FIDO_OK); | ||
317 | assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
318 | assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
319 | assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); | ||
320 | assert(fido_assert_verify(a, 0, COSE_ES256, | ||
321 | pk) == FIDO_ERR_INVALID_ARGUMENT); | ||
322 | free_assert(a); | ||
323 | free_es256_pk(pk); | ||
324 | } | ||
325 | |||
326 | static void | ||
327 | no_sig(void) | ||
328 | { | ||
329 | fido_assert_t *a; | ||
330 | es256_pk_t *pk; | ||
331 | |||
332 | a = alloc_assert(); | ||
333 | pk = alloc_es256_pk(); | ||
334 | assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); | ||
335 | assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); | ||
336 | assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); | ||
337 | assert(fido_assert_set_count(a, 1) == FIDO_OK); | ||
338 | assert(fido_assert_set_authdata(a, 0, authdata, | ||
339 | sizeof(authdata)) == FIDO_OK); | ||
340 | assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
341 | assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
342 | assert(fido_assert_verify(a, 0, COSE_ES256, | ||
343 | pk) == FIDO_ERR_INVALID_ARGUMENT); | ||
344 | free_assert(a); | ||
345 | free_es256_pk(pk); | ||
346 | } | ||
347 | |||
348 | static void | ||
349 | junk_cdh(void) | ||
350 | { | ||
351 | fido_assert_t *a; | ||
352 | es256_pk_t *pk; | ||
353 | unsigned char *junk; | ||
354 | |||
355 | junk = malloc(sizeof(cdh)); | ||
356 | assert(junk != NULL); | ||
357 | memcpy(junk, cdh, sizeof(cdh)); | ||
358 | junk[0] = ~junk[0]; | ||
359 | |||
360 | a = alloc_assert(); | ||
361 | pk = alloc_es256_pk(); | ||
362 | assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); | ||
363 | assert(fido_assert_set_clientdata_hash(a, junk, sizeof(cdh)) == FIDO_OK); | ||
364 | assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); | ||
365 | assert(fido_assert_set_count(a, 1) == FIDO_OK); | ||
366 | assert(fido_assert_set_authdata(a, 0, authdata, | ||
367 | sizeof(authdata)) == FIDO_OK); | ||
368 | assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
369 | assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
370 | assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); | ||
371 | assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_SIG); | ||
372 | free_assert(a); | ||
373 | free_es256_pk(pk); | ||
374 | free(junk); | ||
375 | } | ||
376 | |||
377 | static void | ||
378 | junk_rp(void) | ||
379 | { | ||
380 | fido_assert_t *a; | ||
381 | es256_pk_t *pk; | ||
382 | |||
383 | a = alloc_assert(); | ||
384 | pk = alloc_es256_pk(); | ||
385 | assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); | ||
386 | assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); | ||
387 | assert(fido_assert_set_rp(a, "potato") == FIDO_OK); | ||
388 | assert(fido_assert_set_count(a, 1) == FIDO_OK); | ||
389 | assert(fido_assert_set_authdata(a, 0, authdata, | ||
390 | sizeof(authdata)) == FIDO_OK); | ||
391 | assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
392 | assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
393 | assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); | ||
394 | assert(fido_assert_verify(a, 0, COSE_ES256, | ||
395 | pk) == FIDO_ERR_INVALID_PARAM); | ||
396 | free_assert(a); | ||
397 | free_es256_pk(pk); | ||
398 | } | ||
399 | |||
400 | static void | ||
401 | junk_authdata(void) | ||
402 | { | ||
403 | fido_assert_t *a; | ||
404 | unsigned char *junk; | ||
405 | |||
406 | junk = malloc(sizeof(authdata)); | ||
407 | assert(junk != NULL); | ||
408 | memcpy(junk, authdata, sizeof(authdata)); | ||
409 | junk[0] = ~junk[0]; | ||
410 | |||
411 | a = alloc_assert(); | ||
412 | assert(fido_assert_set_count(a, 1) == FIDO_OK); | ||
413 | assert(fido_assert_set_authdata(a, 0, junk, | ||
414 | sizeof(authdata)) == FIDO_ERR_INVALID_ARGUMENT); | ||
415 | free_assert(a); | ||
416 | free(junk); | ||
417 | } | ||
418 | |||
419 | static void | ||
420 | junk_sig(void) | ||
421 | { | ||
422 | fido_assert_t *a; | ||
423 | es256_pk_t *pk; | ||
424 | unsigned char *junk; | ||
425 | |||
426 | junk = malloc(sizeof(sig)); | ||
427 | assert(junk != NULL); | ||
428 | memcpy(junk, sig, sizeof(sig)); | ||
429 | junk[0] = ~junk[0]; | ||
430 | |||
431 | a = alloc_assert(); | ||
432 | pk = alloc_es256_pk(); | ||
433 | assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); | ||
434 | assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); | ||
435 | assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); | ||
436 | assert(fido_assert_set_count(a, 1) == FIDO_OK); | ||
437 | assert(fido_assert_set_authdata(a, 0, authdata, | ||
438 | sizeof(authdata)) == FIDO_OK); | ||
439 | assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
440 | assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
441 | assert(fido_assert_set_sig(a, 0, junk, sizeof(sig)) == FIDO_OK); | ||
442 | assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_SIG); | ||
443 | free_assert(a); | ||
444 | free_es256_pk(pk); | ||
445 | free(junk); | ||
446 | } | ||
447 | |||
448 | static void | ||
449 | wrong_options(void) | ||
450 | { | ||
451 | fido_assert_t *a; | ||
452 | es256_pk_t *pk; | ||
453 | |||
454 | a = alloc_assert(); | ||
455 | pk = alloc_es256_pk(); | ||
456 | assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); | ||
457 | assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); | ||
458 | assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); | ||
459 | assert(fido_assert_set_count(a, 1) == FIDO_OK); | ||
460 | assert(fido_assert_set_authdata(a, 0, authdata, | ||
461 | sizeof(authdata)) == FIDO_OK); | ||
462 | assert(fido_assert_set_up(a, FIDO_OPT_TRUE) == FIDO_OK); | ||
463 | assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
464 | assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); | ||
465 | assert(fido_assert_verify(a, 0, COSE_ES256, | ||
466 | pk) == FIDO_ERR_INVALID_PARAM); | ||
467 | assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
468 | assert(fido_assert_set_uv(a, FIDO_OPT_TRUE) == FIDO_OK); | ||
469 | assert(fido_assert_verify(a, 0, COSE_ES256, | ||
470 | pk) == FIDO_ERR_INVALID_PARAM); | ||
471 | assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
472 | assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); | ||
473 | assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_OK); | ||
474 | free_assert(a); | ||
475 | free_es256_pk(pk); | ||
476 | } | ||
477 | |||
478 | /* cbor_serialize_alloc misuse */ | ||
479 | static void | ||
480 | bad_cbor_serialize(void) | ||
481 | { | ||
482 | fido_assert_t *a; | ||
483 | |||
484 | a = alloc_assert(); | ||
485 | assert(fido_assert_set_count(a, 1) == FIDO_OK); | ||
486 | assert(fido_assert_set_authdata(a, 0, authdata, | ||
487 | sizeof(authdata)) == FIDO_OK); | ||
488 | assert(fido_assert_authdata_len(a, 0) == sizeof(authdata)); | ||
489 | free_assert(a); | ||
490 | } | ||
491 | |||
492 | int | ||
493 | main(void) | ||
494 | { | ||
495 | fido_init(0); | ||
496 | |||
497 | empty_assert_tests(); | ||
498 | valid_assert(); | ||
499 | no_cdh(); | ||
500 | no_rp(); | ||
501 | no_authdata(); | ||
502 | no_sig(); | ||
503 | junk_cdh(); | ||
504 | junk_rp(); | ||
505 | junk_authdata(); | ||
506 | junk_sig(); | ||
507 | wrong_options(); | ||
508 | bad_cbor_serialize(); | ||
509 | |||
510 | exit(0); | ||
511 | } | ||
diff --git a/regress/cred.c b/regress/cred.c new file mode 100644 index 0000000..4998649 --- /dev/null +++ b/regress/cred.c | |||
@@ -0,0 +1,816 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <assert.h> | ||
8 | #include <fido.h> | ||
9 | #include <string.h> | ||
10 | |||
11 | #define FAKE_DEV_HANDLE ((void *)0xdeadbeef) | ||
12 | |||
13 | static const unsigned char cdh[32] = { | ||
14 | 0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb, | ||
15 | 0xdd, 0xd7, 0xfb, 0x06, 0x37, 0x62, 0xea, 0x26, | ||
16 | 0x20, 0x44, 0x8e, 0x69, 0x7c, 0x03, 0xf2, 0x31, | ||
17 | 0x2f, 0x99, 0xdc, 0xaf, 0x3e, 0x8a, 0x91, 0x6b, | ||
18 | }; | ||
19 | |||
20 | static const unsigned char authdata[198] = { | ||
21 | 0x58, 0xc4, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, | ||
22 | 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, | ||
23 | 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, | ||
24 | 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d, | ||
25 | 0x97, 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0xf8, | ||
26 | 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, | ||
27 | 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, | ||
28 | 0x40, 0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde, | ||
29 | 0xc5, 0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d, | ||
30 | 0x53, 0xa8, 0xbf, 0x9d, 0xd6, 0x09, 0x6b, 0x5e, | ||
31 | 0x7f, 0xe0, 0x0d, 0x51, 0x30, 0x85, 0x6a, 0xda, | ||
32 | 0x68, 0x70, 0x85, 0xb0, 0xdb, 0x08, 0x0b, 0x83, | ||
33 | 0x2c, 0xef, 0x44, 0xe2, 0x36, 0x88, 0xee, 0x76, | ||
34 | 0x90, 0x6e, 0x7b, 0x50, 0x3e, 0x9a, 0xa0, 0xd6, | ||
35 | 0x3c, 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, | ||
36 | 0x25, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, | ||
37 | 0x21, 0x58, 0x20, 0x17, 0x5b, 0x27, 0xa6, 0x56, | ||
38 | 0xb2, 0x26, 0x0c, 0x26, 0x0c, 0x55, 0x42, 0x78, | ||
39 | 0x17, 0x5d, 0x4c, 0xf8, 0xa2, 0xfd, 0x1b, 0xb9, | ||
40 | 0x54, 0xdf, 0xd5, 0xeb, 0xbf, 0x22, 0x64, 0xf5, | ||
41 | 0x21, 0x9a, 0xc6, 0x22, 0x58, 0x20, 0x87, 0x5f, | ||
42 | 0x90, 0xe6, 0xfd, 0x71, 0x27, 0x9f, 0xeb, 0xe3, | ||
43 | 0x03, 0x44, 0xbc, 0x8d, 0x49, 0xc6, 0x1c, 0x31, | ||
44 | 0x3b, 0x72, 0xae, 0xd4, 0x53, 0xb1, 0xfe, 0x5d, | ||
45 | 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2, | ||
46 | }; | ||
47 | |||
48 | static const unsigned char authdata_dupkeys[200] = { | ||
49 | 0x58, 0xc6, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, | ||
50 | 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, | ||
51 | 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, | ||
52 | 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d, | ||
53 | 0x97, 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0xf8, | ||
54 | 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, | ||
55 | 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, | ||
56 | 0x40, 0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde, | ||
57 | 0xc5, 0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d, | ||
58 | 0x53, 0xa8, 0xbf, 0x9d, 0xd6, 0x09, 0x6b, 0x5e, | ||
59 | 0x7f, 0xe0, 0x0d, 0x51, 0x30, 0x85, 0x6a, 0xda, | ||
60 | 0x68, 0x70, 0x85, 0xb0, 0xdb, 0x08, 0x0b, 0x83, | ||
61 | 0x2c, 0xef, 0x44, 0xe2, 0x36, 0x88, 0xee, 0x76, | ||
62 | 0x90, 0x6e, 0x7b, 0x50, 0x3e, 0x9a, 0xa0, 0xd6, | ||
63 | 0x3c, 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, | ||
64 | 0x25, 0xa6, 0x01, 0x02, 0x01, 0x02, 0x03, 0x26, | ||
65 | 0x20, 0x01, 0x21, 0x58, 0x20, 0x17, 0x5b, 0x27, | ||
66 | 0xa6, 0x56, 0xb2, 0x26, 0x0c, 0x26, 0x0c, 0x55, | ||
67 | 0x42, 0x78, 0x17, 0x5d, 0x4c, 0xf8, 0xa2, 0xfd, | ||
68 | 0x1b, 0xb9, 0x54, 0xdf, 0xd5, 0xeb, 0xbf, 0x22, | ||
69 | 0x64, 0xf5, 0x21, 0x9a, 0xc6, 0x22, 0x58, 0x20, | ||
70 | 0x87, 0x5f, 0x90, 0xe6, 0xfd, 0x71, 0x27, 0x9f, | ||
71 | 0xeb, 0xe3, 0x03, 0x44, 0xbc, 0x8d, 0x49, 0xc6, | ||
72 | 0x1c, 0x31, 0x3b, 0x72, 0xae, 0xd4, 0x53, 0xb1, | ||
73 | 0xfe, 0x5d, 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2, | ||
74 | }; | ||
75 | |||
76 | static const unsigned char authdata_unsorted_keys[198] = { | ||
77 | 0x58, 0xc4, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, | ||
78 | 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, | ||
79 | 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, | ||
80 | 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d, | ||
81 | 0x97, 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0xf8, | ||
82 | 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, | ||
83 | 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, | ||
84 | 0x40, 0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde, | ||
85 | 0xc5, 0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d, | ||
86 | 0x53, 0xa8, 0xbf, 0x9d, 0xd6, 0x09, 0x6b, 0x5e, | ||
87 | 0x7f, 0xe0, 0x0d, 0x51, 0x30, 0x85, 0x6a, 0xda, | ||
88 | 0x68, 0x70, 0x85, 0xb0, 0xdb, 0x08, 0x0b, 0x83, | ||
89 | 0x2c, 0xef, 0x44, 0xe2, 0x36, 0x88, 0xee, 0x76, | ||
90 | 0x90, 0x6e, 0x7b, 0x50, 0x3e, 0x9a, 0xa0, 0xd6, | ||
91 | 0x3c, 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, | ||
92 | 0x25, 0xa5, 0x03, 0x26, 0x01, 0x02, 0x20, 0x01, | ||
93 | 0x21, 0x58, 0x20, 0x17, 0x5b, 0x27, 0xa6, 0x56, | ||
94 | 0xb2, 0x26, 0x0c, 0x26, 0x0c, 0x55, 0x42, 0x78, | ||
95 | 0x17, 0x5d, 0x4c, 0xf8, 0xa2, 0xfd, 0x1b, 0xb9, | ||
96 | 0x54, 0xdf, 0xd5, 0xeb, 0xbf, 0x22, 0x64, 0xf5, | ||
97 | 0x21, 0x9a, 0xc6, 0x22, 0x58, 0x20, 0x87, 0x5f, | ||
98 | 0x90, 0xe6, 0xfd, 0x71, 0x27, 0x9f, 0xeb, 0xe3, | ||
99 | 0x03, 0x44, 0xbc, 0x8d, 0x49, 0xc6, 0x1c, 0x31, | ||
100 | 0x3b, 0x72, 0xae, 0xd4, 0x53, 0xb1, 0xfe, 0x5d, | ||
101 | 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2, | ||
102 | }; | ||
103 | |||
104 | static const unsigned char x509[742] = { | ||
105 | 0x30, 0x82, 0x02, 0xe2, 0x30, 0x81, 0xcb, 0x02, | ||
106 | 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, | ||
107 | 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, | ||
108 | 0x00, 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, | ||
109 | 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x59, 0x75, | ||
110 | 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, | ||
111 | 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, | ||
112 | 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x35, | ||
113 | 0x31, 0x35, 0x31, 0x32, 0x35, 0x38, 0x35, 0x34, | ||
114 | 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x36, 0x31, | ||
115 | 0x34, 0x31, 0x32, 0x35, 0x38, 0x35, 0x34, 0x5a, | ||
116 | 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, | ||
117 | 0x55, 0x04, 0x03, 0x13, 0x12, 0x59, 0x75, 0x62, | ||
118 | 0x69, 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20, | ||
119 | 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x45, 0x30, | ||
120 | 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, | ||
121 | 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, | ||
122 | 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, | ||
123 | 0x00, 0x04, 0xdb, 0x0a, 0xdb, 0xf5, 0x21, 0xc7, | ||
124 | 0x5c, 0xce, 0x63, 0xdc, 0xa6, 0xe1, 0xe8, 0x25, | ||
125 | 0x06, 0x0d, 0x94, 0xe6, 0x27, 0x54, 0x19, 0x4f, | ||
126 | 0x9d, 0x24, 0xaf, 0x26, 0x1a, 0xbe, 0xad, 0x99, | ||
127 | 0x44, 0x1f, 0x95, 0xa3, 0x71, 0x91, 0x0a, 0x3a, | ||
128 | 0x20, 0xe7, 0x3e, 0x91, 0x5e, 0x13, 0xe8, 0xbe, | ||
129 | 0x38, 0x05, 0x7a, 0xd5, 0x7a, 0xa3, 0x7e, 0x76, | ||
130 | 0x90, 0x8f, 0xaf, 0xe2, 0x8a, 0x94, 0xb6, 0x30, | ||
131 | 0xeb, 0x9d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, | ||
132 | 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, | ||
133 | 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x95, 0x40, | ||
134 | 0x6b, 0x50, 0x61, 0x7d, 0xad, 0x84, 0xa3, 0xb4, | ||
135 | 0xeb, 0x88, 0x0f, 0xe3, 0x30, 0x0f, 0x2d, 0xa2, | ||
136 | 0x0a, 0x00, 0xd9, 0x25, 0x04, 0xee, 0x72, 0xfa, | ||
137 | 0x67, 0xdf, 0x58, 0x51, 0x0f, 0x0b, 0x47, 0x02, | ||
138 | 0x9c, 0x3e, 0x41, 0x29, 0x4a, 0x93, 0xac, 0x29, | ||
139 | 0x85, 0x89, 0x2d, 0xa4, 0x7a, 0x81, 0x32, 0x28, | ||
140 | 0x57, 0x71, 0x01, 0xef, 0xa8, 0x42, 0x88, 0x16, | ||
141 | 0x96, 0x37, 0x91, 0xd5, 0xdf, 0xe0, 0x8f, 0xc9, | ||
142 | 0x3c, 0x8d, 0xb0, 0xcd, 0x89, 0x70, 0x82, 0xec, | ||
143 | 0x79, 0xd3, 0xc6, 0x78, 0x73, 0x29, 0x32, 0xe5, | ||
144 | 0xab, 0x6c, 0xbd, 0x56, 0x9f, 0xd5, 0x45, 0x91, | ||
145 | 0xce, 0xc1, 0xdd, 0x8d, 0x64, 0xdc, 0xe9, 0x9c, | ||
146 | 0x1f, 0x5e, 0x3c, 0xd2, 0xaf, 0x51, 0xa5, 0x82, | ||
147 | 0x18, 0xaf, 0xe0, 0x37, 0xe7, 0x32, 0x9e, 0x76, | ||
148 | 0x05, 0x77, 0x02, 0x7b, 0xe6, 0x24, 0xa0, 0x31, | ||
149 | 0x56, 0x1b, 0xfd, 0x19, 0xc5, 0x71, 0xd3, 0xf0, | ||
150 | 0x9e, 0xc0, 0x73, 0x05, 0x4e, 0xbc, 0x85, 0xb8, | ||
151 | 0x53, 0x9e, 0xef, 0xc5, 0xbc, 0x9c, 0x56, 0xa3, | ||
152 | 0xba, 0xd9, 0x27, 0x6a, 0xbb, 0xa9, 0x7a, 0x40, | ||
153 | 0xd7, 0x47, 0x8b, 0x55, 0x72, 0x6b, 0xe3, 0xfe, | ||
154 | 0x28, 0x49, 0x71, 0x24, 0xf4, 0x8f, 0xf4, 0x20, | ||
155 | 0x81, 0xea, 0x38, 0xff, 0x7c, 0x0a, 0x4f, 0xdf, | ||
156 | 0x02, 0x82, 0x39, 0x81, 0x82, 0x3b, 0xca, 0x09, | ||
157 | 0xdd, 0xca, 0xaa, 0x0f, 0x27, 0xf5, 0xa4, 0x83, | ||
158 | 0x55, 0x6c, 0x9a, 0x39, 0x9b, 0x15, 0x3a, 0x16, | ||
159 | 0x63, 0xdc, 0x5b, 0xf9, 0xac, 0x5b, 0xbc, 0xf7, | ||
160 | 0x9f, 0xbe, 0x0f, 0x8a, 0xa2, 0x3c, 0x31, 0x13, | ||
161 | 0xa3, 0x32, 0x48, 0xca, 0x58, 0x87, 0xf8, 0x7b, | ||
162 | 0xa0, 0xa1, 0x0a, 0x6a, 0x60, 0x96, 0x93, 0x5f, | ||
163 | 0x5d, 0x26, 0x9e, 0x63, 0x1d, 0x09, 0xae, 0x9a, | ||
164 | 0x41, 0xe5, 0xbd, 0x08, 0x47, 0xfe, 0xe5, 0x09, | ||
165 | 0x9b, 0x20, 0xfd, 0x12, 0xe2, 0xe6, 0x40, 0x7f, | ||
166 | 0xba, 0x4a, 0x61, 0x33, 0x66, 0x0d, 0x0e, 0x73, | ||
167 | 0xdb, 0xb0, 0xd5, 0xa2, 0x9a, 0x9a, 0x17, 0x0d, | ||
168 | 0x34, 0x30, 0x85, 0x6a, 0x42, 0x46, 0x9e, 0xff, | ||
169 | 0x34, 0x8f, 0x5f, 0x87, 0x6c, 0x35, 0xe7, 0xa8, | ||
170 | 0x4d, 0x35, 0xeb, 0xc1, 0x41, 0xaa, 0x8a, 0xd2, | ||
171 | 0xda, 0x19, 0xaa, 0x79, 0xa2, 0x5f, 0x35, 0x2c, | ||
172 | 0xa0, 0xfd, 0x25, 0xd3, 0xf7, 0x9d, 0x25, 0x18, | ||
173 | 0x2d, 0xfa, 0xb4, 0xbc, 0xbb, 0x07, 0x34, 0x3c, | ||
174 | 0x8d, 0x81, 0xbd, 0xf4, 0xe9, 0x37, 0xdb, 0x39, | ||
175 | 0xe9, 0xd1, 0x45, 0x5b, 0x20, 0x41, 0x2f, 0x2d, | ||
176 | 0x27, 0x22, 0xdc, 0x92, 0x74, 0x8a, 0x92, 0xd5, | ||
177 | 0x83, 0xfd, 0x09, 0xfb, 0x13, 0x9b, 0xe3, 0x39, | ||
178 | 0x7a, 0x6b, 0x5c, 0xfa, 0xe6, 0x76, 0x9e, 0xe0, | ||
179 | 0xe4, 0xe3, 0xef, 0xad, 0xbc, 0xfd, 0x42, 0x45, | ||
180 | 0x9a, 0xd4, 0x94, 0xd1, 0x7e, 0x8d, 0xa7, 0xd8, | ||
181 | 0x05, 0xd5, 0xd3, 0x62, 0xcf, 0x15, 0xcf, 0x94, | ||
182 | 0x7d, 0x1f, 0x5b, 0x58, 0x20, 0x44, 0x20, 0x90, | ||
183 | 0x71, 0xbe, 0x66, 0xe9, 0x9a, 0xab, 0x74, 0x32, | ||
184 | 0x70, 0x53, 0x1d, 0x69, 0xed, 0x87, 0x66, 0xf4, | ||
185 | 0x09, 0x4f, 0xca, 0x25, 0x30, 0xc2, 0x63, 0x79, | ||
186 | 0x00, 0x3c, 0xb1, 0x9b, 0x39, 0x3f, 0x00, 0xe0, | ||
187 | 0xa8, 0x88, 0xef, 0x7a, 0x51, 0x5b, 0xe7, 0xbd, | ||
188 | 0x49, 0x64, 0xda, 0x41, 0x7b, 0x24, 0xc3, 0x71, | ||
189 | 0x22, 0xfd, 0xd1, 0xd1, 0x20, 0xb3, 0x3f, 0x97, | ||
190 | 0xd3, 0x97, 0xb2, 0xaa, 0x18, 0x1c, 0x9e, 0x03, | ||
191 | 0x77, 0x7b, 0x5b, 0x7e, 0xf9, 0xa3, 0xa0, 0xd6, | ||
192 | 0x20, 0x81, 0x2c, 0x38, 0x8f, 0x9d, 0x25, 0xde, | ||
193 | 0xe9, 0xc8, 0xf5, 0xdd, 0x6a, 0x47, 0x9c, 0x65, | ||
194 | 0x04, 0x5a, 0x56, 0xe6, 0xc2, 0xeb, 0xf2, 0x02, | ||
195 | 0x97, 0xe1, 0xb9, 0xd8, 0xe1, 0x24, 0x76, 0x9f, | ||
196 | 0x23, 0x62, 0x39, 0x03, 0x4b, 0xc8, 0xf7, 0x34, | ||
197 | 0x07, 0x49, 0xd6, 0xe7, 0x4d, 0x9a, | ||
198 | }; | ||
199 | |||
200 | const unsigned char sig[70] = { | ||
201 | 0x30, 0x44, 0x02, 0x20, 0x54, 0x92, 0x28, 0x3b, | ||
202 | 0x83, 0x33, 0x47, 0x56, 0x68, 0x79, 0xb2, 0x0c, | ||
203 | 0x84, 0x80, 0xcc, 0x67, 0x27, 0x8b, 0xfa, 0x48, | ||
204 | 0x43, 0x0d, 0x3c, 0xb4, 0x02, 0x36, 0x87, 0x97, | ||
205 | 0x3e, 0xdf, 0x2f, 0x65, 0x02, 0x20, 0x1b, 0x56, | ||
206 | 0x17, 0x06, 0xe2, 0x26, 0x0f, 0x6a, 0xe9, 0xa9, | ||
207 | 0x70, 0x99, 0x62, 0xeb, 0x3a, 0x04, 0x1a, 0xc4, | ||
208 | 0xa7, 0x03, 0x28, 0x56, 0x7c, 0xed, 0x47, 0x08, | ||
209 | 0x68, 0x73, 0x6a, 0xb6, 0x89, 0x0d, | ||
210 | }; | ||
211 | |||
212 | const unsigned char pubkey[64] = { | ||
213 | 0x17, 0x5b, 0x27, 0xa6, 0x56, 0xb2, 0x26, 0x0c, | ||
214 | 0x26, 0x0c, 0x55, 0x42, 0x78, 0x17, 0x5d, 0x4c, | ||
215 | 0xf8, 0xa2, 0xfd, 0x1b, 0xb9, 0x54, 0xdf, 0xd5, | ||
216 | 0xeb, 0xbf, 0x22, 0x64, 0xf5, 0x21, 0x9a, 0xc6, | ||
217 | 0x87, 0x5f, 0x90, 0xe6, 0xfd, 0x71, 0x27, 0x9f, | ||
218 | 0xeb, 0xe3, 0x03, 0x44, 0xbc, 0x8d, 0x49, 0xc6, | ||
219 | 0x1c, 0x31, 0x3b, 0x72, 0xae, 0xd4, 0x53, 0xb1, | ||
220 | 0xfe, 0x5d, 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2, | ||
221 | }; | ||
222 | |||
223 | const unsigned char id[64] = { | ||
224 | 0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde, 0xc5, | ||
225 | 0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d, 0x53, | ||
226 | 0xa8, 0xbf, 0x9d, 0xd6, 0x09, 0x6b, 0x5e, 0x7f, | ||
227 | 0xe0, 0x0d, 0x51, 0x30, 0x85, 0x6a, 0xda, 0x68, | ||
228 | 0x70, 0x85, 0xb0, 0xdb, 0x08, 0x0b, 0x83, 0x2c, | ||
229 | 0xef, 0x44, 0xe2, 0x36, 0x88, 0xee, 0x76, 0x90, | ||
230 | 0x6e, 0x7b, 0x50, 0x3e, 0x9a, 0xa0, 0xd6, 0x3c, | ||
231 | 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, 0x25, | ||
232 | }; | ||
233 | |||
234 | const char rp_id[] = "localhost"; | ||
235 | const char rp_name[] = "sweet home localhost"; | ||
236 | |||
237 | static void * | ||
238 | dummy_open(const char *path) | ||
239 | { | ||
240 | (void)path; | ||
241 | |||
242 | return (FAKE_DEV_HANDLE); | ||
243 | } | ||
244 | |||
245 | static void | ||
246 | dummy_close(void *handle) | ||
247 | { | ||
248 | assert(handle == FAKE_DEV_HANDLE); | ||
249 | } | ||
250 | |||
251 | static int | ||
252 | dummy_read(void *handle, unsigned char *buf, size_t len, int ms) | ||
253 | { | ||
254 | (void)handle; | ||
255 | (void)buf; | ||
256 | (void)len; | ||
257 | (void)ms; | ||
258 | |||
259 | abort(); | ||
260 | /* NOTREACHED */ | ||
261 | } | ||
262 | |||
263 | static int | ||
264 | dummy_write(void *handle, const unsigned char *buf, size_t len) | ||
265 | { | ||
266 | (void)handle; | ||
267 | (void)buf; | ||
268 | (void)len; | ||
269 | |||
270 | abort(); | ||
271 | /* NOTREACHED */ | ||
272 | } | ||
273 | |||
274 | static fido_cred_t * | ||
275 | alloc_cred(void) | ||
276 | { | ||
277 | fido_cred_t *c; | ||
278 | |||
279 | c = fido_cred_new(); | ||
280 | assert(c != NULL); | ||
281 | |||
282 | return (c); | ||
283 | } | ||
284 | |||
285 | static void | ||
286 | free_cred(fido_cred_t *c) | ||
287 | { | ||
288 | fido_cred_free(&c); | ||
289 | assert(c == NULL); | ||
290 | } | ||
291 | |||
292 | static fido_dev_t * | ||
293 | alloc_dev(void) | ||
294 | { | ||
295 | fido_dev_t *d; | ||
296 | |||
297 | d = fido_dev_new(); | ||
298 | assert(d != NULL); | ||
299 | |||
300 | return (d); | ||
301 | } | ||
302 | |||
303 | static void | ||
304 | free_dev(fido_dev_t *d) | ||
305 | { | ||
306 | fido_dev_free(&d); | ||
307 | assert(d == NULL); | ||
308 | } | ||
309 | |||
310 | static void | ||
311 | empty_cred(void) | ||
312 | { | ||
313 | fido_cred_t *c; | ||
314 | fido_dev_t *d; | ||
315 | fido_dev_io_t io_f; | ||
316 | |||
317 | c = alloc_cred(); | ||
318 | assert(fido_cred_authdata_len(c) == 0); | ||
319 | assert(fido_cred_authdata_ptr(c) == NULL); | ||
320 | assert(fido_cred_clientdata_hash_len(c) == 0); | ||
321 | assert(fido_cred_clientdata_hash_ptr(c) == NULL); | ||
322 | assert(fido_cred_flags(c) == 0); | ||
323 | assert(fido_cred_fmt(c) == NULL); | ||
324 | assert(fido_cred_id_len(c) == 0); | ||
325 | assert(fido_cred_id_ptr(c) == NULL); | ||
326 | assert(fido_cred_pubkey_len(c) == 0); | ||
327 | assert(fido_cred_pubkey_ptr(c) == NULL); | ||
328 | assert(fido_cred_rp_id(c) == NULL); | ||
329 | assert(fido_cred_rp_name(c) == NULL); | ||
330 | assert(fido_cred_sig_len(c) == 0); | ||
331 | assert(fido_cred_sig_ptr(c) == NULL); | ||
332 | assert(fido_cred_x5c_len(c) == 0); | ||
333 | assert(fido_cred_x5c_ptr(c) == NULL); | ||
334 | assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); | ||
335 | |||
336 | io_f.open = dummy_open; | ||
337 | io_f.close = dummy_close; | ||
338 | io_f.read = dummy_read; | ||
339 | io_f.write = dummy_write; | ||
340 | d = alloc_dev(); | ||
341 | |||
342 | fido_dev_force_u2f(d); | ||
343 | assert(fido_dev_set_io_functions(d, &io_f) == FIDO_OK); | ||
344 | assert(fido_dev_make_cred(d, c, NULL) == FIDO_ERR_INVALID_ARGUMENT); | ||
345 | assert(fido_dev_make_cred(d, c, "") == FIDO_ERR_UNSUPPORTED_OPTION); | ||
346 | assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); | ||
347 | |||
348 | fido_dev_force_fido2(d); | ||
349 | assert(fido_dev_set_io_functions(d, &io_f) == FIDO_OK); | ||
350 | assert(fido_dev_make_cred(d, c, NULL) == FIDO_ERR_INVALID_ARGUMENT); | ||
351 | assert(fido_dev_make_cred(d, c, "") == FIDO_ERR_INVALID_ARGUMENT); | ||
352 | assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); | ||
353 | |||
354 | free_cred(c); | ||
355 | free_dev(d); | ||
356 | } | ||
357 | |||
358 | static void | ||
359 | valid_cred(void) | ||
360 | { | ||
361 | fido_cred_t *c; | ||
362 | |||
363 | c = alloc_cred(); | ||
364 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
365 | assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); | ||
366 | assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); | ||
367 | assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); | ||
368 | assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
369 | assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
370 | assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); | ||
371 | assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); | ||
372 | assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); | ||
373 | assert(fido_cred_verify(c) == FIDO_OK); | ||
374 | assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); | ||
375 | assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); | ||
376 | assert(fido_cred_id_len(c) == sizeof(id)); | ||
377 | assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); | ||
378 | free_cred(c); | ||
379 | } | ||
380 | |||
381 | static void | ||
382 | no_cdh(void) | ||
383 | { | ||
384 | fido_cred_t *c; | ||
385 | |||
386 | c = alloc_cred(); | ||
387 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
388 | assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); | ||
389 | assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); | ||
390 | assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
391 | assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
392 | assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); | ||
393 | assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); | ||
394 | assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); | ||
395 | assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); | ||
396 | assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); | ||
397 | assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); | ||
398 | assert(fido_cred_id_len(c) == sizeof(id)); | ||
399 | assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); | ||
400 | free_cred(c); | ||
401 | } | ||
402 | |||
403 | static void | ||
404 | no_rp_id(void) | ||
405 | { | ||
406 | fido_cred_t *c; | ||
407 | |||
408 | c = alloc_cred(); | ||
409 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
410 | assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); | ||
411 | assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); | ||
412 | assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
413 | assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
414 | assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); | ||
415 | assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); | ||
416 | assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); | ||
417 | assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); | ||
418 | assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); | ||
419 | assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); | ||
420 | assert(fido_cred_id_len(c) == sizeof(id)); | ||
421 | assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); | ||
422 | free_cred(c); | ||
423 | } | ||
424 | |||
425 | static void | ||
426 | no_rp_name(void) | ||
427 | { | ||
428 | fido_cred_t *c; | ||
429 | |||
430 | c = alloc_cred(); | ||
431 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
432 | assert(fido_cred_set_rp(c, rp_id, NULL) == FIDO_OK); | ||
433 | assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); | ||
434 | assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); | ||
435 | assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
436 | assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
437 | assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); | ||
438 | assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); | ||
439 | assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); | ||
440 | assert(fido_cred_verify(c) == FIDO_OK); | ||
441 | assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); | ||
442 | assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); | ||
443 | assert(fido_cred_id_len(c) == sizeof(id)); | ||
444 | assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); | ||
445 | free_cred(c); | ||
446 | } | ||
447 | |||
448 | static void | ||
449 | no_authdata(void) | ||
450 | { | ||
451 | fido_cred_t *c; | ||
452 | |||
453 | c = alloc_cred(); | ||
454 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
455 | assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); | ||
456 | assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); | ||
457 | assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
458 | assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
459 | assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); | ||
460 | assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); | ||
461 | assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); | ||
462 | assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); | ||
463 | assert(fido_cred_pubkey_len(c) == 0); | ||
464 | assert(fido_cred_pubkey_ptr(c) == NULL); | ||
465 | assert(fido_cred_id_len(c) == 0); | ||
466 | assert(fido_cred_id_ptr(c) == NULL); | ||
467 | free_cred(c); | ||
468 | } | ||
469 | |||
470 | static void | ||
471 | no_x509(void) | ||
472 | { | ||
473 | fido_cred_t *c; | ||
474 | |||
475 | c = alloc_cred(); | ||
476 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
477 | assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); | ||
478 | assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); | ||
479 | assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); | ||
480 | assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
481 | assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
482 | assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); | ||
483 | assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); | ||
484 | assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); | ||
485 | assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); | ||
486 | assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); | ||
487 | assert(fido_cred_id_len(c) == sizeof(id)); | ||
488 | assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); | ||
489 | free_cred(c); | ||
490 | } | ||
491 | |||
492 | static void | ||
493 | no_sig(void) | ||
494 | { | ||
495 | fido_cred_t *c; | ||
496 | |||
497 | c = alloc_cred(); | ||
498 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
499 | assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); | ||
500 | assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); | ||
501 | assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); | ||
502 | assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
503 | assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
504 | assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); | ||
505 | assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); | ||
506 | assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); | ||
507 | assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); | ||
508 | assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); | ||
509 | assert(fido_cred_id_len(c) == sizeof(id)); | ||
510 | assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); | ||
511 | free_cred(c); | ||
512 | } | ||
513 | |||
514 | static void | ||
515 | no_fmt(void) | ||
516 | { | ||
517 | fido_cred_t *c; | ||
518 | |||
519 | c = alloc_cred(); | ||
520 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
521 | assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); | ||
522 | assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); | ||
523 | assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); | ||
524 | assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
525 | assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
526 | assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); | ||
527 | assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); | ||
528 | assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); | ||
529 | assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); | ||
530 | assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); | ||
531 | assert(fido_cred_id_len(c) == sizeof(id)); | ||
532 | assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); | ||
533 | free_cred(c); | ||
534 | } | ||
535 | |||
536 | static void | ||
537 | wrong_options(void) | ||
538 | { | ||
539 | fido_cred_t *c; | ||
540 | |||
541 | c = alloc_cred(); | ||
542 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
543 | assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); | ||
544 | assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); | ||
545 | assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); | ||
546 | assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
547 | assert(fido_cred_set_uv(c, FIDO_OPT_TRUE) == FIDO_OK); | ||
548 | assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); | ||
549 | assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); | ||
550 | assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); | ||
551 | assert(fido_cred_verify(c) == FIDO_ERR_INVALID_PARAM); | ||
552 | assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); | ||
553 | assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); | ||
554 | assert(fido_cred_id_len(c) == sizeof(id)); | ||
555 | assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); | ||
556 | free_cred(c); | ||
557 | } | ||
558 | |||
559 | static void | ||
560 | junk_cdh(void) | ||
561 | { | ||
562 | fido_cred_t *c; | ||
563 | unsigned char *junk; | ||
564 | |||
565 | junk = malloc(sizeof(cdh)); | ||
566 | assert(junk != NULL); | ||
567 | memcpy(junk, cdh, sizeof(cdh)); | ||
568 | junk[0] = ~junk[0]; | ||
569 | |||
570 | c = alloc_cred(); | ||
571 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
572 | assert(fido_cred_set_clientdata_hash(c, junk, sizeof(cdh)) == FIDO_OK); | ||
573 | assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); | ||
574 | assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); | ||
575 | assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
576 | assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
577 | assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); | ||
578 | assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); | ||
579 | assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); | ||
580 | assert(fido_cred_verify(c) == FIDO_ERR_INVALID_SIG); | ||
581 | assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); | ||
582 | assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); | ||
583 | assert(fido_cred_id_len(c) == sizeof(id)); | ||
584 | assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); | ||
585 | free_cred(c); | ||
586 | free(junk); | ||
587 | } | ||
588 | |||
589 | static void | ||
590 | junk_rp_id(void) | ||
591 | { | ||
592 | fido_cred_t *c; | ||
593 | |||
594 | c = alloc_cred(); | ||
595 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
596 | assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); | ||
597 | assert(fido_cred_set_rp(c, "potato", rp_name) == FIDO_OK); | ||
598 | assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); | ||
599 | assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
600 | assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
601 | assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); | ||
602 | assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); | ||
603 | assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); | ||
604 | assert(fido_cred_verify(c) == FIDO_ERR_INVALID_PARAM); | ||
605 | assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); | ||
606 | assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); | ||
607 | assert(fido_cred_id_len(c) == sizeof(id)); | ||
608 | assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); | ||
609 | free_cred(c); | ||
610 | } | ||
611 | |||
612 | static void | ||
613 | junk_rp_name(void) | ||
614 | { | ||
615 | fido_cred_t *c; | ||
616 | |||
617 | c = alloc_cred(); | ||
618 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
619 | assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); | ||
620 | assert(fido_cred_set_rp(c, rp_id, "potato") == FIDO_OK); | ||
621 | assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); | ||
622 | assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
623 | assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
624 | assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); | ||
625 | assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); | ||
626 | assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); | ||
627 | assert(fido_cred_verify(c) == FIDO_OK); | ||
628 | assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); | ||
629 | assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); | ||
630 | assert(fido_cred_id_len(c) == sizeof(id)); | ||
631 | assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); | ||
632 | free_cred(c); | ||
633 | } | ||
634 | |||
635 | static void | ||
636 | junk_authdata(void) | ||
637 | { | ||
638 | fido_cred_t *c; | ||
639 | unsigned char *junk; | ||
640 | |||
641 | junk = malloc(sizeof(authdata)); | ||
642 | assert(junk != NULL); | ||
643 | memcpy(junk, authdata, sizeof(authdata)); | ||
644 | junk[0] = ~junk[0]; | ||
645 | |||
646 | c = alloc_cred(); | ||
647 | assert(fido_cred_set_authdata(c, junk, | ||
648 | sizeof(authdata)) == FIDO_ERR_INVALID_ARGUMENT); | ||
649 | assert(fido_cred_authdata_len(c) == 0); | ||
650 | assert(fido_cred_authdata_ptr(c) == NULL); | ||
651 | assert(fido_cred_flags(c) == 0); | ||
652 | assert(fido_cred_fmt(c) == NULL); | ||
653 | assert(fido_cred_id_len(c) == 0); | ||
654 | assert(fido_cred_id_ptr(c) == NULL); | ||
655 | assert(fido_cred_pubkey_len(c) == 0); | ||
656 | assert(fido_cred_pubkey_ptr(c) == NULL); | ||
657 | assert(fido_cred_rp_id(c) == NULL); | ||
658 | assert(fido_cred_rp_name(c) == NULL); | ||
659 | assert(fido_cred_sig_len(c) == 0); | ||
660 | assert(fido_cred_sig_ptr(c) == NULL); | ||
661 | assert(fido_cred_x5c_len(c) == 0); | ||
662 | assert(fido_cred_x5c_ptr(c) == NULL); | ||
663 | assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); | ||
664 | free_cred(c); | ||
665 | free(junk); | ||
666 | } | ||
667 | |||
668 | static void | ||
669 | junk_sig(void) | ||
670 | { | ||
671 | fido_cred_t *c; | ||
672 | unsigned char *junk; | ||
673 | |||
674 | junk = malloc(sizeof(sig)); | ||
675 | assert(junk != NULL); | ||
676 | memcpy(junk, sig, sizeof(sig)); | ||
677 | junk[0] = ~junk[0]; | ||
678 | |||
679 | c = alloc_cred(); | ||
680 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
681 | assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); | ||
682 | assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); | ||
683 | assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); | ||
684 | assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
685 | assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
686 | assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); | ||
687 | assert(fido_cred_set_sig(c, junk, sizeof(sig)) == FIDO_OK); | ||
688 | assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); | ||
689 | assert(fido_cred_verify(c) == FIDO_ERR_INVALID_SIG); | ||
690 | assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); | ||
691 | assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); | ||
692 | assert(fido_cred_id_len(c) == sizeof(id)); | ||
693 | assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); | ||
694 | free_cred(c); | ||
695 | free(junk); | ||
696 | } | ||
697 | |||
698 | static void | ||
699 | junk_x509(void) | ||
700 | { | ||
701 | fido_cred_t *c; | ||
702 | unsigned char *junk; | ||
703 | |||
704 | junk = malloc(sizeof(x509)); | ||
705 | assert(junk != NULL); | ||
706 | memcpy(junk, x509, sizeof(x509)); | ||
707 | junk[0] = ~junk[0]; | ||
708 | |||
709 | c = alloc_cred(); | ||
710 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
711 | assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); | ||
712 | assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); | ||
713 | assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); | ||
714 | assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
715 | assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
716 | assert(fido_cred_set_x509(c, junk, sizeof(x509)) == FIDO_OK); | ||
717 | assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); | ||
718 | assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); | ||
719 | assert(fido_cred_verify(c) == FIDO_ERR_INVALID_SIG); | ||
720 | assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); | ||
721 | assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); | ||
722 | assert(fido_cred_id_len(c) == sizeof(id)); | ||
723 | assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); | ||
724 | free_cred(c); | ||
725 | free(junk); | ||
726 | } | ||
727 | |||
728 | /* github issue #6 */ | ||
729 | static void | ||
730 | invalid_type(void) | ||
731 | { | ||
732 | fido_cred_t *c; | ||
733 | |||
734 | c = alloc_cred(); | ||
735 | assert(fido_cred_set_type(c, COSE_RS256) == FIDO_OK); | ||
736 | assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); | ||
737 | assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); | ||
738 | assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_ERR_INVALID_ARGUMENT); | ||
739 | assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
740 | assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); | ||
741 | assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); | ||
742 | assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); | ||
743 | assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); | ||
744 | assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); | ||
745 | assert(fido_cred_pubkey_len(c) == 0); | ||
746 | assert(fido_cred_pubkey_ptr(c) == NULL); | ||
747 | assert(fido_cred_id_len(c) == 0); | ||
748 | assert(fido_cred_id_ptr(c) == NULL); | ||
749 | free_cred(c); | ||
750 | } | ||
751 | |||
752 | /* cbor_serialize_alloc misuse */ | ||
753 | static void | ||
754 | bad_cbor_serialize(void) | ||
755 | { | ||
756 | fido_cred_t *c; | ||
757 | |||
758 | c = alloc_cred(); | ||
759 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
760 | assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); | ||
761 | assert(fido_cred_authdata_len(c) == sizeof(authdata)); | ||
762 | free_cred(c); | ||
763 | } | ||
764 | |||
765 | static void | ||
766 | duplicate_keys(void) | ||
767 | { | ||
768 | fido_cred_t *c; | ||
769 | |||
770 | c = alloc_cred(); | ||
771 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
772 | assert(fido_cred_set_authdata(c, authdata_dupkeys, | ||
773 | sizeof(authdata_dupkeys)) == FIDO_ERR_INVALID_ARGUMENT); | ||
774 | free_cred(c); | ||
775 | } | ||
776 | |||
777 | static void | ||
778 | unsorted_keys(void) | ||
779 | { | ||
780 | fido_cred_t *c; | ||
781 | |||
782 | c = alloc_cred(); | ||
783 | assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); | ||
784 | assert(fido_cred_set_authdata(c, authdata_unsorted_keys, | ||
785 | sizeof(authdata_unsorted_keys)) == FIDO_ERR_INVALID_ARGUMENT); | ||
786 | free_cred(c); | ||
787 | } | ||
788 | |||
789 | int | ||
790 | main(void) | ||
791 | { | ||
792 | fido_init(0); | ||
793 | |||
794 | empty_cred(); | ||
795 | valid_cred(); | ||
796 | no_cdh(); | ||
797 | no_rp_id(); | ||
798 | no_rp_name(); | ||
799 | no_authdata(); | ||
800 | no_x509(); | ||
801 | no_sig(); | ||
802 | no_fmt(); | ||
803 | junk_cdh(); | ||
804 | junk_rp_id(); | ||
805 | junk_rp_name(); | ||
806 | junk_authdata(); | ||
807 | junk_x509(); | ||
808 | junk_sig(); | ||
809 | wrong_options(); | ||
810 | invalid_type(); | ||
811 | bad_cbor_serialize(); | ||
812 | duplicate_keys(); | ||
813 | unsorted_keys(); | ||
814 | |||
815 | exit(0); | ||
816 | } | ||
diff --git a/regress/dev.c b/regress/dev.c new file mode 100644 index 0000000..39b3584 --- /dev/null +++ b/regress/dev.c | |||
@@ -0,0 +1,77 @@ | |||
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 <assert.h> | ||
8 | #include <fido.h> | ||
9 | |||
10 | #define FAKE_DEV_HANDLE ((void *)0xdeadbeef) | ||
11 | #define REPORT_LEN (64 + 1) | ||
12 | |||
13 | static void * | ||
14 | dummy_open(const char *path) | ||
15 | { | ||
16 | (void)path; | ||
17 | |||
18 | return (FAKE_DEV_HANDLE); | ||
19 | } | ||
20 | |||
21 | static void | ||
22 | dummy_close(void *handle) | ||
23 | { | ||
24 | assert(handle == FAKE_DEV_HANDLE); | ||
25 | } | ||
26 | |||
27 | static int | ||
28 | dummy_read(void *handle, unsigned char *ptr, size_t len, int ms) | ||
29 | { | ||
30 | (void)ptr; | ||
31 | (void)len; | ||
32 | (void)ms; | ||
33 | |||
34 | assert(handle == FAKE_DEV_HANDLE); | ||
35 | |||
36 | return (-1); | ||
37 | } | ||
38 | |||
39 | static int | ||
40 | dummy_write(void *handle, const unsigned char *ptr, size_t len) | ||
41 | { | ||
42 | assert(handle == FAKE_DEV_HANDLE); | ||
43 | assert(ptr != NULL); | ||
44 | assert(len == REPORT_LEN); | ||
45 | |||
46 | return ((int)len); | ||
47 | } | ||
48 | |||
49 | /* gh#56 */ | ||
50 | static void | ||
51 | open_iff_ok(void) | ||
52 | { | ||
53 | fido_dev_t *dev = NULL; | ||
54 | fido_dev_io_t io; | ||
55 | |||
56 | io.open = dummy_open; | ||
57 | io.close = dummy_close; | ||
58 | io.read = dummy_read; | ||
59 | io.write = dummy_write; | ||
60 | |||
61 | assert((dev = fido_dev_new()) != NULL); | ||
62 | assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); | ||
63 | assert(fido_dev_open(dev, "dummy") == FIDO_ERR_RX); | ||
64 | assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT); | ||
65 | |||
66 | fido_dev_free(&dev); | ||
67 | } | ||
68 | |||
69 | int | ||
70 | main(void) | ||
71 | { | ||
72 | fido_init(0); | ||
73 | |||
74 | open_iff_ok(); | ||
75 | |||
76 | exit(0); | ||
77 | } | ||
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..926e7f2 --- /dev/null +++ b/src/CMakeLists.txt | |||
@@ -0,0 +1,104 @@ | |||
1 | # Copyright (c) 2018 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 | add_definitions(-D_FIDO_INTERNAL) | ||
6 | |||
7 | list(APPEND FIDO_SOURCES | ||
8 | aes256.c | ||
9 | assert.c | ||
10 | authkey.c | ||
11 | bio.c | ||
12 | blob.c | ||
13 | buf.c | ||
14 | cbor.c | ||
15 | cred.c | ||
16 | credman.c | ||
17 | dev.c | ||
18 | ecdh.c | ||
19 | eddsa.c | ||
20 | err.c | ||
21 | es256.c | ||
22 | hid.c | ||
23 | info.c | ||
24 | io.c | ||
25 | iso7816.c | ||
26 | log.c | ||
27 | pin.c | ||
28 | reset.c | ||
29 | rs256.c | ||
30 | u2f.c | ||
31 | ) | ||
32 | |||
33 | if(FUZZ) | ||
34 | list(APPEND FIDO_SOURCES ../fuzz/uniform_random.c) | ||
35 | list(APPEND FIDO_SOURCES ../fuzz/wrap.c) | ||
36 | endif() | ||
37 | |||
38 | if(WIN32) | ||
39 | list(APPEND COMPAT_SOURCES hid_win.c) | ||
40 | elseif(APPLE) | ||
41 | list(APPEND COMPAT_SOURCES hid_osx.c) | ||
42 | elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") | ||
43 | list(APPEND COMPAT_SOURCES hid_linux.c) | ||
44 | elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") | ||
45 | list(APPEND COMPAT_SOURCES hid_openbsd.c) | ||
46 | endif() | ||
47 | |||
48 | list(APPEND COMPAT_SOURCES | ||
49 | ../openbsd-compat/bsd-getpagesize.c | ||
50 | ../openbsd-compat/explicit_bzero.c | ||
51 | ../openbsd-compat/explicit_bzero_win32.c | ||
52 | ../openbsd-compat/recallocarray.c | ||
53 | ../openbsd-compat/timingsafe_bcmp.c | ||
54 | ) | ||
55 | |||
56 | # static library | ||
57 | add_library(fido2 STATIC ${FIDO_SOURCES} ${COMPAT_SOURCES}) | ||
58 | target_link_libraries(fido2 ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES} | ||
59 | ${UDEV_LIBRARIES} ${BASE_LIBRARIES}) | ||
60 | if(WIN32) | ||
61 | if (MINGW) | ||
62 | target_link_libraries(fido2 wsock32 ws2_32 bcrypt setupapi hid) | ||
63 | else() | ||
64 | target_link_libraries(fido2 wsock32 ws2_32 bcrypt SetupAPI hid) | ||
65 | set_target_properties(fido2 PROPERTIES OUTPUT_NAME fido2_static) | ||
66 | endif() | ||
67 | elseif(APPLE) | ||
68 | target_link_libraries(fido2 "-framework CoreFoundation" | ||
69 | "-framework IOKit") | ||
70 | endif() | ||
71 | install(TARGETS fido2 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||
72 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) | ||
73 | |||
74 | # dynamic library | ||
75 | add_library(fido2_shared SHARED ${FIDO_SOURCES} ${COMPAT_SOURCES}) | ||
76 | target_link_libraries(fido2_shared ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES} | ||
77 | ${UDEV_LIBRARIES} ${BASE_LIBRARIES}) | ||
78 | if(WIN32) | ||
79 | if (MINGW) | ||
80 | target_link_libraries(fido2_shared wsock32 ws2_32 bcrypt | ||
81 | setupapi hid) | ||
82 | else() | ||
83 | target_link_libraries(fido2_shared wsock32 ws2_32 bcrypt | ||
84 | SetupAPI hid) | ||
85 | endif() | ||
86 | elseif(APPLE) | ||
87 | target_link_libraries(fido2_shared "-framework CoreFoundation" | ||
88 | "-framework IOKit") | ||
89 | endif() | ||
90 | set_target_properties(fido2_shared PROPERTIES OUTPUT_NAME fido2 | ||
91 | VERSION ${LIB_VERSION} SOVERSION ${LIB_SOVERSION}) | ||
92 | install(TARGETS fido2_shared | ||
93 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||
94 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||
95 | RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}) | ||
96 | |||
97 | install(FILES fido.h DESTINATION include) | ||
98 | install(DIRECTORY fido DESTINATION include) | ||
99 | |||
100 | if(NOT WIN32) | ||
101 | configure_file(libfido2.pc.in libfido2.pc @ONLY) | ||
102 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libfido2.pc" | ||
103 | DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") | ||
104 | endif() | ||
diff --git a/src/aes256.c b/src/aes256.c new file mode 100644 index 0000000..767cdb2 --- /dev/null +++ b/src/aes256.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <openssl/evp.h> | ||
8 | #include <string.h> | ||
9 | |||
10 | #include "fido.h" | ||
11 | |||
12 | int | ||
13 | aes256_cbc_enc(const fido_blob_t *key, const fido_blob_t *in, fido_blob_t *out) | ||
14 | { | ||
15 | EVP_CIPHER_CTX *ctx = NULL; | ||
16 | unsigned char iv[32]; | ||
17 | int len; | ||
18 | int ok = -1; | ||
19 | |||
20 | memset(iv, 0, sizeof(iv)); | ||
21 | out->ptr = NULL; | ||
22 | out->len = 0; | ||
23 | |||
24 | /* sanity check */ | ||
25 | if (in->len > INT_MAX || (in->len % 16) != 0 || | ||
26 | (out->ptr = calloc(1, in->len)) == NULL) { | ||
27 | fido_log_debug("%s: in->len=%zu", __func__, in->len); | ||
28 | goto fail; | ||
29 | } | ||
30 | |||
31 | if ((ctx = EVP_CIPHER_CTX_new()) == NULL || key->len != 32 || | ||
32 | !EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key->ptr, iv) || | ||
33 | !EVP_CIPHER_CTX_set_padding(ctx, 0) || | ||
34 | !EVP_EncryptUpdate(ctx, out->ptr, &len, in->ptr, (int)in->len) || | ||
35 | len < 0 || (size_t)len != in->len) { | ||
36 | fido_log_debug("%s: EVP_Encrypt", __func__); | ||
37 | goto fail; | ||
38 | } | ||
39 | |||
40 | out->len = (size_t)len; | ||
41 | |||
42 | ok = 0; | ||
43 | fail: | ||
44 | if (ctx != NULL) | ||
45 | EVP_CIPHER_CTX_free(ctx); | ||
46 | |||
47 | if (ok < 0) { | ||
48 | free(out->ptr); | ||
49 | out->ptr = NULL; | ||
50 | out->len = 0; | ||
51 | } | ||
52 | |||
53 | return (ok); | ||
54 | } | ||
55 | |||
56 | int | ||
57 | aes256_cbc_dec(const fido_blob_t *key, const fido_blob_t *in, fido_blob_t *out) | ||
58 | { | ||
59 | EVP_CIPHER_CTX *ctx = NULL; | ||
60 | unsigned char iv[32]; | ||
61 | int len; | ||
62 | int ok = -1; | ||
63 | |||
64 | memset(iv, 0, sizeof(iv)); | ||
65 | out->ptr = NULL; | ||
66 | out->len = 0; | ||
67 | |||
68 | /* sanity check */ | ||
69 | if (in->len > INT_MAX || (in->len % 16) != 0 || | ||
70 | (out->ptr = calloc(1, in->len)) == NULL) { | ||
71 | fido_log_debug("%s: in->len=%zu", __func__, in->len); | ||
72 | goto fail; | ||
73 | } | ||
74 | |||
75 | if ((ctx = EVP_CIPHER_CTX_new()) == NULL || key->len != 32 || | ||
76 | !EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key->ptr, iv) || | ||
77 | !EVP_CIPHER_CTX_set_padding(ctx, 0) || | ||
78 | !EVP_DecryptUpdate(ctx, out->ptr, &len, in->ptr, (int)in->len) || | ||
79 | len < 0 || (size_t)len > in->len + 32) { | ||
80 | fido_log_debug("%s: EVP_Decrypt", __func__); | ||
81 | goto fail; | ||
82 | } | ||
83 | |||
84 | out->len = (size_t)len; | ||
85 | |||
86 | ok = 0; | ||
87 | fail: | ||
88 | if (ctx != NULL) | ||
89 | EVP_CIPHER_CTX_free(ctx); | ||
90 | |||
91 | if (ok < 0) { | ||
92 | free(out->ptr); | ||
93 | out->ptr = NULL; | ||
94 | out->len = 0; | ||
95 | } | ||
96 | |||
97 | return (ok); | ||
98 | } | ||
diff --git a/src/assert.c b/src/assert.c new file mode 100644 index 0000000..a21b308 --- /dev/null +++ b/src/assert.c | |||
@@ -0,0 +1,1090 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <openssl/ec.h> | ||
8 | #include <openssl/ecdsa.h> | ||
9 | #include <openssl/evp.h> | ||
10 | #include <openssl/sha.h> | ||
11 | |||
12 | #include <string.h> | ||
13 | #include "fido.h" | ||
14 | #include "fido/es256.h" | ||
15 | #include "fido/rs256.h" | ||
16 | #include "fido/eddsa.h" | ||
17 | |||
18 | static int | ||
19 | adjust_assert_count(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
20 | { | ||
21 | fido_assert_t *assert = arg; | ||
22 | uint64_t n; | ||
23 | |||
24 | /* numberOfCredentials; see section 6.2 */ | ||
25 | if (cbor_isa_uint(key) == false || | ||
26 | cbor_int_get_width(key) != CBOR_INT_8 || | ||
27 | cbor_get_uint8(key) != 5) { | ||
28 | fido_log_debug("%s: cbor_type", __func__); | ||
29 | return (0); /* ignore */ | ||
30 | } | ||
31 | |||
32 | if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) { | ||
33 | fido_log_debug("%s: cbor_decode_uint64", __func__); | ||
34 | return (-1); | ||
35 | } | ||
36 | |||
37 | if (assert->stmt_len != 0 || assert->stmt_cnt != 1 || | ||
38 | (size_t)n < assert->stmt_cnt) { | ||
39 | fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu, n=%zu", | ||
40 | __func__, assert->stmt_len, assert->stmt_cnt, (size_t)n); | ||
41 | return (-1); | ||
42 | } | ||
43 | |||
44 | if (fido_assert_set_count(assert, (size_t)n) != FIDO_OK) { | ||
45 | fido_log_debug("%s: fido_assert_set_count", __func__); | ||
46 | return (-1); | ||
47 | } | ||
48 | |||
49 | assert->stmt_len = 0; /* XXX */ | ||
50 | |||
51 | return (0); | ||
52 | } | ||
53 | |||
54 | static int | ||
55 | parse_assert_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
56 | { | ||
57 | fido_assert_stmt *stmt = arg; | ||
58 | |||
59 | if (cbor_isa_uint(key) == false || | ||
60 | cbor_int_get_width(key) != CBOR_INT_8) { | ||
61 | fido_log_debug("%s: cbor type", __func__); | ||
62 | return (0); /* ignore */ | ||
63 | } | ||
64 | |||
65 | switch (cbor_get_uint8(key)) { | ||
66 | case 1: /* credential id */ | ||
67 | return (cbor_decode_cred_id(val, &stmt->id)); | ||
68 | case 2: /* authdata */ | ||
69 | return (cbor_decode_assert_authdata(val, &stmt->authdata_cbor, | ||
70 | &stmt->authdata, &stmt->authdata_ext, | ||
71 | &stmt->hmac_secret_enc)); | ||
72 | case 3: /* signature */ | ||
73 | return (fido_blob_decode(val, &stmt->sig)); | ||
74 | case 4: /* user attributes */ | ||
75 | return (cbor_decode_user(val, &stmt->user)); | ||
76 | default: /* ignore */ | ||
77 | fido_log_debug("%s: cbor type", __func__); | ||
78 | return (0); | ||
79 | } | ||
80 | } | ||
81 | |||
82 | static int | ||
83 | fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert, | ||
84 | const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin) | ||
85 | { | ||
86 | fido_blob_t f; | ||
87 | cbor_item_t *argv[7]; | ||
88 | int r; | ||
89 | |||
90 | memset(argv, 0, sizeof(argv)); | ||
91 | memset(&f, 0, sizeof(f)); | ||
92 | |||
93 | /* do we have everything we need? */ | ||
94 | if (assert->rp_id == NULL || assert->cdh.ptr == NULL) { | ||
95 | fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__, | ||
96 | (void *)assert->rp_id, (void *)assert->cdh.ptr); | ||
97 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
98 | goto fail; | ||
99 | } | ||
100 | |||
101 | if ((argv[0] = cbor_build_string(assert->rp_id)) == NULL || | ||
102 | (argv[1] = fido_blob_encode(&assert->cdh)) == NULL) { | ||
103 | fido_log_debug("%s: cbor encode", __func__); | ||
104 | r = FIDO_ERR_INTERNAL; | ||
105 | goto fail; | ||
106 | } | ||
107 | |||
108 | /* allowed credentials */ | ||
109 | if (assert->allow_list.len) { | ||
110 | const fido_blob_array_t *cl = &assert->allow_list; | ||
111 | if ((argv[2] = cbor_encode_pubkey_list(cl)) == NULL) { | ||
112 | fido_log_debug("%s: cbor_encode_pubkey_list", __func__); | ||
113 | r = FIDO_ERR_INTERNAL; | ||
114 | goto fail; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | /* hmac-secret extension */ | ||
119 | if (assert->ext & FIDO_EXT_HMAC_SECRET) | ||
120 | if ((argv[3] = cbor_encode_hmac_secret_param(ecdh, pk, | ||
121 | &assert->hmac_salt)) == NULL) { | ||
122 | fido_log_debug("%s: cbor_encode_hmac_secret_param", | ||
123 | __func__); | ||
124 | r = FIDO_ERR_INTERNAL; | ||
125 | goto fail; | ||
126 | } | ||
127 | |||
128 | /* options */ | ||
129 | if (assert->up != FIDO_OPT_OMIT || assert->uv != FIDO_OPT_OMIT) | ||
130 | if ((argv[4] = cbor_encode_assert_options(assert->up, | ||
131 | assert->uv)) == NULL) { | ||
132 | fido_log_debug("%s: cbor_encode_assert_options", | ||
133 | __func__); | ||
134 | r = FIDO_ERR_INTERNAL; | ||
135 | goto fail; | ||
136 | } | ||
137 | |||
138 | /* pin authentication */ | ||
139 | if (pin) { | ||
140 | if (pk == NULL || ecdh == NULL) { | ||
141 | fido_log_debug("%s: pin=%p, pk=%p, ecdh=%p", __func__, | ||
142 | (const void *)pin, (const void *)pk, | ||
143 | (const void *)ecdh); | ||
144 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
145 | goto fail; | ||
146 | } | ||
147 | if ((r = cbor_add_pin_params(dev, &assert->cdh, pk, ecdh, pin, | ||
148 | &argv[5], &argv[6])) != FIDO_OK) { | ||
149 | fido_log_debug("%s: cbor_add_pin_params", __func__); | ||
150 | goto fail; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | /* frame and transmit */ | ||
155 | if (cbor_build_frame(CTAP_CBOR_ASSERT, argv, 7, &f) < 0 || | ||
156 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | ||
157 | fido_log_debug("%s: fido_tx", __func__); | ||
158 | r = FIDO_ERR_TX; | ||
159 | goto fail; | ||
160 | } | ||
161 | |||
162 | r = FIDO_OK; | ||
163 | fail: | ||
164 | cbor_vector_free(argv, nitems(argv)); | ||
165 | free(f.ptr); | ||
166 | |||
167 | return (r); | ||
168 | } | ||
169 | |||
170 | static int | ||
171 | fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) | ||
172 | { | ||
173 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
174 | unsigned char reply[2048]; | ||
175 | int reply_len; | ||
176 | int r; | ||
177 | |||
178 | fido_assert_reset_rx(assert); | ||
179 | |||
180 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
181 | fido_log_debug("%s: fido_rx", __func__); | ||
182 | return (FIDO_ERR_RX); | ||
183 | } | ||
184 | |||
185 | /* start with room for a single assertion */ | ||
186 | if ((assert->stmt = calloc(1, sizeof(fido_assert_stmt))) == NULL) | ||
187 | return (FIDO_ERR_INTERNAL); | ||
188 | |||
189 | assert->stmt_len = 0; | ||
190 | assert->stmt_cnt = 1; | ||
191 | |||
192 | /* adjust as needed */ | ||
193 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, assert, | ||
194 | adjust_assert_count)) != FIDO_OK) { | ||
195 | fido_log_debug("%s: adjust_assert_count", __func__); | ||
196 | return (r); | ||
197 | } | ||
198 | |||
199 | /* parse the first assertion */ | ||
200 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, | ||
201 | &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) { | ||
202 | fido_log_debug("%s: parse_assert_reply", __func__); | ||
203 | return (r); | ||
204 | } | ||
205 | |||
206 | assert->stmt_len++; | ||
207 | |||
208 | return (FIDO_OK); | ||
209 | } | ||
210 | |||
211 | static int | ||
212 | fido_get_next_assert_tx(fido_dev_t *dev) | ||
213 | { | ||
214 | const unsigned char cbor[] = { CTAP_CBOR_NEXT_ASSERT }; | ||
215 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
216 | |||
217 | if (fido_tx(dev, cmd, cbor, sizeof(cbor)) < 0) { | ||
218 | fido_log_debug("%s: fido_tx", __func__); | ||
219 | return (FIDO_ERR_TX); | ||
220 | } | ||
221 | |||
222 | return (FIDO_OK); | ||
223 | } | ||
224 | |||
225 | static int | ||
226 | fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) | ||
227 | { | ||
228 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
229 | unsigned char reply[2048]; | ||
230 | int reply_len; | ||
231 | int r; | ||
232 | |||
233 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
234 | fido_log_debug("%s: fido_rx", __func__); | ||
235 | return (FIDO_ERR_RX); | ||
236 | } | ||
237 | |||
238 | /* sanity check */ | ||
239 | if (assert->stmt_len >= assert->stmt_cnt) { | ||
240 | fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu", __func__, | ||
241 | assert->stmt_len, assert->stmt_cnt); | ||
242 | return (FIDO_ERR_INTERNAL); | ||
243 | } | ||
244 | |||
245 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, | ||
246 | &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) { | ||
247 | fido_log_debug("%s: parse_assert_reply", __func__); | ||
248 | return (r); | ||
249 | } | ||
250 | |||
251 | return (FIDO_OK); | ||
252 | } | ||
253 | |||
254 | static int | ||
255 | fido_dev_get_assert_wait(fido_dev_t *dev, fido_assert_t *assert, | ||
256 | const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int ms) | ||
257 | { | ||
258 | int r; | ||
259 | |||
260 | if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin)) != FIDO_OK || | ||
261 | (r = fido_dev_get_assert_rx(dev, assert, ms)) != FIDO_OK) | ||
262 | return (r); | ||
263 | |||
264 | while (assert->stmt_len < assert->stmt_cnt) { | ||
265 | if ((r = fido_get_next_assert_tx(dev)) != FIDO_OK || | ||
266 | (r = fido_get_next_assert_rx(dev, assert, ms)) != FIDO_OK) | ||
267 | return (r); | ||
268 | assert->stmt_len++; | ||
269 | } | ||
270 | |||
271 | return (FIDO_OK); | ||
272 | } | ||
273 | |||
274 | static int | ||
275 | decrypt_hmac_secrets(fido_assert_t *assert, const fido_blob_t *key) | ||
276 | { | ||
277 | for (size_t i = 0; i < assert->stmt_cnt; i++) { | ||
278 | fido_assert_stmt *stmt = &assert->stmt[i]; | ||
279 | if (stmt->hmac_secret_enc.ptr != NULL) { | ||
280 | if (aes256_cbc_dec(key, &stmt->hmac_secret_enc, | ||
281 | &stmt->hmac_secret) < 0) { | ||
282 | fido_log_debug("%s: aes256_cbc_dec %zu", | ||
283 | __func__, i); | ||
284 | return (-1); | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | |||
289 | return (0); | ||
290 | } | ||
291 | |||
292 | int | ||
293 | fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin) | ||
294 | { | ||
295 | fido_blob_t *ecdh = NULL; | ||
296 | es256_pk_t *pk = NULL; | ||
297 | int r; | ||
298 | |||
299 | if (assert->rp_id == NULL || assert->cdh.ptr == NULL) { | ||
300 | fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__, | ||
301 | (void *)assert->rp_id, (void *)assert->cdh.ptr); | ||
302 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
303 | } | ||
304 | |||
305 | if (fido_dev_is_fido2(dev) == false) { | ||
306 | if (pin != NULL || assert->ext != 0) | ||
307 | return (FIDO_ERR_UNSUPPORTED_OPTION); | ||
308 | return (u2f_authenticate(dev, assert, -1)); | ||
309 | } | ||
310 | |||
311 | if (pin != NULL || assert->ext != 0) { | ||
312 | if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { | ||
313 | fido_log_debug("%s: fido_do_ecdh", __func__); | ||
314 | goto fail; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, -1); | ||
319 | if (r == FIDO_OK && assert->ext & FIDO_EXT_HMAC_SECRET) | ||
320 | if (decrypt_hmac_secrets(assert, ecdh) < 0) { | ||
321 | fido_log_debug("%s: decrypt_hmac_secrets", __func__); | ||
322 | r = FIDO_ERR_INTERNAL; | ||
323 | goto fail; | ||
324 | } | ||
325 | |||
326 | fail: | ||
327 | es256_pk_free(&pk); | ||
328 | fido_blob_free(&ecdh); | ||
329 | |||
330 | return (r); | ||
331 | } | ||
332 | |||
333 | int | ||
334 | fido_check_flags(uint8_t flags, fido_opt_t up, fido_opt_t uv) | ||
335 | { | ||
336 | fido_log_debug("%s: flags=%02x", __func__, flags); | ||
337 | fido_log_debug("%s: up=%d, uv=%d", __func__, up, uv); | ||
338 | |||
339 | if (up == FIDO_OPT_TRUE && | ||
340 | (flags & CTAP_AUTHDATA_USER_PRESENT) == 0) { | ||
341 | fido_log_debug("%s: CTAP_AUTHDATA_USER_PRESENT", __func__); | ||
342 | return (-1); /* user not present */ | ||
343 | } | ||
344 | |||
345 | if (uv == FIDO_OPT_TRUE && | ||
346 | (flags & CTAP_AUTHDATA_USER_VERIFIED) == 0) { | ||
347 | fido_log_debug("%s: CTAP_AUTHDATA_USER_VERIFIED", __func__); | ||
348 | return (-1); /* user not verified */ | ||
349 | } | ||
350 | |||
351 | return (0); | ||
352 | } | ||
353 | |||
354 | static int | ||
355 | check_extensions(int authdata_ext, int ext) | ||
356 | { | ||
357 | if (authdata_ext != ext) { | ||
358 | fido_log_debug("%s: authdata_ext=0x%x != ext=0x%x", __func__, | ||
359 | authdata_ext, ext); | ||
360 | return (-1); | ||
361 | } | ||
362 | |||
363 | return (0); | ||
364 | } | ||
365 | |||
366 | static int | ||
367 | get_signed_hash(int cose_alg, fido_blob_t *dgst, const fido_blob_t *clientdata, | ||
368 | const fido_blob_t *authdata_cbor) | ||
369 | { | ||
370 | cbor_item_t *item = NULL; | ||
371 | unsigned char *authdata_ptr = NULL; | ||
372 | size_t authdata_len; | ||
373 | struct cbor_load_result cbor; | ||
374 | SHA256_CTX ctx; | ||
375 | int ok = -1; | ||
376 | |||
377 | if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len, | ||
378 | &cbor)) == NULL || cbor_isa_bytestring(item) == false || | ||
379 | cbor_bytestring_is_definite(item) == false) { | ||
380 | fido_log_debug("%s: authdata", __func__); | ||
381 | goto fail; | ||
382 | } | ||
383 | |||
384 | authdata_ptr = cbor_bytestring_handle(item); | ||
385 | authdata_len = cbor_bytestring_length(item); | ||
386 | |||
387 | if (cose_alg != COSE_EDDSA) { | ||
388 | if (dgst->len < SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 || | ||
389 | SHA256_Update(&ctx, authdata_ptr, authdata_len) == 0 || | ||
390 | SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 || | ||
391 | SHA256_Final(dgst->ptr, &ctx) == 0) { | ||
392 | fido_log_debug("%s: sha256", __func__); | ||
393 | goto fail; | ||
394 | } | ||
395 | dgst->len = SHA256_DIGEST_LENGTH; | ||
396 | } else { | ||
397 | if (SIZE_MAX - authdata_len < clientdata->len || | ||
398 | dgst->len < authdata_len + clientdata->len) { | ||
399 | fido_log_debug("%s: memcpy", __func__); | ||
400 | goto fail; | ||
401 | } | ||
402 | memcpy(dgst->ptr, authdata_ptr, authdata_len); | ||
403 | memcpy(dgst->ptr + authdata_len, clientdata->ptr, | ||
404 | clientdata->len); | ||
405 | dgst->len = authdata_len + clientdata->len; | ||
406 | } | ||
407 | |||
408 | ok = 0; | ||
409 | fail: | ||
410 | if (item != NULL) | ||
411 | cbor_decref(&item); | ||
412 | |||
413 | return (ok); | ||
414 | } | ||
415 | |||
416 | int | ||
417 | fido_verify_sig_es256(const fido_blob_t *dgst, const es256_pk_t *pk, | ||
418 | const fido_blob_t *sig) | ||
419 | { | ||
420 | EVP_PKEY *pkey = NULL; | ||
421 | EC_KEY *ec = NULL; | ||
422 | int ok = -1; | ||
423 | |||
424 | /* ECDSA_verify needs ints */ | ||
425 | if (dgst->len > INT_MAX || sig->len > INT_MAX) { | ||
426 | fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, | ||
427 | dgst->len, sig->len); | ||
428 | return (-1); | ||
429 | } | ||
430 | |||
431 | if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL || | ||
432 | (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) { | ||
433 | fido_log_debug("%s: pk -> ec", __func__); | ||
434 | goto fail; | ||
435 | } | ||
436 | |||
437 | if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr, | ||
438 | (int)sig->len, ec) != 1) { | ||
439 | fido_log_debug("%s: ECDSA_verify", __func__); | ||
440 | goto fail; | ||
441 | } | ||
442 | |||
443 | ok = 0; | ||
444 | fail: | ||
445 | if (pkey != NULL) | ||
446 | EVP_PKEY_free(pkey); | ||
447 | |||
448 | return (ok); | ||
449 | } | ||
450 | |||
451 | int | ||
452 | fido_verify_sig_rs256(const fido_blob_t *dgst, const rs256_pk_t *pk, | ||
453 | const fido_blob_t *sig) | ||
454 | { | ||
455 | EVP_PKEY *pkey = NULL; | ||
456 | RSA *rsa = NULL; | ||
457 | int ok = -1; | ||
458 | |||
459 | /* RSA_verify needs unsigned ints */ | ||
460 | if (dgst->len > UINT_MAX || sig->len > UINT_MAX) { | ||
461 | fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, | ||
462 | dgst->len, sig->len); | ||
463 | return (-1); | ||
464 | } | ||
465 | |||
466 | if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL || | ||
467 | (rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) { | ||
468 | fido_log_debug("%s: pk -> ec", __func__); | ||
469 | goto fail; | ||
470 | } | ||
471 | |||
472 | if (RSA_verify(NID_sha256, dgst->ptr, (unsigned int)dgst->len, sig->ptr, | ||
473 | (unsigned int)sig->len, rsa) != 1) { | ||
474 | fido_log_debug("%s: RSA_verify", __func__); | ||
475 | goto fail; | ||
476 | } | ||
477 | |||
478 | ok = 0; | ||
479 | fail: | ||
480 | if (pkey != NULL) | ||
481 | EVP_PKEY_free(pkey); | ||
482 | |||
483 | return (ok); | ||
484 | } | ||
485 | |||
486 | int | ||
487 | fido_verify_sig_eddsa(const fido_blob_t *dgst, const eddsa_pk_t *pk, | ||
488 | const fido_blob_t *sig) | ||
489 | { | ||
490 | EVP_PKEY *pkey = NULL; | ||
491 | EVP_MD_CTX *mdctx = NULL; | ||
492 | int ok = -1; | ||
493 | |||
494 | /* EVP_DigestVerify needs ints */ | ||
495 | if (dgst->len > INT_MAX || sig->len > INT_MAX) { | ||
496 | fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, | ||
497 | dgst->len, sig->len); | ||
498 | return (-1); | ||
499 | } | ||
500 | |||
501 | if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { | ||
502 | fido_log_debug("%s: pk -> pkey", __func__); | ||
503 | goto fail; | ||
504 | } | ||
505 | |||
506 | if ((mdctx = EVP_MD_CTX_new()) == NULL) { | ||
507 | fido_log_debug("%s: EVP_MD_CTX_new", __func__); | ||
508 | goto fail; | ||
509 | } | ||
510 | |||
511 | if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) { | ||
512 | fido_log_debug("%s: EVP_DigestVerifyInit", __func__); | ||
513 | goto fail; | ||
514 | } | ||
515 | |||
516 | if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr, | ||
517 | dgst->len) != 1) { | ||
518 | fido_log_debug("%s: EVP_DigestVerify", __func__); | ||
519 | goto fail; | ||
520 | } | ||
521 | |||
522 | ok = 0; | ||
523 | fail: | ||
524 | if (mdctx != NULL) | ||
525 | EVP_MD_CTX_free(mdctx); | ||
526 | |||
527 | if (pkey != NULL) | ||
528 | EVP_PKEY_free(pkey); | ||
529 | |||
530 | return (ok); | ||
531 | } | ||
532 | |||
533 | int | ||
534 | fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg, | ||
535 | const void *pk) | ||
536 | { | ||
537 | unsigned char buf[1024]; | ||
538 | fido_blob_t dgst; | ||
539 | const fido_assert_stmt *stmt = NULL; | ||
540 | int ok = -1; | ||
541 | int r; | ||
542 | |||
543 | dgst.ptr = buf; | ||
544 | dgst.len = sizeof(buf); | ||
545 | |||
546 | if (idx >= assert->stmt_len || pk == NULL) { | ||
547 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
548 | goto out; | ||
549 | } | ||
550 | |||
551 | stmt = &assert->stmt[idx]; | ||
552 | |||
553 | /* do we have everything we need? */ | ||
554 | if (assert->cdh.ptr == NULL || assert->rp_id == NULL || | ||
555 | stmt->authdata_cbor.ptr == NULL || stmt->sig.ptr == NULL) { | ||
556 | fido_log_debug("%s: cdh=%p, rp_id=%s, authdata=%p, sig=%p", | ||
557 | __func__, (void *)assert->cdh.ptr, assert->rp_id, | ||
558 | (void *)stmt->authdata_cbor.ptr, (void *)stmt->sig.ptr); | ||
559 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
560 | goto out; | ||
561 | } | ||
562 | |||
563 | if (fido_check_flags(stmt->authdata.flags, assert->up, | ||
564 | assert->uv) < 0) { | ||
565 | fido_log_debug("%s: fido_check_flags", __func__); | ||
566 | r = FIDO_ERR_INVALID_PARAM; | ||
567 | goto out; | ||
568 | } | ||
569 | |||
570 | if (check_extensions(stmt->authdata_ext, assert->ext) < 0) { | ||
571 | fido_log_debug("%s: check_extensions", __func__); | ||
572 | r = FIDO_ERR_INVALID_PARAM; | ||
573 | goto out; | ||
574 | } | ||
575 | |||
576 | if (fido_check_rp_id(assert->rp_id, stmt->authdata.rp_id_hash) != 0) { | ||
577 | fido_log_debug("%s: fido_check_rp_id", __func__); | ||
578 | r = FIDO_ERR_INVALID_PARAM; | ||
579 | goto out; | ||
580 | } | ||
581 | |||
582 | if (get_signed_hash(cose_alg, &dgst, &assert->cdh, | ||
583 | &stmt->authdata_cbor) < 0) { | ||
584 | fido_log_debug("%s: get_signed_hash", __func__); | ||
585 | r = FIDO_ERR_INTERNAL; | ||
586 | goto out; | ||
587 | } | ||
588 | |||
589 | switch (cose_alg) { | ||
590 | case COSE_ES256: | ||
591 | ok = fido_verify_sig_es256(&dgst, pk, &stmt->sig); | ||
592 | break; | ||
593 | case COSE_RS256: | ||
594 | ok = fido_verify_sig_rs256(&dgst, pk, &stmt->sig); | ||
595 | break; | ||
596 | case COSE_EDDSA: | ||
597 | ok = fido_verify_sig_eddsa(&dgst, pk, &stmt->sig); | ||
598 | break; | ||
599 | default: | ||
600 | fido_log_debug("%s: unsupported cose_alg %d", __func__, | ||
601 | cose_alg); | ||
602 | r = FIDO_ERR_UNSUPPORTED_OPTION; | ||
603 | goto out; | ||
604 | } | ||
605 | |||
606 | if (ok < 0) | ||
607 | r = FIDO_ERR_INVALID_SIG; | ||
608 | else | ||
609 | r = FIDO_OK; | ||
610 | out: | ||
611 | explicit_bzero(buf, sizeof(buf)); | ||
612 | |||
613 | return (r); | ||
614 | } | ||
615 | |||
616 | int | ||
617 | fido_assert_set_clientdata_hash(fido_assert_t *assert, | ||
618 | const unsigned char *hash, size_t hash_len) | ||
619 | { | ||
620 | if (fido_blob_set(&assert->cdh, hash, hash_len) < 0) | ||
621 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
622 | |||
623 | return (FIDO_OK); | ||
624 | } | ||
625 | |||
626 | int | ||
627 | fido_assert_set_hmac_salt(fido_assert_t *assert, const unsigned char *salt, | ||
628 | size_t salt_len) | ||
629 | { | ||
630 | if ((salt_len != 32 && salt_len != 64) || | ||
631 | fido_blob_set(&assert->hmac_salt, salt, salt_len) < 0) | ||
632 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
633 | |||
634 | return (FIDO_OK); | ||
635 | } | ||
636 | |||
637 | int | ||
638 | fido_assert_set_rp(fido_assert_t *assert, const char *id) | ||
639 | { | ||
640 | if (assert->rp_id != NULL) { | ||
641 | free(assert->rp_id); | ||
642 | assert->rp_id = NULL; | ||
643 | } | ||
644 | |||
645 | if (id == NULL) | ||
646 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
647 | |||
648 | if ((assert->rp_id = strdup(id)) == NULL) | ||
649 | return (FIDO_ERR_INTERNAL); | ||
650 | |||
651 | return (FIDO_OK); | ||
652 | } | ||
653 | |||
654 | int | ||
655 | fido_assert_allow_cred(fido_assert_t *assert, const unsigned char *ptr, | ||
656 | size_t len) | ||
657 | { | ||
658 | fido_blob_t id; | ||
659 | fido_blob_t *list_ptr; | ||
660 | int r; | ||
661 | |||
662 | memset(&id, 0, sizeof(id)); | ||
663 | |||
664 | if (assert->allow_list.len == SIZE_MAX) { | ||
665 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
666 | goto fail; | ||
667 | } | ||
668 | |||
669 | if (fido_blob_set(&id, ptr, len) < 0 || (list_ptr = | ||
670 | recallocarray(assert->allow_list.ptr, assert->allow_list.len, | ||
671 | assert->allow_list.len + 1, sizeof(fido_blob_t))) == NULL) { | ||
672 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
673 | goto fail; | ||
674 | } | ||
675 | |||
676 | list_ptr[assert->allow_list.len++] = id; | ||
677 | assert->allow_list.ptr = list_ptr; | ||
678 | |||
679 | return (FIDO_OK); | ||
680 | fail: | ||
681 | free(id.ptr); | ||
682 | |||
683 | return (r); | ||
684 | |||
685 | } | ||
686 | |||
687 | int | ||
688 | fido_assert_set_extensions(fido_assert_t *assert, int ext) | ||
689 | { | ||
690 | if (ext != 0 && ext != FIDO_EXT_HMAC_SECRET) | ||
691 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
692 | |||
693 | assert->ext = ext; | ||
694 | |||
695 | return (FIDO_OK); | ||
696 | } | ||
697 | |||
698 | int | ||
699 | fido_assert_set_options(fido_assert_t *assert, bool up, bool uv) | ||
700 | { | ||
701 | assert->up = up ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; | ||
702 | assert->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; | ||
703 | |||
704 | return (FIDO_OK); | ||
705 | } | ||
706 | |||
707 | int | ||
708 | fido_assert_set_up(fido_assert_t *assert, fido_opt_t up) | ||
709 | { | ||
710 | assert->up = up; | ||
711 | |||
712 | return (FIDO_OK); | ||
713 | } | ||
714 | |||
715 | int | ||
716 | fido_assert_set_uv(fido_assert_t *assert, fido_opt_t uv) | ||
717 | { | ||
718 | assert->uv = uv; | ||
719 | |||
720 | return (FIDO_OK); | ||
721 | } | ||
722 | |||
723 | const unsigned char * | ||
724 | fido_assert_clientdata_hash_ptr(const fido_assert_t *assert) | ||
725 | { | ||
726 | return (assert->cdh.ptr); | ||
727 | } | ||
728 | |||
729 | size_t | ||
730 | fido_assert_clientdata_hash_len(const fido_assert_t *assert) | ||
731 | { | ||
732 | return (assert->cdh.len); | ||
733 | } | ||
734 | |||
735 | fido_assert_t * | ||
736 | fido_assert_new(void) | ||
737 | { | ||
738 | return (calloc(1, sizeof(fido_assert_t))); | ||
739 | } | ||
740 | |||
741 | void | ||
742 | fido_assert_reset_tx(fido_assert_t *assert) | ||
743 | { | ||
744 | free(assert->rp_id); | ||
745 | free(assert->cdh.ptr); | ||
746 | free(assert->hmac_salt.ptr); | ||
747 | fido_free_blob_array(&assert->allow_list); | ||
748 | |||
749 | memset(&assert->cdh, 0, sizeof(assert->cdh)); | ||
750 | memset(&assert->hmac_salt, 0, sizeof(assert->hmac_salt)); | ||
751 | memset(&assert->allow_list, 0, sizeof(assert->allow_list)); | ||
752 | |||
753 | assert->rp_id = NULL; | ||
754 | assert->up = FIDO_OPT_OMIT; | ||
755 | assert->uv = FIDO_OPT_OMIT; | ||
756 | assert->ext = 0; | ||
757 | } | ||
758 | |||
759 | void | ||
760 | fido_assert_reset_rx(fido_assert_t *assert) | ||
761 | { | ||
762 | for (size_t i = 0; i < assert->stmt_cnt; i++) { | ||
763 | free(assert->stmt[i].user.id.ptr); | ||
764 | free(assert->stmt[i].user.icon); | ||
765 | free(assert->stmt[i].user.name); | ||
766 | free(assert->stmt[i].user.display_name); | ||
767 | free(assert->stmt[i].id.ptr); | ||
768 | if (assert->stmt[i].hmac_secret.ptr != NULL) { | ||
769 | explicit_bzero(assert->stmt[i].hmac_secret.ptr, | ||
770 | assert->stmt[i].hmac_secret.len); | ||
771 | } | ||
772 | free(assert->stmt[i].hmac_secret.ptr); | ||
773 | free(assert->stmt[i].hmac_secret_enc.ptr); | ||
774 | free(assert->stmt[i].authdata_cbor.ptr); | ||
775 | free(assert->stmt[i].sig.ptr); | ||
776 | memset(&assert->stmt[i], 0, sizeof(assert->stmt[i])); | ||
777 | } | ||
778 | |||
779 | free(assert->stmt); | ||
780 | |||
781 | assert->stmt = NULL; | ||
782 | assert->stmt_len = 0; | ||
783 | assert->stmt_cnt = 0; | ||
784 | } | ||
785 | |||
786 | void | ||
787 | fido_assert_free(fido_assert_t **assert_p) | ||
788 | { | ||
789 | fido_assert_t *assert; | ||
790 | |||
791 | if (assert_p == NULL || (assert = *assert_p) == NULL) | ||
792 | return; | ||
793 | |||
794 | fido_assert_reset_tx(assert); | ||
795 | fido_assert_reset_rx(assert); | ||
796 | |||
797 | free(assert); | ||
798 | |||
799 | *assert_p = NULL; | ||
800 | } | ||
801 | |||
802 | size_t | ||
803 | fido_assert_count(const fido_assert_t *assert) | ||
804 | { | ||
805 | return (assert->stmt_len); | ||
806 | } | ||
807 | |||
808 | const char * | ||
809 | fido_assert_rp_id(const fido_assert_t *assert) | ||
810 | { | ||
811 | return (assert->rp_id); | ||
812 | } | ||
813 | |||
814 | uint8_t | ||
815 | fido_assert_flags(const fido_assert_t *assert, size_t idx) | ||
816 | { | ||
817 | if (idx >= assert->stmt_len) | ||
818 | return (0); | ||
819 | |||
820 | return (assert->stmt[idx].authdata.flags); | ||
821 | } | ||
822 | |||
823 | uint32_t | ||
824 | fido_assert_sigcount(const fido_assert_t *assert, size_t idx) | ||
825 | { | ||
826 | if (idx >= assert->stmt_len) | ||
827 | return (0); | ||
828 | |||
829 | return (assert->stmt[idx].authdata.sigcount); | ||
830 | } | ||
831 | |||
832 | const unsigned char * | ||
833 | fido_assert_authdata_ptr(const fido_assert_t *assert, size_t idx) | ||
834 | { | ||
835 | if (idx >= assert->stmt_len) | ||
836 | return (NULL); | ||
837 | |||
838 | return (assert->stmt[idx].authdata_cbor.ptr); | ||
839 | } | ||
840 | |||
841 | size_t | ||
842 | fido_assert_authdata_len(const fido_assert_t *assert, size_t idx) | ||
843 | { | ||
844 | if (idx >= assert->stmt_len) | ||
845 | return (0); | ||
846 | |||
847 | return (assert->stmt[idx].authdata_cbor.len); | ||
848 | } | ||
849 | |||
850 | const unsigned char * | ||
851 | fido_assert_sig_ptr(const fido_assert_t *assert, size_t idx) | ||
852 | { | ||
853 | if (idx >= assert->stmt_len) | ||
854 | return (NULL); | ||
855 | |||
856 | return (assert->stmt[idx].sig.ptr); | ||
857 | } | ||
858 | |||
859 | size_t | ||
860 | fido_assert_sig_len(const fido_assert_t *assert, size_t idx) | ||
861 | { | ||
862 | if (idx >= assert->stmt_len) | ||
863 | return (0); | ||
864 | |||
865 | return (assert->stmt[idx].sig.len); | ||
866 | } | ||
867 | |||
868 | const unsigned char * | ||
869 | fido_assert_id_ptr(const fido_assert_t *assert, size_t idx) | ||
870 | { | ||
871 | if (idx >= assert->stmt_len) | ||
872 | return (NULL); | ||
873 | |||
874 | return (assert->stmt[idx].id.ptr); | ||
875 | } | ||
876 | |||
877 | size_t | ||
878 | fido_assert_id_len(const fido_assert_t *assert, size_t idx) | ||
879 | { | ||
880 | if (idx >= assert->stmt_len) | ||
881 | return (0); | ||
882 | |||
883 | return (assert->stmt[idx].id.len); | ||
884 | } | ||
885 | |||
886 | const unsigned char * | ||
887 | fido_assert_user_id_ptr(const fido_assert_t *assert, size_t idx) | ||
888 | { | ||
889 | if (idx >= assert->stmt_len) | ||
890 | return (NULL); | ||
891 | |||
892 | return (assert->stmt[idx].user.id.ptr); | ||
893 | } | ||
894 | |||
895 | size_t | ||
896 | fido_assert_user_id_len(const fido_assert_t *assert, size_t idx) | ||
897 | { | ||
898 | if (idx >= assert->stmt_len) | ||
899 | return (0); | ||
900 | |||
901 | return (assert->stmt[idx].user.id.len); | ||
902 | } | ||
903 | |||
904 | const char * | ||
905 | fido_assert_user_icon(const fido_assert_t *assert, size_t idx) | ||
906 | { | ||
907 | if (idx >= assert->stmt_len) | ||
908 | return (NULL); | ||
909 | |||
910 | return (assert->stmt[idx].user.icon); | ||
911 | } | ||
912 | |||
913 | const char * | ||
914 | fido_assert_user_name(const fido_assert_t *assert, size_t idx) | ||
915 | { | ||
916 | if (idx >= assert->stmt_len) | ||
917 | return (NULL); | ||
918 | |||
919 | return (assert->stmt[idx].user.name); | ||
920 | } | ||
921 | |||
922 | const char * | ||
923 | fido_assert_user_display_name(const fido_assert_t *assert, size_t idx) | ||
924 | { | ||
925 | if (idx >= assert->stmt_len) | ||
926 | return (NULL); | ||
927 | |||
928 | return (assert->stmt[idx].user.display_name); | ||
929 | } | ||
930 | |||
931 | const unsigned char * | ||
932 | fido_assert_hmac_secret_ptr(const fido_assert_t *assert, size_t idx) | ||
933 | { | ||
934 | if (idx >= assert->stmt_len) | ||
935 | return (NULL); | ||
936 | |||
937 | return (assert->stmt[idx].hmac_secret.ptr); | ||
938 | } | ||
939 | |||
940 | size_t | ||
941 | fido_assert_hmac_secret_len(const fido_assert_t *assert, size_t idx) | ||
942 | { | ||
943 | if (idx >= assert->stmt_len) | ||
944 | return (0); | ||
945 | |||
946 | return (assert->stmt[idx].hmac_secret.len); | ||
947 | } | ||
948 | |||
949 | static void | ||
950 | fido_assert_clean_authdata(fido_assert_stmt *as) | ||
951 | { | ||
952 | free(as->authdata_cbor.ptr); | ||
953 | free(as->hmac_secret_enc.ptr); | ||
954 | |||
955 | memset(&as->authdata_ext, 0, sizeof(as->authdata_ext)); | ||
956 | memset(&as->authdata_cbor, 0, sizeof(as->authdata_cbor)); | ||
957 | memset(&as->authdata, 0, sizeof(as->authdata)); | ||
958 | memset(&as->hmac_secret_enc, 0, sizeof(as->hmac_secret_enc)); | ||
959 | } | ||
960 | |||
961 | int | ||
962 | fido_assert_set_authdata(fido_assert_t *assert, size_t idx, | ||
963 | const unsigned char *ptr, size_t len) | ||
964 | { | ||
965 | cbor_item_t *item = NULL; | ||
966 | fido_assert_stmt *stmt = NULL; | ||
967 | struct cbor_load_result cbor; | ||
968 | int r; | ||
969 | |||
970 | if (idx >= assert->stmt_len || ptr == NULL || len == 0) | ||
971 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
972 | |||
973 | stmt = &assert->stmt[idx]; | ||
974 | fido_assert_clean_authdata(stmt); | ||
975 | |||
976 | if ((item = cbor_load(ptr, len, &cbor)) == NULL) { | ||
977 | fido_log_debug("%s: cbor_load", __func__); | ||
978 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
979 | goto fail; | ||
980 | } | ||
981 | |||
982 | if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor, | ||
983 | &stmt->authdata, &stmt->authdata_ext, &stmt->hmac_secret_enc) < 0) { | ||
984 | fido_log_debug("%s: cbor_decode_assert_authdata", __func__); | ||
985 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
986 | goto fail; | ||
987 | } | ||
988 | |||
989 | r = FIDO_OK; | ||
990 | fail: | ||
991 | if (item != NULL) | ||
992 | cbor_decref(&item); | ||
993 | |||
994 | if (r != FIDO_OK) | ||
995 | fido_assert_clean_authdata(stmt); | ||
996 | |||
997 | return (r); | ||
998 | } | ||
999 | |||
1000 | int | ||
1001 | fido_assert_set_authdata_raw(fido_assert_t *assert, size_t idx, | ||
1002 | const unsigned char *ptr, size_t len) | ||
1003 | { | ||
1004 | cbor_item_t *item = NULL; | ||
1005 | fido_assert_stmt *stmt = NULL; | ||
1006 | int r; | ||
1007 | |||
1008 | if (idx >= assert->stmt_len || ptr == NULL || len == 0) | ||
1009 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
1010 | |||
1011 | stmt = &assert->stmt[idx]; | ||
1012 | fido_assert_clean_authdata(stmt); | ||
1013 | |||
1014 | if ((item = cbor_build_bytestring(ptr, len)) == NULL) { | ||
1015 | fido_log_debug("%s: cbor_build_bytestring", __func__); | ||
1016 | r = FIDO_ERR_INTERNAL; | ||
1017 | goto fail; | ||
1018 | } | ||
1019 | |||
1020 | if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor, | ||
1021 | &stmt->authdata, &stmt->authdata_ext, &stmt->hmac_secret_enc) < 0) { | ||
1022 | fido_log_debug("%s: cbor_decode_assert_authdata", __func__); | ||
1023 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
1024 | goto fail; | ||
1025 | } | ||
1026 | |||
1027 | r = FIDO_OK; | ||
1028 | fail: | ||
1029 | if (item != NULL) | ||
1030 | cbor_decref(&item); | ||
1031 | |||
1032 | if (r != FIDO_OK) | ||
1033 | fido_assert_clean_authdata(stmt); | ||
1034 | |||
1035 | return (r); | ||
1036 | } | ||
1037 | |||
1038 | static void | ||
1039 | fido_assert_clean_sig(fido_assert_stmt *as) | ||
1040 | { | ||
1041 | free(as->sig.ptr); | ||
1042 | as->sig.ptr = NULL; | ||
1043 | as->sig.len = 0; | ||
1044 | } | ||
1045 | |||
1046 | int | ||
1047 | fido_assert_set_sig(fido_assert_t *a, size_t idx, const unsigned char *ptr, | ||
1048 | size_t len) | ||
1049 | { | ||
1050 | unsigned char *sig; | ||
1051 | |||
1052 | if (idx >= a->stmt_len || ptr == NULL || len == 0) | ||
1053 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
1054 | |||
1055 | fido_assert_clean_sig(&a->stmt[idx]); | ||
1056 | |||
1057 | if ((sig = malloc(len)) == NULL) | ||
1058 | return (FIDO_ERR_INTERNAL); | ||
1059 | |||
1060 | memcpy(sig, ptr, len); | ||
1061 | a->stmt[idx].sig.ptr = sig; | ||
1062 | a->stmt[idx].sig.len = len; | ||
1063 | |||
1064 | return (FIDO_OK); | ||
1065 | } | ||
1066 | |||
1067 | /* XXX shrinking leaks memory; fortunately that shouldn't happen */ | ||
1068 | int | ||
1069 | fido_assert_set_count(fido_assert_t *assert, size_t n) | ||
1070 | { | ||
1071 | void *new_stmt; | ||
1072 | |||
1073 | #ifdef FIDO_FUZZ | ||
1074 | if (n > UINT8_MAX) { | ||
1075 | fido_log_debug("%s: n > UINT8_MAX", __func__); | ||
1076 | return (FIDO_ERR_INTERNAL); | ||
1077 | } | ||
1078 | #endif | ||
1079 | |||
1080 | new_stmt = recallocarray(assert->stmt, assert->stmt_cnt, n, | ||
1081 | sizeof(fido_assert_stmt)); | ||
1082 | if (new_stmt == NULL) | ||
1083 | return (FIDO_ERR_INTERNAL); | ||
1084 | |||
1085 | assert->stmt = new_stmt; | ||
1086 | assert->stmt_cnt = n; | ||
1087 | assert->stmt_len = n; | ||
1088 | |||
1089 | return (FIDO_OK); | ||
1090 | } | ||
diff --git a/src/authkey.c b/src/authkey.c new file mode 100644 index 0000000..9de37f1 --- /dev/null +++ b/src/authkey.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <string.h> | ||
8 | #include "fido.h" | ||
9 | |||
10 | static int | ||
11 | parse_authkey(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
12 | { | ||
13 | es256_pk_t *authkey = arg; | ||
14 | |||
15 | if (cbor_isa_uint(key) == false || | ||
16 | cbor_int_get_width(key) != CBOR_INT_8 || | ||
17 | cbor_get_uint8(key) != 1) { | ||
18 | fido_log_debug("%s: cbor type", __func__); | ||
19 | return (0); /* ignore */ | ||
20 | } | ||
21 | |||
22 | return (es256_pk_decode(val, authkey)); | ||
23 | } | ||
24 | |||
25 | static int | ||
26 | fido_dev_authkey_tx(fido_dev_t *dev) | ||
27 | { | ||
28 | fido_blob_t f; | ||
29 | cbor_item_t *argv[2]; | ||
30 | int r; | ||
31 | |||
32 | fido_log_debug("%s: dev=%p", __func__, (void *)dev); | ||
33 | |||
34 | memset(&f, 0, sizeof(f)); | ||
35 | memset(argv, 0, sizeof(argv)); | ||
36 | |||
37 | /* add command parameters */ | ||
38 | if ((argv[0] = cbor_build_uint8(1)) == NULL || | ||
39 | (argv[1] = cbor_build_uint8(2)) == NULL) { | ||
40 | fido_log_debug("%s: cbor_build", __func__); | ||
41 | r = FIDO_ERR_INTERNAL; | ||
42 | goto fail; | ||
43 | } | ||
44 | |||
45 | /* frame and transmit */ | ||
46 | if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 2, &f) < 0 || | ||
47 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | ||
48 | fido_log_debug("%s: fido_tx", __func__); | ||
49 | r = FIDO_ERR_TX; | ||
50 | goto fail; | ||
51 | } | ||
52 | |||
53 | r = FIDO_OK; | ||
54 | fail: | ||
55 | cbor_vector_free(argv, nitems(argv)); | ||
56 | free(f.ptr); | ||
57 | |||
58 | return (r); | ||
59 | } | ||
60 | |||
61 | static int | ||
62 | fido_dev_authkey_rx(fido_dev_t *dev, es256_pk_t *authkey, int ms) | ||
63 | { | ||
64 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
65 | unsigned char reply[2048]; | ||
66 | int reply_len; | ||
67 | |||
68 | fido_log_debug("%s: dev=%p, authkey=%p, ms=%d", __func__, (void *)dev, | ||
69 | (void *)authkey, ms); | ||
70 | |||
71 | memset(authkey, 0, sizeof(*authkey)); | ||
72 | |||
73 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
74 | fido_log_debug("%s: fido_rx", __func__); | ||
75 | return (FIDO_ERR_RX); | ||
76 | } | ||
77 | |||
78 | return (cbor_parse_reply(reply, (size_t)reply_len, authkey, | ||
79 | parse_authkey)); | ||
80 | } | ||
81 | |||
82 | static int | ||
83 | fido_dev_authkey_wait(fido_dev_t *dev, es256_pk_t *authkey, int ms) | ||
84 | { | ||
85 | int r; | ||
86 | |||
87 | if ((r = fido_dev_authkey_tx(dev)) != FIDO_OK || | ||
88 | (r = fido_dev_authkey_rx(dev, authkey, ms)) != FIDO_OK) | ||
89 | return (r); | ||
90 | |||
91 | return (FIDO_OK); | ||
92 | } | ||
93 | |||
94 | int | ||
95 | fido_dev_authkey(fido_dev_t *dev, es256_pk_t *authkey) | ||
96 | { | ||
97 | return (fido_dev_authkey_wait(dev, authkey, -1)); | ||
98 | } | ||
diff --git a/src/bio.c b/src/bio.c new file mode 100644 index 0000000..74814b9 --- /dev/null +++ b/src/bio.c | |||
@@ -0,0 +1,844 @@ | |||
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 <string.h> | ||
8 | |||
9 | #include "fido.h" | ||
10 | #include "fido/bio.h" | ||
11 | #include "fido/es256.h" | ||
12 | |||
13 | #define CMD_ENROLL_BEGIN 0x01 | ||
14 | #define CMD_ENROLL_NEXT 0x02 | ||
15 | #define CMD_ENROLL_CANCEL 0x03 | ||
16 | #define CMD_ENUM 0x04 | ||
17 | #define CMD_SET_NAME 0x05 | ||
18 | #define CMD_ENROLL_REMOVE 0x06 | ||
19 | #define CMD_GET_INFO 0x07 | ||
20 | |||
21 | static int | ||
22 | bio_prepare_hmac(uint8_t cmd, cbor_item_t **argv, size_t argc, | ||
23 | cbor_item_t **param, fido_blob_t *hmac_data) | ||
24 | { | ||
25 | const uint8_t prefix[2] = { 0x01 /* modality */, cmd }; | ||
26 | int ok = -1; | ||
27 | size_t cbor_alloc_len; | ||
28 | size_t cbor_len; | ||
29 | unsigned char *cbor = NULL; | ||
30 | |||
31 | if (argv == NULL || param == NULL) | ||
32 | return (fido_blob_set(hmac_data, prefix, sizeof(prefix))); | ||
33 | |||
34 | if ((*param = cbor_flatten_vector(argv, argc)) == NULL) { | ||
35 | fido_log_debug("%s: cbor_flatten_vector", __func__); | ||
36 | goto fail; | ||
37 | } | ||
38 | |||
39 | if ((cbor_len = cbor_serialize_alloc(*param, &cbor, | ||
40 | &cbor_alloc_len)) == 0 || cbor_len > SIZE_MAX - sizeof(prefix)) { | ||
41 | fido_log_debug("%s: cbor_serialize_alloc", __func__); | ||
42 | goto fail; | ||
43 | } | ||
44 | |||
45 | if ((hmac_data->ptr = malloc(cbor_len + sizeof(prefix))) == NULL) { | ||
46 | fido_log_debug("%s: malloc", __func__); | ||
47 | goto fail; | ||
48 | } | ||
49 | |||
50 | memcpy(hmac_data->ptr, prefix, sizeof(prefix)); | ||
51 | memcpy(hmac_data->ptr + sizeof(prefix), cbor, cbor_len); | ||
52 | hmac_data->len = cbor_len + sizeof(prefix); | ||
53 | |||
54 | ok = 0; | ||
55 | fail: | ||
56 | free(cbor); | ||
57 | |||
58 | return (ok); | ||
59 | } | ||
60 | |||
61 | static int | ||
62 | bio_tx(fido_dev_t *dev, uint8_t cmd, cbor_item_t **sub_argv, size_t sub_argc, | ||
63 | const char *pin, const fido_blob_t *token) | ||
64 | { | ||
65 | cbor_item_t *argv[5]; | ||
66 | es256_pk_t *pk = NULL; | ||
67 | fido_blob_t *ecdh = NULL; | ||
68 | fido_blob_t f; | ||
69 | fido_blob_t hmac; | ||
70 | int r = FIDO_ERR_INTERNAL; | ||
71 | |||
72 | memset(&f, 0, sizeof(f)); | ||
73 | memset(&hmac, 0, sizeof(hmac)); | ||
74 | memset(&argv, 0, sizeof(argv)); | ||
75 | |||
76 | /* modality, subCommand */ | ||
77 | if ((argv[0] = cbor_build_uint8(1)) == NULL || | ||
78 | (argv[1] = cbor_build_uint8(cmd)) == NULL) { | ||
79 | fido_log_debug("%s: cbor encode", __func__); | ||
80 | goto fail; | ||
81 | } | ||
82 | |||
83 | /* subParams */ | ||
84 | if (pin || token) { | ||
85 | if (bio_prepare_hmac(cmd, sub_argv, sub_argc, &argv[2], | ||
86 | &hmac) < 0) { | ||
87 | fido_log_debug("%s: bio_prepare_hmac", __func__); | ||
88 | goto fail; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | /* pinProtocol, pinAuth */ | ||
93 | if (pin) { | ||
94 | if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { | ||
95 | fido_log_debug("%s: fido_do_ecdh", __func__); | ||
96 | goto fail; | ||
97 | } | ||
98 | if ((r = cbor_add_pin_params(dev, &hmac, pk, ecdh, pin, | ||
99 | &argv[4], &argv[3])) != FIDO_OK) { | ||
100 | fido_log_debug("%s: cbor_add_pin_params", __func__); | ||
101 | goto fail; | ||
102 | } | ||
103 | } else if (token) { | ||
104 | if ((argv[3] = cbor_encode_pin_opt()) == NULL || | ||
105 | (argv[4] = cbor_encode_pin_auth(token, &hmac)) == NULL) { | ||
106 | fido_log_debug("%s: encode pin", __func__); | ||
107 | goto fail; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | /* framing and transmission */ | ||
112 | if (cbor_build_frame(CTAP_CBOR_BIO_ENROLL_PRE, argv, 5, &f) < 0 || | ||
113 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | ||
114 | fido_log_debug("%s: fido_tx", __func__); | ||
115 | r = FIDO_ERR_TX; | ||
116 | goto fail; | ||
117 | } | ||
118 | |||
119 | r = FIDO_OK; | ||
120 | fail: | ||
121 | cbor_vector_free(argv, nitems(argv)); | ||
122 | es256_pk_free(&pk); | ||
123 | fido_blob_free(&ecdh); | ||
124 | free(f.ptr); | ||
125 | free(hmac.ptr); | ||
126 | |||
127 | return (r); | ||
128 | } | ||
129 | |||
130 | static void | ||
131 | bio_reset_template(fido_bio_template_t *t) | ||
132 | { | ||
133 | free(t->name); | ||
134 | free(t->id.ptr); | ||
135 | t->name = NULL; | ||
136 | memset(&t->id, 0, sizeof(t->id)); | ||
137 | } | ||
138 | |||
139 | static void | ||
140 | bio_reset_template_array(fido_bio_template_array_t *ta) | ||
141 | { | ||
142 | for (size_t i = 0; i < ta->n_alloc; i++) | ||
143 | bio_reset_template(&ta->ptr[i]); | ||
144 | |||
145 | free(ta->ptr); | ||
146 | ta->ptr = NULL; | ||
147 | memset(ta, 0, sizeof(*ta)); | ||
148 | } | ||
149 | |||
150 | static int | ||
151 | decode_template(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
152 | { | ||
153 | fido_bio_template_t *t = arg; | ||
154 | |||
155 | if (cbor_isa_uint(key) == false || | ||
156 | cbor_int_get_width(key) != CBOR_INT_8) { | ||
157 | fido_log_debug("%s: cbor type", __func__); | ||
158 | return (0); /* ignore */ | ||
159 | } | ||
160 | |||
161 | switch (cbor_get_uint8(key)) { | ||
162 | case 1: /* id */ | ||
163 | return (fido_blob_decode(val, &t->id)); | ||
164 | case 2: /* name */ | ||
165 | return (cbor_string_copy(val, &t->name)); | ||
166 | } | ||
167 | |||
168 | return (0); /* ignore */ | ||
169 | } | ||
170 | |||
171 | static int | ||
172 | decode_template_array(const cbor_item_t *item, void *arg) | ||
173 | { | ||
174 | fido_bio_template_array_t *ta = arg; | ||
175 | |||
176 | if (cbor_isa_map(item) == false || | ||
177 | cbor_map_is_definite(item) == false) { | ||
178 | fido_log_debug("%s: cbor type", __func__); | ||
179 | return (-1); | ||
180 | } | ||
181 | |||
182 | if (ta->n_rx >= ta->n_alloc) { | ||
183 | fido_log_debug("%s: n_rx >= n_alloc", __func__); | ||
184 | return (-1); | ||
185 | } | ||
186 | |||
187 | if (cbor_map_iter(item, &ta->ptr[ta->n_rx], decode_template) < 0) { | ||
188 | fido_log_debug("%s: decode_template", __func__); | ||
189 | return (-1); | ||
190 | } | ||
191 | |||
192 | ta->n_rx++; | ||
193 | |||
194 | return (0); | ||
195 | } | ||
196 | |||
197 | static int | ||
198 | bio_parse_template_array(const cbor_item_t *key, const cbor_item_t *val, | ||
199 | void *arg) | ||
200 | { | ||
201 | fido_bio_template_array_t *ta = arg; | ||
202 | |||
203 | if (cbor_isa_uint(key) == false || | ||
204 | cbor_int_get_width(key) != CBOR_INT_8 || | ||
205 | cbor_get_uint8(key) != 7) { | ||
206 | fido_log_debug("%s: cbor type", __func__); | ||
207 | return (0); /* ignore */ | ||
208 | } | ||
209 | |||
210 | if (cbor_isa_array(val) == false || | ||
211 | cbor_array_is_definite(val) == false) { | ||
212 | fido_log_debug("%s: cbor type", __func__); | ||
213 | return (-1); | ||
214 | } | ||
215 | |||
216 | if (ta->ptr != NULL || ta->n_alloc != 0 || ta->n_rx != 0) { | ||
217 | fido_log_debug("%s: ptr != NULL || n_alloc != 0 || n_rx != 0", | ||
218 | __func__); | ||
219 | return (-1); | ||
220 | } | ||
221 | |||
222 | if ((ta->ptr = calloc(cbor_array_size(val), sizeof(*ta->ptr))) == NULL) | ||
223 | return (-1); | ||
224 | |||
225 | ta->n_alloc = cbor_array_size(val); | ||
226 | |||
227 | if (cbor_array_iter(val, ta, decode_template_array) < 0) { | ||
228 | fido_log_debug("%s: decode_template_array", __func__); | ||
229 | return (-1); | ||
230 | } | ||
231 | |||
232 | return (0); | ||
233 | } | ||
234 | |||
235 | static int | ||
236 | bio_rx_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, int ms) | ||
237 | { | ||
238 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
239 | unsigned char reply[2048]; | ||
240 | int reply_len; | ||
241 | int r; | ||
242 | |||
243 | bio_reset_template_array(ta); | ||
244 | |||
245 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
246 | fido_log_debug("%s: fido_rx", __func__); | ||
247 | return (FIDO_ERR_RX); | ||
248 | } | ||
249 | |||
250 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, ta, | ||
251 | bio_parse_template_array)) != FIDO_OK) { | ||
252 | fido_log_debug("%s: bio_parse_template_array" , __func__); | ||
253 | return (r); | ||
254 | } | ||
255 | |||
256 | return (FIDO_OK); | ||
257 | } | ||
258 | |||
259 | static int | ||
260 | bio_get_template_array_wait(fido_dev_t *dev, fido_bio_template_array_t *ta, | ||
261 | const char *pin, int ms) | ||
262 | { | ||
263 | int r; | ||
264 | |||
265 | if ((r = bio_tx(dev, CMD_ENUM, NULL, 0, pin, NULL)) != FIDO_OK || | ||
266 | (r = bio_rx_template_array(dev, ta, ms)) != FIDO_OK) | ||
267 | return (r); | ||
268 | |||
269 | return (FIDO_OK); | ||
270 | } | ||
271 | |||
272 | int | ||
273 | fido_bio_dev_get_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, | ||
274 | const char *pin) | ||
275 | { | ||
276 | if (pin == NULL) | ||
277 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
278 | |||
279 | return (bio_get_template_array_wait(dev, ta, pin, -1)); | ||
280 | } | ||
281 | |||
282 | static int | ||
283 | bio_set_template_name_wait(fido_dev_t *dev, const fido_bio_template_t *t, | ||
284 | const char *pin, int ms) | ||
285 | { | ||
286 | cbor_item_t *argv[2]; | ||
287 | int r = FIDO_ERR_INTERNAL; | ||
288 | |||
289 | memset(&argv, 0, sizeof(argv)); | ||
290 | |||
291 | if ((argv[0] = fido_blob_encode(&t->id)) == NULL || | ||
292 | (argv[1] = cbor_build_string(t->name)) == NULL) { | ||
293 | fido_log_debug("%s: cbor encode", __func__); | ||
294 | goto fail; | ||
295 | } | ||
296 | |||
297 | if ((r = bio_tx(dev, CMD_SET_NAME, argv, 2, pin, NULL)) != FIDO_OK || | ||
298 | (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { | ||
299 | fido_log_debug("%s: tx/rx", __func__); | ||
300 | goto fail; | ||
301 | } | ||
302 | |||
303 | r = FIDO_OK; | ||
304 | fail: | ||
305 | cbor_vector_free(argv, nitems(argv)); | ||
306 | |||
307 | return (r); | ||
308 | } | ||
309 | |||
310 | int | ||
311 | fido_bio_dev_set_template_name(fido_dev_t *dev, const fido_bio_template_t *t, | ||
312 | const char *pin) | ||
313 | { | ||
314 | if (pin == NULL || t->name == NULL) | ||
315 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
316 | |||
317 | return (bio_set_template_name_wait(dev, t, pin, -1)); | ||
318 | } | ||
319 | |||
320 | static void | ||
321 | bio_reset_enroll(fido_bio_enroll_t *e) | ||
322 | { | ||
323 | e->remaining_samples = 0; | ||
324 | e->last_status = 0; | ||
325 | |||
326 | if (e->token) | ||
327 | fido_blob_free(&e->token); | ||
328 | } | ||
329 | |||
330 | static int | ||
331 | bio_parse_enroll_status(const cbor_item_t *key, const cbor_item_t *val, | ||
332 | void *arg) | ||
333 | { | ||
334 | fido_bio_enroll_t *e = arg; | ||
335 | uint64_t x; | ||
336 | |||
337 | if (cbor_isa_uint(key) == false || | ||
338 | cbor_int_get_width(key) != CBOR_INT_8) { | ||
339 | fido_log_debug("%s: cbor type", __func__); | ||
340 | return (0); /* ignore */ | ||
341 | } | ||
342 | |||
343 | switch (cbor_get_uint8(key)) { | ||
344 | case 5: | ||
345 | if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) { | ||
346 | fido_log_debug("%s: cbor_decode_uint64", __func__); | ||
347 | return (-1); | ||
348 | } | ||
349 | e->last_status = (uint8_t)x; | ||
350 | break; | ||
351 | case 6: | ||
352 | if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) { | ||
353 | fido_log_debug("%s: cbor_decode_uint64", __func__); | ||
354 | return (-1); | ||
355 | } | ||
356 | e->remaining_samples = (uint8_t)x; | ||
357 | break; | ||
358 | default: | ||
359 | return (0); /* ignore */ | ||
360 | } | ||
361 | |||
362 | return (0); | ||
363 | } | ||
364 | |||
365 | static int | ||
366 | bio_parse_template_id(const cbor_item_t *key, const cbor_item_t *val, | ||
367 | void *arg) | ||
368 | { | ||
369 | fido_blob_t *id = arg; | ||
370 | |||
371 | if (cbor_isa_uint(key) == false || | ||
372 | cbor_int_get_width(key) != CBOR_INT_8 || | ||
373 | cbor_get_uint8(key) != 4) { | ||
374 | fido_log_debug("%s: cbor type", __func__); | ||
375 | return (0); /* ignore */ | ||
376 | } | ||
377 | |||
378 | return (fido_blob_decode(val, id)); | ||
379 | } | ||
380 | |||
381 | static int | ||
382 | bio_rx_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t, | ||
383 | fido_bio_enroll_t *e, int ms) | ||
384 | { | ||
385 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
386 | unsigned char reply[2048]; | ||
387 | int reply_len; | ||
388 | int r; | ||
389 | |||
390 | bio_reset_template(t); | ||
391 | |||
392 | e->remaining_samples = 0; | ||
393 | e->last_status = 0; | ||
394 | |||
395 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
396 | fido_log_debug("%s: fido_rx", __func__); | ||
397 | return (FIDO_ERR_RX); | ||
398 | } | ||
399 | |||
400 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, e, | ||
401 | bio_parse_enroll_status)) != FIDO_OK) { | ||
402 | fido_log_debug("%s: bio_parse_enroll_status", __func__); | ||
403 | return (r); | ||
404 | } | ||
405 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, &t->id, | ||
406 | bio_parse_template_id)) != FIDO_OK) { | ||
407 | fido_log_debug("%s: bio_parse_template_id", __func__); | ||
408 | return (r); | ||
409 | } | ||
410 | |||
411 | return (FIDO_OK); | ||
412 | } | ||
413 | |||
414 | static int | ||
415 | bio_enroll_begin_wait(fido_dev_t *dev, fido_bio_template_t *t, | ||
416 | fido_bio_enroll_t *e, uint32_t timo_ms, int ms) | ||
417 | { | ||
418 | cbor_item_t *argv[3]; | ||
419 | const uint8_t cmd = CMD_ENROLL_BEGIN; | ||
420 | int r = FIDO_ERR_INTERNAL; | ||
421 | |||
422 | memset(&argv, 0, sizeof(argv)); | ||
423 | |||
424 | if ((argv[2] = cbor_build_uint32(timo_ms)) == NULL) { | ||
425 | fido_log_debug("%s: cbor encode", __func__); | ||
426 | goto fail; | ||
427 | } | ||
428 | |||
429 | if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token)) != FIDO_OK || | ||
430 | (r = bio_rx_enroll_begin(dev, t, e, ms)) != FIDO_OK) { | ||
431 | fido_log_debug("%s: tx/rx", __func__); | ||
432 | goto fail; | ||
433 | } | ||
434 | |||
435 | r = FIDO_OK; | ||
436 | fail: | ||
437 | cbor_vector_free(argv, nitems(argv)); | ||
438 | |||
439 | return (r); | ||
440 | } | ||
441 | |||
442 | int | ||
443 | fido_bio_dev_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t, | ||
444 | fido_bio_enroll_t *e, uint32_t timo_ms, const char *pin) | ||
445 | { | ||
446 | es256_pk_t *pk = NULL; | ||
447 | fido_blob_t *ecdh = NULL; | ||
448 | fido_blob_t *token = NULL; | ||
449 | int r; | ||
450 | |||
451 | if (pin == NULL || e->token != NULL) | ||
452 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
453 | |||
454 | if ((token = fido_blob_new()) == NULL) { | ||
455 | r = FIDO_ERR_INTERNAL; | ||
456 | goto fail; | ||
457 | } | ||
458 | |||
459 | if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { | ||
460 | fido_log_debug("%s: fido_do_ecdh", __func__); | ||
461 | goto fail; | ||
462 | } | ||
463 | |||
464 | if ((r = fido_dev_get_pin_token(dev, pin, ecdh, pk, token)) != FIDO_OK) { | ||
465 | fido_log_debug("%s: fido_dev_get_pin_token", __func__); | ||
466 | goto fail; | ||
467 | } | ||
468 | |||
469 | e->token = token; | ||
470 | token = NULL; | ||
471 | fail: | ||
472 | es256_pk_free(&pk); | ||
473 | fido_blob_free(&ecdh); | ||
474 | fido_blob_free(&token); | ||
475 | |||
476 | if (r != FIDO_OK) | ||
477 | return (r); | ||
478 | |||
479 | return (bio_enroll_begin_wait(dev, t, e, timo_ms, -1)); | ||
480 | } | ||
481 | |||
482 | static int | ||
483 | bio_rx_enroll_continue(fido_dev_t *dev, fido_bio_enroll_t *e, int ms) | ||
484 | { | ||
485 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
486 | unsigned char reply[2048]; | ||
487 | int reply_len; | ||
488 | int r; | ||
489 | |||
490 | e->remaining_samples = 0; | ||
491 | e->last_status = 0; | ||
492 | |||
493 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
494 | fido_log_debug("%s: fido_rx", __func__); | ||
495 | return (FIDO_ERR_RX); | ||
496 | } | ||
497 | |||
498 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, e, | ||
499 | bio_parse_enroll_status)) != FIDO_OK) { | ||
500 | fido_log_debug("%s: bio_parse_enroll_status", __func__); | ||
501 | return (r); | ||
502 | } | ||
503 | |||
504 | return (FIDO_OK); | ||
505 | } | ||
506 | |||
507 | static int | ||
508 | bio_enroll_continue_wait(fido_dev_t *dev, const fido_bio_template_t *t, | ||
509 | fido_bio_enroll_t *e, uint32_t timo_ms, int ms) | ||
510 | { | ||
511 | cbor_item_t *argv[3]; | ||
512 | const uint8_t cmd = CMD_ENROLL_NEXT; | ||
513 | int r = FIDO_ERR_INTERNAL; | ||
514 | |||
515 | memset(&argv, 0, sizeof(argv)); | ||
516 | |||
517 | if ((argv[0] = fido_blob_encode(&t->id)) == NULL || | ||
518 | (argv[2] = cbor_build_uint32(timo_ms)) == NULL) { | ||
519 | fido_log_debug("%s: cbor encode", __func__); | ||
520 | goto fail; | ||
521 | } | ||
522 | |||
523 | if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token)) != FIDO_OK || | ||
524 | (r = bio_rx_enroll_continue(dev, e, ms)) != FIDO_OK) { | ||
525 | fido_log_debug("%s: tx/rx", __func__); | ||
526 | goto fail; | ||
527 | } | ||
528 | |||
529 | r = FIDO_OK; | ||
530 | fail: | ||
531 | cbor_vector_free(argv, nitems(argv)); | ||
532 | |||
533 | return (r); | ||
534 | } | ||
535 | |||
536 | int | ||
537 | fido_bio_dev_enroll_continue(fido_dev_t *dev, const fido_bio_template_t *t, | ||
538 | fido_bio_enroll_t *e, uint32_t timo_ms) | ||
539 | { | ||
540 | if (e->token == NULL) | ||
541 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
542 | |||
543 | return (bio_enroll_continue_wait(dev, t, e, timo_ms, -1)); | ||
544 | } | ||
545 | |||
546 | static int | ||
547 | bio_enroll_cancel_wait(fido_dev_t *dev, int ms) | ||
548 | { | ||
549 | const uint8_t cmd = CMD_ENROLL_CANCEL; | ||
550 | int r; | ||
551 | |||
552 | if ((r = bio_tx(dev, cmd, NULL, 0, NULL, NULL)) != FIDO_OK || | ||
553 | (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { | ||
554 | fido_log_debug("%s: tx/rx", __func__); | ||
555 | return (r); | ||
556 | } | ||
557 | |||
558 | return (FIDO_OK); | ||
559 | } | ||
560 | |||
561 | int | ||
562 | fido_bio_dev_enroll_cancel(fido_dev_t *dev) | ||
563 | { | ||
564 | return (bio_enroll_cancel_wait(dev, -1)); | ||
565 | } | ||
566 | |||
567 | static int | ||
568 | bio_enroll_remove_wait(fido_dev_t *dev, const fido_bio_template_t *t, | ||
569 | const char *pin, int ms) | ||
570 | { | ||
571 | cbor_item_t *argv[1]; | ||
572 | const uint8_t cmd = CMD_ENROLL_REMOVE; | ||
573 | int r = FIDO_ERR_INTERNAL; | ||
574 | |||
575 | memset(&argv, 0, sizeof(argv)); | ||
576 | |||
577 | if ((argv[0] = fido_blob_encode(&t->id)) == NULL) { | ||
578 | fido_log_debug("%s: cbor encode", __func__); | ||
579 | goto fail; | ||
580 | } | ||
581 | |||
582 | if ((r = bio_tx(dev, cmd, argv, 1, pin, NULL)) != FIDO_OK || | ||
583 | (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { | ||
584 | fido_log_debug("%s: tx/rx", __func__); | ||
585 | goto fail; | ||
586 | } | ||
587 | |||
588 | r = FIDO_OK; | ||
589 | fail: | ||
590 | cbor_vector_free(argv, nitems(argv)); | ||
591 | |||
592 | return (r); | ||
593 | } | ||
594 | |||
595 | int | ||
596 | fido_bio_dev_enroll_remove(fido_dev_t *dev, const fido_bio_template_t *t, | ||
597 | const char *pin) | ||
598 | { | ||
599 | return (bio_enroll_remove_wait(dev, t, pin, -1)); | ||
600 | } | ||
601 | |||
602 | static void | ||
603 | bio_reset_info(fido_bio_info_t *i) | ||
604 | { | ||
605 | i->type = 0; | ||
606 | i->max_samples = 0; | ||
607 | } | ||
608 | |||
609 | static int | ||
610 | bio_parse_info(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
611 | { | ||
612 | fido_bio_info_t *i = arg; | ||
613 | uint64_t x; | ||
614 | |||
615 | if (cbor_isa_uint(key) == false || | ||
616 | cbor_int_get_width(key) != CBOR_INT_8) { | ||
617 | fido_log_debug("%s: cbor type", __func__); | ||
618 | return (0); /* ignore */ | ||
619 | } | ||
620 | |||
621 | switch (cbor_get_uint8(key)) { | ||
622 | case 2: | ||
623 | if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) { | ||
624 | fido_log_debug("%s: cbor_decode_uint64", __func__); | ||
625 | return (-1); | ||
626 | } | ||
627 | i->type = (uint8_t)x; | ||
628 | break; | ||
629 | case 3: | ||
630 | if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) { | ||
631 | fido_log_debug("%s: cbor_decode_uint64", __func__); | ||
632 | return (-1); | ||
633 | } | ||
634 | i->max_samples = (uint8_t)x; | ||
635 | break; | ||
636 | default: | ||
637 | return (0); /* ignore */ | ||
638 | } | ||
639 | |||
640 | return (0); | ||
641 | } | ||
642 | |||
643 | static int | ||
644 | bio_rx_info(fido_dev_t *dev, fido_bio_info_t *i, int ms) | ||
645 | { | ||
646 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
647 | unsigned char reply[2048]; | ||
648 | int reply_len; | ||
649 | int r; | ||
650 | |||
651 | bio_reset_info(i); | ||
652 | |||
653 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
654 | fido_log_debug("%s: fido_rx", __func__); | ||
655 | return (FIDO_ERR_RX); | ||
656 | } | ||
657 | |||
658 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, i, | ||
659 | bio_parse_info)) != FIDO_OK) { | ||
660 | fido_log_debug("%s: bio_parse_info" , __func__); | ||
661 | return (r); | ||
662 | } | ||
663 | |||
664 | return (FIDO_OK); | ||
665 | } | ||
666 | |||
667 | static int | ||
668 | bio_get_info_wait(fido_dev_t *dev, fido_bio_info_t *i, int ms) | ||
669 | { | ||
670 | int r; | ||
671 | |||
672 | if ((r = bio_tx(dev, CMD_GET_INFO, NULL, 0, NULL, NULL)) != FIDO_OK || | ||
673 | (r = bio_rx_info(dev, i, ms)) != FIDO_OK) { | ||
674 | fido_log_debug("%s: tx/rx", __func__); | ||
675 | return (r); | ||
676 | } | ||
677 | |||
678 | return (FIDO_OK); | ||
679 | } | ||
680 | |||
681 | int | ||
682 | fido_bio_dev_get_info(fido_dev_t *dev, fido_bio_info_t *i) | ||
683 | { | ||
684 | return (bio_get_info_wait(dev, i, -1)); | ||
685 | } | ||
686 | |||
687 | const char * | ||
688 | fido_bio_template_name(const fido_bio_template_t *t) | ||
689 | { | ||
690 | return (t->name); | ||
691 | } | ||
692 | |||
693 | const unsigned char * | ||
694 | fido_bio_template_id_ptr(const fido_bio_template_t *t) | ||
695 | { | ||
696 | return (t->id.ptr); | ||
697 | } | ||
698 | |||
699 | size_t | ||
700 | fido_bio_template_id_len(const fido_bio_template_t *t) | ||
701 | { | ||
702 | return (t->id.len); | ||
703 | } | ||
704 | |||
705 | size_t | ||
706 | fido_bio_template_array_count(const fido_bio_template_array_t *ta) | ||
707 | { | ||
708 | return (ta->n_rx); | ||
709 | } | ||
710 | |||
711 | fido_bio_template_array_t * | ||
712 | fido_bio_template_array_new(void) | ||
713 | { | ||
714 | return (calloc(1, sizeof(fido_bio_template_array_t))); | ||
715 | } | ||
716 | |||
717 | fido_bio_template_t * | ||
718 | fido_bio_template_new(void) | ||
719 | { | ||
720 | return (calloc(1, sizeof(fido_bio_template_t))); | ||
721 | } | ||
722 | |||
723 | void | ||
724 | fido_bio_template_array_free(fido_bio_template_array_t **tap) | ||
725 | { | ||
726 | fido_bio_template_array_t *ta; | ||
727 | |||
728 | if (tap == NULL || (ta = *tap) == NULL) | ||
729 | return; | ||
730 | |||
731 | bio_reset_template_array(ta); | ||
732 | free(ta); | ||
733 | *tap = NULL; | ||
734 | } | ||
735 | |||
736 | void | ||
737 | fido_bio_template_free(fido_bio_template_t **tp) | ||
738 | { | ||
739 | fido_bio_template_t *t; | ||
740 | |||
741 | if (tp == NULL || (t = *tp) == NULL) | ||
742 | return; | ||
743 | |||
744 | bio_reset_template(t); | ||
745 | free(t); | ||
746 | *tp = NULL; | ||
747 | } | ||
748 | |||
749 | int | ||
750 | fido_bio_template_set_name(fido_bio_template_t *t, const char *name) | ||
751 | { | ||
752 | free(t->name); | ||
753 | t->name = NULL; | ||
754 | |||
755 | if (name && (t->name = strdup(name)) == NULL) | ||
756 | return (FIDO_ERR_INTERNAL); | ||
757 | |||
758 | return (FIDO_OK); | ||
759 | } | ||
760 | |||
761 | int | ||
762 | fido_bio_template_set_id(fido_bio_template_t *t, const unsigned char *ptr, | ||
763 | size_t len) | ||
764 | { | ||
765 | free(t->id.ptr); | ||
766 | t->id.ptr = NULL; | ||
767 | t->id.len = 0; | ||
768 | |||
769 | if (ptr && fido_blob_set(&t->id, ptr, len) < 0) | ||
770 | return (FIDO_ERR_INTERNAL); | ||
771 | |||
772 | return (FIDO_OK); | ||
773 | } | ||
774 | |||
775 | const fido_bio_template_t * | ||
776 | fido_bio_template(const fido_bio_template_array_t *ta, size_t idx) | ||
777 | { | ||
778 | if (idx >= ta->n_alloc) | ||
779 | return (NULL); | ||
780 | |||
781 | return (&ta->ptr[idx]); | ||
782 | } | ||
783 | |||
784 | fido_bio_enroll_t * | ||
785 | fido_bio_enroll_new(void) | ||
786 | { | ||
787 | return (calloc(1, sizeof(fido_bio_enroll_t))); | ||
788 | } | ||
789 | |||
790 | fido_bio_info_t * | ||
791 | fido_bio_info_new(void) | ||
792 | { | ||
793 | return (calloc(1, sizeof(fido_bio_info_t))); | ||
794 | } | ||
795 | |||
796 | uint8_t | ||
797 | fido_bio_info_type(const fido_bio_info_t *i) | ||
798 | { | ||
799 | return (i->type); | ||
800 | } | ||
801 | |||
802 | uint8_t | ||
803 | fido_bio_info_max_samples(const fido_bio_info_t *i) | ||
804 | { | ||
805 | return (i->max_samples); | ||
806 | } | ||
807 | |||
808 | void | ||
809 | fido_bio_enroll_free(fido_bio_enroll_t **ep) | ||
810 | { | ||
811 | fido_bio_enroll_t *e; | ||
812 | |||
813 | if (ep == NULL || (e = *ep) == NULL) | ||
814 | return; | ||
815 | |||
816 | bio_reset_enroll(e); | ||
817 | |||
818 | free(e); | ||
819 | *ep = NULL; | ||
820 | } | ||
821 | |||
822 | void | ||
823 | fido_bio_info_free(fido_bio_info_t **ip) | ||
824 | { | ||
825 | fido_bio_info_t *i; | ||
826 | |||
827 | if (ip == NULL || (i = *ip) == NULL) | ||
828 | return; | ||
829 | |||
830 | free(i); | ||
831 | *ip = NULL; | ||
832 | } | ||
833 | |||
834 | uint8_t | ||
835 | fido_bio_enroll_remaining_samples(const fido_bio_enroll_t *e) | ||
836 | { | ||
837 | return (e->remaining_samples); | ||
838 | } | ||
839 | |||
840 | uint8_t | ||
841 | fido_bio_enroll_last_status(const fido_bio_enroll_t *e) | ||
842 | { | ||
843 | return (e->last_status); | ||
844 | } | ||
diff --git a/src/blob.c b/src/blob.c new file mode 100644 index 0000000..d4eae70 --- /dev/null +++ b/src/blob.c | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <string.h> | ||
8 | #include "fido.h" | ||
9 | |||
10 | fido_blob_t * | ||
11 | fido_blob_new(void) | ||
12 | { | ||
13 | return (calloc(1, sizeof(fido_blob_t))); | ||
14 | } | ||
15 | |||
16 | int | ||
17 | fido_blob_set(fido_blob_t *b, const unsigned char *ptr, size_t len) | ||
18 | { | ||
19 | if (b->ptr != NULL) { | ||
20 | explicit_bzero(b->ptr, b->len); | ||
21 | free(b->ptr); | ||
22 | b->ptr = NULL; | ||
23 | } | ||
24 | |||
25 | b->len = 0; | ||
26 | |||
27 | if (ptr == NULL || len == 0) { | ||
28 | fido_log_debug("%s: ptr=%p, len=%zu", __func__, | ||
29 | (const void *)ptr, len); | ||
30 | return (-1); | ||
31 | } | ||
32 | |||
33 | if ((b->ptr = malloc(len)) == NULL) { | ||
34 | fido_log_debug("%s: malloc", __func__); | ||
35 | return (-1); | ||
36 | } | ||
37 | |||
38 | memcpy(b->ptr, ptr, len); | ||
39 | b->len = len; | ||
40 | |||
41 | return (0); | ||
42 | } | ||
43 | |||
44 | void | ||
45 | fido_blob_free(fido_blob_t **bp) | ||
46 | { | ||
47 | fido_blob_t *b; | ||
48 | |||
49 | if (bp == NULL || (b = *bp) == NULL) | ||
50 | return; | ||
51 | |||
52 | if (b->ptr) { | ||
53 | explicit_bzero(b->ptr, b->len); | ||
54 | free(b->ptr); | ||
55 | } | ||
56 | |||
57 | explicit_bzero(b, sizeof(*b)); | ||
58 | free(b); | ||
59 | |||
60 | *bp = NULL; | ||
61 | } | ||
62 | |||
63 | void | ||
64 | fido_free_blob_array(fido_blob_array_t *array) | ||
65 | { | ||
66 | if (array->ptr == NULL) | ||
67 | return; | ||
68 | |||
69 | for (size_t i = 0; i < array->len; i++) { | ||
70 | fido_blob_t *b = &array->ptr[i]; | ||
71 | if (b->ptr != NULL) { | ||
72 | explicit_bzero(b->ptr, b->len); | ||
73 | free(b->ptr); | ||
74 | b->ptr = NULL; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | free(array->ptr); | ||
79 | array->ptr = NULL; | ||
80 | array->len = 0; | ||
81 | } | ||
82 | |||
83 | cbor_item_t * | ||
84 | fido_blob_encode(const fido_blob_t *b) | ||
85 | { | ||
86 | if (b == NULL || b->ptr == NULL) | ||
87 | return (NULL); | ||
88 | |||
89 | return (cbor_build_bytestring(b->ptr, b->len)); | ||
90 | } | ||
91 | |||
92 | int | ||
93 | fido_blob_decode(const cbor_item_t *item, fido_blob_t *b) | ||
94 | { | ||
95 | return (cbor_bytestring_copy(item, &b->ptr, &b->len)); | ||
96 | } | ||
97 | |||
98 | int | ||
99 | fido_blob_is_empty(const fido_blob_t *b) | ||
100 | { | ||
101 | return (b->ptr == NULL || b->len == 0); | ||
102 | } | ||
diff --git a/src/blob.h b/src/blob.h new file mode 100644 index 0000000..24fdc23 --- /dev/null +++ b/src/blob.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | #ifndef _BLOB_H | ||
8 | #define _BLOB_H | ||
9 | |||
10 | typedef struct fido_blob { | ||
11 | unsigned char *ptr; | ||
12 | size_t len; | ||
13 | } fido_blob_t; | ||
14 | |||
15 | typedef struct fido_blob_array { | ||
16 | fido_blob_t *ptr; | ||
17 | size_t len; | ||
18 | } fido_blob_array_t; | ||
19 | |||
20 | cbor_item_t *fido_blob_encode(const fido_blob_t *); | ||
21 | fido_blob_t *fido_blob_new(void); | ||
22 | int fido_blob_decode(const cbor_item_t *, fido_blob_t *); | ||
23 | int fido_blob_is_empty(const fido_blob_t *); | ||
24 | int fido_blob_set(fido_blob_t *, const unsigned char *, size_t); | ||
25 | void fido_blob_free(fido_blob_t **); | ||
26 | void fido_free_blob_array(fido_blob_array_t *); | ||
27 | |||
28 | #endif /* !_BLOB_H */ | ||
diff --git a/src/buf.c b/src/buf.c new file mode 100644 index 0000000..4646476 --- /dev/null +++ b/src/buf.c | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <string.h> | ||
8 | #include "fido.h" | ||
9 | |||
10 | int | ||
11 | fido_buf_read(const unsigned char **buf, size_t *len, void *dst, size_t count) | ||
12 | { | ||
13 | if (count > *len) | ||
14 | return (-1); | ||
15 | |||
16 | memcpy(dst, *buf, count); | ||
17 | *buf += count; | ||
18 | *len -= count; | ||
19 | |||
20 | return (0); | ||
21 | } | ||
22 | |||
23 | int | ||
24 | fido_buf_write(unsigned char **buf, size_t *len, const void *src, size_t count) | ||
25 | { | ||
26 | if (count > *len) | ||
27 | return (-1); | ||
28 | |||
29 | memcpy(*buf, src, count); | ||
30 | *buf += count; | ||
31 | *len -= count; | ||
32 | |||
33 | return (0); | ||
34 | } | ||
diff --git a/src/cbor.c b/src/cbor.c new file mode 100644 index 0000000..3e03592 --- /dev/null +++ b/src/cbor.c | |||
@@ -0,0 +1,1520 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <openssl/evp.h> | ||
8 | #include <openssl/hmac.h> | ||
9 | #include <openssl/sha.h> | ||
10 | |||
11 | #include <string.h> | ||
12 | #include "fido.h" | ||
13 | |||
14 | static int | ||
15 | check_key_type(cbor_item_t *item) | ||
16 | { | ||
17 | if (item->type == CBOR_TYPE_UINT || item->type == CBOR_TYPE_NEGINT || | ||
18 | item->type == CBOR_TYPE_STRING) | ||
19 | return (0); | ||
20 | |||
21 | fido_log_debug("%s: invalid type: %d", __func__, item->type); | ||
22 | |||
23 | return (-1); | ||
24 | } | ||
25 | |||
26 | /* | ||
27 | * Validate CTAP2 canonical CBOR encoding rules for maps. | ||
28 | */ | ||
29 | static int | ||
30 | ctap_check_cbor(cbor_item_t *prev, cbor_item_t *curr) | ||
31 | { | ||
32 | size_t curr_len; | ||
33 | size_t prev_len; | ||
34 | |||
35 | if (check_key_type(prev) < 0 || check_key_type(curr) < 0) | ||
36 | return (-1); | ||
37 | |||
38 | if (prev->type != curr->type) { | ||
39 | if (prev->type < curr->type) | ||
40 | return (0); | ||
41 | fido_log_debug("%s: unsorted types", __func__); | ||
42 | return (-1); | ||
43 | } | ||
44 | |||
45 | if (curr->type == CBOR_TYPE_UINT || curr->type == CBOR_TYPE_NEGINT) { | ||
46 | if (cbor_int_get_width(curr) >= cbor_int_get_width(prev) && | ||
47 | cbor_get_int(curr) > cbor_get_int(prev)) | ||
48 | return (0); | ||
49 | } else { | ||
50 | curr_len = cbor_string_length(curr); | ||
51 | prev_len = cbor_string_length(prev); | ||
52 | |||
53 | if (curr_len > prev_len || (curr_len == prev_len && | ||
54 | memcmp(cbor_string_handle(prev), cbor_string_handle(curr), | ||
55 | curr_len) < 0)) | ||
56 | return (0); | ||
57 | } | ||
58 | |||
59 | fido_log_debug("%s: invalid cbor", __func__); | ||
60 | |||
61 | return (-1); | ||
62 | } | ||
63 | |||
64 | int | ||
65 | cbor_map_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *, | ||
66 | const cbor_item_t *, void *)) | ||
67 | { | ||
68 | struct cbor_pair *v; | ||
69 | size_t n; | ||
70 | |||
71 | if ((v = cbor_map_handle(item)) == NULL) { | ||
72 | fido_log_debug("%s: cbor_map_handle", __func__); | ||
73 | return (-1); | ||
74 | } | ||
75 | |||
76 | n = cbor_map_size(item); | ||
77 | |||
78 | for (size_t i = 0; i < n; i++) { | ||
79 | if (v[i].key == NULL || v[i].value == NULL) { | ||
80 | fido_log_debug("%s: key=%p, value=%p for i=%zu", | ||
81 | __func__, (void *)v[i].key, (void *)v[i].value, i); | ||
82 | return (-1); | ||
83 | } | ||
84 | if (i && ctap_check_cbor(v[i - 1].key, v[i].key) < 0) { | ||
85 | fido_log_debug("%s: ctap_check_cbor", __func__); | ||
86 | return (-1); | ||
87 | } | ||
88 | if (f(v[i].key, v[i].value, arg) < 0) { | ||
89 | fido_log_debug("%s: iterator < 0 on i=%zu", __func__, | ||
90 | i); | ||
91 | return (-1); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | return (0); | ||
96 | } | ||
97 | |||
98 | int | ||
99 | cbor_array_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *, | ||
100 | void *)) | ||
101 | { | ||
102 | cbor_item_t **v; | ||
103 | size_t n; | ||
104 | |||
105 | if ((v = cbor_array_handle(item)) == NULL) { | ||
106 | fido_log_debug("%s: cbor_array_handle", __func__); | ||
107 | return (-1); | ||
108 | } | ||
109 | |||
110 | n = cbor_array_size(item); | ||
111 | |||
112 | for (size_t i = 0; i < n; i++) | ||
113 | if (v[i] == NULL || f(v[i], arg) < 0) { | ||
114 | fido_log_debug("%s: iterator < 0 on i=%zu,%p", | ||
115 | __func__, i, (void *)v[i]); | ||
116 | return (-1); | ||
117 | } | ||
118 | |||
119 | return (0); | ||
120 | } | ||
121 | |||
122 | int | ||
123 | cbor_parse_reply(const unsigned char *blob, size_t blob_len, void *arg, | ||
124 | int(*parser)(const cbor_item_t *, const cbor_item_t *, void *)) | ||
125 | { | ||
126 | cbor_item_t *item = NULL; | ||
127 | struct cbor_load_result cbor; | ||
128 | int r; | ||
129 | |||
130 | if (blob_len < 1) { | ||
131 | fido_log_debug("%s: blob_len=%zu", __func__, blob_len); | ||
132 | r = FIDO_ERR_RX; | ||
133 | goto fail; | ||
134 | } | ||
135 | |||
136 | if (blob[0] != FIDO_OK) { | ||
137 | fido_log_debug("%s: blob[0]=0x%02x", __func__, blob[0]); | ||
138 | r = blob[0]; | ||
139 | goto fail; | ||
140 | } | ||
141 | |||
142 | if ((item = cbor_load(blob + 1, blob_len - 1, &cbor)) == NULL) { | ||
143 | fido_log_debug("%s: cbor_load", __func__); | ||
144 | r = FIDO_ERR_RX_NOT_CBOR; | ||
145 | goto fail; | ||
146 | } | ||
147 | |||
148 | if (cbor_isa_map(item) == false || | ||
149 | cbor_map_is_definite(item) == false) { | ||
150 | fido_log_debug("%s: cbor type", __func__); | ||
151 | r = FIDO_ERR_RX_INVALID_CBOR; | ||
152 | goto fail; | ||
153 | } | ||
154 | |||
155 | if (cbor_map_iter(item, arg, parser) < 0) { | ||
156 | fido_log_debug("%s: cbor_map_iter", __func__); | ||
157 | r = FIDO_ERR_RX_INVALID_CBOR; | ||
158 | goto fail; | ||
159 | } | ||
160 | |||
161 | r = FIDO_OK; | ||
162 | fail: | ||
163 | if (item != NULL) | ||
164 | cbor_decref(&item); | ||
165 | |||
166 | return (r); | ||
167 | } | ||
168 | |||
169 | void | ||
170 | cbor_vector_free(cbor_item_t **item, size_t len) | ||
171 | { | ||
172 | for (size_t i = 0; i < len; i++) | ||
173 | if (item[i] != NULL) | ||
174 | cbor_decref(&item[i]); | ||
175 | } | ||
176 | |||
177 | int | ||
178 | cbor_bytestring_copy(const cbor_item_t *item, unsigned char **buf, size_t *len) | ||
179 | { | ||
180 | if (*buf != NULL || *len != 0) { | ||
181 | fido_log_debug("%s: dup", __func__); | ||
182 | return (-1); | ||
183 | } | ||
184 | |||
185 | if (cbor_isa_bytestring(item) == false || | ||
186 | cbor_bytestring_is_definite(item) == false) { | ||
187 | fido_log_debug("%s: cbor type", __func__); | ||
188 | return (-1); | ||
189 | } | ||
190 | |||
191 | *len = cbor_bytestring_length(item); | ||
192 | if ((*buf = malloc(*len)) == NULL) { | ||
193 | *len = 0; | ||
194 | return (-1); | ||
195 | } | ||
196 | |||
197 | memcpy(*buf, cbor_bytestring_handle(item), *len); | ||
198 | |||
199 | return (0); | ||
200 | } | ||
201 | |||
202 | int | ||
203 | cbor_string_copy(const cbor_item_t *item, char **str) | ||
204 | { | ||
205 | size_t len; | ||
206 | |||
207 | if (*str != NULL) { | ||
208 | fido_log_debug("%s: dup", __func__); | ||
209 | return (-1); | ||
210 | } | ||
211 | |||
212 | if (cbor_isa_string(item) == false || | ||
213 | cbor_string_is_definite(item) == false) { | ||
214 | fido_log_debug("%s: cbor type", __func__); | ||
215 | return (-1); | ||
216 | } | ||
217 | |||
218 | if ((len = cbor_string_length(item)) == SIZE_MAX || | ||
219 | (*str = malloc(len + 1)) == NULL) | ||
220 | return (-1); | ||
221 | |||
222 | memcpy(*str, cbor_string_handle(item), len); | ||
223 | (*str)[len] = '\0'; | ||
224 | |||
225 | return (0); | ||
226 | } | ||
227 | |||
228 | int | ||
229 | cbor_add_bytestring(cbor_item_t *item, const char *key, | ||
230 | const unsigned char *value, size_t value_len) | ||
231 | { | ||
232 | struct cbor_pair pair; | ||
233 | int ok = -1; | ||
234 | |||
235 | memset(&pair, 0, sizeof(pair)); | ||
236 | |||
237 | if ((pair.key = cbor_build_string(key)) == NULL || | ||
238 | (pair.value = cbor_build_bytestring(value, value_len)) == NULL) { | ||
239 | fido_log_debug("%s: cbor_build", __func__); | ||
240 | goto fail; | ||
241 | } | ||
242 | |||
243 | if (!cbor_map_add(item, pair)) { | ||
244 | fido_log_debug("%s: cbor_map_add", __func__); | ||
245 | goto fail; | ||
246 | } | ||
247 | |||
248 | ok = 0; | ||
249 | fail: | ||
250 | if (pair.key) | ||
251 | cbor_decref(&pair.key); | ||
252 | if (pair.value) | ||
253 | cbor_decref(&pair.value); | ||
254 | |||
255 | return (ok); | ||
256 | } | ||
257 | |||
258 | int | ||
259 | cbor_add_string(cbor_item_t *item, const char *key, const char *value) | ||
260 | { | ||
261 | struct cbor_pair pair; | ||
262 | int ok = -1; | ||
263 | |||
264 | memset(&pair, 0, sizeof(pair)); | ||
265 | |||
266 | if ((pair.key = cbor_build_string(key)) == NULL || | ||
267 | (pair.value = cbor_build_string(value)) == NULL) { | ||
268 | fido_log_debug("%s: cbor_build", __func__); | ||
269 | goto fail; | ||
270 | } | ||
271 | |||
272 | if (!cbor_map_add(item, pair)) { | ||
273 | fido_log_debug("%s: cbor_map_add", __func__); | ||
274 | goto fail; | ||
275 | } | ||
276 | |||
277 | ok = 0; | ||
278 | fail: | ||
279 | if (pair.key) | ||
280 | cbor_decref(&pair.key); | ||
281 | if (pair.value) | ||
282 | cbor_decref(&pair.value); | ||
283 | |||
284 | return (ok); | ||
285 | } | ||
286 | |||
287 | int | ||
288 | cbor_add_bool(cbor_item_t *item, const char *key, fido_opt_t value) | ||
289 | { | ||
290 | struct cbor_pair pair; | ||
291 | int ok = -1; | ||
292 | |||
293 | memset(&pair, 0, sizeof(pair)); | ||
294 | |||
295 | if ((pair.key = cbor_build_string(key)) == NULL || | ||
296 | (pair.value = cbor_build_bool(value == FIDO_OPT_TRUE)) == NULL) { | ||
297 | fido_log_debug("%s: cbor_build", __func__); | ||
298 | goto fail; | ||
299 | } | ||
300 | |||
301 | if (!cbor_map_add(item, pair)) { | ||
302 | fido_log_debug("%s: cbor_map_add", __func__); | ||
303 | goto fail; | ||
304 | } | ||
305 | |||
306 | ok = 0; | ||
307 | fail: | ||
308 | if (pair.key) | ||
309 | cbor_decref(&pair.key); | ||
310 | if (pair.value) | ||
311 | cbor_decref(&pair.value); | ||
312 | |||
313 | return (ok); | ||
314 | } | ||
315 | |||
316 | static int | ||
317 | cbor_add_arg(cbor_item_t *item, uint8_t n, cbor_item_t *arg) | ||
318 | { | ||
319 | struct cbor_pair pair; | ||
320 | int ok = -1; | ||
321 | |||
322 | memset(&pair, 0, sizeof(pair)); | ||
323 | |||
324 | if (arg == NULL) | ||
325 | return (0); /* empty argument */ | ||
326 | |||
327 | if ((pair.key = cbor_build_uint8(n)) == NULL) { | ||
328 | fido_log_debug("%s: cbor_build", __func__); | ||
329 | goto fail; | ||
330 | } | ||
331 | |||
332 | pair.value = arg; | ||
333 | |||
334 | if (!cbor_map_add(item, pair)) { | ||
335 | fido_log_debug("%s: cbor_map_add", __func__); | ||
336 | goto fail; | ||
337 | } | ||
338 | |||
339 | ok = 0; | ||
340 | fail: | ||
341 | if (pair.key) | ||
342 | cbor_decref(&pair.key); | ||
343 | |||
344 | return (ok); | ||
345 | } | ||
346 | |||
347 | cbor_item_t * | ||
348 | cbor_flatten_vector(cbor_item_t *argv[], size_t argc) | ||
349 | { | ||
350 | cbor_item_t *map; | ||
351 | uint8_t i; | ||
352 | |||
353 | if (argc > UINT8_MAX - 1) | ||
354 | return (NULL); | ||
355 | |||
356 | if ((map = cbor_new_definite_map(argc)) == NULL) | ||
357 | return (NULL); | ||
358 | |||
359 | for (i = 0; i < argc; i++) | ||
360 | if (cbor_add_arg(map, i + 1, argv[i]) < 0) | ||
361 | break; | ||
362 | |||
363 | if (i != argc) { | ||
364 | cbor_decref(&map); | ||
365 | map = NULL; | ||
366 | } | ||
367 | |||
368 | return (map); | ||
369 | } | ||
370 | |||
371 | int | ||
372 | cbor_build_frame(uint8_t cmd, cbor_item_t *argv[], size_t argc, fido_blob_t *f) | ||
373 | { | ||
374 | cbor_item_t *flat = NULL; | ||
375 | unsigned char *cbor = NULL; | ||
376 | size_t cbor_len; | ||
377 | size_t cbor_alloc_len; | ||
378 | int ok = -1; | ||
379 | |||
380 | if ((flat = cbor_flatten_vector(argv, argc)) == NULL) | ||
381 | goto fail; | ||
382 | |||
383 | cbor_len = cbor_serialize_alloc(flat, &cbor, &cbor_alloc_len); | ||
384 | if (cbor_len == 0 || cbor_len == SIZE_MAX) { | ||
385 | fido_log_debug("%s: cbor_len=%zu", __func__, cbor_len); | ||
386 | goto fail; | ||
387 | } | ||
388 | |||
389 | if ((f->ptr = malloc(cbor_len + 1)) == NULL) | ||
390 | goto fail; | ||
391 | |||
392 | f->len = cbor_len + 1; | ||
393 | f->ptr[0] = cmd; | ||
394 | memcpy(f->ptr + 1, cbor, f->len - 1); | ||
395 | |||
396 | ok = 0; | ||
397 | fail: | ||
398 | if (flat != NULL) | ||
399 | cbor_decref(&flat); | ||
400 | |||
401 | free(cbor); | ||
402 | |||
403 | return (ok); | ||
404 | } | ||
405 | |||
406 | cbor_item_t * | ||
407 | cbor_encode_rp_entity(const fido_rp_t *rp) | ||
408 | { | ||
409 | cbor_item_t *item = NULL; | ||
410 | |||
411 | if ((item = cbor_new_definite_map(2)) == NULL) | ||
412 | return (NULL); | ||
413 | |||
414 | if ((rp->id && cbor_add_string(item, "id", rp->id) < 0) || | ||
415 | (rp->name && cbor_add_string(item, "name", rp->name) < 0)) { | ||
416 | cbor_decref(&item); | ||
417 | return (NULL); | ||
418 | } | ||
419 | |||
420 | return (item); | ||
421 | } | ||
422 | |||
423 | cbor_item_t * | ||
424 | cbor_encode_user_entity(const fido_user_t *user) | ||
425 | { | ||
426 | cbor_item_t *item = NULL; | ||
427 | const fido_blob_t *id = &user->id; | ||
428 | const char *display = user->display_name; | ||
429 | |||
430 | if ((item = cbor_new_definite_map(4)) == NULL) | ||
431 | return (NULL); | ||
432 | |||
433 | if ((id->ptr && cbor_add_bytestring(item, "id", id->ptr, id->len) < 0) || | ||
434 | (user->icon && cbor_add_string(item, "icon", user->icon) < 0) || | ||
435 | (user->name && cbor_add_string(item, "name", user->name) < 0) || | ||
436 | (display && cbor_add_string(item, "displayName", display) < 0)) { | ||
437 | cbor_decref(&item); | ||
438 | return (NULL); | ||
439 | } | ||
440 | |||
441 | return (item); | ||
442 | } | ||
443 | |||
444 | cbor_item_t * | ||
445 | cbor_encode_pubkey_param(int cose_alg) | ||
446 | { | ||
447 | cbor_item_t *item = NULL; | ||
448 | cbor_item_t *body = NULL; | ||
449 | struct cbor_pair alg; | ||
450 | int ok = -1; | ||
451 | |||
452 | memset(&alg, 0, sizeof(alg)); | ||
453 | |||
454 | if ((item = cbor_new_definite_array(1)) == NULL || | ||
455 | (body = cbor_new_definite_map(2)) == NULL || | ||
456 | cose_alg > -1 || cose_alg < INT16_MIN) | ||
457 | goto fail; | ||
458 | |||
459 | alg.key = cbor_build_string("alg"); | ||
460 | |||
461 | if (-cose_alg - 1 > UINT8_MAX) | ||
462 | alg.value = cbor_build_negint16((uint16_t)(-cose_alg - 1)); | ||
463 | else | ||
464 | alg.value = cbor_build_negint8((uint8_t)(-cose_alg - 1)); | ||
465 | |||
466 | if (alg.key == NULL || alg.value == NULL) { | ||
467 | fido_log_debug("%s: cbor_build", __func__); | ||
468 | goto fail; | ||
469 | } | ||
470 | |||
471 | if (cbor_map_add(body, alg) == false || | ||
472 | cbor_add_string(body, "type", "public-key") < 0 || | ||
473 | cbor_array_push(item, body) == false) | ||
474 | goto fail; | ||
475 | |||
476 | ok = 0; | ||
477 | fail: | ||
478 | if (ok < 0) { | ||
479 | if (item != NULL) { | ||
480 | cbor_decref(&item); | ||
481 | item = NULL; | ||
482 | } | ||
483 | } | ||
484 | |||
485 | if (body != NULL) | ||
486 | cbor_decref(&body); | ||
487 | if (alg.key != NULL) | ||
488 | cbor_decref(&alg.key); | ||
489 | if (alg.value != NULL) | ||
490 | cbor_decref(&alg.value); | ||
491 | |||
492 | return (item); | ||
493 | } | ||
494 | |||
495 | cbor_item_t * | ||
496 | cbor_encode_pubkey(const fido_blob_t *pubkey) | ||
497 | { | ||
498 | cbor_item_t *cbor_key = NULL; | ||
499 | |||
500 | if ((cbor_key = cbor_new_definite_map(2)) == NULL || | ||
501 | cbor_add_bytestring(cbor_key, "id", pubkey->ptr, pubkey->len) < 0 || | ||
502 | cbor_add_string(cbor_key, "type", "public-key") < 0) { | ||
503 | if (cbor_key) | ||
504 | cbor_decref(&cbor_key); | ||
505 | return (NULL); | ||
506 | } | ||
507 | |||
508 | return (cbor_key); | ||
509 | } | ||
510 | |||
511 | cbor_item_t * | ||
512 | cbor_encode_pubkey_list(const fido_blob_array_t *list) | ||
513 | { | ||
514 | cbor_item_t *array = NULL; | ||
515 | cbor_item_t *key = NULL; | ||
516 | |||
517 | if ((array = cbor_new_definite_array(list->len)) == NULL) | ||
518 | goto fail; | ||
519 | |||
520 | for (size_t i = 0; i < list->len; i++) { | ||
521 | if ((key = cbor_encode_pubkey(&list->ptr[i])) == NULL || | ||
522 | cbor_array_push(array, key) == false) | ||
523 | goto fail; | ||
524 | cbor_decref(&key); | ||
525 | } | ||
526 | |||
527 | return (array); | ||
528 | fail: | ||
529 | if (key != NULL) | ||
530 | cbor_decref(&key); | ||
531 | if (array != NULL) | ||
532 | cbor_decref(&array); | ||
533 | |||
534 | return (NULL); | ||
535 | } | ||
536 | |||
537 | cbor_item_t * | ||
538 | cbor_encode_extensions(int ext) | ||
539 | { | ||
540 | cbor_item_t *item = NULL; | ||
541 | |||
542 | if (ext == 0 || ext != FIDO_EXT_HMAC_SECRET) | ||
543 | return (NULL); | ||
544 | |||
545 | if ((item = cbor_new_definite_map(1)) == NULL) | ||
546 | return (NULL); | ||
547 | |||
548 | if (cbor_add_bool(item, "hmac-secret", FIDO_OPT_TRUE) < 0) { | ||
549 | cbor_decref(&item); | ||
550 | return (NULL); | ||
551 | } | ||
552 | |||
553 | return (item); | ||
554 | } | ||
555 | |||
556 | cbor_item_t * | ||
557 | cbor_encode_options(fido_opt_t rk, fido_opt_t uv) | ||
558 | { | ||
559 | cbor_item_t *item = NULL; | ||
560 | |||
561 | if ((item = cbor_new_definite_map(2)) == NULL) | ||
562 | return (NULL); | ||
563 | |||
564 | if ((rk != FIDO_OPT_OMIT && cbor_add_bool(item, "rk", rk) < 0) || | ||
565 | (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) { | ||
566 | cbor_decref(&item); | ||
567 | return (NULL); | ||
568 | } | ||
569 | |||
570 | return (item); | ||
571 | } | ||
572 | |||
573 | cbor_item_t * | ||
574 | cbor_encode_assert_options(fido_opt_t up, fido_opt_t uv) | ||
575 | { | ||
576 | cbor_item_t *item = NULL; | ||
577 | |||
578 | if ((item = cbor_new_definite_map(2)) == NULL) | ||
579 | return (NULL); | ||
580 | |||
581 | if ((up != FIDO_OPT_OMIT && cbor_add_bool(item, "up", up) < 0) || | ||
582 | (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) { | ||
583 | cbor_decref(&item); | ||
584 | return (NULL); | ||
585 | } | ||
586 | |||
587 | return (item); | ||
588 | } | ||
589 | |||
590 | cbor_item_t * | ||
591 | cbor_encode_pin_auth(const fido_blob_t *hmac_key, const fido_blob_t *data) | ||
592 | { | ||
593 | const EVP_MD *md = NULL; | ||
594 | unsigned char dgst[SHA256_DIGEST_LENGTH]; | ||
595 | unsigned int dgst_len; | ||
596 | |||
597 | if ((md = EVP_sha256()) == NULL || HMAC(md, hmac_key->ptr, | ||
598 | (int)hmac_key->len, data->ptr, (int)data->len, dgst, | ||
599 | &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH) | ||
600 | return (NULL); | ||
601 | |||
602 | return (cbor_build_bytestring(dgst, 16)); | ||
603 | } | ||
604 | |||
605 | cbor_item_t * | ||
606 | cbor_encode_pin_opt(void) | ||
607 | { | ||
608 | return (cbor_build_uint8(1)); | ||
609 | } | ||
610 | |||
611 | cbor_item_t * | ||
612 | cbor_encode_pin_enc(const fido_blob_t *key, const fido_blob_t *pin) | ||
613 | { | ||
614 | fido_blob_t pe; | ||
615 | cbor_item_t *item = NULL; | ||
616 | |||
617 | if (aes256_cbc_enc(key, pin, &pe) < 0) | ||
618 | return (NULL); | ||
619 | |||
620 | item = cbor_build_bytestring(pe.ptr, pe.len); | ||
621 | free(pe.ptr); | ||
622 | |||
623 | return (item); | ||
624 | } | ||
625 | |||
626 | static int | ||
627 | sha256(const unsigned char *data, size_t data_len, fido_blob_t *digest) | ||
628 | { | ||
629 | if ((digest->ptr = calloc(1, SHA256_DIGEST_LENGTH)) == NULL) | ||
630 | return (-1); | ||
631 | |||
632 | digest->len = SHA256_DIGEST_LENGTH; | ||
633 | |||
634 | if (SHA256(data, data_len, digest->ptr) != digest->ptr) { | ||
635 | free(digest->ptr); | ||
636 | digest->ptr = NULL; | ||
637 | digest->len = 0; | ||
638 | return (-1); | ||
639 | } | ||
640 | |||
641 | return (0); | ||
642 | } | ||
643 | |||
644 | cbor_item_t * | ||
645 | cbor_encode_change_pin_auth(const fido_blob_t *key, const fido_blob_t *new_pin, | ||
646 | const fido_blob_t *pin) | ||
647 | { | ||
648 | unsigned char dgst[SHA256_DIGEST_LENGTH]; | ||
649 | unsigned int dgst_len; | ||
650 | cbor_item_t *item = NULL; | ||
651 | const EVP_MD *md = NULL; | ||
652 | #if OPENSSL_VERSION_NUMBER < 0x10100000L | ||
653 | HMAC_CTX ctx; | ||
654 | #else | ||
655 | HMAC_CTX *ctx = NULL; | ||
656 | #endif | ||
657 | fido_blob_t *npe = NULL; /* new pin, encrypted */ | ||
658 | fido_blob_t *ph = NULL; /* pin hash */ | ||
659 | fido_blob_t *phe = NULL; /* pin hash, encrypted */ | ||
660 | int ok = -1; | ||
661 | |||
662 | if ((npe = fido_blob_new()) == NULL || | ||
663 | (ph = fido_blob_new()) == NULL || | ||
664 | (phe = fido_blob_new()) == NULL) | ||
665 | goto fail; | ||
666 | |||
667 | if (aes256_cbc_enc(key, new_pin, npe) < 0) { | ||
668 | fido_log_debug("%s: aes256_cbc_enc 1", __func__); | ||
669 | goto fail; | ||
670 | } | ||
671 | |||
672 | if (sha256(pin->ptr, pin->len, ph) < 0 || ph->len < 16) { | ||
673 | fido_log_debug("%s: sha256", __func__); | ||
674 | goto fail; | ||
675 | } | ||
676 | |||
677 | ph->len = 16; /* first 16 bytes */ | ||
678 | |||
679 | if (aes256_cbc_enc(key, ph, phe) < 0) { | ||
680 | fido_log_debug("%s: aes256_cbc_enc 2", __func__); | ||
681 | goto fail; | ||
682 | } | ||
683 | |||
684 | #if OPENSSL_VERSION_NUMBER < 0x10100000L | ||
685 | HMAC_CTX_init(&ctx); | ||
686 | |||
687 | if ((md = EVP_sha256()) == NULL || | ||
688 | HMAC_Init_ex(&ctx, key->ptr, (int)key->len, md, NULL) == 0 || | ||
689 | HMAC_Update(&ctx, npe->ptr, (int)npe->len) == 0 || | ||
690 | HMAC_Update(&ctx, phe->ptr, (int)phe->len) == 0 || | ||
691 | HMAC_Final(&ctx, dgst, &dgst_len) == 0 || dgst_len != 32) { | ||
692 | fido_log_debug("%s: HMAC", __func__); | ||
693 | goto fail; | ||
694 | } | ||
695 | #else | ||
696 | if ((ctx = HMAC_CTX_new()) == NULL || | ||
697 | (md = EVP_sha256()) == NULL || | ||
698 | HMAC_Init_ex(ctx, key->ptr, (int)key->len, md, NULL) == 0 || | ||
699 | HMAC_Update(ctx, npe->ptr, (int)npe->len) == 0 || | ||
700 | HMAC_Update(ctx, phe->ptr, (int)phe->len) == 0 || | ||
701 | HMAC_Final(ctx, dgst, &dgst_len) == 0 || dgst_len != 32) { | ||
702 | fido_log_debug("%s: HMAC", __func__); | ||
703 | goto fail; | ||
704 | } | ||
705 | #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ | ||
706 | |||
707 | if ((item = cbor_build_bytestring(dgst, 16)) == NULL) { | ||
708 | fido_log_debug("%s: cbor_build_bytestring", __func__); | ||
709 | goto fail; | ||
710 | } | ||
711 | |||
712 | ok = 0; | ||
713 | fail: | ||
714 | fido_blob_free(&npe); | ||
715 | fido_blob_free(&ph); | ||
716 | fido_blob_free(&phe); | ||
717 | |||
718 | #if OPENSSL_VERSION_NUMBER >= 0x10100000L | ||
719 | if (ctx != NULL) | ||
720 | HMAC_CTX_free(ctx); | ||
721 | #endif | ||
722 | |||
723 | if (ok < 0) { | ||
724 | if (item != NULL) { | ||
725 | cbor_decref(&item); | ||
726 | item = NULL; | ||
727 | } | ||
728 | } | ||
729 | |||
730 | return (item); | ||
731 | } | ||
732 | |||
733 | cbor_item_t * | ||
734 | cbor_encode_set_pin_auth(const fido_blob_t *key, const fido_blob_t *pin) | ||
735 | { | ||
736 | const EVP_MD *md = NULL; | ||
737 | unsigned char dgst[SHA256_DIGEST_LENGTH]; | ||
738 | unsigned int dgst_len; | ||
739 | cbor_item_t *item = NULL; | ||
740 | fido_blob_t *pe = NULL; | ||
741 | |||
742 | if ((pe = fido_blob_new()) == NULL) | ||
743 | goto fail; | ||
744 | |||
745 | if (aes256_cbc_enc(key, pin, pe) < 0) { | ||
746 | fido_log_debug("%s: aes256_cbc_enc", __func__); | ||
747 | goto fail; | ||
748 | } | ||
749 | |||
750 | if ((md = EVP_sha256()) == NULL || key->len != 32 || HMAC(md, key->ptr, | ||
751 | (int)key->len, pe->ptr, (int)pe->len, dgst, &dgst_len) == NULL || | ||
752 | dgst_len != SHA256_DIGEST_LENGTH) { | ||
753 | fido_log_debug("%s: HMAC", __func__); | ||
754 | goto fail; | ||
755 | } | ||
756 | |||
757 | item = cbor_build_bytestring(dgst, 16); | ||
758 | fail: | ||
759 | fido_blob_free(&pe); | ||
760 | |||
761 | return (item); | ||
762 | } | ||
763 | |||
764 | cbor_item_t * | ||
765 | cbor_encode_pin_hash_enc(const fido_blob_t *shared, const fido_blob_t *pin) | ||
766 | { | ||
767 | cbor_item_t *item = NULL; | ||
768 | fido_blob_t *ph = NULL; | ||
769 | fido_blob_t *phe = NULL; | ||
770 | |||
771 | if ((ph = fido_blob_new()) == NULL || (phe = fido_blob_new()) == NULL) | ||
772 | goto fail; | ||
773 | |||
774 | if (sha256(pin->ptr, pin->len, ph) < 0 || ph->len < 16) { | ||
775 | fido_log_debug("%s: SHA256", __func__); | ||
776 | goto fail; | ||
777 | } | ||
778 | |||
779 | ph->len = 16; /* first 16 bytes */ | ||
780 | |||
781 | if (aes256_cbc_enc(shared, ph, phe) < 0) { | ||
782 | fido_log_debug("%s: aes256_cbc_enc", __func__); | ||
783 | goto fail; | ||
784 | } | ||
785 | |||
786 | item = cbor_build_bytestring(phe->ptr, phe->len); | ||
787 | fail: | ||
788 | fido_blob_free(&ph); | ||
789 | fido_blob_free(&phe); | ||
790 | |||
791 | return (item); | ||
792 | } | ||
793 | |||
794 | cbor_item_t * | ||
795 | cbor_encode_hmac_secret_param(const fido_blob_t *ecdh, const es256_pk_t *pk, | ||
796 | const fido_blob_t *hmac_salt) | ||
797 | { | ||
798 | cbor_item_t *item = NULL; | ||
799 | cbor_item_t *param = NULL; | ||
800 | cbor_item_t *argv[3]; | ||
801 | struct cbor_pair pair; | ||
802 | |||
803 | memset(argv, 0, sizeof(argv)); | ||
804 | memset(&pair, 0, sizeof(pair)); | ||
805 | |||
806 | if (ecdh == NULL || pk == NULL || hmac_salt->ptr == NULL) { | ||
807 | fido_log_debug("%s: ecdh=%p, pk=%p, hmac_salt->ptr=%p", | ||
808 | __func__, (const void *)ecdh, (const void *)pk, | ||
809 | (const void *)hmac_salt->ptr); | ||
810 | goto fail; | ||
811 | } | ||
812 | |||
813 | if (hmac_salt->len != 32 && hmac_salt->len != 64) { | ||
814 | fido_log_debug("%s: hmac_salt->len=%zu", __func__, | ||
815 | hmac_salt->len); | ||
816 | goto fail; | ||
817 | } | ||
818 | |||
819 | /* XXX not pin, but salt */ | ||
820 | if ((argv[0] = es256_pk_encode(pk, 1)) == NULL || | ||
821 | (argv[1] = cbor_encode_pin_enc(ecdh, hmac_salt)) == NULL || | ||
822 | (argv[2] = cbor_encode_set_pin_auth(ecdh, hmac_salt)) == NULL) { | ||
823 | fido_log_debug("%s: cbor encode", __func__); | ||
824 | goto fail; | ||
825 | } | ||
826 | |||
827 | if ((param = cbor_flatten_vector(argv, 3)) == NULL) { | ||
828 | fido_log_debug("%s: cbor_flatten_vector", __func__); | ||
829 | goto fail; | ||
830 | } | ||
831 | |||
832 | if ((item = cbor_new_definite_map(1)) == NULL) { | ||
833 | fido_log_debug("%s: cbor_new_definite_map", __func__); | ||
834 | goto fail; | ||
835 | } | ||
836 | |||
837 | if ((pair.key = cbor_build_string("hmac-secret")) == NULL) { | ||
838 | fido_log_debug("%s: cbor_build", __func__); | ||
839 | goto fail; | ||
840 | } | ||
841 | |||
842 | pair.value = param; | ||
843 | |||
844 | if (!cbor_map_add(item, pair)) { | ||
845 | fido_log_debug("%s: cbor_map_add", __func__); | ||
846 | cbor_decref(&item); | ||
847 | item = NULL; | ||
848 | goto fail; | ||
849 | } | ||
850 | |||
851 | fail: | ||
852 | for (size_t i = 0; i < 3; i++) | ||
853 | if (argv[i] != NULL) | ||
854 | cbor_decref(&argv[i]); | ||
855 | |||
856 | if (param != NULL) | ||
857 | cbor_decref(¶m); | ||
858 | if (pair.key != NULL) | ||
859 | cbor_decref(&pair.key); | ||
860 | |||
861 | return (item); | ||
862 | } | ||
863 | |||
864 | int | ||
865 | cbor_decode_fmt(const cbor_item_t *item, char **fmt) | ||
866 | { | ||
867 | char *type = NULL; | ||
868 | |||
869 | if (cbor_string_copy(item, &type) < 0) { | ||
870 | fido_log_debug("%s: cbor_string_copy", __func__); | ||
871 | return (-1); | ||
872 | } | ||
873 | |||
874 | if (strcmp(type, "packed") && strcmp(type, "fido-u2f")) { | ||
875 | fido_log_debug("%s: type=%s", __func__, type); | ||
876 | free(type); | ||
877 | return (-1); | ||
878 | } | ||
879 | |||
880 | *fmt = type; | ||
881 | |||
882 | return (0); | ||
883 | } | ||
884 | |||
885 | struct cose_key { | ||
886 | int kty; | ||
887 | int alg; | ||
888 | int crv; | ||
889 | }; | ||
890 | |||
891 | static int | ||
892 | find_cose_alg(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
893 | { | ||
894 | struct cose_key *cose_key = arg; | ||
895 | |||
896 | if (cbor_isa_uint(key) == true && | ||
897 | cbor_int_get_width(key) == CBOR_INT_8) { | ||
898 | switch (cbor_get_uint8(key)) { | ||
899 | case 1: | ||
900 | if (cbor_isa_uint(val) == false || | ||
901 | cbor_get_int(val) > INT_MAX || cose_key->kty != 0) { | ||
902 | fido_log_debug("%s: kty", __func__); | ||
903 | return (-1); | ||
904 | } | ||
905 | |||
906 | cose_key->kty = (int)cbor_get_int(val); | ||
907 | |||
908 | break; | ||
909 | case 3: | ||
910 | if (cbor_isa_negint(val) == false || | ||
911 | cbor_get_int(val) > INT_MAX || cose_key->alg != 0) { | ||
912 | fido_log_debug("%s: alg", __func__); | ||
913 | return (-1); | ||
914 | } | ||
915 | |||
916 | cose_key->alg = -(int)cbor_get_int(val) - 1; | ||
917 | |||
918 | break; | ||
919 | } | ||
920 | } else if (cbor_isa_negint(key) == true && | ||
921 | cbor_int_get_width(key) == CBOR_INT_8) { | ||
922 | if (cbor_get_uint8(key) == 0) { | ||
923 | /* get crv if not rsa, otherwise ignore */ | ||
924 | if (cbor_isa_uint(val) == true && | ||
925 | cbor_get_int(val) <= INT_MAX && | ||
926 | cose_key->crv == 0) | ||
927 | cose_key->crv = (int)cbor_get_int(val); | ||
928 | } | ||
929 | } | ||
930 | |||
931 | return (0); | ||
932 | } | ||
933 | |||
934 | static int | ||
935 | get_cose_alg(const cbor_item_t *item, int *cose_alg) | ||
936 | { | ||
937 | struct cose_key cose_key; | ||
938 | |||
939 | memset(&cose_key, 0, sizeof(cose_key)); | ||
940 | |||
941 | *cose_alg = 0; | ||
942 | |||
943 | if (cbor_isa_map(item) == false || | ||
944 | cbor_map_is_definite(item) == false || | ||
945 | cbor_map_iter(item, &cose_key, find_cose_alg) < 0) { | ||
946 | fido_log_debug("%s: cbor type", __func__); | ||
947 | return (-1); | ||
948 | } | ||
949 | |||
950 | switch (cose_key.alg) { | ||
951 | case COSE_ES256: | ||
952 | if (cose_key.kty != COSE_KTY_EC2 || | ||
953 | cose_key.crv != COSE_P256) { | ||
954 | fido_log_debug("%s: invalid kty/crv", __func__); | ||
955 | return (-1); | ||
956 | } | ||
957 | |||
958 | break; | ||
959 | case COSE_EDDSA: | ||
960 | if (cose_key.kty != COSE_KTY_OKP || | ||
961 | cose_key.crv != COSE_ED25519) { | ||
962 | fido_log_debug("%s: invalid kty/crv", __func__); | ||
963 | return (-1); | ||
964 | } | ||
965 | |||
966 | break; | ||
967 | case COSE_RS256: | ||
968 | if (cose_key.kty != COSE_KTY_RSA) { | ||
969 | fido_log_debug("%s: invalid kty/crv", __func__); | ||
970 | return (-1); | ||
971 | } | ||
972 | |||
973 | break; | ||
974 | default: | ||
975 | fido_log_debug("%s: unknown alg %d", __func__, cose_key.alg); | ||
976 | |||
977 | return (-1); | ||
978 | } | ||
979 | |||
980 | *cose_alg = cose_key.alg; | ||
981 | |||
982 | return (0); | ||
983 | } | ||
984 | |||
985 | int | ||
986 | cbor_decode_pubkey(const cbor_item_t *item, int *type, void *key) | ||
987 | { | ||
988 | if (get_cose_alg(item, type) < 0) { | ||
989 | fido_log_debug("%s: get_cose_alg", __func__); | ||
990 | return (-1); | ||
991 | } | ||
992 | |||
993 | switch (*type) { | ||
994 | case COSE_ES256: | ||
995 | if (es256_pk_decode(item, key) < 0) { | ||
996 | fido_log_debug("%s: es256_pk_decode", __func__); | ||
997 | return (-1); | ||
998 | } | ||
999 | break; | ||
1000 | case COSE_RS256: | ||
1001 | if (rs256_pk_decode(item, key) < 0) { | ||
1002 | fido_log_debug("%s: rs256_pk_decode", __func__); | ||
1003 | return (-1); | ||
1004 | } | ||
1005 | break; | ||
1006 | case COSE_EDDSA: | ||
1007 | if (eddsa_pk_decode(item, key) < 0) { | ||
1008 | fido_log_debug("%s: eddsa_pk_decode", __func__); | ||
1009 | return (-1); | ||
1010 | } | ||
1011 | break; | ||
1012 | default: | ||
1013 | fido_log_debug("%s: invalid cose_alg %d", __func__, *type); | ||
1014 | return (-1); | ||
1015 | } | ||
1016 | |||
1017 | return (0); | ||
1018 | } | ||
1019 | |||
1020 | static int | ||
1021 | decode_attcred(const unsigned char **buf, size_t *len, int cose_alg, | ||
1022 | fido_attcred_t *attcred) | ||
1023 | { | ||
1024 | cbor_item_t *item = NULL; | ||
1025 | struct cbor_load_result cbor; | ||
1026 | uint16_t id_len; | ||
1027 | int ok = -1; | ||
1028 | |||
1029 | fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf, | ||
1030 | *len); | ||
1031 | |||
1032 | if (fido_buf_read(buf, len, &attcred->aaguid, | ||
1033 | sizeof(attcred->aaguid)) < 0) { | ||
1034 | fido_log_debug("%s: fido_buf_read aaguid", __func__); | ||
1035 | return (-1); | ||
1036 | } | ||
1037 | |||
1038 | if (fido_buf_read(buf, len, &id_len, sizeof(id_len)) < 0) { | ||
1039 | fido_log_debug("%s: fido_buf_read id_len", __func__); | ||
1040 | return (-1); | ||
1041 | } | ||
1042 | |||
1043 | attcred->id.len = (size_t)be16toh(id_len); | ||
1044 | if ((attcred->id.ptr = malloc(attcred->id.len)) == NULL) | ||
1045 | return (-1); | ||
1046 | |||
1047 | fido_log_debug("%s: attcred->id.len=%zu", __func__, attcred->id.len); | ||
1048 | |||
1049 | if (fido_buf_read(buf, len, attcred->id.ptr, attcred->id.len) < 0) { | ||
1050 | fido_log_debug("%s: fido_buf_read id", __func__); | ||
1051 | return (-1); | ||
1052 | } | ||
1053 | |||
1054 | if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { | ||
1055 | fido_log_debug("%s: cbor_load", __func__); | ||
1056 | fido_log_xxd(*buf, *len); | ||
1057 | goto fail; | ||
1058 | } | ||
1059 | |||
1060 | if (cbor_decode_pubkey(item, &attcred->type, &attcred->pubkey) < 0) { | ||
1061 | fido_log_debug("%s: cbor_decode_pubkey", __func__); | ||
1062 | goto fail; | ||
1063 | } | ||
1064 | |||
1065 | if (attcred->type != cose_alg) { | ||
1066 | fido_log_debug("%s: cose_alg mismatch (%d != %d)", __func__, | ||
1067 | attcred->type, cose_alg); | ||
1068 | goto fail; | ||
1069 | } | ||
1070 | |||
1071 | *buf += cbor.read; | ||
1072 | *len -= cbor.read; | ||
1073 | |||
1074 | ok = 0; | ||
1075 | fail: | ||
1076 | if (item != NULL) | ||
1077 | cbor_decref(&item); | ||
1078 | |||
1079 | return (ok); | ||
1080 | } | ||
1081 | |||
1082 | static int | ||
1083 | decode_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
1084 | { | ||
1085 | int *authdata_ext = arg; | ||
1086 | char *type = NULL; | ||
1087 | int ok = -1; | ||
1088 | |||
1089 | if (cbor_string_copy(key, &type) < 0 || strcmp(type, "hmac-secret")) { | ||
1090 | fido_log_debug("%s: cbor type", __func__); | ||
1091 | ok = 0; /* ignore */ | ||
1092 | goto out; | ||
1093 | } | ||
1094 | |||
1095 | if (cbor_isa_float_ctrl(val) == false || | ||
1096 | cbor_float_get_width(val) != CBOR_FLOAT_0 || | ||
1097 | cbor_is_bool(val) == false || *authdata_ext != 0) { | ||
1098 | fido_log_debug("%s: cbor type", __func__); | ||
1099 | goto out; | ||
1100 | } | ||
1101 | |||
1102 | if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE) | ||
1103 | *authdata_ext |= FIDO_EXT_HMAC_SECRET; | ||
1104 | |||
1105 | ok = 0; | ||
1106 | out: | ||
1107 | free(type); | ||
1108 | |||
1109 | return (ok); | ||
1110 | } | ||
1111 | |||
1112 | static int | ||
1113 | decode_extensions(const unsigned char **buf, size_t *len, int *authdata_ext) | ||
1114 | { | ||
1115 | cbor_item_t *item = NULL; | ||
1116 | struct cbor_load_result cbor; | ||
1117 | int ok = -1; | ||
1118 | |||
1119 | fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf, | ||
1120 | *len); | ||
1121 | |||
1122 | *authdata_ext = 0; | ||
1123 | |||
1124 | if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { | ||
1125 | fido_log_debug("%s: cbor_load", __func__); | ||
1126 | fido_log_xxd(*buf, *len); | ||
1127 | goto fail; | ||
1128 | } | ||
1129 | |||
1130 | if (cbor_isa_map(item) == false || | ||
1131 | cbor_map_is_definite(item) == false || | ||
1132 | cbor_map_size(item) != 1 || | ||
1133 | cbor_map_iter(item, authdata_ext, decode_extension) < 0) { | ||
1134 | fido_log_debug("%s: cbor type", __func__); | ||
1135 | goto fail; | ||
1136 | } | ||
1137 | |||
1138 | *buf += cbor.read; | ||
1139 | *len -= cbor.read; | ||
1140 | |||
1141 | ok = 0; | ||
1142 | fail: | ||
1143 | if (item != NULL) | ||
1144 | cbor_decref(&item); | ||
1145 | |||
1146 | return (ok); | ||
1147 | } | ||
1148 | |||
1149 | static int | ||
1150 | decode_hmac_secret_aux(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
1151 | { | ||
1152 | fido_blob_t *out = arg; | ||
1153 | char *type = NULL; | ||
1154 | int ok = -1; | ||
1155 | |||
1156 | if (cbor_string_copy(key, &type) < 0 || strcmp(type, "hmac-secret")) { | ||
1157 | fido_log_debug("%s: cbor type", __func__); | ||
1158 | ok = 0; /* ignore */ | ||
1159 | goto out; | ||
1160 | } | ||
1161 | |||
1162 | ok = cbor_bytestring_copy(val, &out->ptr, &out->len); | ||
1163 | out: | ||
1164 | free(type); | ||
1165 | |||
1166 | return (ok); | ||
1167 | } | ||
1168 | |||
1169 | static int | ||
1170 | decode_hmac_secret(const unsigned char **buf, size_t *len, fido_blob_t *out) | ||
1171 | { | ||
1172 | cbor_item_t *item = NULL; | ||
1173 | struct cbor_load_result cbor; | ||
1174 | int ok = -1; | ||
1175 | |||
1176 | fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf, | ||
1177 | *len); | ||
1178 | |||
1179 | if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { | ||
1180 | fido_log_debug("%s: cbor_load", __func__); | ||
1181 | fido_log_xxd(*buf, *len); | ||
1182 | goto fail; | ||
1183 | } | ||
1184 | |||
1185 | if (cbor_isa_map(item) == false || | ||
1186 | cbor_map_is_definite(item) == false || | ||
1187 | cbor_map_size(item) != 1 || | ||
1188 | cbor_map_iter(item, out, decode_hmac_secret_aux) < 0) { | ||
1189 | fido_log_debug("%s: cbor type", __func__); | ||
1190 | goto fail; | ||
1191 | } | ||
1192 | |||
1193 | *buf += cbor.read; | ||
1194 | *len -= cbor.read; | ||
1195 | |||
1196 | ok = 0; | ||
1197 | fail: | ||
1198 | if (item != NULL) | ||
1199 | cbor_decref(&item); | ||
1200 | |||
1201 | return (ok); | ||
1202 | } | ||
1203 | |||
1204 | int | ||
1205 | cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg, | ||
1206 | fido_blob_t *authdata_cbor, fido_authdata_t *authdata, | ||
1207 | fido_attcred_t *attcred, int *authdata_ext) | ||
1208 | { | ||
1209 | const unsigned char *buf = NULL; | ||
1210 | size_t len; | ||
1211 | size_t alloc_len; | ||
1212 | |||
1213 | if (cbor_isa_bytestring(item) == false || | ||
1214 | cbor_bytestring_is_definite(item) == false) { | ||
1215 | fido_log_debug("%s: cbor type", __func__); | ||
1216 | return (-1); | ||
1217 | } | ||
1218 | |||
1219 | if (authdata_cbor->ptr != NULL || | ||
1220 | (authdata_cbor->len = cbor_serialize_alloc(item, | ||
1221 | &authdata_cbor->ptr, &alloc_len)) == 0) { | ||
1222 | fido_log_debug("%s: cbor_serialize_alloc", __func__); | ||
1223 | return (-1); | ||
1224 | } | ||
1225 | |||
1226 | buf = cbor_bytestring_handle(item); | ||
1227 | len = cbor_bytestring_length(item); | ||
1228 | |||
1229 | fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len); | ||
1230 | |||
1231 | if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) { | ||
1232 | fido_log_debug("%s: fido_buf_read", __func__); | ||
1233 | return (-1); | ||
1234 | } | ||
1235 | |||
1236 | authdata->sigcount = be32toh(authdata->sigcount); | ||
1237 | |||
1238 | if (attcred != NULL) { | ||
1239 | if ((authdata->flags & CTAP_AUTHDATA_ATT_CRED) == 0 || | ||
1240 | decode_attcred(&buf, &len, cose_alg, attcred) < 0) | ||
1241 | return (-1); | ||
1242 | } | ||
1243 | |||
1244 | if (authdata_ext != NULL) { | ||
1245 | if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 && | ||
1246 | decode_extensions(&buf, &len, authdata_ext) < 0) | ||
1247 | return (-1); | ||
1248 | } | ||
1249 | |||
1250 | /* XXX we should probably ensure that len == 0 at this point */ | ||
1251 | |||
1252 | return (FIDO_OK); | ||
1253 | } | ||
1254 | |||
1255 | int | ||
1256 | cbor_decode_assert_authdata(const cbor_item_t *item, fido_blob_t *authdata_cbor, | ||
1257 | fido_authdata_t *authdata, int *authdata_ext, fido_blob_t *hmac_secret_enc) | ||
1258 | { | ||
1259 | const unsigned char *buf = NULL; | ||
1260 | size_t len; | ||
1261 | size_t alloc_len; | ||
1262 | |||
1263 | if (cbor_isa_bytestring(item) == false || | ||
1264 | cbor_bytestring_is_definite(item) == false) { | ||
1265 | fido_log_debug("%s: cbor type", __func__); | ||
1266 | return (-1); | ||
1267 | } | ||
1268 | |||
1269 | if (authdata_cbor->ptr != NULL || | ||
1270 | (authdata_cbor->len = cbor_serialize_alloc(item, | ||
1271 | &authdata_cbor->ptr, &alloc_len)) == 0) { | ||
1272 | fido_log_debug("%s: cbor_serialize_alloc", __func__); | ||
1273 | return (-1); | ||
1274 | } | ||
1275 | |||
1276 | buf = cbor_bytestring_handle(item); | ||
1277 | len = cbor_bytestring_length(item); | ||
1278 | |||
1279 | fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len); | ||
1280 | |||
1281 | if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) { | ||
1282 | fido_log_debug("%s: fido_buf_read", __func__); | ||
1283 | return (-1); | ||
1284 | } | ||
1285 | |||
1286 | authdata->sigcount = be32toh(authdata->sigcount); | ||
1287 | |||
1288 | *authdata_ext = 0; | ||
1289 | if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0) { | ||
1290 | /* XXX semantic leap: extensions -> hmac_secret */ | ||
1291 | if (decode_hmac_secret(&buf, &len, hmac_secret_enc) < 0) { | ||
1292 | fido_log_debug("%s: decode_hmac_secret", __func__); | ||
1293 | return (-1); | ||
1294 | } | ||
1295 | *authdata_ext = FIDO_EXT_HMAC_SECRET; | ||
1296 | } | ||
1297 | |||
1298 | /* XXX we should probably ensure that len == 0 at this point */ | ||
1299 | |||
1300 | return (FIDO_OK); | ||
1301 | } | ||
1302 | |||
1303 | static int | ||
1304 | decode_x5c(const cbor_item_t *item, void *arg) | ||
1305 | { | ||
1306 | fido_blob_t *x5c = arg; | ||
1307 | |||
1308 | if (x5c->len) | ||
1309 | return (0); /* ignore */ | ||
1310 | |||
1311 | return (cbor_bytestring_copy(item, &x5c->ptr, &x5c->len)); | ||
1312 | } | ||
1313 | |||
1314 | static int | ||
1315 | decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
1316 | { | ||
1317 | fido_attstmt_t *attstmt = arg; | ||
1318 | char *name = NULL; | ||
1319 | int ok = -1; | ||
1320 | |||
1321 | if (cbor_string_copy(key, &name) < 0) { | ||
1322 | fido_log_debug("%s: cbor type", __func__); | ||
1323 | ok = 0; /* ignore */ | ||
1324 | goto out; | ||
1325 | } | ||
1326 | |||
1327 | if (!strcmp(name, "alg")) { | ||
1328 | if (cbor_isa_negint(val) == false || | ||
1329 | cbor_int_get_width(val) != CBOR_INT_8 || | ||
1330 | cbor_get_uint8(val) != -COSE_ES256 - 1) { | ||
1331 | fido_log_debug("%s: alg", __func__); | ||
1332 | goto out; | ||
1333 | } | ||
1334 | } else if (!strcmp(name, "sig")) { | ||
1335 | if (cbor_bytestring_copy(val, &attstmt->sig.ptr, | ||
1336 | &attstmt->sig.len) < 0) { | ||
1337 | fido_log_debug("%s: sig", __func__); | ||
1338 | goto out; | ||
1339 | } | ||
1340 | } else if (!strcmp(name, "x5c")) { | ||
1341 | if (cbor_isa_array(val) == false || | ||
1342 | cbor_array_is_definite(val) == false || | ||
1343 | cbor_array_iter(val, &attstmt->x5c, decode_x5c) < 0) { | ||
1344 | fido_log_debug("%s: x5c", __func__); | ||
1345 | goto out; | ||
1346 | } | ||
1347 | } | ||
1348 | |||
1349 | ok = 0; | ||
1350 | out: | ||
1351 | free(name); | ||
1352 | |||
1353 | return (ok); | ||
1354 | } | ||
1355 | |||
1356 | int | ||
1357 | cbor_decode_attstmt(const cbor_item_t *item, fido_attstmt_t *attstmt) | ||
1358 | { | ||
1359 | if (cbor_isa_map(item) == false || | ||
1360 | cbor_map_is_definite(item) == false || | ||
1361 | cbor_map_iter(item, attstmt, decode_attstmt_entry) < 0) { | ||
1362 | fido_log_debug("%s: cbor type", __func__); | ||
1363 | return (-1); | ||
1364 | } | ||
1365 | |||
1366 | return (0); | ||
1367 | } | ||
1368 | |||
1369 | int | ||
1370 | cbor_decode_uint64(const cbor_item_t *item, uint64_t *n) | ||
1371 | { | ||
1372 | if (cbor_isa_uint(item) == false) { | ||
1373 | fido_log_debug("%s: cbor type", __func__); | ||
1374 | return (-1); | ||
1375 | } | ||
1376 | |||
1377 | *n = cbor_get_int(item); | ||
1378 | |||
1379 | return (0); | ||
1380 | } | ||
1381 | |||
1382 | static int | ||
1383 | decode_cred_id_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
1384 | { | ||
1385 | fido_blob_t *id = arg; | ||
1386 | char *name = NULL; | ||
1387 | int ok = -1; | ||
1388 | |||
1389 | if (cbor_string_copy(key, &name) < 0) { | ||
1390 | fido_log_debug("%s: cbor type", __func__); | ||
1391 | ok = 0; /* ignore */ | ||
1392 | goto out; | ||
1393 | } | ||
1394 | |||
1395 | if (!strcmp(name, "id")) | ||
1396 | if (cbor_bytestring_copy(val, &id->ptr, &id->len) < 0) { | ||
1397 | fido_log_debug("%s: cbor_bytestring_copy", __func__); | ||
1398 | goto out; | ||
1399 | } | ||
1400 | |||
1401 | ok = 0; | ||
1402 | out: | ||
1403 | free(name); | ||
1404 | |||
1405 | return (ok); | ||
1406 | } | ||
1407 | |||
1408 | int | ||
1409 | cbor_decode_cred_id(const cbor_item_t *item, fido_blob_t *id) | ||
1410 | { | ||
1411 | if (cbor_isa_map(item) == false || | ||
1412 | cbor_map_is_definite(item) == false || | ||
1413 | cbor_map_iter(item, id, decode_cred_id_entry) < 0) { | ||
1414 | fido_log_debug("%s: cbor type", __func__); | ||
1415 | return (-1); | ||
1416 | } | ||
1417 | |||
1418 | return (0); | ||
1419 | } | ||
1420 | |||
1421 | static int | ||
1422 | decode_user_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
1423 | { | ||
1424 | fido_user_t *user = arg; | ||
1425 | char *name = NULL; | ||
1426 | int ok = -1; | ||
1427 | |||
1428 | if (cbor_string_copy(key, &name) < 0) { | ||
1429 | fido_log_debug("%s: cbor type", __func__); | ||
1430 | ok = 0; /* ignore */ | ||
1431 | goto out; | ||
1432 | } | ||
1433 | |||
1434 | if (!strcmp(name, "icon")) { | ||
1435 | if (cbor_string_copy(val, &user->icon) < 0) { | ||
1436 | fido_log_debug("%s: icon", __func__); | ||
1437 | goto out; | ||
1438 | } | ||
1439 | } else if (!strcmp(name, "name")) { | ||
1440 | if (cbor_string_copy(val, &user->name) < 0) { | ||
1441 | fido_log_debug("%s: name", __func__); | ||
1442 | goto out; | ||
1443 | } | ||
1444 | } else if (!strcmp(name, "displayName")) { | ||
1445 | if (cbor_string_copy(val, &user->display_name) < 0) { | ||
1446 | fido_log_debug("%s: display_name", __func__); | ||
1447 | goto out; | ||
1448 | } | ||
1449 | } else if (!strcmp(name, "id")) { | ||
1450 | if (cbor_bytestring_copy(val, &user->id.ptr, &user->id.len) < 0) { | ||
1451 | fido_log_debug("%s: id", __func__); | ||
1452 | goto out; | ||
1453 | } | ||
1454 | } | ||
1455 | |||
1456 | ok = 0; | ||
1457 | out: | ||
1458 | free(name); | ||
1459 | |||
1460 | return (ok); | ||
1461 | } | ||
1462 | |||
1463 | int | ||
1464 | cbor_decode_user(const cbor_item_t *item, fido_user_t *user) | ||
1465 | { | ||
1466 | if (cbor_isa_map(item) == false || | ||
1467 | cbor_map_is_definite(item) == false || | ||
1468 | cbor_map_iter(item, user, decode_user_entry) < 0) { | ||
1469 | fido_log_debug("%s: cbor type", __func__); | ||
1470 | return (-1); | ||
1471 | } | ||
1472 | |||
1473 | return (0); | ||
1474 | } | ||
1475 | |||
1476 | static int | ||
1477 | decode_rp_entity_entry(const cbor_item_t *key, const cbor_item_t *val, | ||
1478 | void *arg) | ||
1479 | { | ||
1480 | fido_rp_t *rp = arg; | ||
1481 | char *name = NULL; | ||
1482 | int ok = -1; | ||
1483 | |||
1484 | if (cbor_string_copy(key, &name) < 0) { | ||
1485 | fido_log_debug("%s: cbor type", __func__); | ||
1486 | ok = 0; /* ignore */ | ||
1487 | goto out; | ||
1488 | } | ||
1489 | |||
1490 | if (!strcmp(name, "id")) { | ||
1491 | if (cbor_string_copy(val, &rp->id) < 0) { | ||
1492 | fido_log_debug("%s: id", __func__); | ||
1493 | goto out; | ||
1494 | } | ||
1495 | } else if (!strcmp(name, "name")) { | ||
1496 | if (cbor_string_copy(val, &rp->name) < 0) { | ||
1497 | fido_log_debug("%s: name", __func__); | ||
1498 | goto out; | ||
1499 | } | ||
1500 | } | ||
1501 | |||
1502 | ok = 0; | ||
1503 | out: | ||
1504 | free(name); | ||
1505 | |||
1506 | return (ok); | ||
1507 | } | ||
1508 | |||
1509 | int | ||
1510 | cbor_decode_rp_entity(const cbor_item_t *item, fido_rp_t *rp) | ||
1511 | { | ||
1512 | if (cbor_isa_map(item) == false || | ||
1513 | cbor_map_is_definite(item) == false || | ||
1514 | cbor_map_iter(item, rp, decode_rp_entity_entry) < 0) { | ||
1515 | fido_log_debug("%s: cbor type", __func__); | ||
1516 | return (-1); | ||
1517 | } | ||
1518 | |||
1519 | return (0); | ||
1520 | } | ||
diff --git a/src/cred.c b/src/cred.c new file mode 100644 index 0000000..c4e1edb --- /dev/null +++ b/src/cred.c | |||
@@ -0,0 +1,1034 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <openssl/ec.h> | ||
8 | #include <openssl/evp.h> | ||
9 | #include <openssl/sha.h> | ||
10 | #include <openssl/x509.h> | ||
11 | |||
12 | #include <string.h> | ||
13 | #include "fido.h" | ||
14 | #include "fido/es256.h" | ||
15 | |||
16 | static int | ||
17 | parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
18 | { | ||
19 | fido_cred_t *cred = arg; | ||
20 | |||
21 | if (cbor_isa_uint(key) == false || | ||
22 | cbor_int_get_width(key) != CBOR_INT_8) { | ||
23 | fido_log_debug("%s: cbor type", __func__); | ||
24 | return (0); /* ignore */ | ||
25 | } | ||
26 | |||
27 | switch (cbor_get_uint8(key)) { | ||
28 | case 1: /* fmt */ | ||
29 | return (cbor_decode_fmt(val, &cred->fmt)); | ||
30 | case 2: /* authdata */ | ||
31 | return (cbor_decode_cred_authdata(val, cred->type, | ||
32 | &cred->authdata_cbor, &cred->authdata, &cred->attcred, | ||
33 | &cred->authdata_ext)); | ||
34 | case 3: /* attestation statement */ | ||
35 | return (cbor_decode_attstmt(val, &cred->attstmt)); | ||
36 | default: /* ignore */ | ||
37 | fido_log_debug("%s: cbor type", __func__); | ||
38 | return (0); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | static int | ||
43 | fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin) | ||
44 | { | ||
45 | fido_blob_t f; | ||
46 | fido_blob_t *ecdh = NULL; | ||
47 | es256_pk_t *pk = NULL; | ||
48 | cbor_item_t *argv[9]; | ||
49 | int r; | ||
50 | |||
51 | memset(&f, 0, sizeof(f)); | ||
52 | memset(argv, 0, sizeof(argv)); | ||
53 | |||
54 | if (cred->cdh.ptr == NULL || cred->type == 0) { | ||
55 | fido_log_debug("%s: cdh=%p, type=%d", __func__, | ||
56 | (void *)cred->cdh.ptr, cred->type); | ||
57 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
58 | goto fail; | ||
59 | } | ||
60 | |||
61 | if ((argv[0] = fido_blob_encode(&cred->cdh)) == NULL || | ||
62 | (argv[1] = cbor_encode_rp_entity(&cred->rp)) == NULL || | ||
63 | (argv[2] = cbor_encode_user_entity(&cred->user)) == NULL || | ||
64 | (argv[3] = cbor_encode_pubkey_param(cred->type)) == NULL) { | ||
65 | fido_log_debug("%s: cbor encode", __func__); | ||
66 | r = FIDO_ERR_INTERNAL; | ||
67 | goto fail; | ||
68 | } | ||
69 | |||
70 | /* excluded credentials */ | ||
71 | if (cred->excl.len) | ||
72 | if ((argv[4] = cbor_encode_pubkey_list(&cred->excl)) == NULL) { | ||
73 | fido_log_debug("%s: cbor_encode_pubkey_list", __func__); | ||
74 | r = FIDO_ERR_INTERNAL; | ||
75 | goto fail; | ||
76 | } | ||
77 | |||
78 | /* extensions */ | ||
79 | if (cred->ext) | ||
80 | if ((argv[5] = cbor_encode_extensions(cred->ext)) == NULL) { | ||
81 | fido_log_debug("%s: cbor_encode_extensions", __func__); | ||
82 | r = FIDO_ERR_INTERNAL; | ||
83 | goto fail; | ||
84 | } | ||
85 | |||
86 | /* options */ | ||
87 | if (cred->rk != FIDO_OPT_OMIT || cred->uv != FIDO_OPT_OMIT) | ||
88 | if ((argv[6] = cbor_encode_options(cred->rk, | ||
89 | cred->uv)) == NULL) { | ||
90 | fido_log_debug("%s: cbor_encode_options", __func__); | ||
91 | r = FIDO_ERR_INTERNAL; | ||
92 | goto fail; | ||
93 | } | ||
94 | |||
95 | /* pin authentication */ | ||
96 | if (pin) { | ||
97 | if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { | ||
98 | fido_log_debug("%s: fido_do_ecdh", __func__); | ||
99 | goto fail; | ||
100 | } | ||
101 | if ((r = cbor_add_pin_params(dev, &cred->cdh, pk, ecdh, pin, | ||
102 | &argv[7], &argv[8])) != FIDO_OK) { | ||
103 | fido_log_debug("%s: cbor_add_pin_params", __func__); | ||
104 | goto fail; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | /* framing and transmission */ | ||
109 | if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, 9, &f) < 0 || | ||
110 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | ||
111 | fido_log_debug("%s: fido_tx", __func__); | ||
112 | r = FIDO_ERR_TX; | ||
113 | goto fail; | ||
114 | } | ||
115 | |||
116 | r = FIDO_OK; | ||
117 | fail: | ||
118 | es256_pk_free(&pk); | ||
119 | fido_blob_free(&ecdh); | ||
120 | cbor_vector_free(argv, nitems(argv)); | ||
121 | free(f.ptr); | ||
122 | |||
123 | return (r); | ||
124 | } | ||
125 | |||
126 | static int | ||
127 | fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int ms) | ||
128 | { | ||
129 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
130 | unsigned char reply[2048]; | ||
131 | int reply_len; | ||
132 | int r; | ||
133 | |||
134 | fido_cred_reset_rx(cred); | ||
135 | |||
136 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
137 | fido_log_debug("%s: fido_rx", __func__); | ||
138 | return (FIDO_ERR_RX); | ||
139 | } | ||
140 | |||
141 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, cred, | ||
142 | parse_makecred_reply)) != FIDO_OK) { | ||
143 | fido_log_debug("%s: parse_makecred_reply", __func__); | ||
144 | return (r); | ||
145 | } | ||
146 | |||
147 | if (cred->fmt == NULL || fido_blob_is_empty(&cred->authdata_cbor) || | ||
148 | fido_blob_is_empty(&cred->attcred.id) || | ||
149 | fido_blob_is_empty(&cred->attstmt.sig)) { | ||
150 | fido_cred_reset_rx(cred); | ||
151 | return (FIDO_ERR_INVALID_CBOR); | ||
152 | } | ||
153 | |||
154 | return (FIDO_OK); | ||
155 | } | ||
156 | |||
157 | static int | ||
158 | fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin, int ms) | ||
159 | { | ||
160 | int r; | ||
161 | |||
162 | if ((r = fido_dev_make_cred_tx(dev, cred, pin)) != FIDO_OK || | ||
163 | (r = fido_dev_make_cred_rx(dev, cred, ms)) != FIDO_OK) | ||
164 | return (r); | ||
165 | |||
166 | return (FIDO_OK); | ||
167 | } | ||
168 | |||
169 | int | ||
170 | fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin) | ||
171 | { | ||
172 | if (fido_dev_is_fido2(dev) == false) { | ||
173 | if (pin != NULL || cred->rk == FIDO_OPT_TRUE || cred->ext != 0) | ||
174 | return (FIDO_ERR_UNSUPPORTED_OPTION); | ||
175 | return (u2f_register(dev, cred, -1)); | ||
176 | } | ||
177 | |||
178 | return (fido_dev_make_cred_wait(dev, cred, pin, -1)); | ||
179 | } | ||
180 | |||
181 | static int | ||
182 | check_extensions(int authdata_ext, int ext) | ||
183 | { | ||
184 | if (authdata_ext != ext) { | ||
185 | fido_log_debug("%s: authdata_ext=0x%x != ext=0x%x", __func__, | ||
186 | authdata_ext, ext); | ||
187 | return (-1); | ||
188 | } | ||
189 | |||
190 | return (0); | ||
191 | } | ||
192 | |||
193 | int | ||
194 | fido_check_rp_id(const char *id, const unsigned char *obtained_hash) | ||
195 | { | ||
196 | unsigned char expected_hash[SHA256_DIGEST_LENGTH]; | ||
197 | |||
198 | explicit_bzero(expected_hash, sizeof(expected_hash)); | ||
199 | |||
200 | if (SHA256((const unsigned char *)id, strlen(id), | ||
201 | expected_hash) != expected_hash) { | ||
202 | fido_log_debug("%s: sha256", __func__); | ||
203 | return (-1); | ||
204 | } | ||
205 | |||
206 | return (timingsafe_bcmp(expected_hash, obtained_hash, | ||
207 | SHA256_DIGEST_LENGTH)); | ||
208 | } | ||
209 | |||
210 | static int | ||
211 | get_signed_hash_packed(fido_blob_t *dgst, const fido_blob_t *clientdata, | ||
212 | const fido_blob_t *authdata_cbor) | ||
213 | { | ||
214 | cbor_item_t *item = NULL; | ||
215 | unsigned char *authdata_ptr = NULL; | ||
216 | size_t authdata_len; | ||
217 | struct cbor_load_result cbor; | ||
218 | SHA256_CTX ctx; | ||
219 | int ok = -1; | ||
220 | |||
221 | if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len, | ||
222 | &cbor)) == NULL) { | ||
223 | fido_log_debug("%s: cbor_load", __func__); | ||
224 | goto fail; | ||
225 | } | ||
226 | |||
227 | if (cbor_isa_bytestring(item) == false || | ||
228 | cbor_bytestring_is_definite(item) == false) { | ||
229 | fido_log_debug("%s: cbor type", __func__); | ||
230 | goto fail; | ||
231 | } | ||
232 | |||
233 | authdata_ptr = cbor_bytestring_handle(item); | ||
234 | authdata_len = cbor_bytestring_length(item); | ||
235 | |||
236 | if (dgst->len != SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 || | ||
237 | SHA256_Update(&ctx, authdata_ptr, authdata_len) == 0 || | ||
238 | SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 || | ||
239 | SHA256_Final(dgst->ptr, &ctx) == 0) { | ||
240 | fido_log_debug("%s: sha256", __func__); | ||
241 | goto fail; | ||
242 | } | ||
243 | |||
244 | ok = 0; | ||
245 | fail: | ||
246 | if (item != NULL) | ||
247 | cbor_decref(&item); | ||
248 | |||
249 | return (ok); | ||
250 | } | ||
251 | |||
252 | static int | ||
253 | get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id, | ||
254 | size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id, | ||
255 | const es256_pk_t *pk) | ||
256 | { | ||
257 | const uint8_t zero = 0; | ||
258 | const uint8_t four = 4; /* uncompressed point */ | ||
259 | SHA256_CTX ctx; | ||
260 | |||
261 | if (dgst->len != SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 || | ||
262 | SHA256_Update(&ctx, &zero, sizeof(zero)) == 0 || | ||
263 | SHA256_Update(&ctx, rp_id, rp_id_len) == 0 || | ||
264 | SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 || | ||
265 | SHA256_Update(&ctx, id->ptr, id->len) == 0 || | ||
266 | SHA256_Update(&ctx, &four, sizeof(four)) == 0 || | ||
267 | SHA256_Update(&ctx, pk->x, sizeof(pk->x)) == 0 || | ||
268 | SHA256_Update(&ctx, pk->y, sizeof(pk->y)) == 0 || | ||
269 | SHA256_Final(dgst->ptr, &ctx) == 0) { | ||
270 | fido_log_debug("%s: sha256", __func__); | ||
271 | return (-1); | ||
272 | } | ||
273 | |||
274 | return (0); | ||
275 | } | ||
276 | |||
277 | static int | ||
278 | verify_sig(const fido_blob_t *dgst, const fido_blob_t *x5c, | ||
279 | const fido_blob_t *sig) | ||
280 | { | ||
281 | BIO *rawcert = NULL; | ||
282 | X509 *cert = NULL; | ||
283 | EVP_PKEY *pkey = NULL; | ||
284 | EC_KEY *ec; | ||
285 | int ok = -1; | ||
286 | |||
287 | /* openssl needs ints */ | ||
288 | if (dgst->len > INT_MAX || x5c->len > INT_MAX || sig->len > INT_MAX) { | ||
289 | fido_log_debug("%s: dgst->len=%zu, x5c->len=%zu, sig->len=%zu", | ||
290 | __func__, dgst->len, x5c->len, sig->len); | ||
291 | return (-1); | ||
292 | } | ||
293 | |||
294 | /* fetch key from x509 */ | ||
295 | if ((rawcert = BIO_new_mem_buf(x5c->ptr, (int)x5c->len)) == NULL || | ||
296 | (cert = d2i_X509_bio(rawcert, NULL)) == NULL || | ||
297 | (pkey = X509_get_pubkey(cert)) == NULL || | ||
298 | (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) { | ||
299 | fido_log_debug("%s: x509 key", __func__); | ||
300 | goto fail; | ||
301 | } | ||
302 | |||
303 | if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr, | ||
304 | (int)sig->len, ec) != 1) { | ||
305 | fido_log_debug("%s: ECDSA_verify", __func__); | ||
306 | goto fail; | ||
307 | } | ||
308 | |||
309 | ok = 0; | ||
310 | fail: | ||
311 | if (rawcert != NULL) | ||
312 | BIO_free(rawcert); | ||
313 | if (cert != NULL) | ||
314 | X509_free(cert); | ||
315 | if (pkey != NULL) | ||
316 | EVP_PKEY_free(pkey); | ||
317 | |||
318 | return (ok); | ||
319 | } | ||
320 | |||
321 | int | ||
322 | fido_cred_verify(const fido_cred_t *cred) | ||
323 | { | ||
324 | unsigned char buf[SHA256_DIGEST_LENGTH]; | ||
325 | fido_blob_t dgst; | ||
326 | int r; | ||
327 | |||
328 | dgst.ptr = buf; | ||
329 | dgst.len = sizeof(buf); | ||
330 | |||
331 | /* do we have everything we need? */ | ||
332 | if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL || | ||
333 | cred->attstmt.x5c.ptr == NULL || cred->attstmt.sig.ptr == NULL || | ||
334 | cred->fmt == NULL || cred->attcred.id.ptr == NULL || | ||
335 | cred->rp.id == NULL) { | ||
336 | fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, " | ||
337 | "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr, | ||
338 | (void *)cred->authdata_cbor.ptr, | ||
339 | (void *)cred->attstmt.x5c.ptr, | ||
340 | (void *)cred->attstmt.sig.ptr, (void *)cred->fmt, | ||
341 | (void *)cred->attcred.id.ptr, cred->rp.id); | ||
342 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
343 | goto out; | ||
344 | } | ||
345 | |||
346 | if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) { | ||
347 | fido_log_debug("%s: fido_check_rp_id", __func__); | ||
348 | r = FIDO_ERR_INVALID_PARAM; | ||
349 | goto out; | ||
350 | } | ||
351 | |||
352 | if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE, | ||
353 | cred->uv) < 0) { | ||
354 | fido_log_debug("%s: fido_check_flags", __func__); | ||
355 | r = FIDO_ERR_INVALID_PARAM; | ||
356 | goto out; | ||
357 | } | ||
358 | |||
359 | if (check_extensions(cred->authdata_ext, cred->ext) < 0) { | ||
360 | fido_log_debug("%s: check_extensions", __func__); | ||
361 | r = FIDO_ERR_INVALID_PARAM; | ||
362 | goto out; | ||
363 | } | ||
364 | |||
365 | if (!strcmp(cred->fmt, "packed")) { | ||
366 | if (get_signed_hash_packed(&dgst, &cred->cdh, | ||
367 | &cred->authdata_cbor) < 0) { | ||
368 | fido_log_debug("%s: get_signed_hash_packed", __func__); | ||
369 | r = FIDO_ERR_INTERNAL; | ||
370 | goto out; | ||
371 | } | ||
372 | } else { | ||
373 | if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash, | ||
374 | sizeof(cred->authdata.rp_id_hash), &cred->cdh, | ||
375 | &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) { | ||
376 | fido_log_debug("%s: get_signed_hash_u2f", __func__); | ||
377 | r = FIDO_ERR_INTERNAL; | ||
378 | goto out; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | if (verify_sig(&dgst, &cred->attstmt.x5c, &cred->attstmt.sig) < 0) { | ||
383 | fido_log_debug("%s: verify_sig", __func__); | ||
384 | r = FIDO_ERR_INVALID_SIG; | ||
385 | goto out; | ||
386 | } | ||
387 | |||
388 | r = FIDO_OK; | ||
389 | out: | ||
390 | explicit_bzero(buf, sizeof(buf)); | ||
391 | |||
392 | return (r); | ||
393 | } | ||
394 | |||
395 | int | ||
396 | fido_cred_verify_self(const fido_cred_t *cred) | ||
397 | { | ||
398 | unsigned char buf[SHA256_DIGEST_LENGTH]; | ||
399 | fido_blob_t dgst; | ||
400 | int ok = -1; | ||
401 | int r; | ||
402 | |||
403 | dgst.ptr = buf; | ||
404 | dgst.len = sizeof(buf); | ||
405 | |||
406 | /* do we have everything we need? */ | ||
407 | if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL || | ||
408 | cred->attstmt.x5c.ptr != NULL || cred->attstmt.sig.ptr == NULL || | ||
409 | cred->fmt == NULL || cred->attcred.id.ptr == NULL || | ||
410 | cred->rp.id == NULL) { | ||
411 | fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, " | ||
412 | "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr, | ||
413 | (void *)cred->authdata_cbor.ptr, | ||
414 | (void *)cred->attstmt.x5c.ptr, | ||
415 | (void *)cred->attstmt.sig.ptr, (void *)cred->fmt, | ||
416 | (void *)cred->attcred.id.ptr, cred->rp.id); | ||
417 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
418 | goto out; | ||
419 | } | ||
420 | |||
421 | if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) { | ||
422 | fido_log_debug("%s: fido_check_rp_id", __func__); | ||
423 | r = FIDO_ERR_INVALID_PARAM; | ||
424 | goto out; | ||
425 | } | ||
426 | |||
427 | if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE, | ||
428 | cred->uv) < 0) { | ||
429 | fido_log_debug("%s: fido_check_flags", __func__); | ||
430 | r = FIDO_ERR_INVALID_PARAM; | ||
431 | goto out; | ||
432 | } | ||
433 | |||
434 | if (check_extensions(cred->authdata_ext, cred->ext) < 0) { | ||
435 | fido_log_debug("%s: check_extensions", __func__); | ||
436 | r = FIDO_ERR_INVALID_PARAM; | ||
437 | goto out; | ||
438 | } | ||
439 | |||
440 | if (!strcmp(cred->fmt, "packed")) { | ||
441 | if (get_signed_hash_packed(&dgst, &cred->cdh, | ||
442 | &cred->authdata_cbor) < 0) { | ||
443 | fido_log_debug("%s: get_signed_hash_packed", __func__); | ||
444 | r = FIDO_ERR_INTERNAL; | ||
445 | goto out; | ||
446 | } | ||
447 | } else { | ||
448 | if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash, | ||
449 | sizeof(cred->authdata.rp_id_hash), &cred->cdh, | ||
450 | &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) { | ||
451 | fido_log_debug("%s: get_signed_hash_u2f", __func__); | ||
452 | r = FIDO_ERR_INTERNAL; | ||
453 | goto out; | ||
454 | } | ||
455 | } | ||
456 | |||
457 | switch (cred->attcred.type) { | ||
458 | case COSE_ES256: | ||
459 | ok = fido_verify_sig_es256(&dgst, &cred->attcred.pubkey.es256, | ||
460 | &cred->attstmt.sig); | ||
461 | break; | ||
462 | case COSE_RS256: | ||
463 | ok = fido_verify_sig_rs256(&dgst, &cred->attcred.pubkey.rs256, | ||
464 | &cred->attstmt.sig); | ||
465 | break; | ||
466 | case COSE_EDDSA: | ||
467 | ok = fido_verify_sig_eddsa(&dgst, &cred->attcred.pubkey.eddsa, | ||
468 | &cred->attstmt.sig); | ||
469 | break; | ||
470 | default: | ||
471 | fido_log_debug("%s: unsupported cose_alg %d", __func__, | ||
472 | cred->attcred.type); | ||
473 | r = FIDO_ERR_UNSUPPORTED_OPTION; | ||
474 | goto out; | ||
475 | } | ||
476 | |||
477 | if (ok < 0) | ||
478 | r = FIDO_ERR_INVALID_SIG; | ||
479 | else | ||
480 | r = FIDO_OK; | ||
481 | |||
482 | out: | ||
483 | explicit_bzero(buf, sizeof(buf)); | ||
484 | |||
485 | return (r); | ||
486 | } | ||
487 | |||
488 | fido_cred_t * | ||
489 | fido_cred_new(void) | ||
490 | { | ||
491 | return (calloc(1, sizeof(fido_cred_t))); | ||
492 | } | ||
493 | |||
494 | static void | ||
495 | fido_cred_clean_authdata(fido_cred_t *cred) | ||
496 | { | ||
497 | free(cred->authdata_cbor.ptr); | ||
498 | free(cred->attcred.id.ptr); | ||
499 | |||
500 | memset(&cred->authdata_ext, 0, sizeof(cred->authdata_ext)); | ||
501 | memset(&cred->authdata_cbor, 0, sizeof(cred->authdata_cbor)); | ||
502 | memset(&cred->authdata, 0, sizeof(cred->authdata)); | ||
503 | memset(&cred->attcred, 0, sizeof(cred->attcred)); | ||
504 | } | ||
505 | |||
506 | void | ||
507 | fido_cred_reset_tx(fido_cred_t *cred) | ||
508 | { | ||
509 | free(cred->cdh.ptr); | ||
510 | free(cred->rp.id); | ||
511 | free(cred->rp.name); | ||
512 | free(cred->user.id.ptr); | ||
513 | free(cred->user.icon); | ||
514 | free(cred->user.name); | ||
515 | free(cred->user.display_name); | ||
516 | fido_free_blob_array(&cred->excl); | ||
517 | |||
518 | memset(&cred->cdh, 0, sizeof(cred->cdh)); | ||
519 | memset(&cred->rp, 0, sizeof(cred->rp)); | ||
520 | memset(&cred->user, 0, sizeof(cred->user)); | ||
521 | memset(&cred->excl, 0, sizeof(cred->excl)); | ||
522 | |||
523 | cred->type = 0; | ||
524 | cred->ext = 0; | ||
525 | cred->rk = FIDO_OPT_OMIT; | ||
526 | cred->uv = FIDO_OPT_OMIT; | ||
527 | } | ||
528 | |||
529 | static void | ||
530 | fido_cred_clean_x509(fido_cred_t *cred) | ||
531 | { | ||
532 | free(cred->attstmt.x5c.ptr); | ||
533 | cred->attstmt.x5c.ptr = NULL; | ||
534 | cred->attstmt.x5c.len = 0; | ||
535 | } | ||
536 | |||
537 | static void | ||
538 | fido_cred_clean_sig(fido_cred_t *cred) | ||
539 | { | ||
540 | free(cred->attstmt.sig.ptr); | ||
541 | cred->attstmt.sig.ptr = NULL; | ||
542 | cred->attstmt.sig.len = 0; | ||
543 | } | ||
544 | |||
545 | void | ||
546 | fido_cred_reset_rx(fido_cred_t *cred) | ||
547 | { | ||
548 | free(cred->fmt); | ||
549 | cred->fmt = NULL; | ||
550 | |||
551 | fido_cred_clean_authdata(cred); | ||
552 | fido_cred_clean_x509(cred); | ||
553 | fido_cred_clean_sig(cred); | ||
554 | } | ||
555 | |||
556 | void | ||
557 | fido_cred_free(fido_cred_t **cred_p) | ||
558 | { | ||
559 | fido_cred_t *cred; | ||
560 | |||
561 | if (cred_p == NULL || (cred = *cred_p) == NULL) | ||
562 | return; | ||
563 | |||
564 | fido_cred_reset_tx(cred); | ||
565 | fido_cred_reset_rx(cred); | ||
566 | |||
567 | free(cred); | ||
568 | |||
569 | *cred_p = NULL; | ||
570 | } | ||
571 | |||
572 | int | ||
573 | fido_cred_set_authdata(fido_cred_t *cred, const unsigned char *ptr, size_t len) | ||
574 | { | ||
575 | cbor_item_t *item = NULL; | ||
576 | struct cbor_load_result cbor; | ||
577 | int r; | ||
578 | |||
579 | fido_cred_clean_authdata(cred); | ||
580 | |||
581 | if (ptr == NULL || len == 0) { | ||
582 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
583 | goto fail; | ||
584 | } | ||
585 | |||
586 | if ((item = cbor_load(ptr, len, &cbor)) == NULL) { | ||
587 | fido_log_debug("%s: cbor_load", __func__); | ||
588 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
589 | goto fail; | ||
590 | } | ||
591 | |||
592 | if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor, | ||
593 | &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) { | ||
594 | fido_log_debug("%s: cbor_decode_cred_authdata", __func__); | ||
595 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
596 | goto fail; | ||
597 | } | ||
598 | |||
599 | r = FIDO_OK; | ||
600 | fail: | ||
601 | if (item != NULL) | ||
602 | cbor_decref(&item); | ||
603 | |||
604 | if (r != FIDO_OK) | ||
605 | fido_cred_clean_authdata(cred); | ||
606 | |||
607 | return (r); | ||
608 | |||
609 | } | ||
610 | |||
611 | int | ||
612 | fido_cred_set_authdata_raw(fido_cred_t *cred, const unsigned char *ptr, | ||
613 | size_t len) | ||
614 | { | ||
615 | cbor_item_t *item = NULL; | ||
616 | int r; | ||
617 | |||
618 | fido_cred_clean_authdata(cred); | ||
619 | |||
620 | if (ptr == NULL || len == 0) { | ||
621 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
622 | goto fail; | ||
623 | } | ||
624 | |||
625 | if ((item = cbor_build_bytestring(ptr, len)) == NULL) { | ||
626 | fido_log_debug("%s: cbor_build_bytestring", __func__); | ||
627 | r = FIDO_ERR_INTERNAL; | ||
628 | goto fail; | ||
629 | } | ||
630 | |||
631 | if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor, | ||
632 | &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) { | ||
633 | fido_log_debug("%s: cbor_decode_cred_authdata", __func__); | ||
634 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
635 | goto fail; | ||
636 | } | ||
637 | |||
638 | r = FIDO_OK; | ||
639 | fail: | ||
640 | if (item != NULL) | ||
641 | cbor_decref(&item); | ||
642 | |||
643 | if (r != FIDO_OK) | ||
644 | fido_cred_clean_authdata(cred); | ||
645 | |||
646 | return (r); | ||
647 | |||
648 | } | ||
649 | |||
650 | int | ||
651 | fido_cred_set_x509(fido_cred_t *cred, const unsigned char *ptr, size_t len) | ||
652 | { | ||
653 | unsigned char *x509; | ||
654 | |||
655 | fido_cred_clean_x509(cred); | ||
656 | |||
657 | if (ptr == NULL || len == 0) | ||
658 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
659 | if ((x509 = malloc(len)) == NULL) | ||
660 | return (FIDO_ERR_INTERNAL); | ||
661 | |||
662 | memcpy(x509, ptr, len); | ||
663 | cred->attstmt.x5c.ptr = x509; | ||
664 | cred->attstmt.x5c.len = len; | ||
665 | |||
666 | return (FIDO_OK); | ||
667 | } | ||
668 | |||
669 | int | ||
670 | fido_cred_set_sig(fido_cred_t *cred, const unsigned char *ptr, size_t len) | ||
671 | { | ||
672 | unsigned char *sig; | ||
673 | |||
674 | fido_cred_clean_sig(cred); | ||
675 | |||
676 | if (ptr == NULL || len == 0) | ||
677 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
678 | if ((sig = malloc(len)) == NULL) | ||
679 | return (FIDO_ERR_INTERNAL); | ||
680 | |||
681 | memcpy(sig, ptr, len); | ||
682 | cred->attstmt.sig.ptr = sig; | ||
683 | cred->attstmt.sig.len = len; | ||
684 | |||
685 | return (FIDO_OK); | ||
686 | } | ||
687 | |||
688 | int | ||
689 | fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len) | ||
690 | { | ||
691 | fido_blob_t id_blob; | ||
692 | fido_blob_t *list_ptr; | ||
693 | |||
694 | memset(&id_blob, 0, sizeof(id_blob)); | ||
695 | |||
696 | if (fido_blob_set(&id_blob, id_ptr, id_len) < 0) | ||
697 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
698 | |||
699 | if (cred->excl.len == SIZE_MAX) { | ||
700 | free(id_blob.ptr); | ||
701 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
702 | } | ||
703 | |||
704 | if ((list_ptr = recallocarray(cred->excl.ptr, cred->excl.len, | ||
705 | cred->excl.len + 1, sizeof(fido_blob_t))) == NULL) { | ||
706 | free(id_blob.ptr); | ||
707 | return (FIDO_ERR_INTERNAL); | ||
708 | } | ||
709 | |||
710 | list_ptr[cred->excl.len++] = id_blob; | ||
711 | cred->excl.ptr = list_ptr; | ||
712 | |||
713 | return (FIDO_OK); | ||
714 | } | ||
715 | |||
716 | int | ||
717 | fido_cred_set_clientdata_hash(fido_cred_t *cred, const unsigned char *hash, | ||
718 | size_t hash_len) | ||
719 | { | ||
720 | if (fido_blob_set(&cred->cdh, hash, hash_len) < 0) | ||
721 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
722 | |||
723 | return (FIDO_OK); | ||
724 | } | ||
725 | |||
726 | int | ||
727 | fido_cred_set_rp(fido_cred_t *cred, const char *id, const char *name) | ||
728 | { | ||
729 | fido_rp_t *rp = &cred->rp; | ||
730 | |||
731 | if (rp->id != NULL) { | ||
732 | free(rp->id); | ||
733 | rp->id = NULL; | ||
734 | } | ||
735 | if (rp->name != NULL) { | ||
736 | free(rp->name); | ||
737 | rp->name = NULL; | ||
738 | } | ||
739 | |||
740 | if (id != NULL && (rp->id = strdup(id)) == NULL) | ||
741 | goto fail; | ||
742 | if (name != NULL && (rp->name = strdup(name)) == NULL) | ||
743 | goto fail; | ||
744 | |||
745 | return (FIDO_OK); | ||
746 | fail: | ||
747 | free(rp->id); | ||
748 | free(rp->name); | ||
749 | rp->id = NULL; | ||
750 | rp->name = NULL; | ||
751 | |||
752 | return (FIDO_ERR_INTERNAL); | ||
753 | } | ||
754 | |||
755 | int | ||
756 | fido_cred_set_user(fido_cred_t *cred, const unsigned char *user_id, | ||
757 | size_t user_id_len, const char *name, const char *display_name, | ||
758 | const char *icon) | ||
759 | { | ||
760 | fido_user_t *up = &cred->user; | ||
761 | |||
762 | if (up->id.ptr != NULL) { | ||
763 | free(up->id.ptr); | ||
764 | up->id.ptr = NULL; | ||
765 | up->id.len = 0; | ||
766 | } | ||
767 | if (up->name != NULL) { | ||
768 | free(up->name); | ||
769 | up->name = NULL; | ||
770 | } | ||
771 | if (up->display_name != NULL) { | ||
772 | free(up->display_name); | ||
773 | up->display_name = NULL; | ||
774 | } | ||
775 | if (up->icon != NULL) { | ||
776 | free(up->icon); | ||
777 | up->icon = NULL; | ||
778 | } | ||
779 | |||
780 | if (user_id != NULL) { | ||
781 | if ((up->id.ptr = malloc(user_id_len)) == NULL) | ||
782 | goto fail; | ||
783 | memcpy(up->id.ptr, user_id, user_id_len); | ||
784 | up->id.len = user_id_len; | ||
785 | } | ||
786 | if (name != NULL && (up->name = strdup(name)) == NULL) | ||
787 | goto fail; | ||
788 | if (display_name != NULL && | ||
789 | (up->display_name = strdup(display_name)) == NULL) | ||
790 | goto fail; | ||
791 | if (icon != NULL && (up->icon = strdup(icon)) == NULL) | ||
792 | goto fail; | ||
793 | |||
794 | return (FIDO_OK); | ||
795 | fail: | ||
796 | free(up->id.ptr); | ||
797 | free(up->name); | ||
798 | free(up->display_name); | ||
799 | free(up->icon); | ||
800 | |||
801 | up->id.ptr = NULL; | ||
802 | up->id.len = 0; | ||
803 | up->name = NULL; | ||
804 | up->display_name = NULL; | ||
805 | up->icon = NULL; | ||
806 | |||
807 | return (FIDO_ERR_INTERNAL); | ||
808 | } | ||
809 | |||
810 | int | ||
811 | fido_cred_set_extensions(fido_cred_t *cred, int ext) | ||
812 | { | ||
813 | if (ext != 0 && ext != FIDO_EXT_HMAC_SECRET) | ||
814 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
815 | |||
816 | cred->ext = ext; | ||
817 | |||
818 | return (FIDO_OK); | ||
819 | } | ||
820 | |||
821 | int | ||
822 | fido_cred_set_options(fido_cred_t *cred, bool rk, bool uv) | ||
823 | { | ||
824 | cred->rk = rk ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; | ||
825 | cred->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; | ||
826 | |||
827 | return (FIDO_OK); | ||
828 | } | ||
829 | |||
830 | int | ||
831 | fido_cred_set_rk(fido_cred_t *cred, fido_opt_t rk) | ||
832 | { | ||
833 | cred->rk = rk; | ||
834 | |||
835 | return (FIDO_OK); | ||
836 | } | ||
837 | |||
838 | int | ||
839 | fido_cred_set_uv(fido_cred_t *cred, fido_opt_t uv) | ||
840 | { | ||
841 | cred->uv = uv; | ||
842 | |||
843 | return (FIDO_OK); | ||
844 | } | ||
845 | |||
846 | int | ||
847 | fido_cred_set_fmt(fido_cred_t *cred, const char *fmt) | ||
848 | { | ||
849 | free(cred->fmt); | ||
850 | cred->fmt = NULL; | ||
851 | |||
852 | if (fmt == NULL) | ||
853 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
854 | |||
855 | if (strcmp(fmt, "packed") && strcmp(fmt, "fido-u2f")) | ||
856 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
857 | |||
858 | if ((cred->fmt = strdup(fmt)) == NULL) | ||
859 | return (FIDO_ERR_INTERNAL); | ||
860 | |||
861 | return (FIDO_OK); | ||
862 | } | ||
863 | |||
864 | int | ||
865 | fido_cred_set_type(fido_cred_t *cred, int cose_alg) | ||
866 | { | ||
867 | if ((cose_alg != COSE_ES256 && cose_alg != COSE_RS256 && | ||
868 | cose_alg != COSE_EDDSA) || cred->type != 0) | ||
869 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
870 | |||
871 | cred->type = cose_alg; | ||
872 | |||
873 | return (FIDO_OK); | ||
874 | } | ||
875 | |||
876 | int | ||
877 | fido_cred_type(const fido_cred_t *cred) | ||
878 | { | ||
879 | return (cred->type); | ||
880 | } | ||
881 | |||
882 | uint8_t | ||
883 | fido_cred_flags(const fido_cred_t *cred) | ||
884 | { | ||
885 | return (cred->authdata.flags); | ||
886 | } | ||
887 | |||
888 | const unsigned char * | ||
889 | fido_cred_clientdata_hash_ptr(const fido_cred_t *cred) | ||
890 | { | ||
891 | return (cred->cdh.ptr); | ||
892 | } | ||
893 | |||
894 | size_t | ||
895 | fido_cred_clientdata_hash_len(const fido_cred_t *cred) | ||
896 | { | ||
897 | return (cred->cdh.len); | ||
898 | } | ||
899 | |||
900 | const unsigned char * | ||
901 | fido_cred_x5c_ptr(const fido_cred_t *cred) | ||
902 | { | ||
903 | return (cred->attstmt.x5c.ptr); | ||
904 | } | ||
905 | |||
906 | size_t | ||
907 | fido_cred_x5c_len(const fido_cred_t *cred) | ||
908 | { | ||
909 | return (cred->attstmt.x5c.len); | ||
910 | } | ||
911 | |||
912 | const unsigned char * | ||
913 | fido_cred_sig_ptr(const fido_cred_t *cred) | ||
914 | { | ||
915 | return (cred->attstmt.sig.ptr); | ||
916 | } | ||
917 | |||
918 | size_t | ||
919 | fido_cred_sig_len(const fido_cred_t *cred) | ||
920 | { | ||
921 | return (cred->attstmt.sig.len); | ||
922 | } | ||
923 | |||
924 | const unsigned char * | ||
925 | fido_cred_authdata_ptr(const fido_cred_t *cred) | ||
926 | { | ||
927 | return (cred->authdata_cbor.ptr); | ||
928 | } | ||
929 | |||
930 | size_t | ||
931 | fido_cred_authdata_len(const fido_cred_t *cred) | ||
932 | { | ||
933 | return (cred->authdata_cbor.len); | ||
934 | } | ||
935 | |||
936 | const unsigned char * | ||
937 | fido_cred_pubkey_ptr(const fido_cred_t *cred) | ||
938 | { | ||
939 | const void *ptr; | ||
940 | |||
941 | switch (cred->attcred.type) { | ||
942 | case COSE_ES256: | ||
943 | ptr = &cred->attcred.pubkey.es256; | ||
944 | break; | ||
945 | case COSE_RS256: | ||
946 | ptr = &cred->attcred.pubkey.rs256; | ||
947 | break; | ||
948 | case COSE_EDDSA: | ||
949 | ptr = &cred->attcred.pubkey.eddsa; | ||
950 | break; | ||
951 | default: | ||
952 | ptr = NULL; | ||
953 | break; | ||
954 | } | ||
955 | |||
956 | return (ptr); | ||
957 | } | ||
958 | |||
959 | size_t | ||
960 | fido_cred_pubkey_len(const fido_cred_t *cred) | ||
961 | { | ||
962 | size_t len; | ||
963 | |||
964 | switch (cred->attcred.type) { | ||
965 | case COSE_ES256: | ||
966 | len = sizeof(cred->attcred.pubkey.es256); | ||
967 | break; | ||
968 | case COSE_RS256: | ||
969 | len = sizeof(cred->attcred.pubkey.rs256); | ||
970 | break; | ||
971 | case COSE_EDDSA: | ||
972 | len = sizeof(cred->attcred.pubkey.eddsa); | ||
973 | break; | ||
974 | default: | ||
975 | len = 0; | ||
976 | break; | ||
977 | } | ||
978 | |||
979 | return (len); | ||
980 | } | ||
981 | |||
982 | const unsigned char * | ||
983 | fido_cred_id_ptr(const fido_cred_t *cred) | ||
984 | { | ||
985 | return (cred->attcred.id.ptr); | ||
986 | } | ||
987 | |||
988 | size_t | ||
989 | fido_cred_id_len(const fido_cred_t *cred) | ||
990 | { | ||
991 | return (cred->attcred.id.len); | ||
992 | } | ||
993 | |||
994 | const char * | ||
995 | fido_cred_fmt(const fido_cred_t *cred) | ||
996 | { | ||
997 | return (cred->fmt); | ||
998 | } | ||
999 | |||
1000 | const char * | ||
1001 | fido_cred_rp_id(const fido_cred_t *cred) | ||
1002 | { | ||
1003 | return (cred->rp.id); | ||
1004 | } | ||
1005 | |||
1006 | const char * | ||
1007 | fido_cred_rp_name(const fido_cred_t *cred) | ||
1008 | { | ||
1009 | return (cred->rp.name); | ||
1010 | } | ||
1011 | |||
1012 | const char * | ||
1013 | fido_cred_user_name(const fido_cred_t *cred) | ||
1014 | { | ||
1015 | return (cred->user.name); | ||
1016 | } | ||
1017 | |||
1018 | const char * | ||
1019 | fido_cred_display_name(const fido_cred_t *cred) | ||
1020 | { | ||
1021 | return (cred->user.display_name); | ||
1022 | } | ||
1023 | |||
1024 | const unsigned char * | ||
1025 | fido_cred_user_id_ptr(const fido_cred_t *cred) | ||
1026 | { | ||
1027 | return (cred->user.id.ptr); | ||
1028 | } | ||
1029 | |||
1030 | size_t | ||
1031 | fido_cred_user_id_len(const fido_cred_t *cred) | ||
1032 | { | ||
1033 | return (cred->user.id.len); | ||
1034 | } | ||
diff --git a/src/credman.c b/src/credman.c new file mode 100644 index 0000000..76327e5 --- /dev/null +++ b/src/credman.c | |||
@@ -0,0 +1,736 @@ | |||
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 <openssl/sha.h> | ||
8 | |||
9 | #include <string.h> | ||
10 | |||
11 | #include "fido.h" | ||
12 | #include "fido/credman.h" | ||
13 | #include "fido/es256.h" | ||
14 | |||
15 | #define CMD_CRED_METADATA 0x01 | ||
16 | #define CMD_RP_BEGIN 0x02 | ||
17 | #define CMD_RP_NEXT 0x03 | ||
18 | #define CMD_RK_BEGIN 0x04 | ||
19 | #define CMD_RK_NEXT 0x05 | ||
20 | #define CMD_DELETE_CRED 0x06 | ||
21 | |||
22 | static int | ||
23 | credman_grow_array(void **ptr, size_t *n_alloc, size_t *n_rx, size_t n, | ||
24 | size_t size) | ||
25 | { | ||
26 | void *new_ptr; | ||
27 | |||
28 | #ifdef FIDO_FUZZ | ||
29 | if (n > UINT8_MAX) { | ||
30 | fido_log_debug("%s: n > UINT8_MAX", __func__); | ||
31 | return (-1); | ||
32 | } | ||
33 | #endif | ||
34 | |||
35 | if (n < *n_alloc) | ||
36 | return (0); | ||
37 | |||
38 | /* sanity check */ | ||
39 | if (*n_rx > 0 || *n_rx > *n_alloc || n < *n_alloc) { | ||
40 | fido_log_debug("%s: n=%zu, n_rx=%zu, n_alloc=%zu", __func__, n, | ||
41 | *n_rx, *n_alloc); | ||
42 | return (-1); | ||
43 | } | ||
44 | |||
45 | if ((new_ptr = recallocarray(*ptr, *n_alloc, n, size)) == NULL) | ||
46 | return (-1); | ||
47 | |||
48 | *ptr = new_ptr; | ||
49 | *n_alloc = n; | ||
50 | |||
51 | return (0); | ||
52 | } | ||
53 | |||
54 | static int | ||
55 | credman_prepare_hmac(uint8_t cmd, const fido_blob_t *body, cbor_item_t **param, | ||
56 | fido_blob_t *hmac_data) | ||
57 | { | ||
58 | cbor_item_t *param_cbor[2]; | ||
59 | size_t n; | ||
60 | int ok = -1; | ||
61 | |||
62 | memset(¶m_cbor, 0, sizeof(param_cbor)); | ||
63 | |||
64 | if (body == NULL) | ||
65 | return (fido_blob_set(hmac_data, &cmd, sizeof(cmd))); | ||
66 | |||
67 | switch (cmd) { | ||
68 | case CMD_RK_BEGIN: | ||
69 | n = 1; | ||
70 | param_cbor[n - 1] = fido_blob_encode(body); | ||
71 | break; | ||
72 | case CMD_DELETE_CRED: | ||
73 | n = 2; | ||
74 | param_cbor[n - 1] = cbor_encode_pubkey(body); | ||
75 | break; | ||
76 | default: | ||
77 | fido_log_debug("%s: unknown cmd=0x%02x", __func__, cmd); | ||
78 | return (-1); | ||
79 | } | ||
80 | |||
81 | if (param_cbor[n - 1] == NULL) { | ||
82 | fido_log_debug("%s: cbor encode", __func__); | ||
83 | return (-1); | ||
84 | } | ||
85 | if ((*param = cbor_flatten_vector(param_cbor, n)) == NULL) { | ||
86 | fido_log_debug("%s: cbor_flatten_vector", __func__); | ||
87 | goto fail; | ||
88 | } | ||
89 | if (cbor_build_frame(cmd, param_cbor, n, hmac_data) < 0) { | ||
90 | fido_log_debug("%s: cbor_build_frame", __func__); | ||
91 | goto fail; | ||
92 | } | ||
93 | |||
94 | ok = 0; | ||
95 | fail: | ||
96 | cbor_vector_free(param_cbor, nitems(param_cbor)); | ||
97 | |||
98 | return (ok); | ||
99 | } | ||
100 | |||
101 | static int | ||
102 | credman_tx(fido_dev_t *dev, uint8_t cmd, const fido_blob_t *param, | ||
103 | const char *pin) | ||
104 | { | ||
105 | fido_blob_t f; | ||
106 | fido_blob_t *ecdh = NULL; | ||
107 | fido_blob_t hmac; | ||
108 | es256_pk_t *pk = NULL; | ||
109 | cbor_item_t *argv[4]; | ||
110 | int r = FIDO_ERR_INTERNAL; | ||
111 | |||
112 | memset(&f, 0, sizeof(f)); | ||
113 | memset(&hmac, 0, sizeof(hmac)); | ||
114 | memset(&argv, 0, sizeof(argv)); | ||
115 | |||
116 | /* subCommand */ | ||
117 | if ((argv[0] = cbor_build_uint8(cmd)) == NULL) { | ||
118 | fido_log_debug("%s: cbor encode", __func__); | ||
119 | goto fail; | ||
120 | } | ||
121 | |||
122 | /* pinProtocol, pinAuth */ | ||
123 | if (pin != NULL) { | ||
124 | if (credman_prepare_hmac(cmd, param, &argv[1], &hmac) < 0) { | ||
125 | fido_log_debug("%s: credman_prepare_hmac", __func__); | ||
126 | goto fail; | ||
127 | } | ||
128 | if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { | ||
129 | fido_log_debug("%s: fido_do_ecdh", __func__); | ||
130 | goto fail; | ||
131 | } | ||
132 | if ((r = cbor_add_pin_params(dev, &hmac, pk, ecdh, pin, | ||
133 | &argv[3], &argv[2])) != FIDO_OK) { | ||
134 | fido_log_debug("%s: cbor_add_pin_params", __func__); | ||
135 | goto fail; | ||
136 | } | ||
137 | } | ||
138 | |||
139 | /* framing and transmission */ | ||
140 | if (cbor_build_frame(CTAP_CBOR_CRED_MGMT_PRE, argv, 4, &f) < 0 || | ||
141 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | ||
142 | fido_log_debug("%s: fido_tx", __func__); | ||
143 | r = FIDO_ERR_TX; | ||
144 | goto fail; | ||
145 | } | ||
146 | |||
147 | r = FIDO_OK; | ||
148 | fail: | ||
149 | es256_pk_free(&pk); | ||
150 | fido_blob_free(&ecdh); | ||
151 | cbor_vector_free(argv, nitems(argv)); | ||
152 | free(f.ptr); | ||
153 | free(hmac.ptr); | ||
154 | |||
155 | return (r); | ||
156 | } | ||
157 | |||
158 | static int | ||
159 | credman_parse_metadata(const cbor_item_t *key, const cbor_item_t *val, | ||
160 | void *arg) | ||
161 | { | ||
162 | fido_credman_metadata_t *metadata = arg; | ||
163 | |||
164 | if (cbor_isa_uint(key) == false || | ||
165 | cbor_int_get_width(key) != CBOR_INT_8) { | ||
166 | fido_log_debug("%s: cbor type", __func__); | ||
167 | return (0); /* ignore */ | ||
168 | } | ||
169 | |||
170 | switch (cbor_get_uint8(key)) { | ||
171 | case 1: | ||
172 | return (cbor_decode_uint64(val, &metadata->rk_existing)); | ||
173 | case 2: | ||
174 | return (cbor_decode_uint64(val, &metadata->rk_remaining)); | ||
175 | default: | ||
176 | fido_log_debug("%s: cbor type", __func__); | ||
177 | return (0); /* ignore */ | ||
178 | } | ||
179 | } | ||
180 | |||
181 | static int | ||
182 | credman_rx_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, int ms) | ||
183 | { | ||
184 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
185 | unsigned char reply[512]; | ||
186 | int reply_len; | ||
187 | int r; | ||
188 | |||
189 | memset(metadata, 0, sizeof(*metadata)); | ||
190 | |||
191 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
192 | fido_log_debug("%s: fido_rx", __func__); | ||
193 | return (FIDO_ERR_RX); | ||
194 | } | ||
195 | |||
196 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, metadata, | ||
197 | credman_parse_metadata)) != FIDO_OK) { | ||
198 | fido_log_debug("%s: credman_parse_metadata", __func__); | ||
199 | return (r); | ||
200 | } | ||
201 | |||
202 | return (FIDO_OK); | ||
203 | } | ||
204 | |||
205 | static int | ||
206 | credman_get_metadata_wait(fido_dev_t *dev, fido_credman_metadata_t *metadata, | ||
207 | const char *pin, int ms) | ||
208 | { | ||
209 | int r; | ||
210 | |||
211 | if ((r = credman_tx(dev, CMD_CRED_METADATA, NULL, pin)) != FIDO_OK || | ||
212 | (r = credman_rx_metadata(dev, metadata, ms)) != FIDO_OK) | ||
213 | return (r); | ||
214 | |||
215 | return (FIDO_OK); | ||
216 | } | ||
217 | |||
218 | int | ||
219 | fido_credman_get_dev_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, | ||
220 | const char *pin) | ||
221 | { | ||
222 | if (fido_dev_is_fido2(dev) == false) | ||
223 | return (FIDO_ERR_INVALID_COMMAND); | ||
224 | if (pin == NULL) | ||
225 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
226 | |||
227 | return (credman_get_metadata_wait(dev, metadata, pin, -1)); | ||
228 | } | ||
229 | |||
230 | static int | ||
231 | credman_parse_rk(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
232 | { | ||
233 | fido_cred_t *cred = arg; | ||
234 | |||
235 | if (cbor_isa_uint(key) == false || | ||
236 | cbor_int_get_width(key) != CBOR_INT_8) { | ||
237 | fido_log_debug("%s: cbor type", __func__); | ||
238 | return (0); /* ignore */ | ||
239 | } | ||
240 | |||
241 | switch (cbor_get_uint8(key)) { | ||
242 | case 6: /* user entity */ | ||
243 | return (cbor_decode_user(val, &cred->user)); | ||
244 | case 7: | ||
245 | return (cbor_decode_cred_id(val, &cred->attcred.id)); | ||
246 | case 8: | ||
247 | if (cbor_decode_pubkey(val, &cred->attcred.type, | ||
248 | &cred->attcred.pubkey) < 0) | ||
249 | return (-1); | ||
250 | cred->type = cred->attcred.type; /* XXX */ | ||
251 | return (0); | ||
252 | default: | ||
253 | fido_log_debug("%s: cbor type", __func__); | ||
254 | return (0); /* ignore */ | ||
255 | } | ||
256 | } | ||
257 | |||
258 | static void | ||
259 | credman_reset_rk(fido_credman_rk_t *rk) | ||
260 | { | ||
261 | for (size_t i = 0; i < rk->n_alloc; i++) { | ||
262 | fido_cred_reset_tx(&rk->ptr[i]); | ||
263 | fido_cred_reset_rx(&rk->ptr[i]); | ||
264 | } | ||
265 | |||
266 | free(rk->ptr); | ||
267 | rk->ptr = NULL; | ||
268 | memset(rk, 0, sizeof(*rk)); | ||
269 | } | ||
270 | |||
271 | static int | ||
272 | credman_parse_rk_count(const cbor_item_t *key, const cbor_item_t *val, | ||
273 | void *arg) | ||
274 | { | ||
275 | fido_credman_rk_t *rk = arg; | ||
276 | uint64_t n; | ||
277 | |||
278 | /* totalCredentials */ | ||
279 | if (cbor_isa_uint(key) == false || | ||
280 | cbor_int_get_width(key) != CBOR_INT_8 || | ||
281 | cbor_get_uint8(key) != 9) { | ||
282 | fido_log_debug("%s: cbor_type", __func__); | ||
283 | return (0); /* ignore */ | ||
284 | } | ||
285 | |||
286 | if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) { | ||
287 | fido_log_debug("%s: cbor_decode_uint64", __func__); | ||
288 | return (-1); | ||
289 | } | ||
290 | |||
291 | if (credman_grow_array((void **)&rk->ptr, &rk->n_alloc, &rk->n_rx, | ||
292 | (size_t)n, sizeof(*rk->ptr)) < 0) { | ||
293 | fido_log_debug("%s: credman_grow_array", __func__); | ||
294 | return (-1); | ||
295 | } | ||
296 | |||
297 | return (0); | ||
298 | } | ||
299 | |||
300 | static int | ||
301 | credman_rx_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms) | ||
302 | { | ||
303 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
304 | unsigned char reply[2048]; | ||
305 | int reply_len; | ||
306 | int r; | ||
307 | |||
308 | credman_reset_rk(rk); | ||
309 | |||
310 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
311 | fido_log_debug("%s: fido_rx", __func__); | ||
312 | return (FIDO_ERR_RX); | ||
313 | } | ||
314 | |||
315 | /* adjust as needed */ | ||
316 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, rk, | ||
317 | credman_parse_rk_count)) != FIDO_OK) { | ||
318 | fido_log_debug("%s: credman_parse_rk_count", __func__); | ||
319 | return (r); | ||
320 | } | ||
321 | |||
322 | if (rk->n_alloc == 0) { | ||
323 | fido_log_debug("%s: n_alloc=0", __func__); | ||
324 | return (FIDO_OK); | ||
325 | } | ||
326 | |||
327 | /* parse the first rk */ | ||
328 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rk->ptr[0], | ||
329 | credman_parse_rk)) != FIDO_OK) { | ||
330 | fido_log_debug("%s: credman_parse_rk", __func__); | ||
331 | return (r); | ||
332 | } | ||
333 | |||
334 | rk->n_rx++; | ||
335 | |||
336 | return (FIDO_OK); | ||
337 | } | ||
338 | |||
339 | static int | ||
340 | credman_rx_next_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms) | ||
341 | { | ||
342 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
343 | unsigned char reply[2048]; | ||
344 | int reply_len; | ||
345 | int r; | ||
346 | |||
347 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
348 | fido_log_debug("%s: fido_rx", __func__); | ||
349 | return (FIDO_ERR_RX); | ||
350 | } | ||
351 | |||
352 | /* sanity check */ | ||
353 | if (rk->n_rx >= rk->n_alloc) { | ||
354 | fido_log_debug("%s: n_rx=%zu, n_alloc=%zu", __func__, rk->n_rx, | ||
355 | rk->n_alloc); | ||
356 | return (FIDO_ERR_INTERNAL); | ||
357 | } | ||
358 | |||
359 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rk->ptr[rk->n_rx], | ||
360 | credman_parse_rk)) != FIDO_OK) { | ||
361 | fido_log_debug("%s: credman_parse_rk", __func__); | ||
362 | return (r); | ||
363 | } | ||
364 | |||
365 | return (FIDO_OK); | ||
366 | } | ||
367 | |||
368 | static int | ||
369 | credman_get_rk_wait(fido_dev_t *dev, const char *rp_id, fido_credman_rk_t *rk, | ||
370 | const char *pin, int ms) | ||
371 | { | ||
372 | fido_blob_t rp_dgst; | ||
373 | uint8_t dgst[SHA256_DIGEST_LENGTH]; | ||
374 | int r; | ||
375 | |||
376 | if (SHA256((const unsigned char *)rp_id, strlen(rp_id), dgst) != dgst) { | ||
377 | fido_log_debug("%s: sha256", __func__); | ||
378 | return (FIDO_ERR_INTERNAL); | ||
379 | } | ||
380 | |||
381 | rp_dgst.ptr = dgst; | ||
382 | rp_dgst.len = sizeof(dgst); | ||
383 | |||
384 | if ((r = credman_tx(dev, CMD_RK_BEGIN, &rp_dgst, pin)) != FIDO_OK || | ||
385 | (r = credman_rx_rk(dev, rk, ms)) != FIDO_OK) | ||
386 | return (r); | ||
387 | |||
388 | while (rk->n_rx < rk->n_alloc) { | ||
389 | if ((r = credman_tx(dev, CMD_RK_NEXT, NULL, NULL)) != FIDO_OK || | ||
390 | (r = credman_rx_next_rk(dev, rk, ms)) != FIDO_OK) | ||
391 | return (r); | ||
392 | rk->n_rx++; | ||
393 | } | ||
394 | |||
395 | return (FIDO_OK); | ||
396 | } | ||
397 | |||
398 | int | ||
399 | fido_credman_get_dev_rk(fido_dev_t *dev, const char *rp_id, | ||
400 | fido_credman_rk_t *rk, const char *pin) | ||
401 | { | ||
402 | if (fido_dev_is_fido2(dev) == false) | ||
403 | return (FIDO_ERR_INVALID_COMMAND); | ||
404 | if (pin == NULL) | ||
405 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
406 | |||
407 | return (credman_get_rk_wait(dev, rp_id, rk, pin, -1)); | ||
408 | } | ||
409 | |||
410 | static int | ||
411 | credman_del_rk_wait(fido_dev_t *dev, const unsigned char *cred_id, | ||
412 | size_t cred_id_len, const char *pin, int ms) | ||
413 | { | ||
414 | fido_blob_t cred; | ||
415 | int r; | ||
416 | |||
417 | memset(&cred, 0, sizeof(cred)); | ||
418 | |||
419 | if (fido_blob_set(&cred, cred_id, cred_id_len) < 0) | ||
420 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
421 | |||
422 | if ((r = credman_tx(dev, CMD_DELETE_CRED, &cred, pin)) != FIDO_OK || | ||
423 | (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) | ||
424 | goto fail; | ||
425 | |||
426 | r = FIDO_OK; | ||
427 | fail: | ||
428 | free(cred.ptr); | ||
429 | |||
430 | return (r); | ||
431 | } | ||
432 | |||
433 | int | ||
434 | fido_credman_del_dev_rk(fido_dev_t *dev, const unsigned char *cred_id, | ||
435 | size_t cred_id_len, const char *pin) | ||
436 | { | ||
437 | if (fido_dev_is_fido2(dev) == false) | ||
438 | return (FIDO_ERR_INVALID_COMMAND); | ||
439 | if (pin == NULL) | ||
440 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
441 | |||
442 | return (credman_del_rk_wait(dev, cred_id, cred_id_len, pin, -1)); | ||
443 | } | ||
444 | |||
445 | static int | ||
446 | credman_parse_rp(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
447 | { | ||
448 | struct fido_credman_single_rp *rp = arg; | ||
449 | |||
450 | if (cbor_isa_uint(key) == false || | ||
451 | cbor_int_get_width(key) != CBOR_INT_8) { | ||
452 | fido_log_debug("%s: cbor type", __func__); | ||
453 | return (0); /* ignore */ | ||
454 | } | ||
455 | |||
456 | switch (cbor_get_uint8(key)) { | ||
457 | case 3: | ||
458 | return (cbor_decode_rp_entity(val, &rp->rp_entity)); | ||
459 | case 4: | ||
460 | return (fido_blob_decode(val, &rp->rp_id_hash)); | ||
461 | default: | ||
462 | fido_log_debug("%s: cbor type", __func__); | ||
463 | return (0); /* ignore */ | ||
464 | } | ||
465 | } | ||
466 | |||
467 | static void | ||
468 | credman_reset_rp(fido_credman_rp_t *rp) | ||
469 | { | ||
470 | for (size_t i = 0; i < rp->n_alloc; i++) { | ||
471 | free(rp->ptr[i].rp_entity.id); | ||
472 | free(rp->ptr[i].rp_entity.name); | ||
473 | rp->ptr[i].rp_entity.id = NULL; | ||
474 | rp->ptr[i].rp_entity.name = NULL; | ||
475 | free(rp->ptr[i].rp_id_hash.ptr); | ||
476 | memset(&rp->ptr[i].rp_id_hash, 0, | ||
477 | sizeof(rp->ptr[i].rp_id_hash)); | ||
478 | } | ||
479 | |||
480 | free(rp->ptr); | ||
481 | rp->ptr = NULL; | ||
482 | memset(rp, 0, sizeof(*rp)); | ||
483 | } | ||
484 | |||
485 | static int | ||
486 | credman_parse_rp_count(const cbor_item_t *key, const cbor_item_t *val, | ||
487 | void *arg) | ||
488 | { | ||
489 | fido_credman_rp_t *rp = arg; | ||
490 | uint64_t n; | ||
491 | |||
492 | /* totalRPs */ | ||
493 | if (cbor_isa_uint(key) == false || | ||
494 | cbor_int_get_width(key) != CBOR_INT_8 || | ||
495 | cbor_get_uint8(key) != 5) { | ||
496 | fido_log_debug("%s: cbor_type", __func__); | ||
497 | return (0); /* ignore */ | ||
498 | } | ||
499 | |||
500 | if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) { | ||
501 | fido_log_debug("%s: cbor_decode_uint64", __func__); | ||
502 | return (-1); | ||
503 | } | ||
504 | |||
505 | if (credman_grow_array((void **)&rp->ptr, &rp->n_alloc, &rp->n_rx, | ||
506 | (size_t)n, sizeof(*rp->ptr)) < 0) { | ||
507 | fido_log_debug("%s: credman_grow_array", __func__); | ||
508 | return (-1); | ||
509 | } | ||
510 | |||
511 | return (0); | ||
512 | } | ||
513 | |||
514 | static int | ||
515 | credman_rx_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms) | ||
516 | { | ||
517 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
518 | unsigned char reply[2048]; | ||
519 | int reply_len; | ||
520 | int r; | ||
521 | |||
522 | credman_reset_rp(rp); | ||
523 | |||
524 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
525 | fido_log_debug("%s: fido_rx", __func__); | ||
526 | return (FIDO_ERR_RX); | ||
527 | } | ||
528 | |||
529 | /* adjust as needed */ | ||
530 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, rp, | ||
531 | credman_parse_rp_count)) != FIDO_OK) { | ||
532 | fido_log_debug("%s: credman_parse_rp_count", __func__); | ||
533 | return (r); | ||
534 | } | ||
535 | |||
536 | if (rp->n_alloc == 0) { | ||
537 | fido_log_debug("%s: n_alloc=0", __func__); | ||
538 | return (FIDO_OK); | ||
539 | } | ||
540 | |||
541 | /* parse the first rp */ | ||
542 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rp->ptr[0], | ||
543 | credman_parse_rp)) != FIDO_OK) { | ||
544 | fido_log_debug("%s: credman_parse_rp", __func__); | ||
545 | return (r); | ||
546 | } | ||
547 | |||
548 | rp->n_rx++; | ||
549 | |||
550 | return (FIDO_OK); | ||
551 | } | ||
552 | |||
553 | static int | ||
554 | credman_rx_next_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms) | ||
555 | { | ||
556 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
557 | unsigned char reply[2048]; | ||
558 | int reply_len; | ||
559 | int r; | ||
560 | |||
561 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
562 | fido_log_debug("%s: fido_rx", __func__); | ||
563 | return (FIDO_ERR_RX); | ||
564 | } | ||
565 | |||
566 | /* sanity check */ | ||
567 | if (rp->n_rx >= rp->n_alloc) { | ||
568 | fido_log_debug("%s: n_rx=%zu, n_alloc=%zu", __func__, rp->n_rx, | ||
569 | rp->n_alloc); | ||
570 | return (FIDO_ERR_INTERNAL); | ||
571 | } | ||
572 | |||
573 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rp->ptr[rp->n_rx], | ||
574 | credman_parse_rp)) != FIDO_OK) { | ||
575 | fido_log_debug("%s: credman_parse_rp", __func__); | ||
576 | return (r); | ||
577 | } | ||
578 | |||
579 | return (FIDO_OK); | ||
580 | } | ||
581 | |||
582 | static int | ||
583 | credman_get_rp_wait(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin, | ||
584 | int ms) | ||
585 | { | ||
586 | int r; | ||
587 | |||
588 | if ((r = credman_tx(dev, CMD_RP_BEGIN, NULL, pin)) != FIDO_OK || | ||
589 | (r = credman_rx_rp(dev, rp, ms)) != FIDO_OK) | ||
590 | return (r); | ||
591 | |||
592 | while (rp->n_rx < rp->n_alloc) { | ||
593 | if ((r = credman_tx(dev, CMD_RP_NEXT, NULL, NULL)) != FIDO_OK || | ||
594 | (r = credman_rx_next_rp(dev, rp, ms)) != FIDO_OK) | ||
595 | return (r); | ||
596 | rp->n_rx++; | ||
597 | } | ||
598 | |||
599 | return (FIDO_OK); | ||
600 | } | ||
601 | |||
602 | int | ||
603 | fido_credman_get_dev_rp(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin) | ||
604 | { | ||
605 | if (fido_dev_is_fido2(dev) == false) | ||
606 | return (FIDO_ERR_INVALID_COMMAND); | ||
607 | if (pin == NULL) | ||
608 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
609 | |||
610 | return (credman_get_rp_wait(dev, rp, pin, -1)); | ||
611 | } | ||
612 | |||
613 | fido_credman_rk_t * | ||
614 | fido_credman_rk_new(void) | ||
615 | { | ||
616 | return (calloc(1, sizeof(fido_credman_rk_t))); | ||
617 | } | ||
618 | |||
619 | void | ||
620 | fido_credman_rk_free(fido_credman_rk_t **rk_p) | ||
621 | { | ||
622 | fido_credman_rk_t *rk; | ||
623 | |||
624 | if (rk_p == NULL || (rk = *rk_p) == NULL) | ||
625 | return; | ||
626 | |||
627 | credman_reset_rk(rk); | ||
628 | free(rk); | ||
629 | *rk_p = NULL; | ||
630 | } | ||
631 | |||
632 | size_t | ||
633 | fido_credman_rk_count(const fido_credman_rk_t *rk) | ||
634 | { | ||
635 | return (rk->n_rx); | ||
636 | } | ||
637 | |||
638 | const fido_cred_t * | ||
639 | fido_credman_rk(const fido_credman_rk_t *rk, size_t idx) | ||
640 | { | ||
641 | if (idx >= rk->n_alloc) | ||
642 | return (NULL); | ||
643 | |||
644 | return (&rk->ptr[idx]); | ||
645 | } | ||
646 | |||
647 | fido_credman_metadata_t * | ||
648 | fido_credman_metadata_new(void) | ||
649 | { | ||
650 | return (calloc(1, sizeof(fido_credman_metadata_t))); | ||
651 | } | ||
652 | |||
653 | void | ||
654 | fido_credman_metadata_free(fido_credman_metadata_t **metadata_p) | ||
655 | { | ||
656 | fido_credman_metadata_t *metadata; | ||
657 | |||
658 | if (metadata_p == NULL || (metadata = *metadata_p) == NULL) | ||
659 | return; | ||
660 | |||
661 | free(metadata); | ||
662 | *metadata_p = NULL; | ||
663 | } | ||
664 | |||
665 | uint64_t | ||
666 | fido_credman_rk_existing(const fido_credman_metadata_t *metadata) | ||
667 | { | ||
668 | return (metadata->rk_existing); | ||
669 | } | ||
670 | |||
671 | uint64_t | ||
672 | fido_credman_rk_remaining(const fido_credman_metadata_t *metadata) | ||
673 | { | ||
674 | return (metadata->rk_remaining); | ||
675 | } | ||
676 | |||
677 | fido_credman_rp_t * | ||
678 | fido_credman_rp_new(void) | ||
679 | { | ||
680 | return (calloc(1, sizeof(fido_credman_rp_t))); | ||
681 | } | ||
682 | |||
683 | void | ||
684 | fido_credman_rp_free(fido_credman_rp_t **rp_p) | ||
685 | { | ||
686 | fido_credman_rp_t *rp; | ||
687 | |||
688 | if (rp_p == NULL || (rp = *rp_p) == NULL) | ||
689 | return; | ||
690 | |||
691 | credman_reset_rp(rp); | ||
692 | free(rp); | ||
693 | *rp_p = NULL; | ||
694 | } | ||
695 | |||
696 | size_t | ||
697 | fido_credman_rp_count(const fido_credman_rp_t *rp) | ||
698 | { | ||
699 | return (rp->n_rx); | ||
700 | } | ||
701 | |||
702 | const char * | ||
703 | fido_credman_rp_id(const fido_credman_rp_t *rp, size_t idx) | ||
704 | { | ||
705 | if (idx >= rp->n_alloc) | ||
706 | return (NULL); | ||
707 | |||
708 | return (rp->ptr[idx].rp_entity.id); | ||
709 | } | ||
710 | |||
711 | const char * | ||
712 | fido_credman_rp_name(const fido_credman_rp_t *rp, size_t idx) | ||
713 | { | ||
714 | if (idx >= rp->n_alloc) | ||
715 | return (NULL); | ||
716 | |||
717 | return (rp->ptr[idx].rp_entity.name); | ||
718 | } | ||
719 | |||
720 | size_t | ||
721 | fido_credman_rp_id_hash_len(const fido_credman_rp_t *rp, size_t idx) | ||
722 | { | ||
723 | if (idx >= rp->n_alloc) | ||
724 | return (0); | ||
725 | |||
726 | return (rp->ptr[idx].rp_id_hash.len); | ||
727 | } | ||
728 | |||
729 | const unsigned char * | ||
730 | fido_credman_rp_id_hash_ptr(const fido_credman_rp_t *rp, size_t idx) | ||
731 | { | ||
732 | if (idx >= rp->n_alloc) | ||
733 | return (NULL); | ||
734 | |||
735 | return (rp->ptr[idx].rp_id_hash.ptr); | ||
736 | } | ||
diff --git a/src/dev.c b/src/dev.c new file mode 100644 index 0000000..d0efac7 --- /dev/null +++ b/src/dev.c | |||
@@ -0,0 +1,284 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <sys/types.h> | ||
8 | #include <sys/stat.h> | ||
9 | |||
10 | #include <fcntl.h> | ||
11 | #include <stdint.h> | ||
12 | #include <stdlib.h> | ||
13 | #include <string.h> | ||
14 | #ifdef HAVE_UNISTD_H | ||
15 | #include <unistd.h> | ||
16 | #endif | ||
17 | |||
18 | #include "fido.h" | ||
19 | |||
20 | #if defined(_WIN32) | ||
21 | #include <windows.h> | ||
22 | |||
23 | #include <winternl.h> | ||
24 | #include <winerror.h> | ||
25 | #include <stdio.h> | ||
26 | #include <bcrypt.h> | ||
27 | #include <sal.h> | ||
28 | |||
29 | static int | ||
30 | obtain_nonce(uint64_t *nonce) | ||
31 | { | ||
32 | NTSTATUS status; | ||
33 | |||
34 | status = BCryptGenRandom(NULL, (unsigned char *)nonce, sizeof(*nonce), | ||
35 | BCRYPT_USE_SYSTEM_PREFERRED_RNG); | ||
36 | |||
37 | if (!NT_SUCCESS(status)) | ||
38 | return (-1); | ||
39 | |||
40 | return (0); | ||
41 | } | ||
42 | #elif defined(HAS_DEV_URANDOM) | ||
43 | static int | ||
44 | obtain_nonce(uint64_t *nonce) | ||
45 | { | ||
46 | int fd = -1; | ||
47 | int ok = -1; | ||
48 | ssize_t r; | ||
49 | |||
50 | if ((fd = open(FIDO_RANDOM_DEV, O_RDONLY)) < 0) | ||
51 | goto fail; | ||
52 | if ((r = read(fd, nonce, sizeof(*nonce))) < 0 || | ||
53 | (size_t)r != sizeof(*nonce)) | ||
54 | goto fail; | ||
55 | |||
56 | ok = 0; | ||
57 | fail: | ||
58 | if (fd != -1) | ||
59 | close(fd); | ||
60 | |||
61 | return (ok); | ||
62 | } | ||
63 | #else | ||
64 | #error "please provide an implementation of obtain_nonce() for your platform" | ||
65 | #endif /* _WIN32 */ | ||
66 | |||
67 | static int | ||
68 | fido_dev_open_tx(fido_dev_t *dev, const char *path) | ||
69 | { | ||
70 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_INIT; | ||
71 | |||
72 | if (dev->io_handle != NULL) { | ||
73 | fido_log_debug("%s: handle=%p", __func__, dev->io_handle); | ||
74 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
75 | } | ||
76 | |||
77 | if (dev->io.open == NULL || dev->io.close == NULL) { | ||
78 | fido_log_debug("%s: NULL open/close", __func__); | ||
79 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
80 | } | ||
81 | |||
82 | if (obtain_nonce(&dev->nonce) < 0) { | ||
83 | fido_log_debug("%s: obtain_nonce", __func__); | ||
84 | return (FIDO_ERR_INTERNAL); | ||
85 | } | ||
86 | |||
87 | if ((dev->io_handle = dev->io.open(path)) == NULL) { | ||
88 | fido_log_debug("%s: dev->io.open", __func__); | ||
89 | return (FIDO_ERR_INTERNAL); | ||
90 | } | ||
91 | |||
92 | if (fido_tx(dev, cmd, &dev->nonce, sizeof(dev->nonce)) < 0) { | ||
93 | fido_log_debug("%s: fido_tx", __func__); | ||
94 | dev->io.close(dev->io_handle); | ||
95 | dev->io_handle = NULL; | ||
96 | return (FIDO_ERR_TX); | ||
97 | } | ||
98 | |||
99 | return (FIDO_OK); | ||
100 | } | ||
101 | |||
102 | static int | ||
103 | fido_dev_open_rx(fido_dev_t *dev, int ms) | ||
104 | { | ||
105 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_INIT; | ||
106 | int n; | ||
107 | |||
108 | if ((n = fido_rx(dev, cmd, &dev->attr, sizeof(dev->attr), ms)) < 0) { | ||
109 | fido_log_debug("%s: fido_rx", __func__); | ||
110 | goto fail; | ||
111 | } | ||
112 | |||
113 | #ifdef FIDO_FUZZ | ||
114 | dev->attr.nonce = dev->nonce; | ||
115 | #endif | ||
116 | |||
117 | if ((size_t)n != sizeof(dev->attr) || dev->attr.nonce != dev->nonce) { | ||
118 | fido_log_debug("%s: invalid nonce", __func__); | ||
119 | goto fail; | ||
120 | } | ||
121 | |||
122 | dev->cid = dev->attr.cid; | ||
123 | |||
124 | return (FIDO_OK); | ||
125 | fail: | ||
126 | dev->io.close(dev->io_handle); | ||
127 | dev->io_handle = NULL; | ||
128 | |||
129 | return (FIDO_ERR_RX); | ||
130 | } | ||
131 | |||
132 | static int | ||
133 | fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms) | ||
134 | { | ||
135 | int r; | ||
136 | |||
137 | if ((r = fido_dev_open_tx(dev, path)) != FIDO_OK || | ||
138 | (r = fido_dev_open_rx(dev, ms)) != FIDO_OK) | ||
139 | return (r); | ||
140 | |||
141 | return (FIDO_OK); | ||
142 | } | ||
143 | |||
144 | int | ||
145 | fido_dev_open(fido_dev_t *dev, const char *path) | ||
146 | { | ||
147 | return (fido_dev_open_wait(dev, path, -1)); | ||
148 | } | ||
149 | |||
150 | int | ||
151 | fido_dev_close(fido_dev_t *dev) | ||
152 | { | ||
153 | if (dev->io_handle == NULL || dev->io.close == NULL) | ||
154 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
155 | |||
156 | dev->io.close(dev->io_handle); | ||
157 | dev->io_handle = NULL; | ||
158 | |||
159 | return (FIDO_OK); | ||
160 | } | ||
161 | |||
162 | int | ||
163 | fido_dev_cancel(fido_dev_t *dev) | ||
164 | { | ||
165 | if (fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CANCEL, NULL, 0) < 0) | ||
166 | return (FIDO_ERR_TX); | ||
167 | |||
168 | return (FIDO_OK); | ||
169 | } | ||
170 | |||
171 | int | ||
172 | fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) | ||
173 | { | ||
174 | if (dev->io_handle != NULL) { | ||
175 | fido_log_debug("%s: NULL handle", __func__); | ||
176 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
177 | } | ||
178 | |||
179 | if (io == NULL || io->open == NULL || io->close == NULL || | ||
180 | io->read == NULL || io->write == NULL) { | ||
181 | fido_log_debug("%s: NULL function", __func__); | ||
182 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
183 | } | ||
184 | |||
185 | dev->io.open = io->open; | ||
186 | dev->io.close = io->close; | ||
187 | dev->io.read = io->read; | ||
188 | dev->io.write = io->write; | ||
189 | |||
190 | return (FIDO_OK); | ||
191 | } | ||
192 | |||
193 | void | ||
194 | fido_init(int flags) | ||
195 | { | ||
196 | if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL) | ||
197 | fido_log_init(); | ||
198 | } | ||
199 | |||
200 | fido_dev_t * | ||
201 | fido_dev_new(void) | ||
202 | { | ||
203 | fido_dev_t *dev; | ||
204 | fido_dev_io_t io; | ||
205 | |||
206 | if ((dev = calloc(1, sizeof(*dev))) == NULL) | ||
207 | return (NULL); | ||
208 | |||
209 | dev->cid = CTAP_CID_BROADCAST; | ||
210 | |||
211 | io.open = fido_hid_open; | ||
212 | io.close = fido_hid_close; | ||
213 | io.read = fido_hid_read; | ||
214 | io.write = fido_hid_write; | ||
215 | |||
216 | if (fido_dev_set_io_functions(dev, &io) != FIDO_OK) { | ||
217 | fido_log_debug("%s: fido_dev_set_io_functions", __func__); | ||
218 | fido_dev_free(&dev); | ||
219 | return (NULL); | ||
220 | } | ||
221 | |||
222 | return (dev); | ||
223 | } | ||
224 | |||
225 | void | ||
226 | fido_dev_free(fido_dev_t **dev_p) | ||
227 | { | ||
228 | fido_dev_t *dev; | ||
229 | |||
230 | if (dev_p == NULL || (dev = *dev_p) == NULL) | ||
231 | return; | ||
232 | |||
233 | free(dev); | ||
234 | |||
235 | *dev_p = NULL; | ||
236 | } | ||
237 | |||
238 | uint8_t | ||
239 | fido_dev_protocol(const fido_dev_t *dev) | ||
240 | { | ||
241 | return (dev->attr.protocol); | ||
242 | } | ||
243 | |||
244 | uint8_t | ||
245 | fido_dev_major(const fido_dev_t *dev) | ||
246 | { | ||
247 | return (dev->attr.major); | ||
248 | } | ||
249 | |||
250 | uint8_t | ||
251 | fido_dev_minor(const fido_dev_t *dev) | ||
252 | { | ||
253 | return (dev->attr.minor); | ||
254 | } | ||
255 | |||
256 | uint8_t | ||
257 | fido_dev_build(const fido_dev_t *dev) | ||
258 | { | ||
259 | return (dev->attr.build); | ||
260 | } | ||
261 | |||
262 | uint8_t | ||
263 | fido_dev_flags(const fido_dev_t *dev) | ||
264 | { | ||
265 | return (dev->attr.flags); | ||
266 | } | ||
267 | |||
268 | bool | ||
269 | fido_dev_is_fido2(const fido_dev_t *dev) | ||
270 | { | ||
271 | return (dev->attr.flags & FIDO_CAP_CBOR); | ||
272 | } | ||
273 | |||
274 | void | ||
275 | fido_dev_force_u2f(fido_dev_t *dev) | ||
276 | { | ||
277 | dev->attr.flags &= ~FIDO_CAP_CBOR; | ||
278 | } | ||
279 | |||
280 | void | ||
281 | fido_dev_force_fido2(fido_dev_t *dev) | ||
282 | { | ||
283 | dev->attr.flags |= FIDO_CAP_CBOR; | ||
284 | } | ||
diff --git a/src/diff_exports.sh b/src/diff_exports.sh new file mode 100755 index 0000000..7920f47 --- /dev/null +++ b/src/diff_exports.sh | |||
@@ -0,0 +1,23 @@ | |||
1 | #!/bin/bash -u | ||
2 | |||
3 | # Copyright (c) 2018 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 | |||
7 | [[ ! -f export.gnu || ! -f export.llvm || ! -f export.msvc ]] && exit 1 | ||
8 | |||
9 | TMPDIR=$(mktemp -d) | ||
10 | GNU=${TMPDIR}/gnu | ||
11 | LLVM=${TMPDIR}/llvm | ||
12 | MSVC=${TMPDIR}/msvc | ||
13 | |||
14 | egrep -o $'([^*{}\t]+);$' export.gnu | tr -d ';' | sort > ${GNU} | ||
15 | sed 's/^_//g' export.llvm | sort > ${LLVM} | ||
16 | egrep -v "^EXPORTS$" export.msvc | sort > ${MSVC} | ||
17 | diff -u ${GNU} ${LLVM} && diff -u ${MSVC} ${LLVM} | ||
18 | ERROR=$? | ||
19 | |||
20 | rm ${GNU} ${LLVM} ${MSVC} | ||
21 | rmdir ${TMPDIR} | ||
22 | |||
23 | exit ${ERROR} | ||
diff --git a/src/ecdh.c b/src/ecdh.c new file mode 100644 index 0000000..7f25c7b --- /dev/null +++ b/src/ecdh.c | |||
@@ -0,0 +1,121 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <openssl/evp.h> | ||
8 | #include <openssl/sha.h> | ||
9 | |||
10 | #include "fido.h" | ||
11 | #include "fido/es256.h" | ||
12 | |||
13 | static int | ||
14 | do_ecdh(const es256_sk_t *sk, const es256_pk_t *pk, fido_blob_t **ecdh) | ||
15 | { | ||
16 | EVP_PKEY *pk_evp = NULL; | ||
17 | EVP_PKEY *sk_evp = NULL; | ||
18 | EVP_PKEY_CTX *ctx = NULL; | ||
19 | fido_blob_t *secret = NULL; | ||
20 | int ok = -1; | ||
21 | |||
22 | *ecdh = NULL; | ||
23 | |||
24 | /* allocate blobs for secret & ecdh */ | ||
25 | if ((secret = fido_blob_new()) == NULL || | ||
26 | (*ecdh = fido_blob_new()) == NULL) | ||
27 | goto fail; | ||
28 | |||
29 | /* wrap the keys as openssl objects */ | ||
30 | if ((pk_evp = es256_pk_to_EVP_PKEY(pk)) == NULL || | ||
31 | (sk_evp = es256_sk_to_EVP_PKEY(sk)) == NULL) { | ||
32 | fido_log_debug("%s: es256_to_EVP_PKEY", __func__); | ||
33 | goto fail; | ||
34 | } | ||
35 | |||
36 | /* set ecdh parameters */ | ||
37 | if ((ctx = EVP_PKEY_CTX_new(sk_evp, NULL)) == NULL || | ||
38 | EVP_PKEY_derive_init(ctx) <= 0 || | ||
39 | EVP_PKEY_derive_set_peer(ctx, pk_evp) <= 0) { | ||
40 | fido_log_debug("%s: EVP_PKEY_derive_init", __func__); | ||
41 | goto fail; | ||
42 | } | ||
43 | |||
44 | /* perform ecdh */ | ||
45 | if (EVP_PKEY_derive(ctx, NULL, &secret->len) <= 0 || | ||
46 | (secret->ptr = calloc(1, secret->len)) == NULL || | ||
47 | EVP_PKEY_derive(ctx, secret->ptr, &secret->len) <= 0) { | ||
48 | fido_log_debug("%s: EVP_PKEY_derive", __func__); | ||
49 | goto fail; | ||
50 | } | ||
51 | |||
52 | /* use sha256 as a kdf on the resulting secret */ | ||
53 | (*ecdh)->len = SHA256_DIGEST_LENGTH; | ||
54 | if (((*ecdh)->ptr = calloc(1, (*ecdh)->len)) == NULL || | ||
55 | SHA256(secret->ptr, secret->len, (*ecdh)->ptr) != (*ecdh)->ptr) { | ||
56 | fido_log_debug("%s: sha256", __func__); | ||
57 | goto fail; | ||
58 | } | ||
59 | |||
60 | ok = 0; | ||
61 | fail: | ||
62 | if (pk_evp != NULL) | ||
63 | EVP_PKEY_free(pk_evp); | ||
64 | if (sk_evp != NULL) | ||
65 | EVP_PKEY_free(sk_evp); | ||
66 | if (ctx != NULL) | ||
67 | EVP_PKEY_CTX_free(ctx); | ||
68 | if (ok < 0) | ||
69 | fido_blob_free(ecdh); | ||
70 | |||
71 | fido_blob_free(&secret); | ||
72 | |||
73 | return (ok); | ||
74 | } | ||
75 | |||
76 | int | ||
77 | fido_do_ecdh(fido_dev_t *dev, es256_pk_t **pk, fido_blob_t **ecdh) | ||
78 | { | ||
79 | es256_sk_t *sk = NULL; /* our private key */ | ||
80 | es256_pk_t *ak = NULL; /* authenticator's public key */ | ||
81 | int r; | ||
82 | |||
83 | *pk = NULL; /* our public key; returned */ | ||
84 | *ecdh = NULL; /* shared ecdh secret; returned */ | ||
85 | |||
86 | if ((sk = es256_sk_new()) == NULL || (*pk = es256_pk_new()) == NULL) { | ||
87 | r = FIDO_ERR_INTERNAL; | ||
88 | goto fail; | ||
89 | } | ||
90 | |||
91 | if (es256_sk_create(sk) < 0 || es256_derive_pk(sk, *pk) < 0) { | ||
92 | fido_log_debug("%s: es256_derive_pk", __func__); | ||
93 | r = FIDO_ERR_INTERNAL; | ||
94 | goto fail; | ||
95 | } | ||
96 | |||
97 | if ((ak = es256_pk_new()) == NULL || | ||
98 | fido_dev_authkey(dev, ak) != FIDO_OK) { | ||
99 | fido_log_debug("%s: fido_dev_authkey", __func__); | ||
100 | r = FIDO_ERR_INTERNAL; | ||
101 | goto fail; | ||
102 | } | ||
103 | |||
104 | if (do_ecdh(sk, ak, ecdh) < 0) { | ||
105 | fido_log_debug("%s: do_ecdh", __func__); | ||
106 | r = FIDO_ERR_INTERNAL; | ||
107 | goto fail; | ||
108 | } | ||
109 | |||
110 | r = FIDO_OK; | ||
111 | fail: | ||
112 | es256_sk_free(&sk); | ||
113 | es256_pk_free(&ak); | ||
114 | |||
115 | if (r != FIDO_OK) { | ||
116 | es256_pk_free(pk); | ||
117 | fido_blob_free(ecdh); | ||
118 | } | ||
119 | |||
120 | return (r); | ||
121 | } | ||
diff --git a/src/eddsa.c b/src/eddsa.c new file mode 100644 index 0000000..92a0222 --- /dev/null +++ b/src/eddsa.c | |||
@@ -0,0 +1,169 @@ | |||
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 <openssl/bn.h> | ||
8 | #include <openssl/ec.h> | ||
9 | #include <openssl/evp.h> | ||
10 | #include <openssl/obj_mac.h> | ||
11 | |||
12 | #include <string.h> | ||
13 | #include "fido.h" | ||
14 | #include "fido/eddsa.h" | ||
15 | |||
16 | #if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10101000L | ||
17 | EVP_PKEY * | ||
18 | EVP_PKEY_new_raw_public_key(int type, ENGINE *e, const unsigned char *key, | ||
19 | size_t keylen) | ||
20 | { | ||
21 | (void)type; | ||
22 | (void)e; | ||
23 | (void)key; | ||
24 | (void)keylen; | ||
25 | |||
26 | return (NULL); | ||
27 | } | ||
28 | |||
29 | int | ||
30 | EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub, | ||
31 | size_t *len) | ||
32 | { | ||
33 | (void)pkey; | ||
34 | (void)pub; | ||
35 | (void)len; | ||
36 | |||
37 | return (0); | ||
38 | } | ||
39 | |||
40 | int | ||
41 | EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen, | ||
42 | const unsigned char *tbs, size_t tbslen) | ||
43 | { | ||
44 | (void)ctx; | ||
45 | (void)sigret; | ||
46 | (void)siglen; | ||
47 | (void)tbs; | ||
48 | (void)tbslen; | ||
49 | |||
50 | return (0); | ||
51 | } | ||
52 | #endif /* LIBRESSL_VERSION_NUMBER || OPENSSL_VERSION_NUMBER < 0x10101000L */ | ||
53 | |||
54 | #if OPENSSL_VERSION_NUMBER < 0x10100000L | ||
55 | EVP_MD_CTX * | ||
56 | EVP_MD_CTX_new(void) | ||
57 | { | ||
58 | return (NULL); | ||
59 | } | ||
60 | |||
61 | void | ||
62 | EVP_MD_CTX_free(EVP_MD_CTX *ctx) | ||
63 | { | ||
64 | (void)ctx; | ||
65 | } | ||
66 | #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ | ||
67 | |||
68 | static int | ||
69 | decode_coord(const cbor_item_t *item, void *xy, size_t xy_len) | ||
70 | { | ||
71 | if (cbor_isa_bytestring(item) == false || | ||
72 | cbor_bytestring_is_definite(item) == false || | ||
73 | cbor_bytestring_length(item) != xy_len) { | ||
74 | fido_log_debug("%s: cbor type", __func__); | ||
75 | return (-1); | ||
76 | } | ||
77 | |||
78 | memcpy(xy, cbor_bytestring_handle(item), xy_len); | ||
79 | |||
80 | return (0); | ||
81 | } | ||
82 | |||
83 | static int | ||
84 | decode_pubkey_point(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
85 | { | ||
86 | eddsa_pk_t *k = arg; | ||
87 | |||
88 | if (cbor_isa_negint(key) == false || | ||
89 | cbor_int_get_width(key) != CBOR_INT_8) | ||
90 | return (0); /* ignore */ | ||
91 | |||
92 | switch (cbor_get_uint8(key)) { | ||
93 | case 1: /* x coordinate */ | ||
94 | return (decode_coord(val, &k->x, sizeof(k->x))); | ||
95 | } | ||
96 | |||
97 | return (0); /* ignore */ | ||
98 | } | ||
99 | |||
100 | int | ||
101 | eddsa_pk_decode(const cbor_item_t *item, eddsa_pk_t *k) | ||
102 | { | ||
103 | if (cbor_isa_map(item) == false || | ||
104 | cbor_map_is_definite(item) == false || | ||
105 | cbor_map_iter(item, k, decode_pubkey_point) < 0) { | ||
106 | fido_log_debug("%s: cbor type", __func__); | ||
107 | return (-1); | ||
108 | } | ||
109 | |||
110 | return (0); | ||
111 | } | ||
112 | |||
113 | eddsa_pk_t * | ||
114 | eddsa_pk_new(void) | ||
115 | { | ||
116 | return (calloc(1, sizeof(eddsa_pk_t))); | ||
117 | } | ||
118 | |||
119 | void | ||
120 | eddsa_pk_free(eddsa_pk_t **pkp) | ||
121 | { | ||
122 | eddsa_pk_t *pk; | ||
123 | |||
124 | if (pkp == NULL || (pk = *pkp) == NULL) | ||
125 | return; | ||
126 | |||
127 | explicit_bzero(pk, sizeof(*pk)); | ||
128 | free(pk); | ||
129 | |||
130 | *pkp = NULL; | ||
131 | } | ||
132 | |||
133 | int | ||
134 | eddsa_pk_from_ptr(eddsa_pk_t *pk, const void *ptr, size_t len) | ||
135 | { | ||
136 | if (len < sizeof(*pk)) | ||
137 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
138 | |||
139 | memcpy(pk, ptr, sizeof(*pk)); | ||
140 | |||
141 | return (FIDO_OK); | ||
142 | } | ||
143 | |||
144 | EVP_PKEY * | ||
145 | eddsa_pk_to_EVP_PKEY(const eddsa_pk_t *k) | ||
146 | { | ||
147 | EVP_PKEY *pkey = NULL; | ||
148 | |||
149 | if ((pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, k->x, | ||
150 | sizeof(k->x))) == NULL) | ||
151 | fido_log_debug("%s: EVP_PKEY_new_raw_public_key", __func__); | ||
152 | |||
153 | return (pkey); | ||
154 | } | ||
155 | |||
156 | int | ||
157 | eddsa_pk_from_EVP_PKEY(eddsa_pk_t *pk, const EVP_PKEY *pkey) | ||
158 | { | ||
159 | size_t len = 0; | ||
160 | |||
161 | if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1 || | ||
162 | len != sizeof(pk->x)) | ||
163 | return (FIDO_ERR_INTERNAL); | ||
164 | if (EVP_PKEY_get_raw_public_key(pkey, pk->x, &len) != 1 || | ||
165 | len != sizeof(pk->x)) | ||
166 | return (FIDO_ERR_INTERNAL); | ||
167 | |||
168 | return (FIDO_OK); | ||
169 | } | ||
diff --git a/src/err.c b/src/err.c new file mode 100644 index 0000000..5d3efd4 --- /dev/null +++ b/src/err.c | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 "fido/err.h" | ||
8 | |||
9 | const char * | ||
10 | fido_strerr(int n) | ||
11 | { | ||
12 | switch (n) { | ||
13 | case FIDO_ERR_SUCCESS: | ||
14 | return "FIDO_ERR_SUCCESS"; | ||
15 | case FIDO_ERR_INVALID_COMMAND: | ||
16 | return "FIDO_ERR_INVALID_COMMAND"; | ||
17 | case FIDO_ERR_INVALID_PARAMETER: | ||
18 | return "FIDO_ERR_INVALID_PARAMETER"; | ||
19 | case FIDO_ERR_INVALID_LENGTH: | ||
20 | return "FIDO_ERR_INVALID_LENGTH"; | ||
21 | case FIDO_ERR_INVALID_SEQ: | ||
22 | return "FIDO_ERR_INVALID_SEQ"; | ||
23 | case FIDO_ERR_TIMEOUT: | ||
24 | return "FIDO_ERR_TIMEOUT"; | ||
25 | case FIDO_ERR_CHANNEL_BUSY: | ||
26 | return "FIDO_ERR_CHANNEL_BUSY"; | ||
27 | case FIDO_ERR_LOCK_REQUIRED: | ||
28 | return "FIDO_ERR_LOCK_REQUIRED"; | ||
29 | case FIDO_ERR_INVALID_CHANNEL: | ||
30 | return "FIDO_ERR_INVALID_CHANNEL"; | ||
31 | case FIDO_ERR_CBOR_UNEXPECTED_TYPE: | ||
32 | return "FIDO_ERR_UNEXPECTED_TYPE"; | ||
33 | case FIDO_ERR_INVALID_CBOR: | ||
34 | return "FIDO_ERR_INVALID_CBOR"; | ||
35 | case FIDO_ERR_MISSING_PARAMETER: | ||
36 | return "FIDO_ERR_MISSING_PARAMETER"; | ||
37 | case FIDO_ERR_LIMIT_EXCEEDED: | ||
38 | return "FIDO_ERR_LIMIT_EXCEEDED"; | ||
39 | case FIDO_ERR_UNSUPPORTED_EXTENSION: | ||
40 | return "FIDO_ERR_UNSUPPORTED_EXTENSION"; | ||
41 | case FIDO_ERR_CREDENTIAL_EXCLUDED: | ||
42 | return "FIDO_ERR_CREDENTIAL_EXCLUDED"; | ||
43 | case FIDO_ERR_PROCESSING: | ||
44 | return "FIDO_ERR_PROCESSING"; | ||
45 | case FIDO_ERR_INVALID_CREDENTIAL: | ||
46 | return "FIDO_ERR_INVALID_CREDENTIAL"; | ||
47 | case FIDO_ERR_USER_ACTION_PENDING: | ||
48 | return "FIDO_ERR_ACTION_PENDING"; | ||
49 | case FIDO_ERR_OPERATION_PENDING: | ||
50 | return "FIDO_ERR_OPERATION_PENDING"; | ||
51 | case FIDO_ERR_NO_OPERATIONS: | ||
52 | return "FIDO_ERR_NO_OPERATIONS"; | ||
53 | case FIDO_ERR_UNSUPPORTED_ALGORITHM: | ||
54 | return "FIDO_ERR_UNSUPPORTED_ALGORITHM"; | ||
55 | case FIDO_ERR_OPERATION_DENIED: | ||
56 | return "FIDO_ERR_OPERATION_DENIED"; | ||
57 | case FIDO_ERR_KEY_STORE_FULL: | ||
58 | return "FIDO_ERR_STORE_FULL"; | ||
59 | case FIDO_ERR_NOT_BUSY: | ||
60 | return "FIDO_ERR_NOT_BUSY"; | ||
61 | case FIDO_ERR_NO_OPERATION_PENDING: | ||
62 | return "FIDO_ERR_OPERATION_PENDING"; | ||
63 | case FIDO_ERR_UNSUPPORTED_OPTION: | ||
64 | return "FIDO_ERR_UNSUPPORTED_OPTION"; | ||
65 | case FIDO_ERR_INVALID_OPTION: | ||
66 | return "FIDO_ERR_INVALID_OPTION"; | ||
67 | case FIDO_ERR_KEEPALIVE_CANCEL: | ||
68 | return "FIDO_ERR_KEEPALIVE_CANCEL"; | ||
69 | case FIDO_ERR_NO_CREDENTIALS: | ||
70 | return "FIDO_ERR_NO_CREDENTIALS"; | ||
71 | case FIDO_ERR_USER_ACTION_TIMEOUT: | ||
72 | return "FIDO_ERR_ACTION_TIMEOUT"; | ||
73 | case FIDO_ERR_NOT_ALLOWED: | ||
74 | return "FIDO_ERR_NOT_ALLOWED"; | ||
75 | case FIDO_ERR_PIN_INVALID: | ||
76 | return "FIDO_ERR_PIN_INVALID"; | ||
77 | case FIDO_ERR_PIN_BLOCKED: | ||
78 | return "FIDO_ERR_PIN_BLOCKED"; | ||
79 | case FIDO_ERR_PIN_AUTH_INVALID: | ||
80 | return "FIDO_ERR_AUTH_INVALID"; | ||
81 | case FIDO_ERR_PIN_AUTH_BLOCKED: | ||
82 | return "FIDO_ERR_AUTH_BLOCKED"; | ||
83 | case FIDO_ERR_PIN_NOT_SET: | ||
84 | return "FIDO_ERR_NOT_SET"; | ||
85 | case FIDO_ERR_PIN_REQUIRED: | ||
86 | return "FIDO_ERR_PIN_REQUIRED"; | ||
87 | case FIDO_ERR_PIN_POLICY_VIOLATION: | ||
88 | return "FIDO_ERR_POLICY_VIOLATION"; | ||
89 | case FIDO_ERR_PIN_TOKEN_EXPIRED: | ||
90 | return "FIDO_ERR_TOKEN_EXPIRED"; | ||
91 | case FIDO_ERR_REQUEST_TOO_LARGE: | ||
92 | return "FIDO_ERR_TOO_LARGE"; | ||
93 | case FIDO_ERR_ACTION_TIMEOUT: | ||
94 | return "FIDO_ERR_ACTION_TIMEOUT"; | ||
95 | case FIDO_ERR_UP_REQUIRED: | ||
96 | return "FIDO_ERR_UP_REQUIRED"; | ||
97 | case FIDO_ERR_ERR_OTHER: | ||
98 | return "FIDO_ERR_OTHER"; | ||
99 | case FIDO_ERR_SPEC_LAST: | ||
100 | return "FIDO_ERR_SPEC_LAST"; | ||
101 | case FIDO_ERR_TX: | ||
102 | return "FIDO_ERR_TX"; | ||
103 | case FIDO_ERR_RX: | ||
104 | return "FIDO_ERR_RX"; | ||
105 | case FIDO_ERR_RX_NOT_CBOR: | ||
106 | return "FIDO_ERR_RX_NOT_CBOR"; | ||
107 | case FIDO_ERR_RX_INVALID_CBOR: | ||
108 | return "FIDO_ERR_RX_INVALID_CBOR"; | ||
109 | case FIDO_ERR_INVALID_PARAM: | ||
110 | return "FIDO_ERR_INVALID_PARAM"; | ||
111 | case FIDO_ERR_INVALID_SIG: | ||
112 | return "FIDO_ERR_INVALID_SIG"; | ||
113 | case FIDO_ERR_INVALID_ARGUMENT: | ||
114 | return "FIDO_ERR_INVALID_ARGUMENT"; | ||
115 | case FIDO_ERR_USER_PRESENCE_REQUIRED: | ||
116 | return "FIDO_ERR_USER_PRESENCE_REQUIRED"; | ||
117 | case FIDO_ERR_INTERNAL: | ||
118 | return "FIDO_ERR_INTERNAL"; | ||
119 | default: | ||
120 | return "FIDO_ERR_UNKNOWN"; | ||
121 | } | ||
122 | } | ||
diff --git a/src/es256.c b/src/es256.c new file mode 100644 index 0000000..c8fd9f4 --- /dev/null +++ b/src/es256.c | |||
@@ -0,0 +1,434 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <openssl/bn.h> | ||
8 | #include <openssl/ec.h> | ||
9 | #include <openssl/evp.h> | ||
10 | #include <openssl/obj_mac.h> | ||
11 | |||
12 | #include <string.h> | ||
13 | #include "fido.h" | ||
14 | #include "fido/es256.h" | ||
15 | |||
16 | static int | ||
17 | decode_coord(const cbor_item_t *item, void *xy, size_t xy_len) | ||
18 | { | ||
19 | if (cbor_isa_bytestring(item) == false || | ||
20 | cbor_bytestring_is_definite(item) == false || | ||
21 | cbor_bytestring_length(item) != xy_len) { | ||
22 | fido_log_debug("%s: cbor type", __func__); | ||
23 | return (-1); | ||
24 | } | ||
25 | |||
26 | memcpy(xy, cbor_bytestring_handle(item), xy_len); | ||
27 | |||
28 | return (0); | ||
29 | } | ||
30 | |||
31 | static int | ||
32 | decode_pubkey_point(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
33 | { | ||
34 | es256_pk_t *k = arg; | ||
35 | |||
36 | if (cbor_isa_negint(key) == false || | ||
37 | cbor_int_get_width(key) != CBOR_INT_8) | ||
38 | return (0); /* ignore */ | ||
39 | |||
40 | switch (cbor_get_uint8(key)) { | ||
41 | case 1: /* x coordinate */ | ||
42 | return (decode_coord(val, &k->x, sizeof(k->x))); | ||
43 | case 2: /* y coordinate */ | ||
44 | return (decode_coord(val, &k->y, sizeof(k->y))); | ||
45 | } | ||
46 | |||
47 | return (0); /* ignore */ | ||
48 | } | ||
49 | |||
50 | int | ||
51 | es256_pk_decode(const cbor_item_t *item, es256_pk_t *k) | ||
52 | { | ||
53 | if (cbor_isa_map(item) == false || | ||
54 | cbor_map_is_definite(item) == false || | ||
55 | cbor_map_iter(item, k, decode_pubkey_point) < 0) { | ||
56 | fido_log_debug("%s: cbor type", __func__); | ||
57 | return (-1); | ||
58 | } | ||
59 | |||
60 | return (0); | ||
61 | } | ||
62 | |||
63 | cbor_item_t * | ||
64 | es256_pk_encode(const es256_pk_t *pk, int ecdh) | ||
65 | { | ||
66 | cbor_item_t *item = NULL; | ||
67 | struct cbor_pair argv[5]; | ||
68 | int alg; | ||
69 | int ok = -1; | ||
70 | |||
71 | memset(argv, 0, sizeof(argv)); | ||
72 | |||
73 | if ((item = cbor_new_definite_map(5)) == NULL) | ||
74 | goto fail; | ||
75 | |||
76 | /* kty */ | ||
77 | if ((argv[0].key = cbor_build_uint8(1)) == NULL || | ||
78 | (argv[0].value = cbor_build_uint8(2)) == NULL || | ||
79 | !cbor_map_add(item, argv[0])) | ||
80 | goto fail; | ||
81 | |||
82 | /* | ||
83 | * "The COSEAlgorithmIdentifier used is -25 (ECDH-ES + | ||
84 | * HKDF-256) although this is NOT the algorithm actually | ||
85 | * used. Setting this to a different value may result in | ||
86 | * compatibility issues." | ||
87 | */ | ||
88 | if (ecdh) | ||
89 | alg = COSE_ECDH_ES256; | ||
90 | else | ||
91 | alg = COSE_ES256; | ||
92 | |||
93 | /* alg */ | ||
94 | if ((argv[1].key = cbor_build_uint8(3)) == NULL || | ||
95 | (argv[1].value = cbor_build_negint8(-alg - 1)) == NULL || | ||
96 | !cbor_map_add(item, argv[1])) | ||
97 | goto fail; | ||
98 | |||
99 | /* crv */ | ||
100 | if ((argv[2].key = cbor_build_negint8(0)) == NULL || | ||
101 | (argv[2].value = cbor_build_uint8(1)) == NULL || | ||
102 | !cbor_map_add(item, argv[2])) | ||
103 | goto fail; | ||
104 | |||
105 | /* x */ | ||
106 | if ((argv[3].key = cbor_build_negint8(1)) == NULL || | ||
107 | (argv[3].value = cbor_build_bytestring(pk->x, | ||
108 | sizeof(pk->x))) == NULL || !cbor_map_add(item, argv[3])) | ||
109 | goto fail; | ||
110 | |||
111 | /* y */ | ||
112 | if ((argv[4].key = cbor_build_negint8(2)) == NULL || | ||
113 | (argv[4].value = cbor_build_bytestring(pk->y, | ||
114 | sizeof(pk->y))) == NULL || !cbor_map_add(item, argv[4])) | ||
115 | goto fail; | ||
116 | |||
117 | ok = 0; | ||
118 | fail: | ||
119 | if (ok < 0) { | ||
120 | if (item != NULL) { | ||
121 | cbor_decref(&item); | ||
122 | item = NULL; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | for (size_t i = 0; i < 5; i++) { | ||
127 | if (argv[i].key) | ||
128 | cbor_decref(&argv[i].key); | ||
129 | if (argv[i].value) | ||
130 | cbor_decref(&argv[i].value); | ||
131 | } | ||
132 | |||
133 | return (item); | ||
134 | } | ||
135 | |||
136 | es256_sk_t * | ||
137 | es256_sk_new(void) | ||
138 | { | ||
139 | return (calloc(1, sizeof(es256_sk_t))); | ||
140 | } | ||
141 | |||
142 | void | ||
143 | es256_sk_free(es256_sk_t **skp) | ||
144 | { | ||
145 | es256_sk_t *sk; | ||
146 | |||
147 | if (skp == NULL || (sk = *skp) == NULL) | ||
148 | return; | ||
149 | |||
150 | explicit_bzero(sk, sizeof(*sk)); | ||
151 | free(sk); | ||
152 | |||
153 | *skp = NULL; | ||
154 | } | ||
155 | |||
156 | es256_pk_t * | ||
157 | es256_pk_new(void) | ||
158 | { | ||
159 | return (calloc(1, sizeof(es256_pk_t))); | ||
160 | } | ||
161 | |||
162 | void | ||
163 | es256_pk_free(es256_pk_t **pkp) | ||
164 | { | ||
165 | es256_pk_t *pk; | ||
166 | |||
167 | if (pkp == NULL || (pk = *pkp) == NULL) | ||
168 | return; | ||
169 | |||
170 | explicit_bzero(pk, sizeof(*pk)); | ||
171 | free(pk); | ||
172 | |||
173 | *pkp = NULL; | ||
174 | } | ||
175 | |||
176 | int | ||
177 | es256_pk_from_ptr(es256_pk_t *pk, const void *ptr, size_t len) | ||
178 | { | ||
179 | if (len < sizeof(*pk)) | ||
180 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
181 | |||
182 | memcpy(pk, ptr, sizeof(*pk)); | ||
183 | |||
184 | return (FIDO_OK); | ||
185 | } | ||
186 | |||
187 | int | ||
188 | es256_pk_set_x(es256_pk_t *pk, const unsigned char *x) | ||
189 | { | ||
190 | memcpy(pk->x, x, sizeof(pk->x)); | ||
191 | |||
192 | return (0); | ||
193 | } | ||
194 | |||
195 | int | ||
196 | es256_pk_set_y(es256_pk_t *pk, const unsigned char *y) | ||
197 | { | ||
198 | memcpy(pk->y, y, sizeof(pk->y)); | ||
199 | |||
200 | return (0); | ||
201 | } | ||
202 | |||
203 | int | ||
204 | es256_sk_create(es256_sk_t *key) | ||
205 | { | ||
206 | EVP_PKEY_CTX *pctx = NULL; | ||
207 | EVP_PKEY_CTX *kctx = NULL; | ||
208 | EVP_PKEY *p = NULL; | ||
209 | EVP_PKEY *k = NULL; | ||
210 | const EC_KEY *ec; | ||
211 | const BIGNUM *d; | ||
212 | const int nid = NID_X9_62_prime256v1; | ||
213 | int n; | ||
214 | int ok = -1; | ||
215 | |||
216 | if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL || | ||
217 | EVP_PKEY_paramgen_init(pctx) <= 0 || | ||
218 | EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) <= 0 || | ||
219 | EVP_PKEY_paramgen(pctx, &p) <= 0) { | ||
220 | fido_log_debug("%s: EVP_PKEY_paramgen", __func__); | ||
221 | goto fail; | ||
222 | } | ||
223 | |||
224 | if ((kctx = EVP_PKEY_CTX_new(p, NULL)) == NULL || | ||
225 | EVP_PKEY_keygen_init(kctx) <= 0 || EVP_PKEY_keygen(kctx, &k) <= 0) { | ||
226 | fido_log_debug("%s: EVP_PKEY_keygen", __func__); | ||
227 | goto fail; | ||
228 | } | ||
229 | |||
230 | if ((ec = EVP_PKEY_get0_EC_KEY(k)) == NULL || | ||
231 | (d = EC_KEY_get0_private_key(ec)) == NULL || | ||
232 | (n = BN_num_bytes(d)) < 0 || (size_t)n > sizeof(key->d) || | ||
233 | (n = BN_bn2bin(d, key->d)) < 0 || (size_t)n > sizeof(key->d)) { | ||
234 | fido_log_debug("%s: EC_KEY_get0_private_key", __func__); | ||
235 | goto fail; | ||
236 | } | ||
237 | |||
238 | ok = 0; | ||
239 | fail: | ||
240 | if (p != NULL) | ||
241 | EVP_PKEY_free(p); | ||
242 | if (k != NULL) | ||
243 | EVP_PKEY_free(k); | ||
244 | if (pctx != NULL) | ||
245 | EVP_PKEY_CTX_free(pctx); | ||
246 | if (kctx != NULL) | ||
247 | EVP_PKEY_CTX_free(kctx); | ||
248 | |||
249 | return (ok); | ||
250 | } | ||
251 | |||
252 | EVP_PKEY * | ||
253 | es256_pk_to_EVP_PKEY(const es256_pk_t *k) | ||
254 | { | ||
255 | BN_CTX *bnctx = NULL; | ||
256 | EC_KEY *ec = NULL; | ||
257 | EC_POINT *q = NULL; | ||
258 | EVP_PKEY *pkey = NULL; | ||
259 | BIGNUM *x = NULL; | ||
260 | BIGNUM *y = NULL; | ||
261 | const EC_GROUP *g = NULL; | ||
262 | const int nid = NID_X9_62_prime256v1; | ||
263 | int ok = -1; | ||
264 | |||
265 | if ((bnctx = BN_CTX_new()) == NULL || | ||
266 | (x = BN_CTX_get(bnctx)) == NULL || | ||
267 | (y = BN_CTX_get(bnctx)) == NULL) | ||
268 | goto fail; | ||
269 | |||
270 | if (BN_bin2bn(k->x, sizeof(k->x), x) == NULL || | ||
271 | BN_bin2bn(k->y, sizeof(k->y), y) == NULL) { | ||
272 | fido_log_debug("%s: BN_bin2bn", __func__); | ||
273 | goto fail; | ||
274 | } | ||
275 | |||
276 | if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL || | ||
277 | (g = EC_KEY_get0_group(ec)) == NULL) { | ||
278 | fido_log_debug("%s: EC_KEY init", __func__); | ||
279 | goto fail; | ||
280 | } | ||
281 | |||
282 | if ((q = EC_POINT_new(g)) == NULL || | ||
283 | EC_POINT_set_affine_coordinates_GFp(g, q, x, y, bnctx) == 0 || | ||
284 | EC_KEY_set_public_key(ec, q) == 0) { | ||
285 | fido_log_debug("%s: EC_KEY_set_public_key", __func__); | ||
286 | goto fail; | ||
287 | } | ||
288 | |||
289 | if ((pkey = EVP_PKEY_new()) == NULL || | ||
290 | EVP_PKEY_assign_EC_KEY(pkey, ec) == 0) { | ||
291 | fido_log_debug("%s: EVP_PKEY_assign_EC_KEY", __func__); | ||
292 | goto fail; | ||
293 | } | ||
294 | |||
295 | ec = NULL; /* at this point, ec belongs to evp */ | ||
296 | |||
297 | ok = 0; | ||
298 | fail: | ||
299 | if (bnctx != NULL) | ||
300 | BN_CTX_free(bnctx); | ||
301 | if (ec != NULL) | ||
302 | EC_KEY_free(ec); | ||
303 | if (q != NULL) | ||
304 | EC_POINT_free(q); | ||
305 | if (ok < 0 && pkey != NULL) { | ||
306 | EVP_PKEY_free(pkey); | ||
307 | pkey = NULL; | ||
308 | } | ||
309 | |||
310 | return (pkey); | ||
311 | } | ||
312 | |||
313 | int | ||
314 | es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec) | ||
315 | { | ||
316 | BN_CTX *ctx = NULL; | ||
317 | BIGNUM *x = NULL; | ||
318 | BIGNUM *y = NULL; | ||
319 | const EC_POINT *q = NULL; | ||
320 | const EC_GROUP *g = NULL; | ||
321 | int ok = FIDO_ERR_INTERNAL; | ||
322 | int n; | ||
323 | |||
324 | if ((q = EC_KEY_get0_public_key(ec)) == NULL || | ||
325 | (g = EC_KEY_get0_group(ec)) == NULL) | ||
326 | goto fail; | ||
327 | |||
328 | if ((ctx = BN_CTX_new()) == NULL || | ||
329 | (x = BN_CTX_get(ctx)) == NULL || | ||
330 | (y = BN_CTX_get(ctx)) == NULL) | ||
331 | goto fail; | ||
332 | |||
333 | if (EC_POINT_get_affine_coordinates_GFp(g, q, x, y, ctx) == 0 || | ||
334 | (n = BN_num_bytes(x)) < 0 || (size_t)n > sizeof(pk->x) || | ||
335 | (n = BN_num_bytes(y)) < 0 || (size_t)n > sizeof(pk->y)) { | ||
336 | fido_log_debug("%s: EC_POINT_get_affine_coordinates_GFp", | ||
337 | __func__); | ||
338 | goto fail; | ||
339 | } | ||
340 | |||
341 | if ((n = BN_bn2bin(x, pk->x)) < 0 || (size_t)n > sizeof(pk->x) || | ||
342 | (n = BN_bn2bin(y, pk->y)) < 0 || (size_t)n > sizeof(pk->y)) { | ||
343 | fido_log_debug("%s: BN_bn2bin", __func__); | ||
344 | goto fail; | ||
345 | } | ||
346 | |||
347 | ok = FIDO_OK; | ||
348 | fail: | ||
349 | if (ctx != NULL) | ||
350 | BN_CTX_free(ctx); | ||
351 | |||
352 | return (ok); | ||
353 | } | ||
354 | |||
355 | EVP_PKEY * | ||
356 | es256_sk_to_EVP_PKEY(const es256_sk_t *k) | ||
357 | { | ||
358 | BN_CTX *bnctx = NULL; | ||
359 | EC_KEY *ec = NULL; | ||
360 | EVP_PKEY *pkey = NULL; | ||
361 | BIGNUM *d = NULL; | ||
362 | const int nid = NID_X9_62_prime256v1; | ||
363 | int ok = -1; | ||
364 | |||
365 | if ((bnctx = BN_CTX_new()) == NULL || (d = BN_CTX_get(bnctx)) == NULL || | ||
366 | BN_bin2bn(k->d, sizeof(k->d), d) == NULL) { | ||
367 | fido_log_debug("%s: BN_bin2bn", __func__); | ||
368 | goto fail; | ||
369 | } | ||
370 | |||
371 | if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL || | ||
372 | EC_KEY_set_private_key(ec, d) == 0) { | ||
373 | fido_log_debug("%s: EC_KEY_set_private_key", __func__); | ||
374 | goto fail; | ||
375 | } | ||
376 | |||
377 | if ((pkey = EVP_PKEY_new()) == NULL || | ||
378 | EVP_PKEY_assign_EC_KEY(pkey, ec) == 0) { | ||
379 | fido_log_debug("%s: EVP_PKEY_assign_EC_KEY", __func__); | ||
380 | goto fail; | ||
381 | } | ||
382 | |||
383 | ec = NULL; /* at this point, ec belongs to evp */ | ||
384 | |||
385 | ok = 0; | ||
386 | fail: | ||
387 | if (bnctx != NULL) | ||
388 | BN_CTX_free(bnctx); | ||
389 | if (ec != NULL) | ||
390 | EC_KEY_free(ec); | ||
391 | if (ok < 0 && pkey != NULL) { | ||
392 | EVP_PKEY_free(pkey); | ||
393 | pkey = NULL; | ||
394 | } | ||
395 | |||
396 | return (pkey); | ||
397 | } | ||
398 | |||
399 | int | ||
400 | es256_derive_pk(const es256_sk_t *sk, es256_pk_t *pk) | ||
401 | { | ||
402 | BIGNUM *d = NULL; | ||
403 | EC_KEY *ec = NULL; | ||
404 | EC_POINT *q = NULL; | ||
405 | const EC_GROUP *g = NULL; | ||
406 | const int nid = NID_X9_62_prime256v1; | ||
407 | int ok = -1; | ||
408 | |||
409 | if ((d = BN_bin2bn(sk->d, (int)sizeof(sk->d), NULL)) == NULL || | ||
410 | (ec = EC_KEY_new_by_curve_name(nid)) == NULL || | ||
411 | (g = EC_KEY_get0_group(ec)) == NULL || | ||
412 | (q = EC_POINT_new(g)) == NULL) { | ||
413 | fido_log_debug("%s: get", __func__); | ||
414 | goto fail; | ||
415 | } | ||
416 | |||
417 | if (EC_POINT_mul(g, q, d, NULL, NULL, NULL) == 0 || | ||
418 | EC_KEY_set_public_key(ec, q) == 0 || | ||
419 | es256_pk_from_EC_KEY(pk, ec) != FIDO_OK) { | ||
420 | fido_log_debug("%s: set", __func__); | ||
421 | goto fail; | ||
422 | } | ||
423 | |||
424 | ok = 0; | ||
425 | fail: | ||
426 | if (d != NULL) | ||
427 | BN_clear_free(d); | ||
428 | if (q != NULL) | ||
429 | EC_POINT_free(q); | ||
430 | if (ec != NULL) | ||
431 | EC_KEY_free(ec); | ||
432 | |||
433 | return (ok); | ||
434 | } | ||
diff --git a/src/export.gnu b/src/export.gnu new file mode 100644 index 0000000..f111e33 --- /dev/null +++ b/src/export.gnu | |||
@@ -0,0 +1,183 @@ | |||
1 | { | ||
2 | global: | ||
3 | eddsa_pk_free; | ||
4 | eddsa_pk_from_EVP_PKEY; | ||
5 | eddsa_pk_from_ptr; | ||
6 | eddsa_pk_new; | ||
7 | eddsa_pk_to_EVP_PKEY; | ||
8 | es256_pk_free; | ||
9 | es256_pk_from_EC_KEY; | ||
10 | es256_pk_from_ptr; | ||
11 | es256_pk_new; | ||
12 | es256_pk_to_EVP_PKEY; | ||
13 | fido_assert_allow_cred; | ||
14 | fido_assert_authdata_len; | ||
15 | fido_assert_authdata_ptr; | ||
16 | fido_assert_clientdata_hash_len; | ||
17 | fido_assert_clientdata_hash_ptr; | ||
18 | fido_assert_count; | ||
19 | fido_assert_flags; | ||
20 | fido_assert_free; | ||
21 | fido_assert_hmac_secret_len; | ||
22 | fido_assert_hmac_secret_ptr; | ||
23 | fido_assert_id_len; | ||
24 | fido_assert_id_ptr; | ||
25 | fido_assert_new; | ||
26 | fido_assert_rp_id; | ||
27 | fido_assert_set_authdata; | ||
28 | fido_assert_set_authdata_raw; | ||
29 | fido_assert_set_clientdata_hash; | ||
30 | fido_assert_set_count; | ||
31 | fido_assert_set_extensions; | ||
32 | fido_assert_set_hmac_salt; | ||
33 | fido_assert_set_options; | ||
34 | fido_assert_set_rp; | ||
35 | fido_assert_set_sig; | ||
36 | fido_assert_set_up; | ||
37 | fido_assert_set_uv; | ||
38 | fido_assert_sigcount; | ||
39 | fido_assert_sig_len; | ||
40 | fido_assert_sig_ptr; | ||
41 | fido_assert_user_display_name; | ||
42 | fido_assert_user_icon; | ||
43 | fido_assert_user_id_len; | ||
44 | fido_assert_user_id_ptr; | ||
45 | fido_assert_user_name; | ||
46 | fido_assert_verify; | ||
47 | fido_bio_dev_enroll_begin; | ||
48 | fido_bio_dev_enroll_cancel; | ||
49 | fido_bio_dev_enroll_continue; | ||
50 | fido_bio_dev_enroll_remove; | ||
51 | fido_bio_dev_get_info; | ||
52 | fido_bio_dev_get_template_array; | ||
53 | fido_bio_dev_set_template_name; | ||
54 | fido_bio_enroll_free; | ||
55 | fido_bio_enroll_last_status; | ||
56 | fido_bio_enroll_new; | ||
57 | fido_bio_enroll_remaining_samples; | ||
58 | fido_bio_info_free; | ||
59 | fido_bio_info_max_samples; | ||
60 | fido_bio_info_new; | ||
61 | fido_bio_info_type; | ||
62 | fido_bio_template; | ||
63 | fido_bio_template_array_count; | ||
64 | fido_bio_template_array_free; | ||
65 | fido_bio_template_array_new; | ||
66 | fido_bio_template_free; | ||
67 | fido_bio_template_id_len; | ||
68 | fido_bio_template_id_ptr; | ||
69 | fido_bio_template_name; | ||
70 | fido_bio_template_new; | ||
71 | fido_bio_template_set_id; | ||
72 | fido_bio_template_set_name; | ||
73 | fido_cbor_info_aaguid_len; | ||
74 | fido_cbor_info_aaguid_ptr; | ||
75 | fido_cbor_info_extensions_len; | ||
76 | fido_cbor_info_extensions_ptr; | ||
77 | fido_cbor_info_free; | ||
78 | fido_cbor_info_maxmsgsiz; | ||
79 | fido_cbor_info_new; | ||
80 | fido_cbor_info_options_len; | ||
81 | fido_cbor_info_options_name_ptr; | ||
82 | fido_cbor_info_options_value_ptr; | ||
83 | fido_cbor_info_protocols_len; | ||
84 | fido_cbor_info_protocols_ptr; | ||
85 | fido_cbor_info_versions_len; | ||
86 | fido_cbor_info_versions_ptr; | ||
87 | fido_cred_authdata_len; | ||
88 | fido_cred_authdata_ptr; | ||
89 | fido_cred_clientdata_hash_len; | ||
90 | fido_cred_clientdata_hash_ptr; | ||
91 | fido_cred_display_name; | ||
92 | fido_cred_exclude; | ||
93 | fido_cred_flags; | ||
94 | fido_cred_fmt; | ||
95 | fido_cred_free; | ||
96 | fido_cred_id_len; | ||
97 | fido_cred_id_ptr; | ||
98 | fido_credman_del_dev_rk; | ||
99 | fido_credman_get_dev_metadata; | ||
100 | fido_credman_get_dev_rk; | ||
101 | fido_credman_get_dev_rp; | ||
102 | fido_credman_metadata_free; | ||
103 | fido_credman_metadata_new; | ||
104 | fido_credman_rk; | ||
105 | fido_credman_rk_count; | ||
106 | fido_credman_rk_existing; | ||
107 | fido_credman_rk_free; | ||
108 | fido_credman_rk_new; | ||
109 | fido_credman_rk_remaining; | ||
110 | fido_credman_rp_count; | ||
111 | fido_credman_rp_free; | ||
112 | fido_credman_rp_id; | ||
113 | fido_credman_rp_id_hash_len; | ||
114 | fido_credman_rp_id_hash_ptr; | ||
115 | fido_credman_rp_name; | ||
116 | fido_credman_rp_new; | ||
117 | fido_cred_new; | ||
118 | fido_cred_pubkey_len; | ||
119 | fido_cred_pubkey_ptr; | ||
120 | fido_cred_rp_id; | ||
121 | fido_cred_rp_name; | ||
122 | fido_cred_set_authdata; | ||
123 | fido_cred_set_authdata_raw; | ||
124 | fido_cred_set_clientdata_hash; | ||
125 | fido_cred_set_extensions; | ||
126 | fido_cred_set_fmt; | ||
127 | fido_cred_set_options; | ||
128 | fido_cred_set_rk; | ||
129 | fido_cred_set_rp; | ||
130 | fido_cred_set_sig; | ||
131 | fido_cred_set_type; | ||
132 | fido_cred_set_user; | ||
133 | fido_cred_set_uv; | ||
134 | fido_cred_set_x509; | ||
135 | fido_cred_sig_len; | ||
136 | fido_cred_sig_ptr; | ||
137 | fido_cred_type; | ||
138 | fido_cred_user_id_len; | ||
139 | fido_cred_user_id_ptr; | ||
140 | fido_cred_user_name; | ||
141 | fido_cred_verify; | ||
142 | fido_cred_verify_self; | ||
143 | fido_cred_x5c_len; | ||
144 | fido_cred_x5c_ptr; | ||
145 | fido_dev_build; | ||
146 | fido_dev_cancel; | ||
147 | fido_dev_close; | ||
148 | fido_dev_flags; | ||
149 | fido_dev_force_fido2; | ||
150 | fido_dev_force_u2f; | ||
151 | fido_dev_free; | ||
152 | fido_dev_get_assert; | ||
153 | fido_dev_get_cbor_info; | ||
154 | fido_dev_get_retry_count; | ||
155 | fido_dev_info_free; | ||
156 | fido_dev_info_manifest; | ||
157 | fido_dev_info_manufacturer_string; | ||
158 | fido_dev_info_new; | ||
159 | fido_dev_info_path; | ||
160 | fido_dev_info_product; | ||
161 | fido_dev_info_product_string; | ||
162 | fido_dev_info_ptr; | ||
163 | fido_dev_info_vendor; | ||
164 | fido_dev_is_fido2; | ||
165 | fido_dev_major; | ||
166 | fido_dev_make_cred; | ||
167 | fido_dev_minor; | ||
168 | fido_dev_new; | ||
169 | fido_dev_open; | ||
170 | fido_dev_protocol; | ||
171 | fido_dev_reset; | ||
172 | fido_dev_set_io_functions; | ||
173 | fido_dev_set_pin; | ||
174 | fido_init; | ||
175 | fido_strerr; | ||
176 | rs256_pk_free; | ||
177 | rs256_pk_from_ptr; | ||
178 | rs256_pk_from_RSA; | ||
179 | rs256_pk_new; | ||
180 | rs256_pk_to_EVP_PKEY; | ||
181 | local: | ||
182 | *; | ||
183 | }; | ||
diff --git a/src/export.llvm b/src/export.llvm new file mode 100644 index 0000000..ef99a26 --- /dev/null +++ b/src/export.llvm | |||
@@ -0,0 +1,178 @@ | |||
1 | _eddsa_pk_free | ||
2 | _eddsa_pk_from_EVP_PKEY | ||
3 | _eddsa_pk_from_ptr | ||
4 | _eddsa_pk_new | ||
5 | _eddsa_pk_to_EVP_PKEY | ||
6 | _es256_pk_free | ||
7 | _es256_pk_from_EC_KEY | ||
8 | _es256_pk_from_ptr | ||
9 | _es256_pk_new | ||
10 | _es256_pk_to_EVP_PKEY | ||
11 | _fido_assert_allow_cred | ||
12 | _fido_assert_authdata_len | ||
13 | _fido_assert_authdata_ptr | ||
14 | _fido_assert_clientdata_hash_len | ||
15 | _fido_assert_clientdata_hash_ptr | ||
16 | _fido_assert_count | ||
17 | _fido_assert_flags | ||
18 | _fido_assert_free | ||
19 | _fido_assert_hmac_secret_len | ||
20 | _fido_assert_hmac_secret_ptr | ||
21 | _fido_assert_id_len | ||
22 | _fido_assert_id_ptr | ||
23 | _fido_assert_new | ||
24 | _fido_assert_rp_id | ||
25 | _fido_assert_set_authdata | ||
26 | _fido_assert_set_authdata_raw | ||
27 | _fido_assert_set_clientdata_hash | ||
28 | _fido_assert_set_count | ||
29 | _fido_assert_set_extensions | ||
30 | _fido_assert_set_hmac_salt | ||
31 | _fido_assert_set_options | ||
32 | _fido_assert_set_rp | ||
33 | _fido_assert_set_sig | ||
34 | _fido_assert_set_up | ||
35 | _fido_assert_set_uv | ||
36 | _fido_assert_sigcount | ||
37 | _fido_assert_sig_len | ||
38 | _fido_assert_sig_ptr | ||
39 | _fido_assert_user_display_name | ||
40 | _fido_assert_user_icon | ||
41 | _fido_assert_user_id_len | ||
42 | _fido_assert_user_id_ptr | ||
43 | _fido_assert_user_name | ||
44 | _fido_assert_verify | ||
45 | _fido_bio_dev_enroll_begin | ||
46 | _fido_bio_dev_enroll_cancel | ||
47 | _fido_bio_dev_enroll_continue | ||
48 | _fido_bio_dev_enroll_remove | ||
49 | _fido_bio_dev_get_info | ||
50 | _fido_bio_dev_get_template_array | ||
51 | _fido_bio_dev_set_template_name | ||
52 | _fido_bio_enroll_free | ||
53 | _fido_bio_enroll_last_status | ||
54 | _fido_bio_enroll_new | ||
55 | _fido_bio_enroll_remaining_samples | ||
56 | _fido_bio_info_free | ||
57 | _fido_bio_info_max_samples | ||
58 | _fido_bio_info_new | ||
59 | _fido_bio_info_type | ||
60 | _fido_bio_template | ||
61 | _fido_bio_template_array_count | ||
62 | _fido_bio_template_array_free | ||
63 | _fido_bio_template_array_new | ||
64 | _fido_bio_template_free | ||
65 | _fido_bio_template_id_len | ||
66 | _fido_bio_template_id_ptr | ||
67 | _fido_bio_template_name | ||
68 | _fido_bio_template_new | ||
69 | _fido_bio_template_set_id | ||
70 | _fido_bio_template_set_name | ||
71 | _fido_cbor_info_aaguid_len | ||
72 | _fido_cbor_info_aaguid_ptr | ||
73 | _fido_cbor_info_extensions_len | ||
74 | _fido_cbor_info_extensions_ptr | ||
75 | _fido_cbor_info_free | ||
76 | _fido_cbor_info_maxmsgsiz | ||
77 | _fido_cbor_info_new | ||
78 | _fido_cbor_info_options_len | ||
79 | _fido_cbor_info_options_name_ptr | ||
80 | _fido_cbor_info_options_value_ptr | ||
81 | _fido_cbor_info_protocols_len | ||
82 | _fido_cbor_info_protocols_ptr | ||
83 | _fido_cbor_info_versions_len | ||
84 | _fido_cbor_info_versions_ptr | ||
85 | _fido_cred_authdata_len | ||
86 | _fido_cred_authdata_ptr | ||
87 | _fido_cred_clientdata_hash_len | ||
88 | _fido_cred_clientdata_hash_ptr | ||
89 | _fido_cred_display_name | ||
90 | _fido_cred_exclude | ||
91 | _fido_cred_flags | ||
92 | _fido_cred_fmt | ||
93 | _fido_cred_free | ||
94 | _fido_cred_id_len | ||
95 | _fido_cred_id_ptr | ||
96 | _fido_credman_del_dev_rk | ||
97 | _fido_credman_get_dev_metadata | ||
98 | _fido_credman_get_dev_rk | ||
99 | _fido_credman_get_dev_rp | ||
100 | _fido_credman_metadata_free | ||
101 | _fido_credman_metadata_new | ||
102 | _fido_credman_rk | ||
103 | _fido_credman_rk_count | ||
104 | _fido_credman_rk_existing | ||
105 | _fido_credman_rk_free | ||
106 | _fido_credman_rk_new | ||
107 | _fido_credman_rk_remaining | ||
108 | _fido_credman_rp_count | ||
109 | _fido_credman_rp_free | ||
110 | _fido_credman_rp_id | ||
111 | _fido_credman_rp_id_hash_len | ||
112 | _fido_credman_rp_id_hash_ptr | ||
113 | _fido_credman_rp_name | ||
114 | _fido_credman_rp_new | ||
115 | _fido_cred_new | ||
116 | _fido_cred_pubkey_len | ||
117 | _fido_cred_pubkey_ptr | ||
118 | _fido_cred_rp_id | ||
119 | _fido_cred_rp_name | ||
120 | _fido_cred_set_authdata | ||
121 | _fido_cred_set_authdata_raw | ||
122 | _fido_cred_set_clientdata_hash | ||
123 | _fido_cred_set_extensions | ||
124 | _fido_cred_set_fmt | ||
125 | _fido_cred_set_options | ||
126 | _fido_cred_set_rk | ||
127 | _fido_cred_set_rp | ||
128 | _fido_cred_set_sig | ||
129 | _fido_cred_set_type | ||
130 | _fido_cred_set_user | ||
131 | _fido_cred_set_uv | ||
132 | _fido_cred_set_x509 | ||
133 | _fido_cred_sig_len | ||
134 | _fido_cred_sig_ptr | ||
135 | _fido_cred_type | ||
136 | _fido_cred_user_id_len | ||
137 | _fido_cred_user_id_ptr | ||
138 | _fido_cred_user_name | ||
139 | _fido_cred_verify | ||
140 | _fido_cred_verify_self | ||
141 | _fido_cred_x5c_len | ||
142 | _fido_cred_x5c_ptr | ||
143 | _fido_dev_build | ||
144 | _fido_dev_cancel | ||
145 | _fido_dev_close | ||
146 | _fido_dev_flags | ||
147 | _fido_dev_force_fido2 | ||
148 | _fido_dev_force_u2f | ||
149 | _fido_dev_free | ||
150 | _fido_dev_get_assert | ||
151 | _fido_dev_get_cbor_info | ||
152 | _fido_dev_get_retry_count | ||
153 | _fido_dev_info_free | ||
154 | _fido_dev_info_manifest | ||
155 | _fido_dev_info_manufacturer_string | ||
156 | _fido_dev_info_new | ||
157 | _fido_dev_info_path | ||
158 | _fido_dev_info_product | ||
159 | _fido_dev_info_product_string | ||
160 | _fido_dev_info_ptr | ||
161 | _fido_dev_info_vendor | ||
162 | _fido_dev_is_fido2 | ||
163 | _fido_dev_major | ||
164 | _fido_dev_make_cred | ||
165 | _fido_dev_minor | ||
166 | _fido_dev_new | ||
167 | _fido_dev_open | ||
168 | _fido_dev_protocol | ||
169 | _fido_dev_reset | ||
170 | _fido_dev_set_io_functions | ||
171 | _fido_dev_set_pin | ||
172 | _fido_init | ||
173 | _fido_strerr | ||
174 | _rs256_pk_free | ||
175 | _rs256_pk_from_ptr | ||
176 | _rs256_pk_from_RSA | ||
177 | _rs256_pk_new | ||
178 | _rs256_pk_to_EVP_PKEY | ||
diff --git a/src/export.msvc b/src/export.msvc new file mode 100644 index 0000000..ff5425a --- /dev/null +++ b/src/export.msvc | |||
@@ -0,0 +1,179 @@ | |||
1 | EXPORTS | ||
2 | eddsa_pk_free | ||
3 | eddsa_pk_from_EVP_PKEY | ||
4 | eddsa_pk_from_ptr | ||
5 | eddsa_pk_new | ||
6 | eddsa_pk_to_EVP_PKEY | ||
7 | es256_pk_free | ||
8 | es256_pk_from_EC_KEY | ||
9 | es256_pk_from_ptr | ||
10 | es256_pk_new | ||
11 | es256_pk_to_EVP_PKEY | ||
12 | fido_assert_allow_cred | ||
13 | fido_assert_authdata_len | ||
14 | fido_assert_authdata_ptr | ||
15 | fido_assert_clientdata_hash_len | ||
16 | fido_assert_clientdata_hash_ptr | ||
17 | fido_assert_count | ||
18 | fido_assert_flags | ||
19 | fido_assert_free | ||
20 | fido_assert_hmac_secret_len | ||
21 | fido_assert_hmac_secret_ptr | ||
22 | fido_assert_id_len | ||
23 | fido_assert_id_ptr | ||
24 | fido_assert_new | ||
25 | fido_assert_rp_id | ||
26 | fido_assert_set_authdata | ||
27 | fido_assert_set_authdata_raw | ||
28 | fido_assert_set_clientdata_hash | ||
29 | fido_assert_set_count | ||
30 | fido_assert_set_extensions | ||
31 | fido_assert_set_hmac_salt | ||
32 | fido_assert_set_options | ||
33 | fido_assert_set_rp | ||
34 | fido_assert_set_sig | ||
35 | fido_assert_set_up | ||
36 | fido_assert_set_uv | ||
37 | fido_assert_sigcount | ||
38 | fido_assert_sig_len | ||
39 | fido_assert_sig_ptr | ||
40 | fido_assert_user_display_name | ||
41 | fido_assert_user_icon | ||
42 | fido_assert_user_id_len | ||
43 | fido_assert_user_id_ptr | ||
44 | fido_assert_user_name | ||
45 | fido_assert_verify | ||
46 | fido_bio_dev_enroll_begin | ||
47 | fido_bio_dev_enroll_cancel | ||
48 | fido_bio_dev_enroll_continue | ||
49 | fido_bio_dev_enroll_remove | ||
50 | fido_bio_dev_get_info | ||
51 | fido_bio_dev_get_template_array | ||
52 | fido_bio_dev_set_template_name | ||
53 | fido_bio_enroll_free | ||
54 | fido_bio_enroll_last_status | ||
55 | fido_bio_enroll_new | ||
56 | fido_bio_enroll_remaining_samples | ||
57 | fido_bio_info_free | ||
58 | fido_bio_info_max_samples | ||
59 | fido_bio_info_new | ||
60 | fido_bio_info_type | ||
61 | fido_bio_template | ||
62 | fido_bio_template_array_count | ||
63 | fido_bio_template_array_free | ||
64 | fido_bio_template_array_new | ||
65 | fido_bio_template_free | ||
66 | fido_bio_template_id_len | ||
67 | fido_bio_template_id_ptr | ||
68 | fido_bio_template_name | ||
69 | fido_bio_template_new | ||
70 | fido_bio_template_set_id | ||
71 | fido_bio_template_set_name | ||
72 | fido_cbor_info_aaguid_len | ||
73 | fido_cbor_info_aaguid_ptr | ||
74 | fido_cbor_info_extensions_len | ||
75 | fido_cbor_info_extensions_ptr | ||
76 | fido_cbor_info_free | ||
77 | fido_cbor_info_maxmsgsiz | ||
78 | fido_cbor_info_new | ||
79 | fido_cbor_info_options_len | ||
80 | fido_cbor_info_options_name_ptr | ||
81 | fido_cbor_info_options_value_ptr | ||
82 | fido_cbor_info_protocols_len | ||
83 | fido_cbor_info_protocols_ptr | ||
84 | fido_cbor_info_versions_len | ||
85 | fido_cbor_info_versions_ptr | ||
86 | fido_cred_authdata_len | ||
87 | fido_cred_authdata_ptr | ||
88 | fido_cred_clientdata_hash_len | ||
89 | fido_cred_clientdata_hash_ptr | ||
90 | fido_cred_display_name | ||
91 | fido_cred_exclude | ||
92 | fido_cred_flags | ||
93 | fido_cred_fmt | ||
94 | fido_cred_free | ||
95 | fido_cred_id_len | ||
96 | fido_cred_id_ptr | ||
97 | fido_credman_del_dev_rk | ||
98 | fido_credman_get_dev_metadata | ||
99 | fido_credman_get_dev_rk | ||
100 | fido_credman_get_dev_rp | ||
101 | fido_credman_metadata_free | ||
102 | fido_credman_metadata_new | ||
103 | fido_credman_rk | ||
104 | fido_credman_rk_count | ||
105 | fido_credman_rk_existing | ||
106 | fido_credman_rk_free | ||
107 | fido_credman_rk_new | ||
108 | fido_credman_rk_remaining | ||
109 | fido_credman_rp_count | ||
110 | fido_credman_rp_free | ||
111 | fido_credman_rp_id | ||
112 | fido_credman_rp_id_hash_len | ||
113 | fido_credman_rp_id_hash_ptr | ||
114 | fido_credman_rp_name | ||
115 | fido_credman_rp_new | ||
116 | fido_cred_new | ||
117 | fido_cred_pubkey_len | ||
118 | fido_cred_pubkey_ptr | ||
119 | fido_cred_rp_id | ||
120 | fido_cred_rp_name | ||
121 | fido_cred_set_authdata | ||
122 | fido_cred_set_authdata_raw | ||
123 | fido_cred_set_clientdata_hash | ||
124 | fido_cred_set_extensions | ||
125 | fido_cred_set_fmt | ||
126 | fido_cred_set_options | ||
127 | fido_cred_set_rk | ||
128 | fido_cred_set_rp | ||
129 | fido_cred_set_sig | ||
130 | fido_cred_set_type | ||
131 | fido_cred_set_user | ||
132 | fido_cred_set_uv | ||
133 | fido_cred_set_x509 | ||
134 | fido_cred_sig_len | ||
135 | fido_cred_sig_ptr | ||
136 | fido_cred_type | ||
137 | fido_cred_user_id_len | ||
138 | fido_cred_user_id_ptr | ||
139 | fido_cred_user_name | ||
140 | fido_cred_verify | ||
141 | fido_cred_verify_self | ||
142 | fido_cred_x5c_len | ||
143 | fido_cred_x5c_ptr | ||
144 | fido_dev_build | ||
145 | fido_dev_cancel | ||
146 | fido_dev_close | ||
147 | fido_dev_flags | ||
148 | fido_dev_force_fido2 | ||
149 | fido_dev_force_u2f | ||
150 | fido_dev_free | ||
151 | fido_dev_get_assert | ||
152 | fido_dev_get_cbor_info | ||
153 | fido_dev_get_retry_count | ||
154 | fido_dev_info_free | ||
155 | fido_dev_info_manifest | ||
156 | fido_dev_info_manufacturer_string | ||
157 | fido_dev_info_new | ||
158 | fido_dev_info_path | ||
159 | fido_dev_info_product | ||
160 | fido_dev_info_product_string | ||
161 | fido_dev_info_ptr | ||
162 | fido_dev_info_vendor | ||
163 | fido_dev_is_fido2 | ||
164 | fido_dev_major | ||
165 | fido_dev_make_cred | ||
166 | fido_dev_minor | ||
167 | fido_dev_new | ||
168 | fido_dev_open | ||
169 | fido_dev_protocol | ||
170 | fido_dev_reset | ||
171 | fido_dev_set_io_functions | ||
172 | fido_dev_set_pin | ||
173 | fido_init | ||
174 | fido_strerr | ||
175 | rs256_pk_free | ||
176 | rs256_pk_from_ptr | ||
177 | rs256_pk_from_RSA | ||
178 | rs256_pk_new | ||
179 | rs256_pk_to_EVP_PKEY | ||
diff --git a/src/extern.h b/src/extern.h new file mode 100644 index 0000000..c35af58 --- /dev/null +++ b/src/extern.h | |||
@@ -0,0 +1,132 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | #ifndef _EXTERN_H | ||
8 | #define _EXTERN_H | ||
9 | |||
10 | /* aes256 */ | ||
11 | int aes256_cbc_dec(const fido_blob_t *, const fido_blob_t *, fido_blob_t *); | ||
12 | int aes256_cbc_enc(const fido_blob_t *, const fido_blob_t *, fido_blob_t *); | ||
13 | |||
14 | /* cbor encoding functions */ | ||
15 | cbor_item_t *cbor_flatten_vector(cbor_item_t **, size_t); | ||
16 | cbor_item_t *cbor_encode_assert_options(fido_opt_t, fido_opt_t); | ||
17 | cbor_item_t *cbor_encode_change_pin_auth(const fido_blob_t *, | ||
18 | const fido_blob_t *, const fido_blob_t *); | ||
19 | cbor_item_t *cbor_encode_extensions(int); | ||
20 | cbor_item_t *cbor_encode_hmac_secret_param(const fido_blob_t *, | ||
21 | const es256_pk_t *, const fido_blob_t *); | ||
22 | cbor_item_t *cbor_encode_options(fido_opt_t, fido_opt_t); | ||
23 | cbor_item_t *cbor_encode_pin_auth(const fido_blob_t *, const fido_blob_t *); | ||
24 | cbor_item_t *cbor_encode_pin_enc(const fido_blob_t *, const fido_blob_t *); | ||
25 | cbor_item_t *cbor_encode_pin_hash_enc(const fido_blob_t *, const fido_blob_t *); | ||
26 | cbor_item_t *cbor_encode_pin_opt(void); | ||
27 | cbor_item_t *cbor_encode_pubkey(const fido_blob_t *); | ||
28 | cbor_item_t *cbor_encode_pubkey_list(const fido_blob_array_t *); | ||
29 | cbor_item_t *cbor_encode_pubkey_param(int); | ||
30 | cbor_item_t *cbor_encode_rp_entity(const fido_rp_t *); | ||
31 | cbor_item_t *cbor_encode_set_pin_auth(const fido_blob_t *, const fido_blob_t *); | ||
32 | cbor_item_t *cbor_encode_user_entity(const fido_user_t *); | ||
33 | cbor_item_t *es256_pk_encode(const es256_pk_t *, int); | ||
34 | |||
35 | /* cbor decoding functions */ | ||
36 | int cbor_decode_attstmt(const cbor_item_t *, fido_attstmt_t *); | ||
37 | int cbor_decode_cred_authdata(const cbor_item_t *, int, fido_blob_t *, | ||
38 | fido_authdata_t *, fido_attcred_t *, int *); | ||
39 | int cbor_decode_assert_authdata(const cbor_item_t *, fido_blob_t *, | ||
40 | fido_authdata_t *, int *, fido_blob_t *); | ||
41 | int cbor_decode_cred_id(const cbor_item_t *, fido_blob_t *); | ||
42 | int cbor_decode_fmt(const cbor_item_t *, char **); | ||
43 | int cbor_decode_pubkey(const cbor_item_t *, int *, void *); | ||
44 | int cbor_decode_rp_entity(const cbor_item_t *, fido_rp_t *); | ||
45 | int cbor_decode_uint64(const cbor_item_t *, uint64_t *); | ||
46 | int cbor_decode_user(const cbor_item_t *, fido_user_t *); | ||
47 | int es256_pk_decode(const cbor_item_t *, es256_pk_t *); | ||
48 | int rs256_pk_decode(const cbor_item_t *, rs256_pk_t *); | ||
49 | int eddsa_pk_decode(const cbor_item_t *, eddsa_pk_t *); | ||
50 | |||
51 | /* auxiliary cbor routines */ | ||
52 | int cbor_add_bool(cbor_item_t *, const char *, fido_opt_t); | ||
53 | int cbor_add_bytestring(cbor_item_t *, const char *, const unsigned char *, | ||
54 | size_t); | ||
55 | int cbor_add_string(cbor_item_t *, const char *, const char *); | ||
56 | int cbor_array_iter(const cbor_item_t *, void *, int(*)(const cbor_item_t *, | ||
57 | void *)); | ||
58 | int cbor_build_frame(uint8_t, cbor_item_t *[], size_t, fido_blob_t *); | ||
59 | int cbor_bytestring_copy(const cbor_item_t *, unsigned char **, size_t *); | ||
60 | int cbor_map_iter(const cbor_item_t *, void *, int(*)(const cbor_item_t *, | ||
61 | const cbor_item_t *, void *)); | ||
62 | int cbor_string_copy(const cbor_item_t *, char **); | ||
63 | int cbor_parse_reply(const unsigned char *, size_t, void *, | ||
64 | int(*)(const cbor_item_t *, const cbor_item_t *, void *)); | ||
65 | int cbor_add_pin_params(fido_dev_t *, const fido_blob_t *, const es256_pk_t *, | ||
66 | const fido_blob_t *,const char *, cbor_item_t **, cbor_item_t **); | ||
67 | void cbor_vector_free(cbor_item_t **, size_t); | ||
68 | |||
69 | #ifndef nitems | ||
70 | #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) | ||
71 | #endif | ||
72 | |||
73 | /* buf */ | ||
74 | int fido_buf_read(const unsigned char **, size_t *, void *, size_t); | ||
75 | int fido_buf_write(unsigned char **, size_t *, const void *, size_t); | ||
76 | |||
77 | /* hid i/o */ | ||
78 | void *fido_hid_open(const char *); | ||
79 | void fido_hid_close(void *); | ||
80 | int fido_hid_read(void *, unsigned char *, size_t, int); | ||
81 | int fido_hid_write(void *, const unsigned char *, size_t); | ||
82 | |||
83 | /* generic i/o */ | ||
84 | int fido_rx_cbor_status(fido_dev_t *, int); | ||
85 | int fido_rx(fido_dev_t *, uint8_t, void *, size_t, int); | ||
86 | int fido_tx(fido_dev_t *, uint8_t, const void *, size_t); | ||
87 | |||
88 | /* log */ | ||
89 | #ifdef FIDO_NO_DIAGNOSTIC | ||
90 | #define fido_log_init(...) do { /* nothing */ } while (0) | ||
91 | #define fido_log_debug(...) do { /* nothing */ } while (0) | ||
92 | #define fido_log_xxd(...) do { /* nothing */ } while (0) | ||
93 | #else | ||
94 | #ifdef __GNUC__ | ||
95 | void fido_log_init(void); | ||
96 | void fido_log_debug(const char *, ...) | ||
97 | __attribute__((__format__ (printf, 1, 2))); | ||
98 | void fido_log_xxd(const void *, size_t); | ||
99 | #else | ||
100 | void fido_log_init(void); | ||
101 | void fido_log_debug(const char *, ...); | ||
102 | void fido_log_xxd(const void *, size_t); | ||
103 | #endif /* __GNUC__ */ | ||
104 | #endif /* FIDO_NO_DIAGNOSTIC */ | ||
105 | |||
106 | /* u2f */ | ||
107 | int u2f_register(fido_dev_t *, fido_cred_t *, int); | ||
108 | int u2f_authenticate(fido_dev_t *, fido_assert_t *, int); | ||
109 | |||
110 | /* unexposed fido ops */ | ||
111 | int fido_dev_authkey(fido_dev_t *, es256_pk_t *); | ||
112 | int fido_dev_get_pin_token(fido_dev_t *, const char *, const fido_blob_t *, | ||
113 | const es256_pk_t *, fido_blob_t *); | ||
114 | int fido_do_ecdh(fido_dev_t *, es256_pk_t **, fido_blob_t **); | ||
115 | |||
116 | /* misc */ | ||
117 | void fido_assert_reset_rx(fido_assert_t *); | ||
118 | void fido_assert_reset_tx(fido_assert_t *); | ||
119 | void fido_cred_reset_rx(fido_cred_t *); | ||
120 | void fido_cred_reset_tx(fido_cred_t *); | ||
121 | int fido_check_rp_id(const char *, const unsigned char *); | ||
122 | int fido_check_flags(uint8_t, fido_opt_t, fido_opt_t); | ||
123 | |||
124 | /* crypto */ | ||
125 | int fido_verify_sig_es256(const fido_blob_t *, const es256_pk_t *, | ||
126 | const fido_blob_t *); | ||
127 | int fido_verify_sig_rs256(const fido_blob_t *, const rs256_pk_t *, | ||
128 | const fido_blob_t *); | ||
129 | int fido_verify_sig_eddsa(const fido_blob_t *, const eddsa_pk_t *, | ||
130 | const fido_blob_t *); | ||
131 | |||
132 | #endif /* !_EXTERN_H */ | ||
diff --git a/src/fido.h b/src/fido.h new file mode 100644 index 0000000..f85a41a --- /dev/null +++ b/src/fido.h | |||
@@ -0,0 +1,194 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | #ifndef _FIDO_H | ||
8 | #define _FIDO_H | ||
9 | |||
10 | #include <openssl/ec.h> | ||
11 | #include <openssl/evp.h> | ||
12 | |||
13 | #include <stdbool.h> | ||
14 | #include <stdint.h> | ||
15 | #include <stdlib.h> | ||
16 | |||
17 | typedef void *fido_dev_io_open_t(const char *); | ||
18 | typedef void fido_dev_io_close_t(void *); | ||
19 | typedef int fido_dev_io_read_t(void *, unsigned char *, size_t, int); | ||
20 | typedef int fido_dev_io_write_t(void *, const unsigned char *, size_t); | ||
21 | |||
22 | typedef struct fido_dev_io { | ||
23 | fido_dev_io_open_t *open; | ||
24 | fido_dev_io_close_t *close; | ||
25 | fido_dev_io_read_t *read; | ||
26 | fido_dev_io_write_t *write; | ||
27 | } fido_dev_io_t; | ||
28 | |||
29 | typedef enum { | ||
30 | FIDO_OPT_OMIT = 0, /* use authenticator's default */ | ||
31 | FIDO_OPT_FALSE, /* explicitly set option to false */ | ||
32 | FIDO_OPT_TRUE, /* explicitly set option to true */ | ||
33 | } fido_opt_t; | ||
34 | |||
35 | #ifdef _FIDO_INTERNAL | ||
36 | #include <cbor.h> | ||
37 | #include <limits.h> | ||
38 | |||
39 | #include "blob.h" | ||
40 | #include "../openbsd-compat/openbsd-compat.h" | ||
41 | #include "iso7816.h" | ||
42 | #include "types.h" | ||
43 | #include "extern.h" | ||
44 | #endif | ||
45 | |||
46 | #include "fido/err.h" | ||
47 | #include "fido/param.h" | ||
48 | |||
49 | #ifndef _FIDO_INTERNAL | ||
50 | typedef struct fido_assert fido_assert_t; | ||
51 | typedef struct fido_cbor_info fido_cbor_info_t; | ||
52 | typedef struct fido_cred fido_cred_t; | ||
53 | typedef struct fido_dev fido_dev_t; | ||
54 | typedef struct fido_dev_info fido_dev_info_t; | ||
55 | typedef struct es256_pk es256_pk_t; | ||
56 | typedef struct es256_sk es256_sk_t; | ||
57 | typedef struct rs256_pk rs256_pk_t; | ||
58 | typedef struct eddsa_pk eddsa_pk_t; | ||
59 | #endif | ||
60 | |||
61 | fido_assert_t *fido_assert_new(void); | ||
62 | fido_cred_t *fido_cred_new(void); | ||
63 | fido_dev_t *fido_dev_new(void); | ||
64 | fido_dev_info_t *fido_dev_info_new(size_t); | ||
65 | fido_cbor_info_t *fido_cbor_info_new(void); | ||
66 | |||
67 | void fido_assert_free(fido_assert_t **); | ||
68 | void fido_cbor_info_free(fido_cbor_info_t **); | ||
69 | void fido_cred_free(fido_cred_t **); | ||
70 | void fido_dev_force_fido2(fido_dev_t *); | ||
71 | void fido_dev_force_u2f(fido_dev_t *); | ||
72 | void fido_dev_free(fido_dev_t **); | ||
73 | void fido_dev_info_free(fido_dev_info_t **, size_t); | ||
74 | |||
75 | /* fido_init() flags. */ | ||
76 | #define FIDO_DEBUG 0x01 | ||
77 | |||
78 | void fido_init(int); | ||
79 | |||
80 | const unsigned char *fido_assert_authdata_ptr(const fido_assert_t *, size_t); | ||
81 | const unsigned char *fido_assert_clientdata_hash_ptr(const fido_assert_t *); | ||
82 | const unsigned char *fido_assert_hmac_secret_ptr(const fido_assert_t *, size_t); | ||
83 | const unsigned char *fido_assert_id_ptr(const fido_assert_t *, size_t); | ||
84 | const unsigned char *fido_assert_sig_ptr(const fido_assert_t *, size_t); | ||
85 | const unsigned char *fido_assert_user_id_ptr(const fido_assert_t *, size_t); | ||
86 | |||
87 | char **fido_cbor_info_extensions_ptr(const fido_cbor_info_t *); | ||
88 | char **fido_cbor_info_options_name_ptr(const fido_cbor_info_t *); | ||
89 | char **fido_cbor_info_versions_ptr(const fido_cbor_info_t *); | ||
90 | const bool *fido_cbor_info_options_value_ptr(const fido_cbor_info_t *); | ||
91 | const char *fido_assert_rp_id(const fido_assert_t *); | ||
92 | const char *fido_assert_user_display_name(const fido_assert_t *, size_t); | ||
93 | const char *fido_assert_user_icon(const fido_assert_t *, size_t); | ||
94 | const char *fido_assert_user_name(const fido_assert_t *, size_t); | ||
95 | const char *fido_cred_display_name(const fido_cred_t *); | ||
96 | const char *fido_cred_fmt(const fido_cred_t *); | ||
97 | const char *fido_cred_rp_id(const fido_cred_t *); | ||
98 | const char *fido_cred_rp_name(const fido_cred_t *); | ||
99 | const char *fido_cred_user_name(const fido_cred_t *); | ||
100 | const char *fido_dev_info_manufacturer_string(const fido_dev_info_t *); | ||
101 | const char *fido_dev_info_path(const fido_dev_info_t *); | ||
102 | const char *fido_dev_info_product_string(const fido_dev_info_t *); | ||
103 | const fido_dev_info_t *fido_dev_info_ptr(const fido_dev_info_t *, size_t); | ||
104 | const uint8_t *fido_cbor_info_protocols_ptr(const fido_cbor_info_t *); | ||
105 | const unsigned char *fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *); | ||
106 | const unsigned char *fido_cred_authdata_ptr(const fido_cred_t *); | ||
107 | const unsigned char *fido_cred_clientdata_hash_ptr(const fido_cred_t *); | ||
108 | const unsigned char *fido_cred_id_ptr(const fido_cred_t *); | ||
109 | const unsigned char *fido_cred_user_id_ptr(const fido_cred_t *); | ||
110 | const unsigned char *fido_cred_pubkey_ptr(const fido_cred_t *); | ||
111 | const unsigned char *fido_cred_sig_ptr(const fido_cred_t *); | ||
112 | const unsigned char *fido_cred_x5c_ptr(const fido_cred_t *); | ||
113 | |||
114 | int fido_assert_allow_cred(fido_assert_t *, const unsigned char *, size_t); | ||
115 | int fido_assert_set_authdata(fido_assert_t *, size_t, const unsigned char *, | ||
116 | size_t); | ||
117 | int fido_assert_set_authdata_raw(fido_assert_t *, size_t, const unsigned char *, | ||
118 | size_t); | ||
119 | int fido_assert_set_clientdata_hash(fido_assert_t *, const unsigned char *, | ||
120 | size_t); | ||
121 | int fido_assert_set_count(fido_assert_t *, size_t); | ||
122 | int fido_assert_set_extensions(fido_assert_t *, int); | ||
123 | int fido_assert_set_hmac_salt(fido_assert_t *, const unsigned char *, size_t); | ||
124 | int fido_assert_set_options(fido_assert_t *, bool, bool) __attribute__((__deprecated__)); | ||
125 | int fido_assert_set_rp(fido_assert_t *, const char *); | ||
126 | int fido_assert_set_up(fido_assert_t *, fido_opt_t); | ||
127 | int fido_assert_set_uv(fido_assert_t *, fido_opt_t); | ||
128 | int fido_assert_set_sig(fido_assert_t *, size_t, const unsigned char *, size_t); | ||
129 | int fido_assert_verify(const fido_assert_t *, size_t, int, const void *); | ||
130 | int fido_cred_exclude(fido_cred_t *, const unsigned char *, size_t); | ||
131 | int fido_cred_set_authdata(fido_cred_t *, const unsigned char *, size_t); | ||
132 | int fido_cred_set_authdata_raw(fido_cred_t *, const unsigned char *, size_t); | ||
133 | int fido_cred_set_clientdata_hash(fido_cred_t *, const unsigned char *, size_t); | ||
134 | int fido_cred_set_extensions(fido_cred_t *, int); | ||
135 | int fido_cred_set_fmt(fido_cred_t *, const char *); | ||
136 | int fido_cred_set_options(fido_cred_t *, bool, bool) __attribute__((__deprecated__)); | ||
137 | int fido_cred_set_rk(fido_cred_t *, fido_opt_t); | ||
138 | int fido_cred_set_rp(fido_cred_t *, const char *, const char *); | ||
139 | int fido_cred_set_sig(fido_cred_t *, const unsigned char *, size_t); | ||
140 | int fido_cred_set_type(fido_cred_t *, int); | ||
141 | int fido_cred_set_uv(fido_cred_t *, fido_opt_t); | ||
142 | int fido_cred_type(const fido_cred_t *); | ||
143 | int fido_cred_set_user(fido_cred_t *, const unsigned char *, size_t, | ||
144 | const char *, const char *, const char *); | ||
145 | int fido_cred_set_x509(fido_cred_t *, const unsigned char *, size_t); | ||
146 | int fido_cred_verify(const fido_cred_t *); | ||
147 | int fido_cred_verify_self(const fido_cred_t *); | ||
148 | int fido_dev_cancel(fido_dev_t *); | ||
149 | int fido_dev_close(fido_dev_t *); | ||
150 | int fido_dev_get_assert(fido_dev_t *, fido_assert_t *, const char *); | ||
151 | int fido_dev_get_cbor_info(fido_dev_t *, fido_cbor_info_t *); | ||
152 | int fido_dev_get_retry_count(fido_dev_t *, int *); | ||
153 | int fido_dev_info_manifest(fido_dev_info_t *, size_t, size_t *); | ||
154 | int fido_dev_make_cred(fido_dev_t *, fido_cred_t *, const char *); | ||
155 | int fido_dev_open(fido_dev_t *, const char *); | ||
156 | int fido_dev_reset(fido_dev_t *); | ||
157 | int fido_dev_set_io_functions(fido_dev_t *, const fido_dev_io_t *); | ||
158 | int fido_dev_set_pin(fido_dev_t *, const char *, const char *); | ||
159 | |||
160 | size_t fido_assert_authdata_len(const fido_assert_t *, size_t); | ||
161 | size_t fido_assert_clientdata_hash_len(const fido_assert_t *); | ||
162 | size_t fido_assert_count(const fido_assert_t *); | ||
163 | size_t fido_assert_hmac_secret_len(const fido_assert_t *, size_t); | ||
164 | size_t fido_assert_id_len(const fido_assert_t *, size_t); | ||
165 | size_t fido_assert_sig_len(const fido_assert_t *, size_t); | ||
166 | size_t fido_assert_user_id_len(const fido_assert_t *, size_t); | ||
167 | size_t fido_cbor_info_aaguid_len(const fido_cbor_info_t *); | ||
168 | size_t fido_cbor_info_extensions_len(const fido_cbor_info_t *); | ||
169 | size_t fido_cbor_info_options_len(const fido_cbor_info_t *); | ||
170 | size_t fido_cbor_info_protocols_len(const fido_cbor_info_t *); | ||
171 | size_t fido_cbor_info_versions_len(const fido_cbor_info_t *); | ||
172 | size_t fido_cred_authdata_len(const fido_cred_t *); | ||
173 | size_t fido_cred_clientdata_hash_len(const fido_cred_t *); | ||
174 | size_t fido_cred_id_len(const fido_cred_t *); | ||
175 | size_t fido_cred_user_id_len(const fido_cred_t *); | ||
176 | size_t fido_cred_pubkey_len(const fido_cred_t *); | ||
177 | size_t fido_cred_sig_len(const fido_cred_t *); | ||
178 | size_t fido_cred_x5c_len(const fido_cred_t *); | ||
179 | |||
180 | uint8_t fido_assert_flags(const fido_assert_t *, size_t); | ||
181 | uint32_t fido_assert_sigcount(const fido_assert_t *, size_t); | ||
182 | uint8_t fido_cred_flags(const fido_cred_t *); | ||
183 | uint8_t fido_dev_protocol(const fido_dev_t *); | ||
184 | uint8_t fido_dev_major(const fido_dev_t *); | ||
185 | uint8_t fido_dev_minor(const fido_dev_t *); | ||
186 | uint8_t fido_dev_build(const fido_dev_t *); | ||
187 | uint8_t fido_dev_flags(const fido_dev_t *); | ||
188 | int16_t fido_dev_info_vendor(const fido_dev_info_t *); | ||
189 | int16_t fido_dev_info_product(const fido_dev_info_t *); | ||
190 | uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *); | ||
191 | |||
192 | bool fido_dev_is_fido2(const fido_dev_t *); | ||
193 | |||
194 | #endif /* !_FIDO_H */ | ||
diff --git a/src/fido/bio.h b/src/fido/bio.h new file mode 100644 index 0000000..31dffe4 --- /dev/null +++ b/src/fido/bio.h | |||
@@ -0,0 +1,95 @@ | |||
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 | #ifndef _FIDO_BIO_H | ||
8 | #define _FIDO_BIO_H | ||
9 | |||
10 | #include <stdint.h> | ||
11 | #include <stdlib.h> | ||
12 | |||
13 | #include "fido/err.h" | ||
14 | #include "fido/param.h" | ||
15 | |||
16 | #ifdef _FIDO_INTERNAL | ||
17 | struct fido_bio_template { | ||
18 | fido_blob_t id; | ||
19 | char *name; | ||
20 | }; | ||
21 | |||
22 | struct fido_bio_template_array { | ||
23 | struct fido_bio_template *ptr; | ||
24 | size_t n_alloc; /* number of allocated entries */ | ||
25 | size_t n_rx; /* number of populated entries */ | ||
26 | }; | ||
27 | |||
28 | struct fido_bio_enroll { | ||
29 | uint8_t remaining_samples; | ||
30 | uint8_t last_status; | ||
31 | fido_blob_t *token; | ||
32 | }; | ||
33 | |||
34 | struct fido_bio_info { | ||
35 | uint8_t type; | ||
36 | uint8_t max_samples; | ||
37 | }; | ||
38 | #endif | ||
39 | |||
40 | typedef struct fido_bio_template fido_bio_template_t; | ||
41 | typedef struct fido_bio_template_array fido_bio_template_array_t; | ||
42 | typedef struct fido_bio_enroll fido_bio_enroll_t; | ||
43 | typedef struct fido_bio_info fido_bio_info_t; | ||
44 | |||
45 | #define FIDO_BIO_ENROLL_FP_GOOD 0x00 | ||
46 | #define FIDO_BIO_ENROLL_FP_TOO_HIGH 0x01 | ||
47 | #define FIDO_BIO_ENROLL_FP_TOO_LOW 0x02 | ||
48 | #define FIDO_BIO_ENROLL_FP_TOO_LEFT 0x03 | ||
49 | #define FIDO_BIO_ENROLL_FP_TOO_RIGHT 0x04 | ||
50 | #define FIDO_BIO_ENROLL_FP_TOO_FAST 0x05 | ||
51 | #define FIDO_BIO_ENROLL_FP_TOO_SLOW 0x06 | ||
52 | #define FIDO_BIO_ENROLL_FP_POOR_QUALITY 0x07 | ||
53 | #define FIDO_BIO_ENROLL_FP_TOO_SKEWED 0x08 | ||
54 | #define FIDO_BIO_ENROLL_FP_TOO_SHORT 0x09 | ||
55 | #define FIDO_BIO_ENROLL_FP_MERGE_FAILURE 0x0a | ||
56 | #define FIDO_BIO_ENROLL_FP_EXISTS 0x0b | ||
57 | #define FIDO_BIO_ENROLL_FP_DATABASE_FULL 0x0c | ||
58 | #define FIDO_BIO_ENROLL_NO_USER_ACTIVITY 0x0d | ||
59 | #define FIDO_BIO_ENROLL_NO_USER_PRESENCE_TRANSITION 0x0e | ||
60 | |||
61 | const char *fido_bio_template_name(const fido_bio_template_t *); | ||
62 | const fido_bio_template_t *fido_bio_template(const fido_bio_template_array_t *, | ||
63 | size_t); | ||
64 | const unsigned char *fido_bio_template_id_ptr(const fido_bio_template_t *); | ||
65 | fido_bio_enroll_t *fido_bio_enroll_new(void); | ||
66 | fido_bio_info_t *fido_bio_info_new(void); | ||
67 | fido_bio_template_array_t *fido_bio_template_array_new(void); | ||
68 | fido_bio_template_t *fido_bio_template_new(void); | ||
69 | int fido_bio_dev_enroll_begin(fido_dev_t *, fido_bio_template_t *, | ||
70 | fido_bio_enroll_t *, uint32_t, const char *); | ||
71 | int fido_bio_dev_enroll_cancel(fido_dev_t *); | ||
72 | int fido_bio_dev_enroll_continue(fido_dev_t *, const fido_bio_template_t *, | ||
73 | fido_bio_enroll_t *, uint32_t); | ||
74 | int fido_bio_dev_enroll_remove(fido_dev_t *, const fido_bio_template_t *, | ||
75 | const char *); | ||
76 | int fido_bio_dev_get_info(fido_dev_t *, fido_bio_info_t *); | ||
77 | int fido_bio_dev_get_template_array(fido_dev_t *, fido_bio_template_array_t *, | ||
78 | const char *); | ||
79 | int fido_bio_dev_set_template_name(fido_dev_t *, const fido_bio_template_t *, | ||
80 | const char *); | ||
81 | int fido_bio_template_set_id(fido_bio_template_t *, const unsigned char *, | ||
82 | size_t); | ||
83 | int fido_bio_template_set_name(fido_bio_template_t *, const char *); | ||
84 | size_t fido_bio_template_array_count(const fido_bio_template_array_t *); | ||
85 | size_t fido_bio_template_id_len(const fido_bio_template_t *); | ||
86 | uint8_t fido_bio_enroll_last_status(const fido_bio_enroll_t *); | ||
87 | uint8_t fido_bio_enroll_remaining_samples(const fido_bio_enroll_t *); | ||
88 | uint8_t fido_bio_info_max_samples(const fido_bio_info_t *); | ||
89 | uint8_t fido_bio_info_type(const fido_bio_info_t *); | ||
90 | void fido_bio_enroll_free(fido_bio_enroll_t **); | ||
91 | void fido_bio_info_free(fido_bio_info_t **); | ||
92 | void fido_bio_template_array_free(fido_bio_template_array_t **); | ||
93 | void fido_bio_template_free(fido_bio_template_t **); | ||
94 | |||
95 | #endif /* !_FIDO_BIO_H */ | ||
diff --git a/src/fido/credman.h b/src/fido/credman.h new file mode 100644 index 0000000..1c7cafe --- /dev/null +++ b/src/fido/credman.h | |||
@@ -0,0 +1,74 @@ | |||
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 | #ifndef _FIDO_CREDMAN_H | ||
8 | #define _FIDO_CREDMAN_H | ||
9 | |||
10 | #include <stdint.h> | ||
11 | #include <stdlib.h> | ||
12 | |||
13 | #include "fido/err.h" | ||
14 | #include "fido/param.h" | ||
15 | |||
16 | #ifdef _FIDO_INTERNAL | ||
17 | struct fido_credman_metadata { | ||
18 | uint64_t rk_existing; | ||
19 | uint64_t rk_remaining; | ||
20 | }; | ||
21 | |||
22 | struct fido_credman_single_rp { | ||
23 | fido_rp_t rp_entity; | ||
24 | fido_blob_t rp_id_hash; | ||
25 | }; | ||
26 | |||
27 | struct fido_credman_rp { | ||
28 | struct fido_credman_single_rp *ptr; | ||
29 | size_t n_alloc; /* number of allocated entries */ | ||
30 | size_t n_rx; /* number of populated entries */ | ||
31 | }; | ||
32 | |||
33 | struct fido_credman_rk { | ||
34 | fido_cred_t *ptr; | ||
35 | size_t n_alloc; /* number of allocated entries */ | ||
36 | size_t n_rx; /* number of populated entries */ | ||
37 | }; | ||
38 | #endif | ||
39 | |||
40 | typedef struct fido_credman_metadata fido_credman_metadata_t; | ||
41 | typedef struct fido_credman_rk fido_credman_rk_t; | ||
42 | typedef struct fido_credman_rp fido_credman_rp_t; | ||
43 | |||
44 | const char *fido_credman_rp_id(const fido_credman_rp_t *, size_t); | ||
45 | const char *fido_credman_rp_name(const fido_credman_rp_t *, size_t); | ||
46 | |||
47 | const fido_cred_t *fido_credman_rk(const fido_credman_rk_t *, size_t); | ||
48 | const unsigned char *fido_credman_rp_id_hash_ptr(const fido_credman_rp_t *, | ||
49 | size_t); | ||
50 | |||
51 | fido_credman_metadata_t *fido_credman_metadata_new(void); | ||
52 | fido_credman_rk_t *fido_credman_rk_new(void); | ||
53 | fido_credman_rp_t *fido_credman_rp_new(void); | ||
54 | |||
55 | int fido_credman_del_dev_rk(fido_dev_t *, const unsigned char *, size_t, | ||
56 | const char *); | ||
57 | int fido_credman_get_dev_metadata(fido_dev_t *, fido_credman_metadata_t *, | ||
58 | const char *); | ||
59 | int fido_credman_get_dev_rk(fido_dev_t *, const char *, fido_credman_rk_t *, | ||
60 | const char *); | ||
61 | int fido_credman_get_dev_rp(fido_dev_t *, fido_credman_rp_t *, const char *); | ||
62 | |||
63 | size_t fido_credman_rk_count(const fido_credman_rk_t *); | ||
64 | size_t fido_credman_rp_count(const fido_credman_rp_t *); | ||
65 | size_t fido_credman_rp_id_hash_len(const fido_credman_rp_t *, size_t); | ||
66 | |||
67 | uint64_t fido_credman_rk_existing(const fido_credman_metadata_t *); | ||
68 | uint64_t fido_credman_rk_remaining(const fido_credman_metadata_t *); | ||
69 | |||
70 | void fido_credman_metadata_free(fido_credman_metadata_t **); | ||
71 | void fido_credman_rk_free(fido_credman_rk_t **); | ||
72 | void fido_credman_rp_free(fido_credman_rp_t **); | ||
73 | |||
74 | #endif /* !_FIDO_CREDMAN_H */ | ||
diff --git a/src/fido/eddsa.h b/src/fido/eddsa.h new file mode 100644 index 0000000..9de272d --- /dev/null +++ b/src/fido/eddsa.h | |||
@@ -0,0 +1,40 @@ | |||
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 | #ifndef _FIDO_EDDSA_H | ||
8 | #define _FIDO_EDDSA_H | ||
9 | |||
10 | #include <openssl/ec.h> | ||
11 | |||
12 | #include <stdint.h> | ||
13 | #include <stdlib.h> | ||
14 | |||
15 | eddsa_pk_t *eddsa_pk_new(void); | ||
16 | void eddsa_pk_free(eddsa_pk_t **); | ||
17 | EVP_PKEY *eddsa_pk_to_EVP_PKEY(const eddsa_pk_t *); | ||
18 | |||
19 | int eddsa_pk_from_EVP_PKEY(eddsa_pk_t *, const EVP_PKEY *); | ||
20 | int eddsa_pk_from_ptr(eddsa_pk_t *, const void *, size_t); | ||
21 | |||
22 | #ifdef _FIDO_INTERNAL | ||
23 | |||
24 | #if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10101000L | ||
25 | #define EVP_PKEY_ED25519 EVP_PKEY_NONE | ||
26 | int EVP_PKEY_get_raw_public_key(const EVP_PKEY *, unsigned char *, size_t *); | ||
27 | EVP_PKEY *EVP_PKEY_new_raw_public_key(int, ENGINE *, const unsigned char *, | ||
28 | size_t); | ||
29 | int EVP_DigestVerify(EVP_MD_CTX *, const unsigned char *, size_t, | ||
30 | const unsigned char *, size_t); | ||
31 | #endif /* LIBRESSL_VERSION_NUMBER || OPENSSL_VERSION_NUMBER < 0x10101000L */ | ||
32 | |||
33 | #if OPENSSL_VERSION_NUMBER < 0x10100000L | ||
34 | EVP_MD_CTX *EVP_MD_CTX_new(void); | ||
35 | void EVP_MD_CTX_free(EVP_MD_CTX *); | ||
36 | #endif | ||
37 | |||
38 | #endif /* _FIDO_INTERNAL */ | ||
39 | |||
40 | #endif /* !_FIDO_EDDSA_H */ | ||
diff --git a/src/fido/err.h b/src/fido/err.h new file mode 100644 index 0000000..11f52bc --- /dev/null +++ b/src/fido/err.h | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | #ifndef _FIDO_ERR_H | ||
8 | #define _FIDO_ERR_H | ||
9 | |||
10 | #define FIDO_ERR_SUCCESS 0x00 | ||
11 | #define FIDO_ERR_INVALID_COMMAND 0x01 | ||
12 | #define FIDO_ERR_INVALID_PARAMETER 0x02 | ||
13 | #define FIDO_ERR_INVALID_LENGTH 0x03 | ||
14 | #define FIDO_ERR_INVALID_SEQ 0x04 | ||
15 | #define FIDO_ERR_TIMEOUT 0x05 | ||
16 | #define FIDO_ERR_CHANNEL_BUSY 0x06 | ||
17 | #define FIDO_ERR_LOCK_REQUIRED 0x0a | ||
18 | #define FIDO_ERR_INVALID_CHANNEL 0x0b | ||
19 | #define FIDO_ERR_CBOR_UNEXPECTED_TYPE 0x11 | ||
20 | #define FIDO_ERR_INVALID_CBOR 0x12 | ||
21 | #define FIDO_ERR_MISSING_PARAMETER 0x14 | ||
22 | #define FIDO_ERR_LIMIT_EXCEEDED 0x15 | ||
23 | #define FIDO_ERR_UNSUPPORTED_EXTENSION 0x16 | ||
24 | #define FIDO_ERR_CREDENTIAL_EXCLUDED 0x19 | ||
25 | #define FIDO_ERR_PROCESSING 0x21 | ||
26 | #define FIDO_ERR_INVALID_CREDENTIAL 0x22 | ||
27 | #define FIDO_ERR_USER_ACTION_PENDING 0x23 | ||
28 | #define FIDO_ERR_OPERATION_PENDING 0x24 | ||
29 | #define FIDO_ERR_NO_OPERATIONS 0x25 | ||
30 | #define FIDO_ERR_UNSUPPORTED_ALGORITHM 0x26 | ||
31 | #define FIDO_ERR_OPERATION_DENIED 0x27 | ||
32 | #define FIDO_ERR_KEY_STORE_FULL 0x28 | ||
33 | #define FIDO_ERR_NOT_BUSY 0x29 | ||
34 | #define FIDO_ERR_NO_OPERATION_PENDING 0x2a | ||
35 | #define FIDO_ERR_UNSUPPORTED_OPTION 0x2b | ||
36 | #define FIDO_ERR_INVALID_OPTION 0x2c | ||
37 | #define FIDO_ERR_KEEPALIVE_CANCEL 0x2d | ||
38 | #define FIDO_ERR_NO_CREDENTIALS 0x2e | ||
39 | #define FIDO_ERR_USER_ACTION_TIMEOUT 0x2f | ||
40 | #define FIDO_ERR_NOT_ALLOWED 0x30 | ||
41 | #define FIDO_ERR_PIN_INVALID 0x31 | ||
42 | #define FIDO_ERR_PIN_BLOCKED 0x32 | ||
43 | #define FIDO_ERR_PIN_AUTH_INVALID 0x33 | ||
44 | #define FIDO_ERR_PIN_AUTH_BLOCKED 0x34 | ||
45 | #define FIDO_ERR_PIN_NOT_SET 0x35 | ||
46 | #define FIDO_ERR_PIN_REQUIRED 0x36 | ||
47 | #define FIDO_ERR_PIN_POLICY_VIOLATION 0x37 | ||
48 | #define FIDO_ERR_PIN_TOKEN_EXPIRED 0x38 | ||
49 | #define FIDO_ERR_REQUEST_TOO_LARGE 0x39 | ||
50 | #define FIDO_ERR_ACTION_TIMEOUT 0x3a | ||
51 | #define FIDO_ERR_UP_REQUIRED 0x3b | ||
52 | #define FIDO_ERR_ERR_OTHER 0x7f | ||
53 | #define FIDO_ERR_SPEC_LAST 0xdf | ||
54 | |||
55 | /* defined internally */ | ||
56 | #define FIDO_OK FIDO_ERR_SUCCESS | ||
57 | #define FIDO_ERR_TX -1 | ||
58 | #define FIDO_ERR_RX -2 | ||
59 | #define FIDO_ERR_RX_NOT_CBOR -3 | ||
60 | #define FIDO_ERR_RX_INVALID_CBOR -4 | ||
61 | #define FIDO_ERR_INVALID_PARAM -5 | ||
62 | #define FIDO_ERR_INVALID_SIG -6 | ||
63 | #define FIDO_ERR_INVALID_ARGUMENT -7 | ||
64 | #define FIDO_ERR_USER_PRESENCE_REQUIRED -8 | ||
65 | #define FIDO_ERR_INTERNAL -9 | ||
66 | |||
67 | const char *fido_strerr(int); | ||
68 | |||
69 | #endif /* _FIDO_ERR_H */ | ||
diff --git a/src/fido/es256.h b/src/fido/es256.h new file mode 100644 index 0000000..d3d13dd --- /dev/null +++ b/src/fido/es256.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | #ifndef _FIDO_ES256_H | ||
8 | #define _FIDO_ES256_H | ||
9 | |||
10 | #include <openssl/ec.h> | ||
11 | |||
12 | #include <stdint.h> | ||
13 | #include <stdlib.h> | ||
14 | |||
15 | es256_pk_t *es256_pk_new(void); | ||
16 | void es256_pk_free(es256_pk_t **); | ||
17 | EVP_PKEY *es256_pk_to_EVP_PKEY(const es256_pk_t *); | ||
18 | |||
19 | int es256_pk_from_EC_KEY(es256_pk_t *, const EC_KEY *); | ||
20 | int es256_pk_from_ptr(es256_pk_t *, const void *, size_t); | ||
21 | |||
22 | #ifdef _FIDO_INTERNAL | ||
23 | es256_sk_t *es256_sk_new(void); | ||
24 | void es256_sk_free(es256_sk_t **); | ||
25 | EVP_PKEY *es256_sk_to_EVP_PKEY(const es256_sk_t *); | ||
26 | |||
27 | int es256_derive_pk(const es256_sk_t *, es256_pk_t *); | ||
28 | int es256_sk_create(es256_sk_t *); | ||
29 | |||
30 | int es256_pk_set_x(es256_pk_t *, const unsigned char *); | ||
31 | int es256_pk_set_y(es256_pk_t *, const unsigned char *); | ||
32 | #endif | ||
33 | |||
34 | #endif /* !_FIDO_ES256_H */ | ||
diff --git a/src/fido/param.h b/src/fido/param.h new file mode 100644 index 0000000..9e12ac6 --- /dev/null +++ b/src/fido/param.h | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | #ifndef _FIDO_PARAM_H | ||
8 | #define _FIDO_PARAM_H | ||
9 | |||
10 | /* Authentication data flags. */ | ||
11 | #define CTAP_AUTHDATA_USER_PRESENT 0x01 | ||
12 | #define CTAP_AUTHDATA_USER_VERIFIED 0x04 | ||
13 | #define CTAP_AUTHDATA_ATT_CRED 0x40 | ||
14 | #define CTAP_AUTHDATA_EXT_DATA 0x80 | ||
15 | |||
16 | /* CTAPHID command opcodes. */ | ||
17 | #define CTAP_CMD_PING 0x01 | ||
18 | #define CTAP_CMD_MSG 0x03 | ||
19 | #define CTAP_CMD_LOCK 0x04 | ||
20 | #define CTAP_CMD_INIT 0x06 | ||
21 | #define CTAP_CMD_WINK 0x08 | ||
22 | #define CTAP_CMD_CBOR 0x10 | ||
23 | #define CTAP_CMD_CANCEL 0x11 | ||
24 | #define CTAP_KEEPALIVE 0x3b | ||
25 | #define CTAP_FRAME_INIT 0x80 | ||
26 | |||
27 | /* CTAPHID CBOR command opcodes. */ | ||
28 | #define CTAP_CBOR_MAKECRED 0x01 | ||
29 | #define CTAP_CBOR_ASSERT 0x02 | ||
30 | #define CTAP_CBOR_GETINFO 0x04 | ||
31 | #define CTAP_CBOR_CLIENT_PIN 0x06 | ||
32 | #define CTAP_CBOR_RESET 0x07 | ||
33 | #define CTAP_CBOR_NEXT_ASSERT 0x08 | ||
34 | #define CTAP_CBOR_BIO_ENROLL_PRE 0x40 | ||
35 | #define CTAP_CBOR_CRED_MGMT_PRE 0x41 | ||
36 | |||
37 | /* U2F command opcodes. */ | ||
38 | #define U2F_CMD_REGISTER 0x01 | ||
39 | #define U2F_CMD_AUTH 0x02 | ||
40 | |||
41 | /* U2F command flags. */ | ||
42 | #define U2F_AUTH_SIGN 0x03 | ||
43 | #define U2F_AUTH_CHECK 0x07 | ||
44 | |||
45 | /* ISO7816-4 status words. */ | ||
46 | #define SW_CONDITIONS_NOT_SATISFIED 0x6985 | ||
47 | #define SW_WRONG_DATA 0x6a80 | ||
48 | #define SW_NO_ERROR 0x9000 | ||
49 | |||
50 | /* HID Broadcast channel ID. */ | ||
51 | #define CTAP_CID_BROADCAST 0xffffffff | ||
52 | |||
53 | /* Expected size of a HID report in bytes. */ | ||
54 | #define CTAP_RPT_SIZE 64 | ||
55 | |||
56 | /* Randomness device on UNIX-like platforms. */ | ||
57 | #ifndef FIDO_RANDOM_DEV | ||
58 | #define FIDO_RANDOM_DEV "/dev/urandom" | ||
59 | #endif | ||
60 | |||
61 | /* CTAP capability bits. */ | ||
62 | #define FIDO_CAP_WINK 0x01 /* if set, device supports CTAP_CMD_WINK */ | ||
63 | #define FIDO_CAP_CBOR 0x04 /* if set, device supports CTAP_CMD_CBOR */ | ||
64 | #define FIDO_CAP_NMSG 0x08 /* if set, device doesn't support CTAP_CMD_MSG */ | ||
65 | |||
66 | /* Supported COSE algorithms. */ | ||
67 | #define COSE_ES256 -7 | ||
68 | #define COSE_EDDSA -8 | ||
69 | #define COSE_ECDH_ES256 -25 | ||
70 | #define COSE_RS256 -257 | ||
71 | |||
72 | /* Supported COSE types. */ | ||
73 | #define COSE_KTY_OKP 1 | ||
74 | #define COSE_KTY_EC2 2 | ||
75 | #define COSE_KTY_RSA 3 | ||
76 | |||
77 | /* Supported curves. */ | ||
78 | #define COSE_P256 1 | ||
79 | #define COSE_ED25519 6 | ||
80 | |||
81 | /* Supported extensions. */ | ||
82 | #define FIDO_EXT_HMAC_SECRET 0x01 | ||
83 | |||
84 | #endif /* !_FIDO_PARAM_H */ | ||
diff --git a/src/fido/rs256.h b/src/fido/rs256.h new file mode 100644 index 0000000..d2fa162 --- /dev/null +++ b/src/fido/rs256.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | #ifndef _FIDO_RS256_H | ||
8 | #define _FIDO_RS256_H | ||
9 | |||
10 | #include <openssl/rsa.h> | ||
11 | |||
12 | #include <stdint.h> | ||
13 | #include <stdlib.h> | ||
14 | |||
15 | rs256_pk_t *rs256_pk_new(void); | ||
16 | void rs256_pk_free(rs256_pk_t **); | ||
17 | EVP_PKEY *rs256_pk_to_EVP_PKEY(const rs256_pk_t *); | ||
18 | |||
19 | int rs256_pk_from_RSA(rs256_pk_t *, const RSA *); | ||
20 | int rs256_pk_from_ptr(rs256_pk_t *, const void *, size_t); | ||
21 | |||
22 | #endif /* !_FIDO_RS256_H */ | ||
diff --git a/src/hid.c b/src/hid.c new file mode 100644 index 0000000..783d22c --- /dev/null +++ b/src/hid.c | |||
@@ -0,0 +1,70 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <string.h> | ||
8 | #include "fido.h" | ||
9 | |||
10 | fido_dev_info_t * | ||
11 | fido_dev_info_new(size_t n) | ||
12 | { | ||
13 | return (calloc(n, sizeof(fido_dev_info_t))); | ||
14 | } | ||
15 | |||
16 | void | ||
17 | fido_dev_info_free(fido_dev_info_t **devlist_p, size_t n) | ||
18 | { | ||
19 | fido_dev_info_t *devlist; | ||
20 | |||
21 | if (devlist_p == NULL || (devlist = *devlist_p) == NULL) | ||
22 | return; | ||
23 | |||
24 | for (size_t i = 0; i < n; i++) { | ||
25 | const fido_dev_info_t *di = &devlist[i]; | ||
26 | free(di->path); | ||
27 | free(di->manufacturer); | ||
28 | free(di->product); | ||
29 | } | ||
30 | |||
31 | free(devlist); | ||
32 | |||
33 | *devlist_p = NULL; | ||
34 | } | ||
35 | |||
36 | const fido_dev_info_t * | ||
37 | fido_dev_info_ptr(const fido_dev_info_t *devlist, size_t i) | ||
38 | { | ||
39 | return (&devlist[i]); | ||
40 | } | ||
41 | |||
42 | const char * | ||
43 | fido_dev_info_path(const fido_dev_info_t *di) | ||
44 | { | ||
45 | return (di->path); | ||
46 | } | ||
47 | |||
48 | int16_t | ||
49 | fido_dev_info_vendor(const fido_dev_info_t *di) | ||
50 | { | ||
51 | return (di->vendor_id); | ||
52 | } | ||
53 | |||
54 | int16_t | ||
55 | fido_dev_info_product(const fido_dev_info_t *di) | ||
56 | { | ||
57 | return (di->product_id); | ||
58 | } | ||
59 | |||
60 | const char * | ||
61 | fido_dev_info_manufacturer_string(const fido_dev_info_t *di) | ||
62 | { | ||
63 | return (di->manufacturer); | ||
64 | } | ||
65 | |||
66 | const char * | ||
67 | fido_dev_info_product_string(const fido_dev_info_t *di) | ||
68 | { | ||
69 | return (di->product); | ||
70 | } | ||
diff --git a/src/hid_linux.c b/src/hid_linux.c new file mode 100644 index 0000000..c7cabc9 --- /dev/null +++ b/src/hid_linux.c | |||
@@ -0,0 +1,344 @@ | |||
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 <sys/types.h> | ||
8 | |||
9 | #include <sys/ioctl.h> | ||
10 | #include <linux/hidraw.h> | ||
11 | |||
12 | #include <fcntl.h> | ||
13 | #include <libudev.h> | ||
14 | #include <string.h> | ||
15 | #include <unistd.h> | ||
16 | |||
17 | #include "fido.h" | ||
18 | |||
19 | #define REPORT_LEN 65 | ||
20 | |||
21 | static int | ||
22 | get_key_len(uint8_t tag, uint8_t *key, size_t *key_len) | ||
23 | { | ||
24 | *key = tag & 0xfc; | ||
25 | if ((*key & 0xf0) == 0xf0) { | ||
26 | fido_log_debug("%s: *key=0x%02x", __func__, *key); | ||
27 | return (-1); | ||
28 | } | ||
29 | |||
30 | *key_len = tag & 0x3; | ||
31 | if (*key_len == 3) { | ||
32 | *key_len = 4; | ||
33 | } | ||
34 | |||
35 | return (0); | ||
36 | } | ||
37 | |||
38 | static int | ||
39 | get_key_val(const void *body, size_t key_len, uint32_t *val) | ||
40 | { | ||
41 | const uint8_t *ptr = body; | ||
42 | |||
43 | switch (key_len) { | ||
44 | case 0: | ||
45 | *val = 0; | ||
46 | break; | ||
47 | case 1: | ||
48 | *val = ptr[0]; | ||
49 | break; | ||
50 | case 2: | ||
51 | *val = (uint32_t)((ptr[1] << 8) | ptr[0]); | ||
52 | break; | ||
53 | default: | ||
54 | fido_log_debug("%s: key_len=%zu", __func__, key_len); | ||
55 | return (-1); | ||
56 | } | ||
57 | |||
58 | return (0); | ||
59 | } | ||
60 | |||
61 | static int | ||
62 | get_usage_info(const struct hidraw_report_descriptor *hrd, uint32_t *usage_page, | ||
63 | uint32_t *usage) | ||
64 | { | ||
65 | const uint8_t *ptr; | ||
66 | size_t len; | ||
67 | |||
68 | ptr = hrd->value; | ||
69 | len = hrd->size; | ||
70 | |||
71 | while (len > 0) { | ||
72 | const uint8_t tag = ptr[0]; | ||
73 | ptr++; | ||
74 | len--; | ||
75 | |||
76 | uint8_t key; | ||
77 | size_t key_len; | ||
78 | uint32_t key_val; | ||
79 | |||
80 | if (get_key_len(tag, &key, &key_len) < 0 || key_len > len || | ||
81 | get_key_val(ptr, key_len, &key_val) < 0) { | ||
82 | return (-1); | ||
83 | } | ||
84 | |||
85 | if (key == 0x4) { | ||
86 | *usage_page = key_val; | ||
87 | } else if (key == 0x8) { | ||
88 | *usage = key_val; | ||
89 | } | ||
90 | |||
91 | ptr += key_len; | ||
92 | len -= key_len; | ||
93 | } | ||
94 | |||
95 | return (0); | ||
96 | } | ||
97 | |||
98 | static int | ||
99 | get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd) | ||
100 | { | ||
101 | int r; | ||
102 | int s = -1; | ||
103 | int fd; | ||
104 | int ok = -1; | ||
105 | |||
106 | if ((fd = open(path, O_RDONLY)) < 0) { | ||
107 | fido_log_debug("%s: open", __func__); | ||
108 | return (-1); | ||
109 | } | ||
110 | |||
111 | if ((r = ioctl(fd, HIDIOCGRDESCSIZE, &s)) < 0 || s < 0 || | ||
112 | (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) { | ||
113 | fido_log_debug("%s: ioctl HIDIOCGRDESCSIZE", __func__); | ||
114 | goto fail; | ||
115 | } | ||
116 | |||
117 | hrd->size = s; | ||
118 | |||
119 | if ((r = ioctl(fd, HIDIOCGRDESC, hrd)) < 0) { | ||
120 | fido_log_debug("%s: ioctl HIDIOCGRDESC", __func__); | ||
121 | goto fail; | ||
122 | } | ||
123 | |||
124 | ok = 0; | ||
125 | fail: | ||
126 | if (fd != -1) | ||
127 | close(fd); | ||
128 | |||
129 | return (ok); | ||
130 | } | ||
131 | |||
132 | static bool | ||
133 | is_fido(const char *path) | ||
134 | { | ||
135 | uint32_t usage = 0; | ||
136 | uint32_t usage_page = 0; | ||
137 | struct hidraw_report_descriptor hrd; | ||
138 | |||
139 | memset(&hrd, 0, sizeof(hrd)); | ||
140 | |||
141 | if (get_report_descriptor(path, &hrd) < 0 || | ||
142 | get_usage_info(&hrd, &usage_page, &usage) < 0) { | ||
143 | return (false); | ||
144 | } | ||
145 | |||
146 | return (usage_page == 0xf1d0); | ||
147 | } | ||
148 | |||
149 | static int | ||
150 | parse_uevent(struct udev_device *dev, int16_t *vendor_id, int16_t *product_id) | ||
151 | { | ||
152 | const char *uevent; | ||
153 | char *cp; | ||
154 | char *p; | ||
155 | char *s; | ||
156 | int ok = -1; | ||
157 | short unsigned int x; | ||
158 | short unsigned int y; | ||
159 | |||
160 | if ((uevent = udev_device_get_sysattr_value(dev, "uevent")) == NULL) | ||
161 | return (-1); | ||
162 | |||
163 | if ((s = cp = strdup(uevent)) == NULL) | ||
164 | return (-1); | ||
165 | |||
166 | for ((p = strsep(&cp, "\n")); p && *p != '\0'; (p = strsep(&cp, "\n"))) { | ||
167 | if (strncmp(p, "HID_ID=", 7) == 0) { | ||
168 | if (sscanf(p + 7, "%*x:%hx:%hx", &x, &y) == 2) { | ||
169 | *vendor_id = (int16_t)x; | ||
170 | *product_id = (int16_t)y; | ||
171 | ok = 0; | ||
172 | } | ||
173 | break; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | free(s); | ||
178 | |||
179 | return (ok); | ||
180 | } | ||
181 | |||
182 | static int | ||
183 | copy_info(fido_dev_info_t *di, struct udev *udev, | ||
184 | struct udev_list_entry *udev_entry) | ||
185 | { | ||
186 | const char *name; | ||
187 | const char *path; | ||
188 | const char *manufacturer; | ||
189 | const char *product; | ||
190 | struct udev_device *dev = NULL; | ||
191 | struct udev_device *hid_parent; | ||
192 | struct udev_device *usb_parent; | ||
193 | int ok = -1; | ||
194 | |||
195 | memset(di, 0, sizeof(*di)); | ||
196 | |||
197 | if ((name = udev_list_entry_get_name(udev_entry)) == NULL || | ||
198 | (dev = udev_device_new_from_syspath(udev, name)) == NULL || | ||
199 | (path = udev_device_get_devnode(dev)) == NULL || | ||
200 | is_fido(path) == 0) | ||
201 | goto fail; | ||
202 | |||
203 | if ((hid_parent = udev_device_get_parent_with_subsystem_devtype(dev, | ||
204 | "hid", NULL)) == NULL) | ||
205 | goto fail; | ||
206 | |||
207 | if ((usb_parent = udev_device_get_parent_with_subsystem_devtype(dev, | ||
208 | "usb", "usb_device")) == NULL) | ||
209 | goto fail; | ||
210 | |||
211 | if (parse_uevent(hid_parent, &di->vendor_id, &di->product_id) < 0 || | ||
212 | (manufacturer = udev_device_get_sysattr_value(usb_parent, | ||
213 | "manufacturer")) == NULL || | ||
214 | (product = udev_device_get_sysattr_value(usb_parent, | ||
215 | "product")) == NULL) | ||
216 | goto fail; | ||
217 | |||
218 | di->path = strdup(path); | ||
219 | di->manufacturer = strdup(manufacturer); | ||
220 | di->product = strdup(product); | ||
221 | |||
222 | if (di->path == NULL || | ||
223 | di->manufacturer == NULL || | ||
224 | di->product == NULL) | ||
225 | goto fail; | ||
226 | |||
227 | ok = 0; | ||
228 | fail: | ||
229 | if (dev != NULL) | ||
230 | udev_device_unref(dev); | ||
231 | |||
232 | if (ok < 0) { | ||
233 | free(di->path); | ||
234 | free(di->manufacturer); | ||
235 | free(di->product); | ||
236 | explicit_bzero(di, sizeof(*di)); | ||
237 | } | ||
238 | |||
239 | return (ok); | ||
240 | } | ||
241 | |||
242 | int | ||
243 | fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) | ||
244 | { | ||
245 | struct udev *udev = NULL; | ||
246 | struct udev_enumerate *udev_enum = NULL; | ||
247 | struct udev_list_entry *udev_list; | ||
248 | struct udev_list_entry *udev_entry; | ||
249 | int r = FIDO_ERR_INTERNAL; | ||
250 | |||
251 | *olen = 0; | ||
252 | |||
253 | if (ilen == 0) | ||
254 | return (FIDO_OK); /* nothing to do */ | ||
255 | |||
256 | if (devlist == NULL) | ||
257 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
258 | |||
259 | if ((udev = udev_new()) == NULL || | ||
260 | (udev_enum = udev_enumerate_new(udev)) == NULL) | ||
261 | goto fail; | ||
262 | |||
263 | if (udev_enumerate_add_match_subsystem(udev_enum, "hidraw") < 0 || | ||
264 | udev_enumerate_scan_devices(udev_enum) < 0 || | ||
265 | (udev_list = udev_enumerate_get_list_entry(udev_enum)) == NULL) | ||
266 | goto fail; | ||
267 | |||
268 | udev_list_entry_foreach(udev_entry, udev_list) { | ||
269 | if (copy_info(&devlist[*olen], udev, udev_entry) == 0) { | ||
270 | if (++(*olen) == ilen) | ||
271 | break; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | r = FIDO_OK; | ||
276 | fail: | ||
277 | if (udev_enum != NULL) | ||
278 | udev_enumerate_unref(udev_enum); | ||
279 | if (udev != NULL) | ||
280 | udev_unref(udev); | ||
281 | |||
282 | return (r); | ||
283 | } | ||
284 | |||
285 | void * | ||
286 | fido_hid_open(const char *path) | ||
287 | { | ||
288 | int *fd; | ||
289 | |||
290 | if ((fd = malloc(sizeof(*fd))) == NULL || | ||
291 | (*fd = open(path, O_RDWR)) < 0) { | ||
292 | free(fd); | ||
293 | return (NULL); | ||
294 | } | ||
295 | |||
296 | return (fd); | ||
297 | } | ||
298 | |||
299 | void | ||
300 | fido_hid_close(void *handle) | ||
301 | { | ||
302 | int *fd = handle; | ||
303 | |||
304 | close(*fd); | ||
305 | free(fd); | ||
306 | } | ||
307 | |||
308 | int | ||
309 | fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) | ||
310 | { | ||
311 | int *fd = handle; | ||
312 | ssize_t r; | ||
313 | |||
314 | (void)ms; /* XXX */ | ||
315 | |||
316 | if (len != REPORT_LEN - 1) { | ||
317 | fido_log_debug("%s: invalid len", __func__); | ||
318 | return (-1); | ||
319 | } | ||
320 | |||
321 | if ((r = read(*fd, buf, len)) < 0 || r != REPORT_LEN - 1) | ||
322 | return (-1); | ||
323 | |||
324 | return (REPORT_LEN - 1); | ||
325 | } | ||
326 | |||
327 | int | ||
328 | fido_hid_write(void *handle, const unsigned char *buf, size_t len) | ||
329 | { | ||
330 | int *fd = handle; | ||
331 | ssize_t r; | ||
332 | |||
333 | if (len != REPORT_LEN) { | ||
334 | fido_log_debug("%s: invalid len", __func__); | ||
335 | return (-1); | ||
336 | } | ||
337 | |||
338 | if ((r = write(*fd, buf, len)) < 0 || r != REPORT_LEN) { | ||
339 | fido_log_debug("%s: write", __func__); | ||
340 | return (-1); | ||
341 | } | ||
342 | |||
343 | return (REPORT_LEN); | ||
344 | } | ||
diff --git a/src/hid_openbsd.c b/src/hid_openbsd.c new file mode 100644 index 0000000..8b92bd6 --- /dev/null +++ b/src/hid_openbsd.c | |||
@@ -0,0 +1,277 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2019 Google LLC. 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 <sys/types.h> | ||
8 | |||
9 | #include <sys/ioctl.h> | ||
10 | #include <dev/usb/usb.h> | ||
11 | #include <dev/usb/usbhid.h> | ||
12 | |||
13 | #include <errno.h> | ||
14 | #include <fcntl.h> | ||
15 | #include <string.h> | ||
16 | #include <unistd.h> | ||
17 | #include <usbhid.h> | ||
18 | #include <poll.h> | ||
19 | |||
20 | #include "fido.h" | ||
21 | |||
22 | #define MAX_UHID 64 | ||
23 | #define MAX_REPORT_LEN (sizeof(((struct usb_ctl_report *)(NULL))->ucr_data)) | ||
24 | |||
25 | struct hid_openbsd { | ||
26 | int fd; | ||
27 | size_t report_in_len; | ||
28 | size_t report_out_len; | ||
29 | }; | ||
30 | |||
31 | int | ||
32 | fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) | ||
33 | { | ||
34 | size_t i; | ||
35 | char path[64]; | ||
36 | int is_fido, fd; | ||
37 | 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; | ||
42 | |||
43 | if (ilen == 0) | ||
44 | return (FIDO_OK); /* nothing to do */ | ||
45 | |||
46 | if (devlist == NULL || olen == NULL) | ||
47 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
48 | |||
49 | for (i = *olen = 0; i < MAX_UHID && *olen < ilen; i++) { | ||
50 | snprintf(path, sizeof(path), "/dev/uhid%zu", i); | ||
51 | if ((fd = open(path, O_RDWR)) == -1) { | ||
52 | if (errno != ENOENT && errno != ENXIO) { | ||
53 | fido_log_debug("%s: open %s: %s", __func__, | ||
54 | path, strerror(errno)); | ||
55 | } | ||
56 | continue; | ||
57 | } | ||
58 | memset(&udi, 0, sizeof(udi)); | ||
59 | if (ioctl(fd, USB_GET_DEVICEINFO, &udi) != 0) { | ||
60 | fido_log_debug("%s: get device info %s: %s", __func__, | ||
61 | path, strerror(errno)); | ||
62 | close(fd); | ||
63 | continue; | ||
64 | } | ||
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); | ||
90 | |||
91 | if (!is_fido) | ||
92 | continue; | ||
93 | |||
94 | fido_log_debug("%s: %s: bus = 0x%02x, addr = 0x%02x", | ||
95 | __func__, path, udi.udi_bus, udi.udi_addr); | ||
96 | fido_log_debug("%s: %s: vendor = \"%s\", product = \"%s\"", | ||
97 | __func__, path, udi.udi_vendor, udi.udi_product); | ||
98 | fido_log_debug("%s: %s: productNo = 0x%04x, vendorNo = 0x%04x, " | ||
99 | "releaseNo = 0x%04x", __func__, path, udi.udi_productNo, | ||
100 | udi.udi_vendorNo, udi.udi_releaseNo); | ||
101 | |||
102 | di = &devlist[*olen]; | ||
103 | memset(di, 0, sizeof(*di)); | ||
104 | if ((di->path = strdup(path)) == NULL || | ||
105 | (di->manufacturer = strdup(udi.udi_vendor)) == NULL || | ||
106 | (di->product = strdup(udi.udi_product)) == NULL) { | ||
107 | free(di->path); | ||
108 | free(di->manufacturer); | ||
109 | free(di->product); | ||
110 | explicit_bzero(di, sizeof(*di)); | ||
111 | return FIDO_ERR_INTERNAL; | ||
112 | } | ||
113 | di->vendor_id = udi.udi_vendorNo; | ||
114 | di->product_id = udi.udi_productNo; | ||
115 | (*olen)++; | ||
116 | } | ||
117 | |||
118 | return FIDO_OK; | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * Workaround for OpenBSD <=6.6-current (as of 201910) bug that loses | ||
123 | * sync of DATA0/DATA1 sequence bit across uhid open/close. | ||
124 | * Send pings until we get a response - early pings with incorrect | ||
125 | * sequence bits will be ignored as duplicate packets by the device. | ||
126 | */ | ||
127 | static int | ||
128 | terrible_ping_kludge(struct hid_openbsd *ctx) | ||
129 | { | ||
130 | u_char data[256]; | ||
131 | int i, n; | ||
132 | struct pollfd pfd; | ||
133 | |||
134 | if (sizeof(data) < ctx->report_out_len + 1) | ||
135 | return -1; | ||
136 | for (i = 0; i < 4; i++) { | ||
137 | memset(data, 0, sizeof(data)); | ||
138 | /* broadcast channel ID */ | ||
139 | data[1] = 0xff; | ||
140 | data[2] = 0xff; | ||
141 | data[3] = 0xff; | ||
142 | data[4] = 0xff; | ||
143 | /* Ping command */ | ||
144 | data[5] = 0x81; | ||
145 | /* One byte ping only, Vasili */ | ||
146 | data[6] = 0; | ||
147 | data[7] = 1; | ||
148 | fido_log_debug("%s: send ping %d", __func__, i); | ||
149 | if (fido_hid_write(ctx, data, ctx->report_out_len + 1) == -1) | ||
150 | return -1; | ||
151 | fido_log_debug("%s: wait reply", __func__); | ||
152 | memset(&pfd, 0, sizeof(pfd)); | ||
153 | pfd.fd = ctx->fd; | ||
154 | pfd.events = POLLIN; | ||
155 | if ((n = poll(&pfd, 1, 100)) == -1) { | ||
156 | fido_log_debug("%s: poll: %s", __func__, strerror(errno)); | ||
157 | return -1; | ||
158 | } else if (n == 0) { | ||
159 | fido_log_debug("%s: timed out", __func__); | ||
160 | continue; | ||
161 | } | ||
162 | if (fido_hid_read(ctx, data, ctx->report_out_len, 250) == -1) | ||
163 | return -1; | ||
164 | /* | ||
165 | * Ping isn't always supported on the broadcast channel, | ||
166 | * so we might get an error, but we don't care - we're | ||
167 | * synched now. | ||
168 | */ | ||
169 | fido_log_debug("%s: got reply", __func__); | ||
170 | fido_log_xxd(data, ctx->report_out_len); | ||
171 | return 0; | ||
172 | } | ||
173 | fido_log_debug("%s: no response", __func__); | ||
174 | return -1; | ||
175 | } | ||
176 | |||
177 | void * | ||
178 | fido_hid_open(const char *path) | ||
179 | { | ||
180 | struct hid_openbsd *ret = NULL; | ||
181 | report_desc_t rdesc = NULL; | ||
182 | int len, usb_report_id = 0; | ||
183 | |||
184 | if ((ret = calloc(1, sizeof(*ret))) == NULL || | ||
185 | (ret->fd = open(path, O_RDWR)) < 0) { | ||
186 | free(ret); | ||
187 | return (NULL); | ||
188 | } | ||
189 | if (ioctl(ret->fd, USB_GET_REPORT_ID, &usb_report_id) != 0) { | ||
190 | fido_log_debug("%s: failed to get report ID: %s", __func__, | ||
191 | strerror(errno)); | ||
192 | goto fail; | ||
193 | } | ||
194 | if ((rdesc = hid_get_report_desc(ret->fd)) == NULL) { | ||
195 | fido_log_debug("%s: failed to get report descriptor", __func__); | ||
196 | goto fail; | ||
197 | } | ||
198 | if ((len = hid_report_size(rdesc, hid_input, usb_report_id)) <= 0 || | ||
199 | (size_t)len > MAX_REPORT_LEN) { | ||
200 | fido_log_debug("%s: bad input report size %d", __func__, len); | ||
201 | goto fail; | ||
202 | } | ||
203 | ret->report_in_len = (size_t)len; | ||
204 | if ((len = hid_report_size(rdesc, hid_output, usb_report_id)) <= 0 || | ||
205 | (size_t)len > MAX_REPORT_LEN) { | ||
206 | fido_log_debug("%s: bad output report size %d", __func__, len); | ||
207 | fail: | ||
208 | hid_dispose_report_desc(rdesc); | ||
209 | close(ret->fd); | ||
210 | free(ret); | ||
211 | return NULL; | ||
212 | } | ||
213 | ret->report_out_len = (size_t)len; | ||
214 | hid_dispose_report_desc(rdesc); | ||
215 | fido_log_debug("%s: USB report ID %d, inlen = %zu outlen = %zu", | ||
216 | __func__, usb_report_id, ret->report_in_len, ret->report_out_len); | ||
217 | |||
218 | /* | ||
219 | * OpenBSD (as of 201910) has a bug that causes it to lose | ||
220 | * track of the DATA0/DATA1 sequence toggle across uhid device | ||
221 | * open and close. This is a terrible hack to work around it. | ||
222 | */ | ||
223 | if (terrible_ping_kludge(ret) != 0) { | ||
224 | fido_hid_close(ret); | ||
225 | return NULL; | ||
226 | } | ||
227 | |||
228 | return (ret); | ||
229 | } | ||
230 | |||
231 | void | ||
232 | fido_hid_close(void *handle) | ||
233 | { | ||
234 | struct hid_openbsd *ctx = (struct hid_openbsd *)handle; | ||
235 | |||
236 | close(ctx->fd); | ||
237 | free(ctx); | ||
238 | } | ||
239 | |||
240 | int | ||
241 | fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) | ||
242 | { | ||
243 | struct hid_openbsd *ctx = (struct hid_openbsd *)handle; | ||
244 | ssize_t r; | ||
245 | |||
246 | (void)ms; /* XXX */ | ||
247 | |||
248 | if (len != ctx->report_in_len) { | ||
249 | fido_log_debug("%s: invalid len: got %zu, want %zu", __func__, | ||
250 | len, ctx->report_in_len); | ||
251 | return (-1); | ||
252 | } | ||
253 | if ((r = read(ctx->fd, buf, len)) == -1 || (size_t)r != len) { | ||
254 | fido_log_debug("%s: read: %s", __func__, strerror(errno)); | ||
255 | return (-1); | ||
256 | } | ||
257 | return ((int)len); | ||
258 | } | ||
259 | |||
260 | int | ||
261 | fido_hid_write(void *handle, const unsigned char *buf, size_t len) | ||
262 | { | ||
263 | struct hid_openbsd *ctx = (struct hid_openbsd *)handle; | ||
264 | ssize_t r; | ||
265 | |||
266 | if (len != ctx->report_out_len + 1) { | ||
267 | fido_log_debug("%s: invalid len: got %zu, want %zu", __func__, | ||
268 | len, ctx->report_out_len); | ||
269 | return (-1); | ||
270 | } | ||
271 | if ((r = write(ctx->fd, buf + 1, len - 1)) == -1 || | ||
272 | (size_t)r != len - 1) { | ||
273 | fido_log_debug("%s: write: %s", __func__, strerror(errno)); | ||
274 | return (-1); | ||
275 | } | ||
276 | return ((int)len); | ||
277 | } | ||
diff --git a/src/hid_osx.c b/src/hid_osx.c new file mode 100644 index 0000000..b705b43 --- /dev/null +++ b/src/hid_osx.c | |||
@@ -0,0 +1,410 @@ | |||
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 <sys/types.h> | ||
8 | |||
9 | #include <fcntl.h> | ||
10 | #include <string.h> | ||
11 | #ifdef HAVE_UNISTD_H | ||
12 | #include <unistd.h> | ||
13 | #endif | ||
14 | |||
15 | #include <CoreFoundation/CoreFoundation.h> | ||
16 | #include <IOKit/IOKitLib.h> | ||
17 | #include <IOKit/hid/IOHIDKeys.h> | ||
18 | #include <IOKit/hid/IOHIDManager.h> | ||
19 | |||
20 | #include "fido.h" | ||
21 | |||
22 | #define REPORT_LEN 65 | ||
23 | |||
24 | struct dev { | ||
25 | IOHIDDeviceRef ref; | ||
26 | CFStringRef loop_id; | ||
27 | }; | ||
28 | |||
29 | static int | ||
30 | get_int32(IOHIDDeviceRef dev, CFStringRef key, int32_t *v) | ||
31 | { | ||
32 | CFTypeRef ref; | ||
33 | |||
34 | if ((ref = IOHIDDeviceGetProperty(dev, key)) == NULL || | ||
35 | CFGetTypeID(ref) != CFNumberGetTypeID()) { | ||
36 | fido_log_debug("%s: IOHIDDeviceGetProperty", __func__); | ||
37 | return (-1); | ||
38 | } | ||
39 | |||
40 | if (CFNumberGetType(ref) != kCFNumberSInt32Type && | ||
41 | CFNumberGetType(ref) != kCFNumberSInt64Type) { | ||
42 | fido_log_debug("%s: CFNumberGetType", __func__); | ||
43 | return (-1); | ||
44 | } | ||
45 | |||
46 | if (CFNumberGetValue(ref, kCFNumberSInt32Type, v) == false) { | ||
47 | fido_log_debug("%s: CFNumberGetValue", __func__); | ||
48 | return (-1); | ||
49 | } | ||
50 | |||
51 | return (0); | ||
52 | } | ||
53 | |||
54 | static int | ||
55 | get_utf8(IOHIDDeviceRef dev, CFStringRef key, void *buf, size_t len) | ||
56 | { | ||
57 | CFTypeRef ref; | ||
58 | |||
59 | memset(buf, 0, len); | ||
60 | |||
61 | if ((ref = IOHIDDeviceGetProperty(dev, key)) == NULL || | ||
62 | CFGetTypeID(ref) != CFStringGetTypeID()) { | ||
63 | fido_log_debug("%s: IOHIDDeviceGetProperty", __func__); | ||
64 | return (-1); | ||
65 | } | ||
66 | |||
67 | if (CFStringGetCString(ref, buf, len, kCFStringEncodingUTF8) == false) { | ||
68 | fido_log_debug("%s: CFStringGetCString", __func__); | ||
69 | return (-1); | ||
70 | } | ||
71 | |||
72 | return (0); | ||
73 | } | ||
74 | |||
75 | static bool | ||
76 | is_fido(IOHIDDeviceRef dev) | ||
77 | { | ||
78 | uint32_t usage_page; | ||
79 | int32_t report_len; | ||
80 | |||
81 | if (get_int32(dev, CFSTR(kIOHIDPrimaryUsagePageKey), | ||
82 | (int32_t *)&usage_page) != 0 || usage_page != 0xf1d0) | ||
83 | return (false); | ||
84 | |||
85 | if (get_int32(dev, CFSTR(kIOHIDMaxInputReportSizeKey), | ||
86 | &report_len) < 0 || report_len != REPORT_LEN - 1) { | ||
87 | fido_log_debug("%s: unsupported report len", __func__); | ||
88 | return (false); | ||
89 | } | ||
90 | |||
91 | return (true); | ||
92 | } | ||
93 | |||
94 | static int | ||
95 | get_id(IOHIDDeviceRef dev, int16_t *vendor_id, int16_t *product_id) | ||
96 | { | ||
97 | int32_t vendor; | ||
98 | int32_t product; | ||
99 | |||
100 | if (get_int32(dev, CFSTR(kIOHIDVendorIDKey), &vendor) < 0 || | ||
101 | vendor > UINT16_MAX) { | ||
102 | fido_log_debug("%s: get_int32 vendor", __func__); | ||
103 | return (-1); | ||
104 | } | ||
105 | |||
106 | if (get_int32(dev, CFSTR(kIOHIDProductIDKey), &product) < 0 || | ||
107 | product > UINT16_MAX) { | ||
108 | fido_log_debug("%s: get_int32 product", __func__); | ||
109 | return (-1); | ||
110 | } | ||
111 | |||
112 | *vendor_id = (int16_t)vendor; | ||
113 | *product_id = (int16_t)product; | ||
114 | |||
115 | return (0); | ||
116 | } | ||
117 | |||
118 | static int | ||
119 | get_str(IOHIDDeviceRef dev, char **manufacturer, char **product) | ||
120 | { | ||
121 | char buf[512]; | ||
122 | int ok = -1; | ||
123 | |||
124 | *manufacturer = NULL; | ||
125 | *product = NULL; | ||
126 | |||
127 | if (get_utf8(dev, CFSTR(kIOHIDManufacturerKey), buf, sizeof(buf)) < 0) { | ||
128 | fido_log_debug("%s: get_utf8 manufacturer", __func__); | ||
129 | goto fail; | ||
130 | } | ||
131 | |||
132 | if ((*manufacturer = strdup(buf)) == NULL) { | ||
133 | fido_log_debug("%s: strdup manufacturer", __func__); | ||
134 | goto fail; | ||
135 | } | ||
136 | |||
137 | if (get_utf8(dev, CFSTR(kIOHIDProductKey), buf, sizeof(buf)) < 0) { | ||
138 | fido_log_debug("%s: get_utf8 product", __func__); | ||
139 | goto fail; | ||
140 | } | ||
141 | |||
142 | if ((*product = strdup(buf)) == NULL) { | ||
143 | fido_log_debug("%s: strdup product", __func__); | ||
144 | goto fail; | ||
145 | } | ||
146 | |||
147 | ok = 0; | ||
148 | fail: | ||
149 | if (ok < 0) { | ||
150 | free(*manufacturer); | ||
151 | free(*product); | ||
152 | *manufacturer = NULL; | ||
153 | *product = NULL; | ||
154 | } | ||
155 | |||
156 | return (ok); | ||
157 | } | ||
158 | |||
159 | static char * | ||
160 | get_path(IOHIDDeviceRef dev) | ||
161 | { | ||
162 | io_service_t s; | ||
163 | io_string_t path; | ||
164 | |||
165 | if ((s = IOHIDDeviceGetService(dev)) == MACH_PORT_NULL) { | ||
166 | fido_log_debug("%s: IOHIDDeviceGetService", __func__); | ||
167 | return (NULL); | ||
168 | } | ||
169 | |||
170 | if (IORegistryEntryGetPath(s, kIOServicePlane, path) != KERN_SUCCESS) { | ||
171 | fido_log_debug("%s: IORegistryEntryGetPath", __func__); | ||
172 | return (NULL); | ||
173 | } | ||
174 | |||
175 | return (strdup(path)); | ||
176 | } | ||
177 | |||
178 | static int | ||
179 | copy_info(fido_dev_info_t *di, IOHIDDeviceRef dev) | ||
180 | { | ||
181 | memset(di, 0, sizeof(*di)); | ||
182 | |||
183 | if (is_fido(dev) == false) | ||
184 | return (-1); | ||
185 | |||
186 | if (get_id(dev, &di->vendor_id, &di->product_id) < 0 || | ||
187 | get_str(dev, &di->manufacturer, &di->product) < 0 || | ||
188 | (di->path = get_path(dev)) == NULL) { | ||
189 | free(di->path); | ||
190 | free(di->manufacturer); | ||
191 | free(di->product); | ||
192 | explicit_bzero(di, sizeof(*di)); | ||
193 | return (-1); | ||
194 | } | ||
195 | |||
196 | return (0); | ||
197 | } | ||
198 | |||
199 | int | ||
200 | fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) | ||
201 | { | ||
202 | IOHIDManagerRef manager = NULL; | ||
203 | CFSetRef devset = NULL; | ||
204 | CFIndex devcnt; | ||
205 | IOHIDDeviceRef *devs = NULL; | ||
206 | int r = FIDO_ERR_INTERNAL; | ||
207 | |||
208 | *olen = 0; | ||
209 | |||
210 | if (ilen == 0) | ||
211 | return (FIDO_OK); /* nothing to do */ | ||
212 | |||
213 | if (devlist == NULL) | ||
214 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
215 | |||
216 | if ((manager = IOHIDManagerCreate(kCFAllocatorDefault, | ||
217 | kIOHIDManagerOptionNone)) == NULL) { | ||
218 | fido_log_debug("%s: IOHIDManagerCreate", __func__); | ||
219 | goto fail; | ||
220 | } | ||
221 | |||
222 | IOHIDManagerSetDeviceMatching(manager, NULL); | ||
223 | |||
224 | if ((devset = IOHIDManagerCopyDevices(manager)) == NULL) { | ||
225 | fido_log_debug("%s: IOHIDManagerCopyDevices", __func__); | ||
226 | goto fail; | ||
227 | } | ||
228 | |||
229 | if ((devcnt = CFSetGetCount(devset)) < 0) { | ||
230 | fido_log_debug("%s: CFSetGetCount", __func__); | ||
231 | goto fail; | ||
232 | } | ||
233 | |||
234 | if ((devs = calloc(devcnt, sizeof(*devs))) == NULL) { | ||
235 | fido_log_debug("%s: calloc", __func__); | ||
236 | goto fail; | ||
237 | } | ||
238 | |||
239 | CFSetGetValues(devset, (void *)devs); | ||
240 | |||
241 | for (CFIndex i = 0; i < devcnt; i++) { | ||
242 | if (copy_info(&devlist[*olen], devs[i]) == 0) { | ||
243 | if (++(*olen) == ilen) | ||
244 | break; | ||
245 | } | ||
246 | } | ||
247 | |||
248 | r = FIDO_OK; | ||
249 | fail: | ||
250 | if (manager != NULL) | ||
251 | CFRelease(manager); | ||
252 | if (devset != NULL) | ||
253 | CFRelease(devset); | ||
254 | |||
255 | free(devs); | ||
256 | |||
257 | return (r); | ||
258 | } | ||
259 | |||
260 | void * | ||
261 | fido_hid_open(const char *path) | ||
262 | { | ||
263 | io_registry_entry_t entry = MACH_PORT_NULL; | ||
264 | struct dev *dev = NULL; | ||
265 | int ok = -1; | ||
266 | int r; | ||
267 | char loop_id[32]; | ||
268 | |||
269 | if ((dev = calloc(1, sizeof(*dev))) == NULL) { | ||
270 | fido_log_debug("%s: calloc", __func__); | ||
271 | goto fail; | ||
272 | } | ||
273 | |||
274 | if ((entry = IORegistryEntryFromPath(kIOMasterPortDefault, | ||
275 | path)) == MACH_PORT_NULL) { | ||
276 | fido_log_debug("%s: IORegistryEntryFromPath", __func__); | ||
277 | goto fail; | ||
278 | } | ||
279 | |||
280 | if ((dev->ref = IOHIDDeviceCreate(kCFAllocatorDefault, | ||
281 | entry)) == NULL) { | ||
282 | fido_log_debug("%s: IOHIDDeviceCreate", __func__); | ||
283 | goto fail; | ||
284 | } | ||
285 | |||
286 | if (IOHIDDeviceOpen(dev->ref, | ||
287 | kIOHIDOptionsTypeSeizeDevice) != kIOReturnSuccess) { | ||
288 | fido_log_debug("%s: IOHIDDeviceOpen", __func__); | ||
289 | goto fail; | ||
290 | } | ||
291 | |||
292 | if ((r = snprintf(loop_id, sizeof(loop_id), "fido2-%p", | ||
293 | (void *)dev->ref)) < 0 || (size_t)r >= sizeof(loop_id)) { | ||
294 | fido_log_debug("%s: snprintf", __func__); | ||
295 | goto fail; | ||
296 | } | ||
297 | |||
298 | if ((dev->loop_id = CFStringCreateWithCString(NULL, loop_id, | ||
299 | kCFStringEncodingASCII)) == NULL) { | ||
300 | fido_log_debug("%s: CFStringCreateWithCString", __func__); | ||
301 | goto fail; | ||
302 | } | ||
303 | |||
304 | ok = 0; | ||
305 | fail: | ||
306 | if (entry != MACH_PORT_NULL) | ||
307 | IOObjectRelease(entry); | ||
308 | |||
309 | if (ok < 0 && dev != NULL) { | ||
310 | if (dev->ref != NULL) | ||
311 | CFRelease(dev->ref); | ||
312 | if (dev->loop_id != NULL) | ||
313 | CFRelease(dev->loop_id); | ||
314 | free(dev); | ||
315 | dev = NULL; | ||
316 | } | ||
317 | |||
318 | return (dev); | ||
319 | } | ||
320 | |||
321 | void | ||
322 | fido_hid_close(void *handle) | ||
323 | { | ||
324 | struct dev *dev = handle; | ||
325 | |||
326 | if (IOHIDDeviceClose(dev->ref, | ||
327 | kIOHIDOptionsTypeSeizeDevice) != kIOReturnSuccess) | ||
328 | fido_log_debug("%s: IOHIDDeviceClose", __func__); | ||
329 | |||
330 | CFRelease(dev->ref); | ||
331 | CFRelease(dev->loop_id); | ||
332 | |||
333 | free(dev); | ||
334 | } | ||
335 | |||
336 | static void | ||
337 | read_callback(void *context, IOReturn result, void *dev, IOHIDReportType type, | ||
338 | uint32_t report_id, uint8_t *report, CFIndex report_len) | ||
339 | { | ||
340 | (void)context; | ||
341 | (void)dev; | ||
342 | (void)report; | ||
343 | |||
344 | if (result != kIOReturnSuccess || type != kIOHIDReportTypeInput || | ||
345 | report_id != 0 || report_len != REPORT_LEN - 1) { | ||
346 | fido_log_debug("%s: io error", __func__); | ||
347 | } | ||
348 | } | ||
349 | |||
350 | static void | ||
351 | removal_callback(void *context, IOReturn result, void *sender) | ||
352 | { | ||
353 | (void)context; | ||
354 | (void)result; | ||
355 | (void)sender; | ||
356 | |||
357 | CFRunLoopStop(CFRunLoopGetCurrent()); | ||
358 | } | ||
359 | |||
360 | int | ||
361 | fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) | ||
362 | { | ||
363 | struct dev *dev = handle; | ||
364 | CFRunLoopRunResult r; | ||
365 | |||
366 | (void)ms; /* XXX */ | ||
367 | |||
368 | if (len != REPORT_LEN - 1) { | ||
369 | fido_log_debug("%s: invalid len", __func__); | ||
370 | return (-1); | ||
371 | } | ||
372 | |||
373 | explicit_bzero(buf, len); | ||
374 | |||
375 | IOHIDDeviceRegisterInputReportCallback(dev->ref, buf, len, | ||
376 | &read_callback, NULL); | ||
377 | IOHIDDeviceRegisterRemovalCallback(dev->ref, &removal_callback, dev); | ||
378 | IOHIDDeviceScheduleWithRunLoop(dev->ref, CFRunLoopGetCurrent(), | ||
379 | dev->loop_id); | ||
380 | |||
381 | do | ||
382 | r = CFRunLoopRunInMode(dev->loop_id, 0.003, true); | ||
383 | while (r != kCFRunLoopRunHandledSource); | ||
384 | |||
385 | IOHIDDeviceRegisterInputReportCallback(dev->ref, buf, len, NULL, NULL); | ||
386 | IOHIDDeviceRegisterRemovalCallback(dev->ref, NULL, NULL); | ||
387 | IOHIDDeviceUnscheduleFromRunLoop(dev->ref, CFRunLoopGetCurrent(), | ||
388 | dev->loop_id); | ||
389 | |||
390 | return (REPORT_LEN - 1); | ||
391 | } | ||
392 | |||
393 | int | ||
394 | fido_hid_write(void *handle, const unsigned char *buf, size_t len) | ||
395 | { | ||
396 | struct dev *dev = handle; | ||
397 | |||
398 | if (len != REPORT_LEN) { | ||
399 | fido_log_debug("%s: invalid len", __func__); | ||
400 | return (-1); | ||
401 | } | ||
402 | |||
403 | if (IOHIDDeviceSetReport(dev->ref, kIOHIDReportTypeOutput, 0, buf + 1, | ||
404 | len - 1) != kIOReturnSuccess) { | ||
405 | fido_log_debug("%s: IOHIDDeviceSetReport", __func__); | ||
406 | return (-1); | ||
407 | } | ||
408 | |||
409 | return (REPORT_LEN); | ||
410 | } | ||
diff --git a/src/hid_win.c b/src/hid_win.c new file mode 100644 index 0000000..6d93778 --- /dev/null +++ b/src/hid_win.c | |||
@@ -0,0 +1,324 @@ | |||
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 <sys/types.h> | ||
8 | |||
9 | #include <fcntl.h> | ||
10 | #include <string.h> | ||
11 | #ifdef HAVE_UNISTD_H | ||
12 | #include <unistd.h> | ||
13 | #endif | ||
14 | #include <windows.h> | ||
15 | #include <setupapi.h> | ||
16 | #include <initguid.h> | ||
17 | #include <hidclass.h> | ||
18 | #include <hidsdi.h> | ||
19 | |||
20 | #include "fido.h" | ||
21 | |||
22 | #define REPORT_LEN 65 | ||
23 | |||
24 | static bool | ||
25 | is_fido(HANDLE dev) | ||
26 | { | ||
27 | PHIDP_PREPARSED_DATA data = NULL; | ||
28 | HIDP_CAPS caps; | ||
29 | uint16_t usage_page = 0; | ||
30 | |||
31 | if (HidD_GetPreparsedData(dev, &data) == false) { | ||
32 | fido_log_debug("%s: HidD_GetPreparsedData", __func__); | ||
33 | goto fail; | ||
34 | } | ||
35 | |||
36 | if (HidP_GetCaps(data, &caps) != HIDP_STATUS_SUCCESS) { | ||
37 | fido_log_debug("%s: HidP_GetCaps", __func__); | ||
38 | goto fail; | ||
39 | } | ||
40 | |||
41 | if (caps.OutputReportByteLength != REPORT_LEN || | ||
42 | caps.InputReportByteLength != REPORT_LEN) { | ||
43 | fido_log_debug("%s: unsupported report len", __func__); | ||
44 | goto fail; | ||
45 | } | ||
46 | |||
47 | usage_page = caps.UsagePage; | ||
48 | fail: | ||
49 | if (data != NULL) | ||
50 | HidD_FreePreparsedData(data); | ||
51 | |||
52 | return (usage_page == 0xf1d0); | ||
53 | } | ||
54 | |||
55 | static int | ||
56 | get_int(HANDLE dev, int16_t *vendor_id, int16_t *product_id) | ||
57 | { | ||
58 | HIDD_ATTRIBUTES attr; | ||
59 | |||
60 | attr.Size = sizeof(attr); | ||
61 | |||
62 | if (HidD_GetAttributes(dev, &attr) == false) { | ||
63 | fido_log_debug("%s: HidD_GetAttributes", __func__); | ||
64 | return (-1); | ||
65 | } | ||
66 | |||
67 | *vendor_id = attr.VendorID; | ||
68 | *product_id = attr.ProductID; | ||
69 | |||
70 | return (0); | ||
71 | } | ||
72 | |||
73 | static int | ||
74 | get_str(HANDLE dev, char **manufacturer, char **product) | ||
75 | { | ||
76 | wchar_t buf[512]; | ||
77 | int utf8_len; | ||
78 | int ok = -1; | ||
79 | |||
80 | *manufacturer = NULL; | ||
81 | *product = NULL; | ||
82 | |||
83 | if (HidD_GetManufacturerString(dev, &buf, sizeof(buf)) == false) { | ||
84 | fido_log_debug("%s: HidD_GetManufacturerString", __func__); | ||
85 | goto fail; | ||
86 | } | ||
87 | |||
88 | if ((utf8_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, buf, | ||
89 | -1, NULL, 0, NULL, NULL)) <= 0 || utf8_len > 128) { | ||
90 | fido_log_debug("%s: WideCharToMultiByte", __func__); | ||
91 | goto fail; | ||
92 | } | ||
93 | |||
94 | if ((*manufacturer = malloc(utf8_len)) == NULL) { | ||
95 | fido_log_debug("%s: malloc", __func__); | ||
96 | goto fail; | ||
97 | } | ||
98 | |||
99 | if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, buf, -1, | ||
100 | *manufacturer, utf8_len, NULL, NULL) != utf8_len) { | ||
101 | fido_log_debug("%s: WideCharToMultiByte", __func__); | ||
102 | goto fail; | ||
103 | } | ||
104 | |||
105 | if (HidD_GetProductString(dev, &buf, sizeof(buf)) == false) { | ||
106 | fido_log_debug("%s: HidD_GetProductString", __func__); | ||
107 | goto fail; | ||
108 | } | ||
109 | |||
110 | if ((utf8_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, buf, | ||
111 | -1, NULL, 0, NULL, NULL)) <= 0 || utf8_len > 128) { | ||
112 | fido_log_debug("%s: WideCharToMultiByte", __func__); | ||
113 | goto fail; | ||
114 | } | ||
115 | |||
116 | if ((*product = malloc(utf8_len)) == NULL) { | ||
117 | fido_log_debug("%s: malloc", __func__); | ||
118 | goto fail; | ||
119 | } | ||
120 | |||
121 | if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, buf, -1, | ||
122 | *product, utf8_len, NULL, NULL) != utf8_len) { | ||
123 | fido_log_debug("%s: WideCharToMultiByte", __func__); | ||
124 | goto fail; | ||
125 | } | ||
126 | |||
127 | ok = 0; | ||
128 | fail: | ||
129 | if (ok < 0) { | ||
130 | free(*manufacturer); | ||
131 | free(*product); | ||
132 | *manufacturer = NULL; | ||
133 | *product = NULL; | ||
134 | } | ||
135 | |||
136 | return (ok); | ||
137 | } | ||
138 | |||
139 | static int | ||
140 | copy_info(fido_dev_info_t *di, const char *path) | ||
141 | { | ||
142 | HANDLE dev = INVALID_HANDLE_VALUE; | ||
143 | int ok = -1; | ||
144 | |||
145 | memset(di, 0, sizeof(*di)); | ||
146 | |||
147 | dev = CreateFileA(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, | ||
148 | OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | ||
149 | if (dev == INVALID_HANDLE_VALUE || is_fido(dev) == 0) | ||
150 | goto fail; | ||
151 | |||
152 | if (get_int(dev, &di->vendor_id, &di->product_id) < 0 || | ||
153 | get_str(dev, &di->manufacturer, &di->product) < 0) | ||
154 | goto fail; | ||
155 | |||
156 | if ((di->path = strdup(path)) == NULL) | ||
157 | goto fail; | ||
158 | |||
159 | ok = 0; | ||
160 | fail: | ||
161 | if (dev != INVALID_HANDLE_VALUE) | ||
162 | CloseHandle(dev); | ||
163 | |||
164 | if (ok < 0) { | ||
165 | free(di->path); | ||
166 | free(di->manufacturer); | ||
167 | free(di->product); | ||
168 | explicit_bzero(di, sizeof(*di)); | ||
169 | } | ||
170 | |||
171 | return (ok); | ||
172 | } | ||
173 | |||
174 | int | ||
175 | fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) | ||
176 | { | ||
177 | GUID hid_guid = GUID_DEVINTERFACE_HID; | ||
178 | HDEVINFO devinfo = INVALID_HANDLE_VALUE; | ||
179 | SP_DEVICE_INTERFACE_DATA ifdata; | ||
180 | SP_DEVICE_INTERFACE_DETAIL_DATA_A *ifdetail = NULL; | ||
181 | DWORD len = 0; | ||
182 | DWORD idx = 0; | ||
183 | int r = FIDO_ERR_INTERNAL; | ||
184 | |||
185 | *olen = 0; | ||
186 | |||
187 | if (ilen == 0) | ||
188 | return (FIDO_OK); /* nothing to do */ | ||
189 | |||
190 | if (devlist == NULL) | ||
191 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
192 | |||
193 | devinfo = SetupDiGetClassDevsA(&hid_guid, NULL, NULL, | ||
194 | DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); | ||
195 | if (devinfo == INVALID_HANDLE_VALUE) { | ||
196 | fido_log_debug("%s: SetupDiGetClassDevsA", __func__); | ||
197 | goto fail; | ||
198 | } | ||
199 | |||
200 | ifdata.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); | ||
201 | |||
202 | while (SetupDiEnumDeviceInterfaces(devinfo, NULL, &hid_guid, idx++, | ||
203 | &ifdata) == true) { | ||
204 | /* | ||
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 | if (++(*olen) == ilen) | ||
238 | break; | ||
239 | } | ||
240 | |||
241 | free(ifdetail); | ||
242 | ifdetail = NULL; | ||
243 | } | ||
244 | |||
245 | r = FIDO_OK; | ||
246 | fail: | ||
247 | if (devinfo != INVALID_HANDLE_VALUE) | ||
248 | SetupDiDestroyDeviceInfoList(devinfo); | ||
249 | |||
250 | free(ifdetail); | ||
251 | |||
252 | return (r); | ||
253 | } | ||
254 | |||
255 | void * | ||
256 | fido_hid_open(const char *path) | ||
257 | { | ||
258 | HANDLE dev; | ||
259 | |||
260 | dev = CreateFileA(path, GENERIC_READ | GENERIC_WRITE, | ||
261 | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, | ||
262 | FILE_ATTRIBUTE_NORMAL, NULL); | ||
263 | |||
264 | if (dev == INVALID_HANDLE_VALUE) | ||
265 | return (NULL); | ||
266 | |||
267 | return (dev); | ||
268 | } | ||
269 | |||
270 | void | ||
271 | fido_hid_close(void *handle) | ||
272 | { | ||
273 | CloseHandle(handle); | ||
274 | } | ||
275 | |||
276 | int | ||
277 | fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) | ||
278 | { | ||
279 | DWORD n; | ||
280 | int r = -1; | ||
281 | uint8_t report[REPORT_LEN]; | ||
282 | |||
283 | (void)ms; /* XXX */ | ||
284 | |||
285 | memset(report, 0, sizeof(report)); | ||
286 | |||
287 | if (len != sizeof(report) - 1) { | ||
288 | fido_log_debug("%s: invalid len", __func__); | ||
289 | return (-1); | ||
290 | } | ||
291 | |||
292 | if (ReadFile(handle, report, sizeof(report), &n, NULL) == false || | ||
293 | n != sizeof(report)) { | ||
294 | fido_log_debug("%s: ReadFile", __func__); | ||
295 | goto fail; | ||
296 | } | ||
297 | |||
298 | r = sizeof(report) - 1; | ||
299 | memcpy(buf, report + 1, len); | ||
300 | |||
301 | fail: | ||
302 | explicit_bzero(report, sizeof(report)); | ||
303 | |||
304 | return (r); | ||
305 | } | ||
306 | |||
307 | int | ||
308 | fido_hid_write(void *handle, const unsigned char *buf, size_t len) | ||
309 | { | ||
310 | DWORD n; | ||
311 | |||
312 | if (len != REPORT_LEN) { | ||
313 | fido_log_debug("%s: invalid len", __func__); | ||
314 | return (-1); | ||
315 | } | ||
316 | |||
317 | if (WriteFile(handle, buf, (DWORD)len, &n, NULL) == false || | ||
318 | n != REPORT_LEN) { | ||
319 | fido_log_debug("%s: WriteFile", __func__); | ||
320 | return (-1); | ||
321 | } | ||
322 | |||
323 | return (REPORT_LEN); | ||
324 | } | ||
diff --git a/src/info.c b/src/info.c new file mode 100644 index 0000000..e896503 --- /dev/null +++ b/src/info.c | |||
@@ -0,0 +1,410 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <string.h> | ||
8 | #include "fido.h" | ||
9 | |||
10 | static int | ||
11 | decode_version(const cbor_item_t *item, void *arg) | ||
12 | { | ||
13 | fido_str_array_t *v = arg; | ||
14 | const size_t i = v->len; | ||
15 | |||
16 | /* keep ptr[x] and len consistent */ | ||
17 | if (cbor_string_copy(item, &v->ptr[i]) < 0) { | ||
18 | fido_log_debug("%s: cbor_string_copy", __func__); | ||
19 | return (-1); | ||
20 | } | ||
21 | |||
22 | v->len++; | ||
23 | |||
24 | return (0); | ||
25 | } | ||
26 | |||
27 | static int | ||
28 | decode_versions(const cbor_item_t *item, fido_str_array_t *v) | ||
29 | { | ||
30 | v->ptr = NULL; | ||
31 | v->len = 0; | ||
32 | |||
33 | if (cbor_isa_array(item) == false || | ||
34 | cbor_array_is_definite(item) == false) { | ||
35 | fido_log_debug("%s: cbor type", __func__); | ||
36 | return (-1); | ||
37 | } | ||
38 | |||
39 | v->ptr = calloc(cbor_array_size(item), sizeof(char *)); | ||
40 | if (v->ptr == NULL) | ||
41 | return (-1); | ||
42 | |||
43 | if (cbor_array_iter(item, v, decode_version) < 0) { | ||
44 | fido_log_debug("%s: decode_version", __func__); | ||
45 | return (-1); | ||
46 | } | ||
47 | |||
48 | return (0); | ||
49 | } | ||
50 | |||
51 | static int | ||
52 | decode_extension(const cbor_item_t *item, void *arg) | ||
53 | { | ||
54 | fido_str_array_t *e = arg; | ||
55 | const size_t i = e->len; | ||
56 | |||
57 | /* keep ptr[x] and len consistent */ | ||
58 | if (cbor_string_copy(item, &e->ptr[i]) < 0) { | ||
59 | fido_log_debug("%s: cbor_string_copy", __func__); | ||
60 | return (-1); | ||
61 | } | ||
62 | |||
63 | e->len++; | ||
64 | |||
65 | return (0); | ||
66 | } | ||
67 | |||
68 | static int | ||
69 | decode_extensions(const cbor_item_t *item, fido_str_array_t *e) | ||
70 | { | ||
71 | e->ptr = NULL; | ||
72 | e->len = 0; | ||
73 | |||
74 | if (cbor_isa_array(item) == false || | ||
75 | cbor_array_is_definite(item) == false) { | ||
76 | fido_log_debug("%s: cbor type", __func__); | ||
77 | return (-1); | ||
78 | } | ||
79 | |||
80 | e->ptr = calloc(cbor_array_size(item), sizeof(char *)); | ||
81 | if (e->ptr == NULL) | ||
82 | return (-1); | ||
83 | |||
84 | if (cbor_array_iter(item, e, decode_extension) < 0) { | ||
85 | fido_log_debug("%s: decode_extension", __func__); | ||
86 | return (-1); | ||
87 | } | ||
88 | |||
89 | return (0); | ||
90 | } | ||
91 | |||
92 | static int | ||
93 | decode_aaguid(const cbor_item_t *item, unsigned char *aaguid, size_t aaguid_len) | ||
94 | { | ||
95 | if (cbor_isa_bytestring(item) == false || | ||
96 | cbor_bytestring_is_definite(item) == false || | ||
97 | cbor_bytestring_length(item) != aaguid_len) { | ||
98 | fido_log_debug("%s: cbor type", __func__); | ||
99 | return (-1); | ||
100 | } | ||
101 | |||
102 | memcpy(aaguid, cbor_bytestring_handle(item), aaguid_len); | ||
103 | |||
104 | return (0); | ||
105 | } | ||
106 | |||
107 | static int | ||
108 | decode_option(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
109 | { | ||
110 | fido_opt_array_t *o = arg; | ||
111 | const size_t i = o->len; | ||
112 | |||
113 | if (cbor_isa_float_ctrl(val) == false || | ||
114 | cbor_float_get_width(val) != CBOR_FLOAT_0 || | ||
115 | cbor_is_bool(val) == false) { | ||
116 | fido_log_debug("%s: cbor type", __func__); | ||
117 | return (0); /* ignore */ | ||
118 | } | ||
119 | |||
120 | if (cbor_string_copy(key, &o->name[i]) < 0) { | ||
121 | fido_log_debug("%s: cbor_string_copy", __func__); | ||
122 | return (0); /* ignore */ | ||
123 | } | ||
124 | |||
125 | /* keep name/value and len consistent */ | ||
126 | o->value[i] = cbor_ctrl_value(val) == CBOR_CTRL_TRUE; | ||
127 | o->len++; | ||
128 | |||
129 | return (0); | ||
130 | } | ||
131 | |||
132 | static int | ||
133 | decode_options(const cbor_item_t *item, fido_opt_array_t *o) | ||
134 | { | ||
135 | o->name = NULL; | ||
136 | o->value = NULL; | ||
137 | o->len = 0; | ||
138 | |||
139 | if (cbor_isa_map(item) == false || | ||
140 | cbor_map_is_definite(item) == false) { | ||
141 | fido_log_debug("%s: cbor type", __func__); | ||
142 | return (-1); | ||
143 | } | ||
144 | |||
145 | o->name = calloc(cbor_map_size(item), sizeof(char *)); | ||
146 | o->value = calloc(cbor_map_size(item), sizeof(bool)); | ||
147 | if (o->name == NULL || o->value == NULL) | ||
148 | return (-1); | ||
149 | |||
150 | return (cbor_map_iter(item, o, decode_option)); | ||
151 | } | ||
152 | |||
153 | static int | ||
154 | decode_protocol(const cbor_item_t *item, void *arg) | ||
155 | { | ||
156 | fido_byte_array_t *p = arg; | ||
157 | const size_t i = p->len; | ||
158 | |||
159 | if (cbor_isa_uint(item) == false || | ||
160 | cbor_int_get_width(item) != CBOR_INT_8) { | ||
161 | fido_log_debug("%s: cbor type", __func__); | ||
162 | return (-1); | ||
163 | } | ||
164 | |||
165 | /* keep ptr[x] and len consistent */ | ||
166 | p->ptr[i] = cbor_get_uint8(item); | ||
167 | p->len++; | ||
168 | |||
169 | return (0); | ||
170 | } | ||
171 | |||
172 | static int | ||
173 | decode_protocols(const cbor_item_t *item, fido_byte_array_t *p) | ||
174 | { | ||
175 | p->ptr = NULL; | ||
176 | p->len = 0; | ||
177 | |||
178 | if (cbor_isa_array(item) == false || | ||
179 | cbor_array_is_definite(item) == false) { | ||
180 | fido_log_debug("%s: cbor type", __func__); | ||
181 | return (-1); | ||
182 | } | ||
183 | |||
184 | p->ptr = calloc(cbor_array_size(item), sizeof(uint8_t)); | ||
185 | if (p->ptr == NULL) | ||
186 | return (-1); | ||
187 | |||
188 | if (cbor_array_iter(item, p, decode_protocol) < 0) { | ||
189 | fido_log_debug("%s: decode_protocol", __func__); | ||
190 | return (-1); | ||
191 | } | ||
192 | |||
193 | return (0); | ||
194 | } | ||
195 | |||
196 | static int | ||
197 | parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
198 | { | ||
199 | fido_cbor_info_t *ci = arg; | ||
200 | |||
201 | if (cbor_isa_uint(key) == false || | ||
202 | cbor_int_get_width(key) != CBOR_INT_8) { | ||
203 | fido_log_debug("%s: cbor type", __func__); | ||
204 | return (0); /* ignore */ | ||
205 | } | ||
206 | |||
207 | switch (cbor_get_uint8(key)) { | ||
208 | case 1: /* versions */ | ||
209 | return (decode_versions(val, &ci->versions)); | ||
210 | case 2: /* extensions */ | ||
211 | return (decode_extensions(val, &ci->extensions)); | ||
212 | case 3: /* aaguid */ | ||
213 | return (decode_aaguid(val, ci->aaguid, sizeof(ci->aaguid))); | ||
214 | case 4: /* options */ | ||
215 | return (decode_options(val, &ci->options)); | ||
216 | case 5: /* maxMsgSize */ | ||
217 | return (cbor_decode_uint64(val, &ci->maxmsgsiz)); | ||
218 | case 6: /* pinProtocols */ | ||
219 | return (decode_protocols(val, &ci->protocols)); | ||
220 | default: /* ignore */ | ||
221 | fido_log_debug("%s: cbor type", __func__); | ||
222 | return (0); | ||
223 | } | ||
224 | } | ||
225 | |||
226 | static int | ||
227 | fido_dev_get_cbor_info_tx(fido_dev_t *dev) | ||
228 | { | ||
229 | const unsigned char cbor[] = { CTAP_CBOR_GETINFO }; | ||
230 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
231 | |||
232 | fido_log_debug("%s: dev=%p", __func__, (void *)dev); | ||
233 | |||
234 | if (fido_tx(dev, cmd, cbor, sizeof(cbor)) < 0) { | ||
235 | fido_log_debug("%s: fido_tx", __func__); | ||
236 | return (FIDO_ERR_TX); | ||
237 | } | ||
238 | |||
239 | return (FIDO_OK); | ||
240 | } | ||
241 | |||
242 | static int | ||
243 | fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) | ||
244 | { | ||
245 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
246 | unsigned char reply[512]; | ||
247 | int reply_len; | ||
248 | |||
249 | fido_log_debug("%s: dev=%p, ci=%p, ms=%d", __func__, (void *)dev, | ||
250 | (void *)ci, ms); | ||
251 | |||
252 | memset(ci, 0, sizeof(*ci)); | ||
253 | |||
254 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
255 | fido_log_debug("%s: fido_rx", __func__); | ||
256 | return (FIDO_ERR_RX); | ||
257 | } | ||
258 | |||
259 | return (cbor_parse_reply(reply, (size_t)reply_len, ci, | ||
260 | parse_reply_element)); | ||
261 | } | ||
262 | |||
263 | static int | ||
264 | fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) | ||
265 | { | ||
266 | int r; | ||
267 | |||
268 | if ((r = fido_dev_get_cbor_info_tx(dev)) != FIDO_OK || | ||
269 | (r = fido_dev_get_cbor_info_rx(dev, ci, ms)) != FIDO_OK) | ||
270 | return (r); | ||
271 | |||
272 | return (FIDO_OK); | ||
273 | } | ||
274 | |||
275 | int | ||
276 | fido_dev_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci) | ||
277 | { | ||
278 | return (fido_dev_get_cbor_info_wait(dev, ci, -1)); | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * get/set functions for fido_cbor_info_t; always at the end of the file | ||
283 | */ | ||
284 | |||
285 | fido_cbor_info_t * | ||
286 | fido_cbor_info_new(void) | ||
287 | { | ||
288 | return (calloc(1, sizeof(fido_cbor_info_t))); | ||
289 | } | ||
290 | |||
291 | static void | ||
292 | free_str_array(fido_str_array_t *sa) | ||
293 | { | ||
294 | for (size_t i = 0; i < sa->len; i++) | ||
295 | free(sa->ptr[i]); | ||
296 | |||
297 | free(sa->ptr); | ||
298 | sa->ptr = NULL; | ||
299 | sa->len = 0; | ||
300 | } | ||
301 | |||
302 | static void | ||
303 | free_opt_array(fido_opt_array_t *oa) | ||
304 | { | ||
305 | for (size_t i = 0; i < oa->len; i++) | ||
306 | free(oa->name[i]); | ||
307 | |||
308 | free(oa->name); | ||
309 | free(oa->value); | ||
310 | oa->name = NULL; | ||
311 | oa->value = NULL; | ||
312 | } | ||
313 | |||
314 | static void | ||
315 | free_byte_array(fido_byte_array_t *ba) | ||
316 | { | ||
317 | free(ba->ptr); | ||
318 | |||
319 | ba->ptr = NULL; | ||
320 | ba->len = 0; | ||
321 | } | ||
322 | |||
323 | void | ||
324 | fido_cbor_info_free(fido_cbor_info_t **ci_p) | ||
325 | { | ||
326 | fido_cbor_info_t *ci; | ||
327 | |||
328 | if (ci_p == NULL || (ci = *ci_p) == NULL) | ||
329 | return; | ||
330 | |||
331 | free_str_array(&ci->versions); | ||
332 | free_str_array(&ci->extensions); | ||
333 | free_opt_array(&ci->options); | ||
334 | free_byte_array(&ci->protocols); | ||
335 | free(ci); | ||
336 | |||
337 | *ci_p = NULL; | ||
338 | } | ||
339 | |||
340 | char ** | ||
341 | fido_cbor_info_versions_ptr(const fido_cbor_info_t *ci) | ||
342 | { | ||
343 | return (ci->versions.ptr); | ||
344 | } | ||
345 | |||
346 | size_t | ||
347 | fido_cbor_info_versions_len(const fido_cbor_info_t *ci) | ||
348 | { | ||
349 | return (ci->versions.len); | ||
350 | } | ||
351 | |||
352 | char ** | ||
353 | fido_cbor_info_extensions_ptr(const fido_cbor_info_t *ci) | ||
354 | { | ||
355 | return (ci->extensions.ptr); | ||
356 | } | ||
357 | |||
358 | size_t | ||
359 | fido_cbor_info_extensions_len(const fido_cbor_info_t *ci) | ||
360 | { | ||
361 | return (ci->extensions.len); | ||
362 | } | ||
363 | |||
364 | const unsigned char * | ||
365 | fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *ci) | ||
366 | { | ||
367 | return (ci->aaguid); | ||
368 | } | ||
369 | |||
370 | size_t | ||
371 | fido_cbor_info_aaguid_len(const fido_cbor_info_t *ci) | ||
372 | { | ||
373 | return (sizeof(ci->aaguid)); | ||
374 | } | ||
375 | |||
376 | char ** | ||
377 | fido_cbor_info_options_name_ptr(const fido_cbor_info_t *ci) | ||
378 | { | ||
379 | return (ci->options.name); | ||
380 | } | ||
381 | |||
382 | const bool * | ||
383 | fido_cbor_info_options_value_ptr(const fido_cbor_info_t *ci) | ||
384 | { | ||
385 | return (ci->options.value); | ||
386 | } | ||
387 | |||
388 | size_t | ||
389 | fido_cbor_info_options_len(const fido_cbor_info_t *ci) | ||
390 | { | ||
391 | return (ci->options.len); | ||
392 | } | ||
393 | |||
394 | uint64_t | ||
395 | fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci) | ||
396 | { | ||
397 | return (ci->maxmsgsiz); | ||
398 | } | ||
399 | |||
400 | const uint8_t * | ||
401 | fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci) | ||
402 | { | ||
403 | return (ci->protocols.ptr); | ||
404 | } | ||
405 | |||
406 | size_t | ||
407 | fido_cbor_info_protocols_len(const fido_cbor_info_t *ci) | ||
408 | { | ||
409 | return (ci->protocols.len); | ||
410 | } | ||
diff --git a/src/io.c b/src/io.c new file mode 100644 index 0000000..aa88720 --- /dev/null +++ b/src/io.c | |||
@@ -0,0 +1,256 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <stdint.h> | ||
8 | #include <stdio.h> | ||
9 | #include <string.h> | ||
10 | |||
11 | #include "fido.h" | ||
12 | #include "packed.h" | ||
13 | |||
14 | PACKED_TYPE(frame_t, | ||
15 | struct frame { | ||
16 | uint32_t cid; /* channel id */ | ||
17 | union { | ||
18 | uint8_t type; | ||
19 | struct { | ||
20 | uint8_t cmd; | ||
21 | uint8_t bcnth; | ||
22 | uint8_t bcntl; | ||
23 | uint8_t data[CTAP_RPT_SIZE - 7]; | ||
24 | } init; | ||
25 | struct { | ||
26 | uint8_t seq; | ||
27 | uint8_t data[CTAP_RPT_SIZE - 5]; | ||
28 | } cont; | ||
29 | } body; | ||
30 | }) | ||
31 | |||
32 | #ifndef MIN | ||
33 | #define MIN(x, y) ((x) > (y) ? (y) : (x)) | ||
34 | #endif | ||
35 | |||
36 | static size_t | ||
37 | tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count) | ||
38 | { | ||
39 | struct frame *fp; | ||
40 | unsigned char pkt[sizeof(*fp) + 1]; | ||
41 | int n; | ||
42 | |||
43 | if (d->io.write == NULL || (cmd & 0x80) == 0) | ||
44 | return (0); | ||
45 | |||
46 | memset(&pkt, 0, sizeof(pkt)); | ||
47 | fp = (struct frame *)(pkt + 1); | ||
48 | fp->cid = d->cid; | ||
49 | fp->body.init.cmd = 0x80 | cmd; | ||
50 | fp->body.init.bcnth = (count >> 8) & 0xff; | ||
51 | fp->body.init.bcntl = count & 0xff; | ||
52 | count = MIN(count, sizeof(fp->body.init.data)); | ||
53 | if (count) | ||
54 | memcpy(&fp->body.init.data, buf, count); | ||
55 | |||
56 | n = d->io.write(d->io_handle, pkt, sizeof(pkt)); | ||
57 | if (n < 0 || (size_t)n != sizeof(pkt)) | ||
58 | return (0); | ||
59 | |||
60 | return (count); | ||
61 | } | ||
62 | |||
63 | static size_t | ||
64 | tx_frame(fido_dev_t *d, int seq, const void *buf, size_t count) | ||
65 | { | ||
66 | struct frame *fp; | ||
67 | unsigned char pkt[sizeof(*fp) + 1]; | ||
68 | int n; | ||
69 | |||
70 | if (d->io.write == NULL || seq < 0 || seq > UINT8_MAX) | ||
71 | return (0); | ||
72 | |||
73 | memset(&pkt, 0, sizeof(pkt)); | ||
74 | fp = (struct frame *)(pkt + 1); | ||
75 | fp->cid = d->cid; | ||
76 | fp->body.cont.seq = (uint8_t)seq; | ||
77 | count = MIN(count, sizeof(fp->body.cont.data)); | ||
78 | memcpy(&fp->body.cont.data, buf, count); | ||
79 | |||
80 | n = d->io.write(d->io_handle, pkt, sizeof(pkt)); | ||
81 | if (n < 0 || (size_t)n != sizeof(pkt)) | ||
82 | return (0); | ||
83 | |||
84 | return (count); | ||
85 | } | ||
86 | |||
87 | int | ||
88 | fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count) | ||
89 | { | ||
90 | int seq = 0; | ||
91 | size_t sent; | ||
92 | |||
93 | fido_log_debug("%s: d=%p, cmd=0x%02x, buf=%p, count=%zu", __func__, | ||
94 | (void *)d, cmd, buf, count); | ||
95 | fido_log_xxd(buf, count); | ||
96 | |||
97 | if (d->io_handle == NULL || count > UINT16_MAX) { | ||
98 | fido_log_debug("%s: invalid argument (%p, %zu)", __func__, | ||
99 | d->io_handle, count); | ||
100 | return (-1); | ||
101 | } | ||
102 | |||
103 | if ((sent = tx_preamble(d, cmd, buf, count)) == 0) { | ||
104 | fido_log_debug("%s: tx_preamble", __func__); | ||
105 | return (-1); | ||
106 | } | ||
107 | |||
108 | while (sent < count) { | ||
109 | if (seq & 0x80) { | ||
110 | fido_log_debug("%s: seq & 0x80", __func__); | ||
111 | return (-1); | ||
112 | } | ||
113 | const uint8_t *p = (const uint8_t *)buf + sent; | ||
114 | size_t n = tx_frame(d, seq++, p, count - sent); | ||
115 | if (n == 0) { | ||
116 | fido_log_debug("%s: tx_frame", __func__); | ||
117 | return (-1); | ||
118 | } | ||
119 | sent += n; | ||
120 | } | ||
121 | |||
122 | return (0); | ||
123 | } | ||
124 | |||
125 | static int | ||
126 | rx_frame(fido_dev_t *d, struct frame *fp, int ms) | ||
127 | { | ||
128 | int n; | ||
129 | |||
130 | if (d->io.read == NULL) | ||
131 | return (-1); | ||
132 | |||
133 | n = d->io.read(d->io_handle, (unsigned char *)fp, sizeof(*fp), ms); | ||
134 | if (n < 0 || (size_t)n != sizeof(*fp)) | ||
135 | return (-1); | ||
136 | |||
137 | return (0); | ||
138 | } | ||
139 | |||
140 | static int | ||
141 | rx_preamble(fido_dev_t *d, struct frame *fp, int ms) | ||
142 | { | ||
143 | do { | ||
144 | if (rx_frame(d, fp, ms) < 0) | ||
145 | return (-1); | ||
146 | #ifdef FIDO_FUZZ | ||
147 | fp->cid = d->cid; | ||
148 | #endif | ||
149 | } while (fp->cid == d->cid && | ||
150 | fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE)); | ||
151 | |||
152 | return (0); | ||
153 | } | ||
154 | |||
155 | int | ||
156 | fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms) | ||
157 | { | ||
158 | struct frame f; | ||
159 | uint16_t r; | ||
160 | uint16_t flen; | ||
161 | int seq; | ||
162 | |||
163 | if (d->io_handle == NULL || (cmd & 0x80) == 0) { | ||
164 | fido_log_debug("%s: invalid argument (%p, 0x%02x)", __func__, | ||
165 | d->io_handle, cmd); | ||
166 | return (-1); | ||
167 | } | ||
168 | |||
169 | if (rx_preamble(d, &f, ms) < 0) { | ||
170 | fido_log_debug("%s: rx_preamble", __func__); | ||
171 | return (-1); | ||
172 | } | ||
173 | |||
174 | fido_log_debug("%s: initiation frame at %p, len %zu", __func__, | ||
175 | (void *)&f, sizeof(f)); | ||
176 | fido_log_xxd(&f, sizeof(f)); | ||
177 | |||
178 | #ifdef FIDO_FUZZ | ||
179 | f.cid = d->cid; | ||
180 | f.body.init.cmd = cmd; | ||
181 | #endif | ||
182 | |||
183 | if (f.cid != d->cid || f.body.init.cmd != cmd) { | ||
184 | fido_log_debug("%s: cid (0x%x, 0x%x), cmd (0x%02x, 0x%02x)", | ||
185 | __func__, f.cid, d->cid, f.body.init.cmd, cmd); | ||
186 | return (-1); | ||
187 | } | ||
188 | |||
189 | flen = (f.body.init.bcnth << 8) | f.body.init.bcntl; | ||
190 | if (count < (size_t)flen) { | ||
191 | fido_log_debug("%s: count < flen (%zu, %zu)", __func__, count, | ||
192 | (size_t)flen); | ||
193 | return (-1); | ||
194 | } | ||
195 | if (flen < sizeof(f.body.init.data)) { | ||
196 | memcpy(buf, f.body.init.data, flen); | ||
197 | return (flen); | ||
198 | } | ||
199 | |||
200 | memcpy(buf, f.body.init.data, sizeof(f.body.init.data)); | ||
201 | r = sizeof(f.body.init.data); | ||
202 | seq = 0; | ||
203 | |||
204 | while ((size_t)r < flen) { | ||
205 | if (rx_frame(d, &f, ms) < 0) { | ||
206 | fido_log_debug("%s: rx_frame", __func__); | ||
207 | return (-1); | ||
208 | } | ||
209 | |||
210 | fido_log_debug("%s: continuation frame at %p, len %zu", | ||
211 | __func__, (void *)&f, sizeof(f)); | ||
212 | fido_log_xxd(&f, sizeof(f)); | ||
213 | |||
214 | #ifdef FIDO_FUZZ | ||
215 | f.cid = d->cid; | ||
216 | f.body.cont.seq = seq; | ||
217 | #endif | ||
218 | |||
219 | if (f.cid != d->cid || f.body.cont.seq != seq++) { | ||
220 | fido_log_debug("%s: cid (0x%x, 0x%x), seq (%d, %d)", | ||
221 | __func__, f.cid, d->cid, f.body.cont.seq, seq); | ||
222 | return (-1); | ||
223 | } | ||
224 | |||
225 | uint8_t *p = (uint8_t *)buf + r; | ||
226 | |||
227 | if ((size_t)(flen - r) > sizeof(f.body.cont.data)) { | ||
228 | memcpy(p, f.body.cont.data, sizeof(f.body.cont.data)); | ||
229 | r += sizeof(f.body.cont.data); | ||
230 | } else { | ||
231 | memcpy(p, f.body.cont.data, flen - r); | ||
232 | r += (flen - r); /* break */ | ||
233 | } | ||
234 | } | ||
235 | |||
236 | fido_log_debug("%s: payload at %p, len %zu", __func__, buf, (size_t)r); | ||
237 | fido_log_xxd(buf, r); | ||
238 | |||
239 | return (r); | ||
240 | } | ||
241 | |||
242 | int | ||
243 | fido_rx_cbor_status(fido_dev_t *d, int ms) | ||
244 | { | ||
245 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
246 | unsigned char reply[2048]; | ||
247 | int reply_len; | ||
248 | |||
249 | if ((reply_len = fido_rx(d, cmd, &reply, sizeof(reply), ms)) < 0 || | ||
250 | (size_t)reply_len < 1) { | ||
251 | fido_log_debug("%s: fido_rx", __func__); | ||
252 | return (FIDO_ERR_RX); | ||
253 | } | ||
254 | |||
255 | return (reply[0]); | ||
256 | } | ||
diff --git a/src/iso7816.c b/src/iso7816.c new file mode 100644 index 0000000..e2ea281 --- /dev/null +++ b/src/iso7816.c | |||
@@ -0,0 +1,70 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <string.h> | ||
8 | #include "fido.h" | ||
9 | |||
10 | iso7816_apdu_t * | ||
11 | iso7816_new(uint8_t ins, uint8_t p1, uint16_t payload_len) | ||
12 | { | ||
13 | iso7816_apdu_t *apdu; | ||
14 | size_t alloc_len; | ||
15 | |||
16 | alloc_len = sizeof(iso7816_apdu_t) + payload_len; | ||
17 | |||
18 | if ((apdu = calloc(1, alloc_len)) == NULL) | ||
19 | return (NULL); | ||
20 | |||
21 | apdu->alloc_len = alloc_len; | ||
22 | apdu->payload_len = payload_len; | ||
23 | apdu->payload_ptr = apdu->payload; | ||
24 | apdu->header.ins = ins; | ||
25 | apdu->header.p1 = p1; | ||
26 | apdu->header.lc2 = (payload_len >> 8) & 0xff; | ||
27 | apdu->header.lc3 = payload_len & 0xff; | ||
28 | |||
29 | return (apdu); | ||
30 | } | ||
31 | |||
32 | void | ||
33 | iso7816_free(iso7816_apdu_t **apdu_p) | ||
34 | { | ||
35 | iso7816_apdu_t *apdu; | ||
36 | |||
37 | if (apdu_p == NULL || (apdu = *apdu_p) == NULL) | ||
38 | return; | ||
39 | |||
40 | explicit_bzero(apdu, apdu->alloc_len); | ||
41 | free(apdu); | ||
42 | |||
43 | *apdu_p = NULL; | ||
44 | } | ||
45 | |||
46 | int | ||
47 | iso7816_add(iso7816_apdu_t *apdu, const void *buf, size_t cnt) | ||
48 | { | ||
49 | if (cnt > apdu->payload_len || cnt > UINT16_MAX) | ||
50 | return (-1); | ||
51 | |||
52 | memcpy(apdu->payload_ptr, buf, cnt); | ||
53 | apdu->payload_ptr += cnt; | ||
54 | apdu->payload_len -= (uint16_t)cnt; | ||
55 | |||
56 | return (0); | ||
57 | } | ||
58 | |||
59 | const unsigned char * | ||
60 | iso7816_ptr(const iso7816_apdu_t *apdu) | ||
61 | { | ||
62 | return ((const unsigned char *)&apdu->header); | ||
63 | } | ||
64 | |||
65 | size_t | ||
66 | iso7816_len(const iso7816_apdu_t *apdu) | ||
67 | { | ||
68 | return (apdu->alloc_len - sizeof(apdu->alloc_len) - | ||
69 | sizeof(apdu->payload_len) - sizeof(apdu->payload_ptr)); | ||
70 | } | ||
diff --git a/src/iso7816.h b/src/iso7816.h new file mode 100644 index 0000000..426cd97 --- /dev/null +++ b/src/iso7816.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | #ifndef _ISO7816_H | ||
8 | #define _ISO7816_H | ||
9 | |||
10 | #include "packed.h" | ||
11 | |||
12 | PACKED_TYPE(iso7816_header_t, | ||
13 | struct iso7816_header { | ||
14 | uint8_t cla; | ||
15 | uint8_t ins; | ||
16 | uint8_t p1; | ||
17 | uint8_t p2; | ||
18 | uint8_t lc1; | ||
19 | uint8_t lc2; | ||
20 | uint8_t lc3; | ||
21 | }) | ||
22 | |||
23 | PACKED_TYPE(iso7816_apdu_t, | ||
24 | struct iso7816_apdu { | ||
25 | size_t alloc_len; | ||
26 | uint16_t payload_len; | ||
27 | uint8_t *payload_ptr; | ||
28 | iso7816_header_t header; | ||
29 | uint8_t payload[]; | ||
30 | }) | ||
31 | |||
32 | const unsigned char *iso7816_ptr(const iso7816_apdu_t *); | ||
33 | int iso7816_add(iso7816_apdu_t *, const void *, size_t); | ||
34 | iso7816_apdu_t *iso7816_new(uint8_t, uint8_t, uint16_t); | ||
35 | size_t iso7816_len(const iso7816_apdu_t *); | ||
36 | void iso7816_free(iso7816_apdu_t **); | ||
37 | |||
38 | #endif /* !_ISO7816_H */ | ||
diff --git a/src/libfido2.pc.in b/src/libfido2.pc.in new file mode 100644 index 0000000..03d0606 --- /dev/null +++ b/src/libfido2.pc.in | |||
@@ -0,0 +1,12 @@ | |||
1 | prefix=@CMAKE_INSTALL_PREFIX@ | ||
2 | exec_prefix=${prefix} | ||
3 | libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ | ||
4 | includedir=${prefix}/include | ||
5 | |||
6 | Name: @PROJECT_NAME@ | ||
7 | Description: A FIDO2 library | ||
8 | URL: https://github.com/yubico/libfido2 | ||
9 | Version: @FIDO_VERSION@ | ||
10 | Requires: libcrypto | ||
11 | Libs: -L${libdir} -lfido2 | ||
12 | Cflags: -I${includedir} | ||
diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..982bdb7 --- /dev/null +++ b/src/log.c | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <stdarg.h> | ||
8 | #include <stdio.h> | ||
9 | #include <stdlib.h> | ||
10 | #include "fido.h" | ||
11 | |||
12 | #ifndef FIDO_NO_DIAGNOSTIC | ||
13 | |||
14 | #ifndef TLS | ||
15 | #define TLS | ||
16 | #endif | ||
17 | |||
18 | static TLS int logging; | ||
19 | |||
20 | void | ||
21 | fido_log_init(void) | ||
22 | { | ||
23 | logging = 1; | ||
24 | } | ||
25 | |||
26 | void | ||
27 | fido_log_xxd(const void *buf, size_t count) | ||
28 | { | ||
29 | const uint8_t *ptr = buf; | ||
30 | size_t i; | ||
31 | |||
32 | if (!logging) | ||
33 | return; | ||
34 | |||
35 | fprintf(stderr, " "); | ||
36 | |||
37 | for (i = 0; i < count; i++) { | ||
38 | fprintf(stderr, "%02x ", *ptr++); | ||
39 | if ((i + 1) % 16 == 0 && i + 1 < count) | ||
40 | fprintf(stderr, "\n "); | ||
41 | } | ||
42 | |||
43 | fprintf(stderr, "\n"); | ||
44 | fflush(stderr); | ||
45 | } | ||
46 | |||
47 | void | ||
48 | fido_log_debug(const char *fmt, ...) | ||
49 | { | ||
50 | va_list ap; | ||
51 | |||
52 | if (!logging) | ||
53 | return; | ||
54 | |||
55 | va_start(ap, fmt); | ||
56 | vfprintf(stderr, fmt, ap); | ||
57 | va_end(ap); | ||
58 | |||
59 | fprintf(stderr, "\n"); | ||
60 | fflush(stderr); | ||
61 | } | ||
62 | |||
63 | #endif /* !FIDO_NO_DIAGNOSTIC */ | ||
diff --git a/src/packed.h b/src/packed.h new file mode 100644 index 0000000..3857c22 --- /dev/null +++ b/src/packed.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | #ifndef _PACKED_H | ||
8 | #define _PACKED_H | ||
9 | |||
10 | #if defined(__GNUC__) | ||
11 | #define PACKED_TYPE(type, def) \ | ||
12 | typedef def __attribute__ ((__packed__)) type; | ||
13 | #elif defined(_MSC_VER) | ||
14 | #define PACKED_TYPE(type, def) \ | ||
15 | __pragma(pack(push, 1)) \ | ||
16 | typedef def type; \ | ||
17 | __pragma(pack(pop)) | ||
18 | #else | ||
19 | #error "please provide a way to define packed types on your platform" | ||
20 | #endif | ||
21 | |||
22 | #endif /* !_PACKED_H */ | ||
diff --git a/src/pin.c b/src/pin.c new file mode 100644 index 0000000..1ed555c --- /dev/null +++ b/src/pin.c | |||
@@ -0,0 +1,428 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <string.h> | ||
8 | #include "fido.h" | ||
9 | #include "fido/es256.h" | ||
10 | |||
11 | static int | ||
12 | parse_pintoken(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
13 | { | ||
14 | fido_blob_t *token = arg; | ||
15 | |||
16 | if (cbor_isa_uint(key) == false || | ||
17 | cbor_int_get_width(key) != CBOR_INT_8 || | ||
18 | cbor_get_uint8(key) != 2) { | ||
19 | fido_log_debug("%s: cbor type", __func__); | ||
20 | return (0); /* ignore */ | ||
21 | } | ||
22 | |||
23 | return (fido_blob_decode(val, token)); | ||
24 | } | ||
25 | |||
26 | static int | ||
27 | fido_dev_get_pin_token_tx(fido_dev_t *dev, const char *pin, | ||
28 | const fido_blob_t *ecdh, const es256_pk_t *pk) | ||
29 | { | ||
30 | fido_blob_t f; | ||
31 | fido_blob_t *p = NULL; | ||
32 | cbor_item_t *argv[6]; | ||
33 | int r; | ||
34 | |||
35 | memset(&f, 0, sizeof(f)); | ||
36 | memset(argv, 0, sizeof(argv)); | ||
37 | |||
38 | if ((p = fido_blob_new()) == NULL || fido_blob_set(p, | ||
39 | (const unsigned char *)pin, strlen(pin)) < 0) { | ||
40 | fido_log_debug("%s: fido_blob_set", __func__); | ||
41 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
42 | goto fail; | ||
43 | } | ||
44 | |||
45 | if ((argv[0] = cbor_build_uint8(1)) == NULL || | ||
46 | (argv[1] = cbor_build_uint8(5)) == NULL || | ||
47 | (argv[2] = es256_pk_encode(pk, 0)) == NULL || | ||
48 | (argv[5] = cbor_encode_pin_hash_enc(ecdh, p)) == NULL) { | ||
49 | fido_log_debug("%s: cbor encode", __func__); | ||
50 | r = FIDO_ERR_INTERNAL; | ||
51 | goto fail; | ||
52 | } | ||
53 | |||
54 | if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 6, &f) < 0 || | ||
55 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | ||
56 | fido_log_debug("%s: fido_tx", __func__); | ||
57 | r = FIDO_ERR_TX; | ||
58 | goto fail; | ||
59 | } | ||
60 | |||
61 | r = FIDO_OK; | ||
62 | fail: | ||
63 | cbor_vector_free(argv, nitems(argv)); | ||
64 | fido_blob_free(&p); | ||
65 | free(f.ptr); | ||
66 | |||
67 | return (r); | ||
68 | } | ||
69 | |||
70 | static int | ||
71 | fido_dev_get_pin_token_rx(fido_dev_t *dev, const fido_blob_t *ecdh, | ||
72 | fido_blob_t *token, int ms) | ||
73 | { | ||
74 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
75 | fido_blob_t *aes_token = NULL; | ||
76 | unsigned char reply[2048]; | ||
77 | int reply_len; | ||
78 | int r; | ||
79 | |||
80 | if ((aes_token = fido_blob_new()) == NULL) { | ||
81 | r = FIDO_ERR_INTERNAL; | ||
82 | goto fail; | ||
83 | } | ||
84 | |||
85 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
86 | fido_log_debug("%s: fido_rx", __func__); | ||
87 | r = FIDO_ERR_RX; | ||
88 | goto fail; | ||
89 | } | ||
90 | |||
91 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, aes_token, | ||
92 | parse_pintoken)) != FIDO_OK) { | ||
93 | fido_log_debug("%s: parse_pintoken", __func__); | ||
94 | goto fail; | ||
95 | } | ||
96 | |||
97 | if (aes256_cbc_dec(ecdh, aes_token, token) < 0) { | ||
98 | fido_log_debug("%s: aes256_cbc_dec", __func__); | ||
99 | r = FIDO_ERR_RX; | ||
100 | goto fail; | ||
101 | } | ||
102 | |||
103 | r = FIDO_OK; | ||
104 | fail: | ||
105 | fido_blob_free(&aes_token); | ||
106 | |||
107 | return (r); | ||
108 | } | ||
109 | |||
110 | static int | ||
111 | fido_dev_get_pin_token_wait(fido_dev_t *dev, const char *pin, | ||
112 | const fido_blob_t *ecdh, const es256_pk_t *pk, fido_blob_t *token, int ms) | ||
113 | { | ||
114 | int r; | ||
115 | |||
116 | if ((r = fido_dev_get_pin_token_tx(dev, pin, ecdh, pk)) != FIDO_OK || | ||
117 | (r = fido_dev_get_pin_token_rx(dev, ecdh, token, ms)) != FIDO_OK) | ||
118 | return (r); | ||
119 | |||
120 | return (FIDO_OK); | ||
121 | } | ||
122 | |||
123 | int | ||
124 | fido_dev_get_pin_token(fido_dev_t *dev, const char *pin, | ||
125 | const fido_blob_t *ecdh, const es256_pk_t *pk, fido_blob_t *token) | ||
126 | { | ||
127 | return (fido_dev_get_pin_token_wait(dev, pin, ecdh, pk, token, -1)); | ||
128 | } | ||
129 | |||
130 | static int | ||
131 | pad64(const char *pin, fido_blob_t **ppin) | ||
132 | { | ||
133 | size_t pin_len; | ||
134 | size_t ppin_len; | ||
135 | |||
136 | pin_len = strlen(pin); | ||
137 | if (pin_len < 4 || pin_len > 255) { | ||
138 | fido_log_debug("%s: invalid pin length", __func__); | ||
139 | return (FIDO_ERR_PIN_POLICY_VIOLATION); | ||
140 | } | ||
141 | |||
142 | if ((*ppin = fido_blob_new()) == NULL) | ||
143 | return (FIDO_ERR_INTERNAL); | ||
144 | |||
145 | ppin_len = (pin_len + 63) & ~63; | ||
146 | if (ppin_len < pin_len || ((*ppin)->ptr = calloc(1, ppin_len)) == NULL) { | ||
147 | fido_blob_free(ppin); | ||
148 | return (FIDO_ERR_INTERNAL); | ||
149 | } | ||
150 | |||
151 | memcpy((*ppin)->ptr, pin, pin_len); | ||
152 | (*ppin)->len = ppin_len; | ||
153 | |||
154 | return (FIDO_OK); | ||
155 | } | ||
156 | |||
157 | static int | ||
158 | fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin) | ||
159 | { | ||
160 | fido_blob_t f; | ||
161 | fido_blob_t *ppin = NULL; | ||
162 | fido_blob_t *ecdh = NULL; | ||
163 | fido_blob_t *opin = NULL; | ||
164 | cbor_item_t *argv[6]; | ||
165 | es256_pk_t *pk = NULL; | ||
166 | int r; | ||
167 | |||
168 | memset(&f, 0, sizeof(f)); | ||
169 | memset(argv, 0, sizeof(argv)); | ||
170 | |||
171 | if ((opin = fido_blob_new()) == NULL || fido_blob_set(opin, | ||
172 | (const unsigned char *)oldpin, strlen(oldpin)) < 0) { | ||
173 | fido_log_debug("%s: fido_blob_set", __func__); | ||
174 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
175 | goto fail; | ||
176 | } | ||
177 | |||
178 | if ((r = pad64(pin, &ppin)) != FIDO_OK) { | ||
179 | fido_log_debug("%s: pad64", __func__); | ||
180 | goto fail; | ||
181 | } | ||
182 | |||
183 | if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { | ||
184 | fido_log_debug("%s: fido_do_ecdh", __func__); | ||
185 | goto fail; | ||
186 | } | ||
187 | |||
188 | if ((argv[0] = cbor_build_uint8(1)) == NULL || | ||
189 | (argv[1] = cbor_build_uint8(4)) == NULL || | ||
190 | (argv[2] = es256_pk_encode(pk, 0)) == NULL || | ||
191 | (argv[3] = cbor_encode_change_pin_auth(ecdh, ppin, opin)) == NULL || | ||
192 | (argv[4] = cbor_encode_pin_enc(ecdh, ppin)) == NULL || | ||
193 | (argv[5] = cbor_encode_pin_hash_enc(ecdh, opin)) == NULL) { | ||
194 | fido_log_debug("%s: cbor encode", __func__); | ||
195 | r = FIDO_ERR_INTERNAL; | ||
196 | goto fail; | ||
197 | } | ||
198 | |||
199 | if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 6, &f) < 0 || | ||
200 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | ||
201 | fido_log_debug("%s: fido_tx", __func__); | ||
202 | r = FIDO_ERR_TX; | ||
203 | goto fail; | ||
204 | } | ||
205 | |||
206 | r = FIDO_OK; | ||
207 | fail: | ||
208 | cbor_vector_free(argv, nitems(argv)); | ||
209 | es256_pk_free(&pk); | ||
210 | fido_blob_free(&ppin); | ||
211 | fido_blob_free(&ecdh); | ||
212 | fido_blob_free(&opin); | ||
213 | free(f.ptr); | ||
214 | |||
215 | return (r); | ||
216 | |||
217 | } | ||
218 | |||
219 | static int | ||
220 | fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin) | ||
221 | { | ||
222 | fido_blob_t f; | ||
223 | fido_blob_t *ppin = NULL; | ||
224 | fido_blob_t *ecdh = NULL; | ||
225 | cbor_item_t *argv[5]; | ||
226 | es256_pk_t *pk = NULL; | ||
227 | int r; | ||
228 | |||
229 | memset(&f, 0, sizeof(f)); | ||
230 | memset(argv, 0, sizeof(argv)); | ||
231 | |||
232 | if ((r = pad64(pin, &ppin)) != FIDO_OK) { | ||
233 | fido_log_debug("%s: pad64", __func__); | ||
234 | goto fail; | ||
235 | } | ||
236 | |||
237 | if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { | ||
238 | fido_log_debug("%s: fido_do_ecdh", __func__); | ||
239 | goto fail; | ||
240 | } | ||
241 | |||
242 | if ((argv[0] = cbor_build_uint8(1)) == NULL || | ||
243 | (argv[1] = cbor_build_uint8(3)) == NULL || | ||
244 | (argv[2] = es256_pk_encode(pk, 0)) == NULL || | ||
245 | (argv[3] = cbor_encode_set_pin_auth(ecdh, ppin)) == NULL || | ||
246 | (argv[4] = cbor_encode_pin_enc(ecdh, ppin)) == NULL) { | ||
247 | fido_log_debug("%s: cbor encode", __func__); | ||
248 | r = FIDO_ERR_INTERNAL; | ||
249 | goto fail; | ||
250 | } | ||
251 | |||
252 | if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 5, &f) < 0 || | ||
253 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | ||
254 | fido_log_debug("%s: fido_tx", __func__); | ||
255 | r = FIDO_ERR_TX; | ||
256 | goto fail; | ||
257 | } | ||
258 | |||
259 | r = FIDO_OK; | ||
260 | fail: | ||
261 | cbor_vector_free(argv, nitems(argv)); | ||
262 | es256_pk_free(&pk); | ||
263 | fido_blob_free(&ppin); | ||
264 | fido_blob_free(&ecdh); | ||
265 | free(f.ptr); | ||
266 | |||
267 | return (r); | ||
268 | } | ||
269 | |||
270 | static int | ||
271 | fido_dev_set_pin_wait(fido_dev_t *dev, const char *pin, const char *oldpin, | ||
272 | int ms) | ||
273 | { | ||
274 | int r; | ||
275 | |||
276 | if (oldpin != NULL) { | ||
277 | if ((r = fido_dev_change_pin_tx(dev, pin, oldpin)) != FIDO_OK) { | ||
278 | fido_log_debug("%s: fido_dev_change_pin_tx", __func__); | ||
279 | return (r); | ||
280 | } | ||
281 | } else { | ||
282 | if ((r = fido_dev_set_pin_tx(dev, pin)) != FIDO_OK) { | ||
283 | fido_log_debug("%s: fido_dev_set_pin_tx", __func__); | ||
284 | return (r); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | if ((r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { | ||
289 | fido_log_debug("%s: fido_rx_cbor_status", __func__); | ||
290 | return (r); | ||
291 | } | ||
292 | |||
293 | return (FIDO_OK); | ||
294 | } | ||
295 | |||
296 | int | ||
297 | fido_dev_set_pin(fido_dev_t *dev, const char *pin, const char *oldpin) | ||
298 | { | ||
299 | return (fido_dev_set_pin_wait(dev, pin, oldpin, -1)); | ||
300 | } | ||
301 | |||
302 | static int | ||
303 | parse_retry_count(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
304 | { | ||
305 | int *retries = arg; | ||
306 | uint64_t n; | ||
307 | |||
308 | if (cbor_isa_uint(key) == false || | ||
309 | cbor_int_get_width(key) != CBOR_INT_8 || | ||
310 | cbor_get_uint8(key) != 3) { | ||
311 | fido_log_debug("%s: cbor type", __func__); | ||
312 | return (0); /* ignore */ | ||
313 | } | ||
314 | |||
315 | if (cbor_decode_uint64(val, &n) < 0 || n > INT_MAX) { | ||
316 | fido_log_debug("%s: cbor_decode_uint64", __func__); | ||
317 | return (-1); | ||
318 | } | ||
319 | |||
320 | *retries = (int)n; | ||
321 | |||
322 | return (0); | ||
323 | } | ||
324 | |||
325 | static int | ||
326 | fido_dev_get_retry_count_tx(fido_dev_t *dev) | ||
327 | { | ||
328 | fido_blob_t f; | ||
329 | cbor_item_t *argv[2]; | ||
330 | int r; | ||
331 | |||
332 | memset(&f, 0, sizeof(f)); | ||
333 | memset(argv, 0, sizeof(argv)); | ||
334 | |||
335 | if ((argv[0] = cbor_build_uint8(1)) == NULL || | ||
336 | (argv[1] = cbor_build_uint8(1)) == NULL) { | ||
337 | r = FIDO_ERR_INTERNAL; | ||
338 | goto fail; | ||
339 | } | ||
340 | |||
341 | if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 2, &f) < 0 || | ||
342 | fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) { | ||
343 | fido_log_debug("%s: fido_tx", __func__); | ||
344 | r = FIDO_ERR_TX; | ||
345 | goto fail; | ||
346 | } | ||
347 | |||
348 | r = FIDO_OK; | ||
349 | fail: | ||
350 | cbor_vector_free(argv, nitems(argv)); | ||
351 | free(f.ptr); | ||
352 | |||
353 | return (r); | ||
354 | } | ||
355 | |||
356 | static int | ||
357 | fido_dev_get_retry_count_rx(fido_dev_t *dev, int *retries, int ms) | ||
358 | { | ||
359 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
360 | unsigned char reply[512]; | ||
361 | int reply_len; | ||
362 | int r; | ||
363 | |||
364 | *retries = 0; | ||
365 | |||
366 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
367 | fido_log_debug("%s: fido_rx", __func__); | ||
368 | return (FIDO_ERR_RX); | ||
369 | } | ||
370 | |||
371 | if ((r = cbor_parse_reply(reply, (size_t)reply_len, retries, | ||
372 | parse_retry_count)) != FIDO_OK) { | ||
373 | fido_log_debug("%s: parse_retry_count", __func__); | ||
374 | return (r); | ||
375 | } | ||
376 | |||
377 | return (FIDO_OK); | ||
378 | } | ||
379 | |||
380 | static int | ||
381 | fido_dev_get_retry_count_wait(fido_dev_t *dev, int *retries, int ms) | ||
382 | { | ||
383 | int r; | ||
384 | |||
385 | if ((r = fido_dev_get_retry_count_tx(dev)) != FIDO_OK || | ||
386 | (r = fido_dev_get_retry_count_rx(dev, retries, ms)) != FIDO_OK) | ||
387 | return (r); | ||
388 | |||
389 | return (FIDO_OK); | ||
390 | } | ||
391 | |||
392 | int | ||
393 | fido_dev_get_retry_count(fido_dev_t *dev, int *retries) | ||
394 | { | ||
395 | return (fido_dev_get_retry_count_wait(dev, retries, -1)); | ||
396 | } | ||
397 | |||
398 | int | ||
399 | cbor_add_pin_params(fido_dev_t *dev, const fido_blob_t *hmac_data, | ||
400 | const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, | ||
401 | cbor_item_t **auth, cbor_item_t **opt) | ||
402 | { | ||
403 | fido_blob_t *token = NULL; | ||
404 | int r; | ||
405 | |||
406 | if ((token = fido_blob_new()) == NULL) { | ||
407 | r = FIDO_ERR_INTERNAL; | ||
408 | goto fail; | ||
409 | } | ||
410 | |||
411 | if ((r = fido_dev_get_pin_token(dev, pin, ecdh, pk, token)) != FIDO_OK) { | ||
412 | fido_log_debug("%s: fido_dev_get_pin_token", __func__); | ||
413 | goto fail; | ||
414 | } | ||
415 | |||
416 | if ((*auth = cbor_encode_pin_auth(token, hmac_data)) == NULL || | ||
417 | (*opt = cbor_encode_pin_opt()) == NULL) { | ||
418 | fido_log_debug("%s: cbor encode", __func__); | ||
419 | r = FIDO_ERR_INTERNAL; | ||
420 | goto fail; | ||
421 | } | ||
422 | |||
423 | r = FIDO_OK; | ||
424 | fail: | ||
425 | fido_blob_free(&token); | ||
426 | |||
427 | return (r); | ||
428 | } | ||
diff --git a/src/reset.c b/src/reset.c new file mode 100644 index 0000000..4b2c88a --- /dev/null +++ b/src/reset.c | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <stdlib.h> | ||
8 | #include "fido.h" | ||
9 | |||
10 | static int | ||
11 | fido_dev_reset_tx(fido_dev_t *dev) | ||
12 | { | ||
13 | const unsigned char cbor[] = { CTAP_CBOR_RESET }; | ||
14 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
15 | |||
16 | if (fido_tx(dev, cmd, cbor, sizeof(cbor)) < 0) { | ||
17 | fido_log_debug("%s: fido_tx", __func__); | ||
18 | return (FIDO_ERR_TX); | ||
19 | } | ||
20 | |||
21 | return (FIDO_OK); | ||
22 | } | ||
23 | |||
24 | static int | ||
25 | fido_dev_reset_wait(fido_dev_t *dev, int ms) | ||
26 | { | ||
27 | int r; | ||
28 | |||
29 | if ((r = fido_dev_reset_tx(dev)) != FIDO_OK || | ||
30 | (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) | ||
31 | return (r); | ||
32 | |||
33 | return (FIDO_OK); | ||
34 | } | ||
35 | |||
36 | int | ||
37 | fido_dev_reset(fido_dev_t *dev) | ||
38 | { | ||
39 | return (fido_dev_reset_wait(dev, -1)); | ||
40 | } | ||
diff --git a/src/rs256.c b/src/rs256.c new file mode 100644 index 0000000..9f30163 --- /dev/null +++ b/src/rs256.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <openssl/bn.h> | ||
8 | #include <openssl/rsa.h> | ||
9 | #include <openssl/evp.h> | ||
10 | #include <openssl/obj_mac.h> | ||
11 | |||
12 | #include <string.h> | ||
13 | #include "fido.h" | ||
14 | #include "fido/rs256.h" | ||
15 | |||
16 | #if OPENSSL_VERSION_NUMBER < 0x10100000L | ||
17 | static int | ||
18 | RSA_bits(const RSA *r) | ||
19 | { | ||
20 | return (BN_num_bits(r->n)); | ||
21 | } | ||
22 | |||
23 | static int | ||
24 | RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) | ||
25 | { | ||
26 | r->n = n; | ||
27 | r->e = e; | ||
28 | r->d = d; | ||
29 | |||
30 | return (1); | ||
31 | } | ||
32 | |||
33 | static void | ||
34 | RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) | ||
35 | { | ||
36 | *n = r->n; | ||
37 | *e = r->e; | ||
38 | *d = r->d; | ||
39 | } | ||
40 | #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ | ||
41 | |||
42 | static int | ||
43 | decode_bignum(const cbor_item_t *item, void *ptr, size_t len) | ||
44 | { | ||
45 | if (cbor_isa_bytestring(item) == false || | ||
46 | cbor_bytestring_is_definite(item) == false || | ||
47 | cbor_bytestring_length(item) != len) { | ||
48 | fido_log_debug("%s: cbor type", __func__); | ||
49 | return (-1); | ||
50 | } | ||
51 | |||
52 | memcpy(ptr, cbor_bytestring_handle(item), len); | ||
53 | |||
54 | return (0); | ||
55 | } | ||
56 | |||
57 | static int | ||
58 | decode_rsa_pubkey(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
59 | { | ||
60 | rs256_pk_t *k = arg; | ||
61 | |||
62 | if (cbor_isa_negint(key) == false || | ||
63 | cbor_int_get_width(key) != CBOR_INT_8) | ||
64 | return (0); /* ignore */ | ||
65 | |||
66 | switch (cbor_get_uint8(key)) { | ||
67 | case 0: /* modulus */ | ||
68 | return (decode_bignum(val, &k->n, sizeof(k->n))); | ||
69 | case 1: /* public exponent */ | ||
70 | return (decode_bignum(val, &k->e, sizeof(k->e))); | ||
71 | } | ||
72 | |||
73 | return (0); /* ignore */ | ||
74 | } | ||
75 | |||
76 | int | ||
77 | rs256_pk_decode(const cbor_item_t *item, rs256_pk_t *k) | ||
78 | { | ||
79 | if (cbor_isa_map(item) == false || | ||
80 | cbor_map_is_definite(item) == false || | ||
81 | cbor_map_iter(item, k, decode_rsa_pubkey) < 0) { | ||
82 | fido_log_debug("%s: cbor type", __func__); | ||
83 | return (-1); | ||
84 | } | ||
85 | |||
86 | return (0); | ||
87 | } | ||
88 | |||
89 | rs256_pk_t * | ||
90 | rs256_pk_new(void) | ||
91 | { | ||
92 | return (calloc(1, sizeof(rs256_pk_t))); | ||
93 | } | ||
94 | |||
95 | void | ||
96 | rs256_pk_free(rs256_pk_t **pkp) | ||
97 | { | ||
98 | rs256_pk_t *pk; | ||
99 | |||
100 | if (pkp == NULL || (pk = *pkp) == NULL) | ||
101 | return; | ||
102 | |||
103 | explicit_bzero(pk, sizeof(*pk)); | ||
104 | free(pk); | ||
105 | |||
106 | *pkp = NULL; | ||
107 | } | ||
108 | |||
109 | int | ||
110 | rs256_pk_from_ptr(rs256_pk_t *pk, const void *ptr, size_t len) | ||
111 | { | ||
112 | if (len < sizeof(*pk)) | ||
113 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
114 | |||
115 | memcpy(pk, ptr, sizeof(*pk)); | ||
116 | |||
117 | return (FIDO_OK); | ||
118 | } | ||
119 | |||
120 | EVP_PKEY * | ||
121 | rs256_pk_to_EVP_PKEY(const rs256_pk_t *k) | ||
122 | { | ||
123 | RSA *rsa = NULL; | ||
124 | EVP_PKEY *pkey = NULL; | ||
125 | BIGNUM *n = NULL; | ||
126 | BIGNUM *e = NULL; | ||
127 | int ok = -1; | ||
128 | |||
129 | if ((n = BN_new()) == NULL || (e = BN_new()) == NULL) | ||
130 | goto fail; | ||
131 | |||
132 | if (BN_bin2bn(k->n, sizeof(k->n), n) == NULL || | ||
133 | BN_bin2bn(k->e, sizeof(k->e), e) == NULL) { | ||
134 | fido_log_debug("%s: BN_bin2bn", __func__); | ||
135 | goto fail; | ||
136 | } | ||
137 | |||
138 | if ((rsa = RSA_new()) == NULL || RSA_set0_key(rsa, n, e, NULL) == 0) { | ||
139 | fido_log_debug("%s: RSA_set0_key", __func__); | ||
140 | goto fail; | ||
141 | } | ||
142 | |||
143 | /* at this point, n and e belong to rsa */ | ||
144 | n = NULL; | ||
145 | e = NULL; | ||
146 | |||
147 | if ((pkey = EVP_PKEY_new()) == NULL || | ||
148 | EVP_PKEY_assign_RSA(pkey, rsa) == 0) { | ||
149 | fido_log_debug("%s: EVP_PKEY_assign_RSA", __func__); | ||
150 | goto fail; | ||
151 | } | ||
152 | |||
153 | rsa = NULL; /* at this point, rsa belongs to evp */ | ||
154 | |||
155 | ok = 0; | ||
156 | fail: | ||
157 | if (n != NULL) | ||
158 | BN_free(n); | ||
159 | if (e != NULL) | ||
160 | BN_free(e); | ||
161 | if (rsa != NULL) | ||
162 | RSA_free(rsa); | ||
163 | if (ok < 0 && pkey != NULL) { | ||
164 | EVP_PKEY_free(pkey); | ||
165 | pkey = NULL; | ||
166 | } | ||
167 | |||
168 | return (pkey); | ||
169 | } | ||
170 | |||
171 | int | ||
172 | rs256_pk_from_RSA(rs256_pk_t *pk, const RSA *rsa) | ||
173 | { | ||
174 | const BIGNUM *n = NULL; | ||
175 | const BIGNUM *e = NULL; | ||
176 | const BIGNUM *d = NULL; | ||
177 | int k; | ||
178 | |||
179 | if (RSA_bits(rsa) != 2048) { | ||
180 | fido_log_debug("%s: invalid key length", __func__); | ||
181 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
182 | } | ||
183 | |||
184 | RSA_get0_key(rsa, &n, &e, &d); | ||
185 | |||
186 | if (n == NULL || e == NULL) { | ||
187 | fido_log_debug("%s: RSA_get0_key", __func__); | ||
188 | return (FIDO_ERR_INTERNAL); | ||
189 | } | ||
190 | |||
191 | if ((k = BN_num_bytes(n)) < 0 || (size_t)k > sizeof(pk->n) || | ||
192 | (k = BN_num_bytes(e)) < 0 || (size_t)k > sizeof(pk->e)) { | ||
193 | fido_log_debug("%s: invalid key", __func__); | ||
194 | return (FIDO_ERR_INTERNAL); | ||
195 | } | ||
196 | |||
197 | if ((k = BN_bn2bin(n, pk->n)) < 0 || (size_t)k > sizeof(pk->n) || | ||
198 | (k = BN_bn2bin(e, pk->e)) < 0 || (size_t)k > sizeof(pk->e)) { | ||
199 | fido_log_debug("%s: BN_bn2bin", __func__); | ||
200 | return (FIDO_ERR_INTERNAL); | ||
201 | } | ||
202 | |||
203 | return (FIDO_OK); | ||
204 | } | ||
diff --git a/src/types.h b/src/types.h new file mode 100644 index 0000000..42ed1b7 --- /dev/null +++ b/src/types.h | |||
@@ -0,0 +1,171 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | #ifndef _TYPES_H | ||
8 | #define _TYPES_H | ||
9 | |||
10 | #include "packed.h" | ||
11 | |||
12 | /* COSE ES256 (ECDSA over P-256 with SHA-256) public key */ | ||
13 | typedef struct es256_pk { | ||
14 | unsigned char x[32]; | ||
15 | unsigned char y[32]; | ||
16 | } es256_pk_t; | ||
17 | |||
18 | /* COSE ES256 (ECDSA over P-256 with SHA-256) (secret) key */ | ||
19 | typedef struct es256_sk { | ||
20 | unsigned char d[32]; | ||
21 | } es256_sk_t; | ||
22 | |||
23 | /* COSE RS256 (2048-bit RSA with PKCS1 padding and SHA-256) public key */ | ||
24 | typedef struct rs256_pk { | ||
25 | unsigned char n[256]; | ||
26 | unsigned char e[3]; | ||
27 | } rs256_pk_t; | ||
28 | |||
29 | /* COSE EDDSA (ED25519) */ | ||
30 | typedef struct eddsa_pk { | ||
31 | unsigned char x[32]; | ||
32 | } eddsa_pk_t; | ||
33 | |||
34 | PACKED_TYPE(fido_authdata_t, | ||
35 | struct fido_authdata { | ||
36 | unsigned char rp_id_hash[32]; /* sha256 of fido_rp.id */ | ||
37 | uint8_t flags; /* user present/verified */ | ||
38 | uint32_t sigcount; /* signature counter */ | ||
39 | /* actually longer */ | ||
40 | }) | ||
41 | |||
42 | PACKED_TYPE(fido_attcred_raw_t, | ||
43 | struct fido_attcred_raw { | ||
44 | unsigned char aaguid[16]; /* credential's aaguid */ | ||
45 | uint16_t id_len; /* credential id length */ | ||
46 | uint8_t body[]; /* credential id + pubkey */ | ||
47 | }) | ||
48 | |||
49 | typedef struct fido_attcred { | ||
50 | unsigned char aaguid[16]; /* credential's aaguid */ | ||
51 | fido_blob_t id; /* credential id */ | ||
52 | int type; /* credential's cose algorithm */ | ||
53 | union { /* credential's public key */ | ||
54 | es256_pk_t es256; | ||
55 | rs256_pk_t rs256; | ||
56 | eddsa_pk_t eddsa; | ||
57 | } pubkey; | ||
58 | } fido_attcred_t; | ||
59 | |||
60 | typedef struct fido_attstmt { | ||
61 | fido_blob_t x5c; /* attestation certificate */ | ||
62 | fido_blob_t sig; /* attestation signature */ | ||
63 | } fido_attstmt_t; | ||
64 | |||
65 | typedef struct fido_rp { | ||
66 | char *id; /* relying party id */ | ||
67 | char *name; /* relying party name */ | ||
68 | } fido_rp_t; | ||
69 | |||
70 | typedef struct fido_user { | ||
71 | fido_blob_t id; /* required */ | ||
72 | char *icon; /* optional */ | ||
73 | char *name; /* optional */ | ||
74 | char *display_name; /* required */ | ||
75 | } fido_user_t; | ||
76 | |||
77 | typedef struct fido_cred { | ||
78 | fido_blob_t cdh; /* client data hash */ | ||
79 | fido_rp_t rp; /* relying party */ | ||
80 | fido_user_t user; /* user entity */ | ||
81 | fido_blob_array_t excl; /* list of credential ids to exclude */ | ||
82 | fido_opt_t rk; /* resident key */ | ||
83 | fido_opt_t uv; /* user verification */ | ||
84 | int ext; /* enabled extensions */ | ||
85 | int type; /* cose algorithm */ | ||
86 | char *fmt; /* credential format */ | ||
87 | int authdata_ext; /* decoded extensions */ | ||
88 | fido_blob_t authdata_cbor; /* raw cbor payload */ | ||
89 | fido_authdata_t authdata; /* decoded authdata payload */ | ||
90 | fido_attcred_t attcred; /* returned credential (key + id) */ | ||
91 | fido_attstmt_t attstmt; /* attestation statement (x509 + sig) */ | ||
92 | } fido_cred_t; | ||
93 | |||
94 | typedef struct _fido_assert_stmt { | ||
95 | fido_blob_t id; /* credential id */ | ||
96 | fido_user_t user; /* user attributes */ | ||
97 | fido_blob_t hmac_secret_enc; /* hmac secret, encrypted */ | ||
98 | fido_blob_t hmac_secret; /* hmac secret */ | ||
99 | int authdata_ext; /* decoded extensions */ | ||
100 | fido_blob_t authdata_cbor; /* raw cbor payload */ | ||
101 | fido_authdata_t authdata; /* decoded authdata payload */ | ||
102 | fido_blob_t sig; /* signature of cdh + authdata */ | ||
103 | } fido_assert_stmt; | ||
104 | |||
105 | typedef struct fido_assert { | ||
106 | char *rp_id; /* relying party id */ | ||
107 | fido_blob_t cdh; /* client data hash */ | ||
108 | fido_blob_t hmac_salt; /* optional hmac-secret salt */ | ||
109 | fido_blob_array_t allow_list; /* list of allowed credentials */ | ||
110 | fido_opt_t up; /* user presence */ | ||
111 | fido_opt_t uv; /* user verification */ | ||
112 | int ext; /* enabled extensions */ | ||
113 | fido_assert_stmt *stmt; /* array of expected assertions */ | ||
114 | size_t stmt_cnt; /* number of allocated assertions */ | ||
115 | size_t stmt_len; /* number of received assertions */ | ||
116 | } fido_assert_t; | ||
117 | |||
118 | typedef struct fido_opt_array { | ||
119 | char **name; | ||
120 | bool *value; | ||
121 | size_t len; | ||
122 | } fido_opt_array_t; | ||
123 | |||
124 | typedef struct fido_str_array { | ||
125 | char **ptr; | ||
126 | size_t len; | ||
127 | } fido_str_array_t; | ||
128 | |||
129 | typedef struct fido_byte_array { | ||
130 | uint8_t *ptr; | ||
131 | size_t len; | ||
132 | } fido_byte_array_t; | ||
133 | |||
134 | typedef struct fido_cbor_info { | ||
135 | fido_str_array_t versions; /* supported versions: fido2|u2f */ | ||
136 | fido_str_array_t extensions; /* list of supported extensions */ | ||
137 | unsigned char aaguid[16]; /* aaguid */ | ||
138 | fido_opt_array_t options; /* list of supported options */ | ||
139 | uint64_t maxmsgsiz; /* maximum message size */ | ||
140 | fido_byte_array_t protocols; /* supported pin protocols */ | ||
141 | } fido_cbor_info_t; | ||
142 | |||
143 | typedef struct fido_dev_info { | ||
144 | char *path; /* device path */ | ||
145 | int16_t vendor_id; /* 2-byte vendor id */ | ||
146 | int16_t product_id; /* 2-byte product id */ | ||
147 | char *manufacturer; /* manufacturer string */ | ||
148 | char *product; /* product string */ | ||
149 | } fido_dev_info_t; | ||
150 | |||
151 | PACKED_TYPE(fido_ctap_info_t, | ||
152 | /* defined in section 8.1.9.1.3 (CTAPHID_INIT) of the fido2 ctap spec */ | ||
153 | struct fido_ctap_info { | ||
154 | uint64_t nonce; /* echoed nonce */ | ||
155 | uint32_t cid; /* channel id */ | ||
156 | uint8_t protocol; /* ctaphid protocol id */ | ||
157 | uint8_t major; /* major version number */ | ||
158 | uint8_t minor; /* minor version number */ | ||
159 | uint8_t build; /* build version number */ | ||
160 | uint8_t flags; /* capabilities flags; see FIDO_CAP_* */ | ||
161 | }) | ||
162 | |||
163 | typedef struct fido_dev { | ||
164 | uint64_t nonce; /* issued nonce */ | ||
165 | fido_ctap_info_t attr; /* device attributes */ | ||
166 | uint32_t cid; /* assigned channel id */ | ||
167 | void *io_handle; /* abstract i/o handle */ | ||
168 | fido_dev_io_t io; /* i/o functions & data */ | ||
169 | } fido_dev_t; | ||
170 | |||
171 | #endif /* !_TYPES_H */ | ||
diff --git a/src/u2f.c b/src/u2f.c new file mode 100644 index 0000000..3f2d9aa --- /dev/null +++ b/src/u2f.c | |||
@@ -0,0 +1,758 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <openssl/sha.h> | ||
8 | #include <openssl/x509.h> | ||
9 | |||
10 | #include <string.h> | ||
11 | #ifdef HAVE_UNISTD_H | ||
12 | #include <unistd.h> | ||
13 | #endif | ||
14 | |||
15 | #include "fido.h" | ||
16 | #include "fido/es256.h" | ||
17 | |||
18 | #if defined(_MSC_VER) | ||
19 | static int | ||
20 | usleep(unsigned int usec) | ||
21 | { | ||
22 | Sleep(usec / 1000); | ||
23 | |||
24 | return (0); | ||
25 | } | ||
26 | #endif | ||
27 | |||
28 | static int | ||
29 | sig_get(fido_blob_t *sig, const unsigned char **buf, size_t *len) | ||
30 | { | ||
31 | sig->len = *len; /* consume the whole buffer */ | ||
32 | if ((sig->ptr = calloc(1, sig->len)) == NULL || | ||
33 | fido_buf_read(buf, len, sig->ptr, sig->len) < 0) { | ||
34 | fido_log_debug("%s: fido_buf_read", __func__); | ||
35 | if (sig->ptr != NULL) { | ||
36 | explicit_bzero(sig->ptr, sig->len); | ||
37 | free(sig->ptr); | ||
38 | sig->ptr = NULL; | ||
39 | sig->len = 0; | ||
40 | return (-1); | ||
41 | } | ||
42 | } | ||
43 | |||
44 | return (0); | ||
45 | } | ||
46 | |||
47 | static int | ||
48 | x5c_get(fido_blob_t *x5c, const unsigned char **buf, size_t *len) | ||
49 | { | ||
50 | X509 *cert = NULL; | ||
51 | int ok = -1; | ||
52 | |||
53 | if (*len > LONG_MAX) { | ||
54 | fido_log_debug("%s: invalid len %zu", __func__, *len); | ||
55 | goto fail; | ||
56 | } | ||
57 | |||
58 | /* find out the certificate's length */ | ||
59 | const unsigned char *end = *buf; | ||
60 | if ((cert = d2i_X509(NULL, &end, (long)*len)) == NULL || end <= *buf || | ||
61 | (x5c->len = (size_t)(end - *buf)) >= *len) { | ||
62 | fido_log_debug("%s: d2i_X509", __func__); | ||
63 | goto fail; | ||
64 | } | ||
65 | |||
66 | /* read accordingly */ | ||
67 | if ((x5c->ptr = calloc(1, x5c->len)) == NULL || | ||
68 | fido_buf_read(buf, len, x5c->ptr, x5c->len) < 0) { | ||
69 | fido_log_debug("%s: fido_buf_read", __func__); | ||
70 | goto fail; | ||
71 | } | ||
72 | |||
73 | ok = 0; | ||
74 | fail: | ||
75 | if (cert != NULL) | ||
76 | X509_free(cert); | ||
77 | |||
78 | if (ok < 0) { | ||
79 | free(x5c->ptr); | ||
80 | x5c->ptr = NULL; | ||
81 | x5c->len = 0; | ||
82 | } | ||
83 | |||
84 | return (ok); | ||
85 | } | ||
86 | |||
87 | static int | ||
88 | authdata_fake(const char *rp_id, uint8_t flags, uint32_t sigcount, | ||
89 | fido_blob_t *fake_cbor_ad) | ||
90 | { | ||
91 | fido_authdata_t ad; | ||
92 | cbor_item_t *item = NULL; | ||
93 | size_t alloc_len; | ||
94 | |||
95 | memset(&ad, 0, sizeof(ad)); | ||
96 | |||
97 | if (SHA256((const void *)rp_id, strlen(rp_id), | ||
98 | ad.rp_id_hash) != ad.rp_id_hash) { | ||
99 | fido_log_debug("%s: sha256", __func__); | ||
100 | return (-1); | ||
101 | } | ||
102 | |||
103 | ad.flags = flags; /* XXX translate? */ | ||
104 | ad.sigcount = sigcount; | ||
105 | |||
106 | if ((item = cbor_build_bytestring((const unsigned char *)&ad, | ||
107 | sizeof(ad))) == NULL) { | ||
108 | fido_log_debug("%s: cbor_build_bytestring", __func__); | ||
109 | return (-1); | ||
110 | } | ||
111 | |||
112 | if (fake_cbor_ad->ptr != NULL || | ||
113 | (fake_cbor_ad->len = cbor_serialize_alloc(item, &fake_cbor_ad->ptr, | ||
114 | &alloc_len)) == 0) { | ||
115 | fido_log_debug("%s: cbor_serialize_alloc", __func__); | ||
116 | cbor_decref(&item); | ||
117 | return (-1); | ||
118 | } | ||
119 | |||
120 | cbor_decref(&item); | ||
121 | |||
122 | return (0); | ||
123 | } | ||
124 | |||
125 | static int | ||
126 | send_dummy_register(fido_dev_t *dev, int ms) | ||
127 | { | ||
128 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_MSG; | ||
129 | iso7816_apdu_t *apdu = NULL; | ||
130 | unsigned char challenge[SHA256_DIGEST_LENGTH]; | ||
131 | unsigned char application[SHA256_DIGEST_LENGTH]; | ||
132 | unsigned char reply[2048]; | ||
133 | int r; | ||
134 | |||
135 | #ifdef FIDO_FUZZ | ||
136 | ms = 0; /* XXX */ | ||
137 | #endif | ||
138 | |||
139 | /* dummy challenge & application */ | ||
140 | memset(&challenge, 0xff, sizeof(challenge)); | ||
141 | memset(&application, 0xff, sizeof(application)); | ||
142 | |||
143 | if ((apdu = iso7816_new(U2F_CMD_REGISTER, 0, 2 * | ||
144 | SHA256_DIGEST_LENGTH)) == NULL || | ||
145 | iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 || | ||
146 | iso7816_add(apdu, &application, sizeof(application)) < 0) { | ||
147 | fido_log_debug("%s: iso7816", __func__); | ||
148 | r = FIDO_ERR_INTERNAL; | ||
149 | goto fail; | ||
150 | } | ||
151 | |||
152 | do { | ||
153 | if (fido_tx(dev, cmd, iso7816_ptr(apdu), | ||
154 | iso7816_len(apdu)) < 0) { | ||
155 | fido_log_debug("%s: fido_tx", __func__); | ||
156 | r = FIDO_ERR_TX; | ||
157 | goto fail; | ||
158 | } | ||
159 | if (fido_rx(dev, cmd, &reply, sizeof(reply), ms) < 2) { | ||
160 | fido_log_debug("%s: fido_rx", __func__); | ||
161 | r = FIDO_ERR_RX; | ||
162 | goto fail; | ||
163 | } | ||
164 | if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) { | ||
165 | fido_log_debug("%s: usleep", __func__); | ||
166 | r = FIDO_ERR_RX; | ||
167 | goto fail; | ||
168 | } | ||
169 | } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED); | ||
170 | |||
171 | r = FIDO_OK; | ||
172 | fail: | ||
173 | iso7816_free(&apdu); | ||
174 | |||
175 | return (r); | ||
176 | } | ||
177 | |||
178 | static int | ||
179 | key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id, | ||
180 | int *found, int ms) | ||
181 | { | ||
182 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_MSG; | ||
183 | iso7816_apdu_t *apdu = NULL; | ||
184 | unsigned char challenge[SHA256_DIGEST_LENGTH]; | ||
185 | unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; | ||
186 | unsigned char reply[8]; | ||
187 | uint8_t key_id_len; | ||
188 | int r; | ||
189 | |||
190 | if (key_id->len > UINT8_MAX || rp_id == NULL) { | ||
191 | fido_log_debug("%s: key_id->len=%zu, rp_id=%p", __func__, | ||
192 | key_id->len, (const void *)rp_id); | ||
193 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
194 | goto fail; | ||
195 | } | ||
196 | |||
197 | memset(&challenge, 0xff, sizeof(challenge)); | ||
198 | memset(&rp_id_hash, 0, sizeof(rp_id_hash)); | ||
199 | |||
200 | if (SHA256((const void *)rp_id, strlen(rp_id), | ||
201 | rp_id_hash) != rp_id_hash) { | ||
202 | fido_log_debug("%s: sha256", __func__); | ||
203 | r = FIDO_ERR_INTERNAL; | ||
204 | goto fail; | ||
205 | } | ||
206 | |||
207 | key_id_len = (uint8_t)key_id->len; | ||
208 | |||
209 | if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_CHECK, 2 * | ||
210 | SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len)) == NULL || | ||
211 | iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 || | ||
212 | iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 || | ||
213 | iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 || | ||
214 | iso7816_add(apdu, key_id->ptr, key_id_len) < 0) { | ||
215 | fido_log_debug("%s: iso7816", __func__); | ||
216 | r = FIDO_ERR_INTERNAL; | ||
217 | goto fail; | ||
218 | } | ||
219 | |||
220 | if (fido_tx(dev, cmd, iso7816_ptr(apdu), iso7816_len(apdu)) < 0) { | ||
221 | fido_log_debug("%s: fido_tx", __func__); | ||
222 | r = FIDO_ERR_TX; | ||
223 | goto fail; | ||
224 | } | ||
225 | if (fido_rx(dev, cmd, &reply, sizeof(reply), ms) != 2) { | ||
226 | fido_log_debug("%s: fido_rx", __func__); | ||
227 | r = FIDO_ERR_RX; | ||
228 | goto fail; | ||
229 | } | ||
230 | |||
231 | switch ((reply[0] << 8) | reply[1]) { | ||
232 | case SW_CONDITIONS_NOT_SATISFIED: | ||
233 | *found = 1; /* key exists */ | ||
234 | break; | ||
235 | case SW_WRONG_DATA: | ||
236 | *found = 0; /* key does not exist */ | ||
237 | break; | ||
238 | default: | ||
239 | /* unexpected sw */ | ||
240 | r = FIDO_ERR_INTERNAL; | ||
241 | goto fail; | ||
242 | } | ||
243 | |||
244 | r = FIDO_OK; | ||
245 | fail: | ||
246 | iso7816_free(&apdu); | ||
247 | |||
248 | return (r); | ||
249 | } | ||
250 | |||
251 | static int | ||
252 | parse_auth_reply(fido_blob_t *sig, fido_blob_t *ad, const char *rp_id, | ||
253 | const unsigned char *reply, size_t len) | ||
254 | { | ||
255 | uint8_t flags; | ||
256 | uint32_t sigcount; | ||
257 | |||
258 | if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) { | ||
259 | fido_log_debug("%s: unexpected sw", __func__); | ||
260 | return (FIDO_ERR_RX); | ||
261 | } | ||
262 | |||
263 | len -= 2; | ||
264 | |||
265 | if (fido_buf_read(&reply, &len, &flags, sizeof(flags)) < 0 || | ||
266 | fido_buf_read(&reply, &len, &sigcount, sizeof(sigcount)) < 0) { | ||
267 | fido_log_debug("%s: fido_buf_read", __func__); | ||
268 | return (FIDO_ERR_RX); | ||
269 | } | ||
270 | |||
271 | if (sig_get(sig, &reply, &len) < 0) { | ||
272 | fido_log_debug("%s: sig_get", __func__); | ||
273 | return (FIDO_ERR_RX); | ||
274 | } | ||
275 | |||
276 | if (authdata_fake(rp_id, flags, sigcount, ad) < 0) { | ||
277 | fido_log_debug("%s; authdata_fake", __func__); | ||
278 | return (FIDO_ERR_RX); | ||
279 | } | ||
280 | |||
281 | return (FIDO_OK); | ||
282 | } | ||
283 | |||
284 | static int | ||
285 | do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id, | ||
286 | const fido_blob_t *key_id, fido_blob_t *sig, fido_blob_t *ad, int ms) | ||
287 | { | ||
288 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_MSG; | ||
289 | iso7816_apdu_t *apdu = NULL; | ||
290 | unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; | ||
291 | unsigned char reply[128]; | ||
292 | int reply_len; | ||
293 | uint8_t key_id_len; | ||
294 | int r; | ||
295 | |||
296 | #ifdef FIDO_FUZZ | ||
297 | ms = 0; /* XXX */ | ||
298 | #endif | ||
299 | |||
300 | if (cdh->len != SHA256_DIGEST_LENGTH || key_id->len > UINT8_MAX || | ||
301 | rp_id == NULL) { | ||
302 | r = FIDO_ERR_INVALID_ARGUMENT; | ||
303 | goto fail; | ||
304 | } | ||
305 | |||
306 | memset(&rp_id_hash, 0, sizeof(rp_id_hash)); | ||
307 | |||
308 | if (SHA256((const void *)rp_id, strlen(rp_id), | ||
309 | rp_id_hash) != rp_id_hash) { | ||
310 | fido_log_debug("%s: sha256", __func__); | ||
311 | r = FIDO_ERR_INTERNAL; | ||
312 | goto fail; | ||
313 | } | ||
314 | |||
315 | key_id_len = (uint8_t)key_id->len; | ||
316 | |||
317 | if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_SIGN, 2 * | ||
318 | SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len)) == NULL || | ||
319 | iso7816_add(apdu, cdh->ptr, cdh->len) < 0 || | ||
320 | iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 || | ||
321 | iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 || | ||
322 | iso7816_add(apdu, key_id->ptr, key_id_len) < 0) { | ||
323 | fido_log_debug("%s: iso7816", __func__); | ||
324 | r = FIDO_ERR_INTERNAL; | ||
325 | goto fail; | ||
326 | } | ||
327 | |||
328 | do { | ||
329 | if (fido_tx(dev, cmd, iso7816_ptr(apdu), | ||
330 | iso7816_len(apdu)) < 0) { | ||
331 | fido_log_debug("%s: fido_tx", __func__); | ||
332 | r = FIDO_ERR_TX; | ||
333 | goto fail; | ||
334 | } | ||
335 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), | ||
336 | ms)) < 2) { | ||
337 | fido_log_debug("%s: fido_rx", __func__); | ||
338 | r = FIDO_ERR_RX; | ||
339 | goto fail; | ||
340 | } | ||
341 | if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) { | ||
342 | fido_log_debug("%s: usleep", __func__); | ||
343 | r = FIDO_ERR_RX; | ||
344 | goto fail; | ||
345 | } | ||
346 | } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED); | ||
347 | |||
348 | if ((r = parse_auth_reply(sig, ad, rp_id, reply, | ||
349 | (size_t)reply_len)) != FIDO_OK) { | ||
350 | fido_log_debug("%s: parse_auth_reply", __func__); | ||
351 | goto fail; | ||
352 | } | ||
353 | |||
354 | fail: | ||
355 | iso7816_free(&apdu); | ||
356 | |||
357 | return (r); | ||
358 | } | ||
359 | |||
360 | static int | ||
361 | cbor_blob_from_ec_point(const uint8_t *ec_point, size_t ec_point_len, | ||
362 | fido_blob_t *cbor_blob) | ||
363 | { | ||
364 | es256_pk_t *pk = NULL; | ||
365 | cbor_item_t *pk_cbor = NULL; | ||
366 | size_t alloc_len; | ||
367 | int ok = -1; | ||
368 | |||
369 | /* only handle uncompressed points */ | ||
370 | if (ec_point_len != 65 || ec_point[0] != 0x04) { | ||
371 | fido_log_debug("%s: unexpected format", __func__); | ||
372 | goto fail; | ||
373 | } | ||
374 | |||
375 | if ((pk = es256_pk_new()) == NULL || | ||
376 | es256_pk_set_x(pk, &ec_point[1]) < 0 || | ||
377 | es256_pk_set_y(pk, &ec_point[33]) < 0) { | ||
378 | fido_log_debug("%s: es256_pk_set", __func__); | ||
379 | goto fail; | ||
380 | } | ||
381 | |||
382 | if ((pk_cbor = es256_pk_encode(pk, 0)) == NULL) { | ||
383 | fido_log_debug("%s: es256_pk_encode", __func__); | ||
384 | goto fail; | ||
385 | } | ||
386 | |||
387 | if ((cbor_blob->len = cbor_serialize_alloc(pk_cbor, &cbor_blob->ptr, | ||
388 | &alloc_len)) != 77) { | ||
389 | fido_log_debug("%s: cbor_serialize_alloc", __func__); | ||
390 | goto fail; | ||
391 | } | ||
392 | |||
393 | ok = 0; | ||
394 | fail: | ||
395 | es256_pk_free(&pk); | ||
396 | |||
397 | if (pk_cbor) | ||
398 | cbor_decref(&pk_cbor); | ||
399 | |||
400 | return (ok); | ||
401 | } | ||
402 | |||
403 | static int | ||
404 | encode_cred_authdata(const char *rp_id, const uint8_t *kh, uint8_t kh_len, | ||
405 | const uint8_t *pubkey, size_t pubkey_len, fido_blob_t *out) | ||
406 | { | ||
407 | fido_authdata_t authdata; | ||
408 | fido_attcred_raw_t attcred_raw; | ||
409 | fido_blob_t pk_blob; | ||
410 | fido_blob_t authdata_blob; | ||
411 | cbor_item_t *authdata_cbor = NULL; | ||
412 | unsigned char *ptr; | ||
413 | size_t len; | ||
414 | size_t alloc_len; | ||
415 | int ok = -1; | ||
416 | |||
417 | memset(&pk_blob, 0, sizeof(pk_blob)); | ||
418 | memset(&authdata, 0, sizeof(authdata)); | ||
419 | memset(&authdata_blob, 0, sizeof(authdata_blob)); | ||
420 | memset(out, 0, sizeof(*out)); | ||
421 | |||
422 | if (rp_id == NULL) { | ||
423 | fido_log_debug("%s: NULL rp_id", __func__); | ||
424 | goto fail; | ||
425 | } | ||
426 | |||
427 | if (cbor_blob_from_ec_point(pubkey, pubkey_len, &pk_blob) < 0) { | ||
428 | fido_log_debug("%s: cbor_blob_from_ec_point", __func__); | ||
429 | goto fail; | ||
430 | } | ||
431 | |||
432 | if (SHA256((const void *)rp_id, strlen(rp_id), | ||
433 | authdata.rp_id_hash) != authdata.rp_id_hash) { | ||
434 | fido_log_debug("%s: sha256", __func__); | ||
435 | goto fail; | ||
436 | } | ||
437 | |||
438 | authdata.flags = (CTAP_AUTHDATA_ATT_CRED | CTAP_AUTHDATA_USER_PRESENT); | ||
439 | authdata.sigcount = 0; | ||
440 | |||
441 | memset(&attcred_raw.aaguid, 0, sizeof(attcred_raw.aaguid)); | ||
442 | attcred_raw.id_len = (uint16_t)(kh_len << 8); /* XXX */ | ||
443 | |||
444 | len = authdata_blob.len = sizeof(authdata) + sizeof(attcred_raw) + | ||
445 | kh_len + pk_blob.len; | ||
446 | ptr = authdata_blob.ptr = calloc(1, authdata_blob.len); | ||
447 | |||
448 | fido_log_debug("%s: ptr=%p, len=%zu", __func__, (void *)ptr, len); | ||
449 | |||
450 | if (authdata_blob.ptr == NULL) | ||
451 | goto fail; | ||
452 | |||
453 | if (fido_buf_write(&ptr, &len, &authdata, sizeof(authdata)) < 0 || | ||
454 | fido_buf_write(&ptr, &len, &attcred_raw, sizeof(attcred_raw)) < 0 || | ||
455 | fido_buf_write(&ptr, &len, kh, kh_len) < 0 || | ||
456 | fido_buf_write(&ptr, &len, pk_blob.ptr, pk_blob.len) < 0) { | ||
457 | fido_log_debug("%s: fido_buf_write", __func__); | ||
458 | goto fail; | ||
459 | } | ||
460 | |||
461 | if ((authdata_cbor = fido_blob_encode(&authdata_blob)) == NULL) { | ||
462 | fido_log_debug("%s: fido_blob_encode", __func__); | ||
463 | goto fail; | ||
464 | } | ||
465 | |||
466 | if ((out->len = cbor_serialize_alloc(authdata_cbor, &out->ptr, | ||
467 | &alloc_len)) == 0) { | ||
468 | fido_log_debug("%s: cbor_serialize_alloc", __func__); | ||
469 | goto fail; | ||
470 | } | ||
471 | |||
472 | ok = 0; | ||
473 | fail: | ||
474 | if (authdata_cbor) | ||
475 | cbor_decref(&authdata_cbor); | ||
476 | |||
477 | if (pk_blob.ptr) { | ||
478 | explicit_bzero(pk_blob.ptr, pk_blob.len); | ||
479 | free(pk_blob.ptr); | ||
480 | } | ||
481 | if (authdata_blob.ptr) { | ||
482 | explicit_bzero(authdata_blob.ptr, authdata_blob.len); | ||
483 | free(authdata_blob.ptr); | ||
484 | } | ||
485 | |||
486 | return (ok); | ||
487 | } | ||
488 | |||
489 | static int | ||
490 | parse_register_reply(fido_cred_t *cred, const unsigned char *reply, size_t len) | ||
491 | { | ||
492 | fido_blob_t x5c; | ||
493 | fido_blob_t sig; | ||
494 | fido_blob_t ad; | ||
495 | uint8_t dummy; | ||
496 | uint8_t pubkey[65]; | ||
497 | uint8_t kh_len = 0; | ||
498 | uint8_t *kh = NULL; | ||
499 | int r; | ||
500 | |||
501 | memset(&x5c, 0, sizeof(x5c)); | ||
502 | memset(&sig, 0, sizeof(sig)); | ||
503 | memset(&ad, 0, sizeof(ad)); | ||
504 | r = FIDO_ERR_RX; | ||
505 | |||
506 | /* status word */ | ||
507 | if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) { | ||
508 | fido_log_debug("%s: unexpected sw", __func__); | ||
509 | goto fail; | ||
510 | } | ||
511 | |||
512 | len -= 2; | ||
513 | |||
514 | /* reserved byte */ | ||
515 | if (fido_buf_read(&reply, &len, &dummy, sizeof(dummy)) < 0 || | ||
516 | dummy != 0x05) { | ||
517 | fido_log_debug("%s: reserved byte", __func__); | ||
518 | goto fail; | ||
519 | } | ||
520 | |||
521 | /* pubkey + key handle */ | ||
522 | if (fido_buf_read(&reply, &len, &pubkey, sizeof(pubkey)) < 0 || | ||
523 | fido_buf_read(&reply, &len, &kh_len, sizeof(kh_len)) < 0 || | ||
524 | (kh = calloc(1, kh_len)) == NULL || | ||
525 | fido_buf_read(&reply, &len, kh, kh_len) < 0) { | ||
526 | fido_log_debug("%s: fido_buf_read", __func__); | ||
527 | goto fail; | ||
528 | } | ||
529 | |||
530 | /* x5c + sig */ | ||
531 | if (x5c_get(&x5c, &reply, &len) < 0 || | ||
532 | sig_get(&sig, &reply, &len) < 0) { | ||
533 | fido_log_debug("%s: x5c || sig", __func__); | ||
534 | goto fail; | ||
535 | } | ||
536 | |||
537 | /* authdata */ | ||
538 | if (encode_cred_authdata(cred->rp.id, kh, kh_len, pubkey, | ||
539 | sizeof(pubkey), &ad) < 0) { | ||
540 | fido_log_debug("%s: encode_cred_authdata", __func__); | ||
541 | goto fail; | ||
542 | } | ||
543 | |||
544 | if (fido_cred_set_fmt(cred, "fido-u2f") != FIDO_OK || | ||
545 | fido_cred_set_authdata(cred, ad.ptr, ad.len) != FIDO_OK || | ||
546 | fido_cred_set_x509(cred, x5c.ptr, x5c.len) != FIDO_OK || | ||
547 | fido_cred_set_sig(cred, sig.ptr, sig.len) != FIDO_OK) { | ||
548 | fido_log_debug("%s: fido_cred_set", __func__); | ||
549 | r = FIDO_ERR_INTERNAL; | ||
550 | goto fail; | ||
551 | } | ||
552 | |||
553 | r = FIDO_OK; | ||
554 | fail: | ||
555 | if (kh) { | ||
556 | explicit_bzero(kh, kh_len); | ||
557 | free(kh); | ||
558 | } | ||
559 | if (x5c.ptr) { | ||
560 | explicit_bzero(x5c.ptr, x5c.len); | ||
561 | free(x5c.ptr); | ||
562 | } | ||
563 | if (sig.ptr) { | ||
564 | explicit_bzero(sig.ptr, sig.len); | ||
565 | free(sig.ptr); | ||
566 | } | ||
567 | if (ad.ptr) { | ||
568 | explicit_bzero(ad.ptr, ad.len); | ||
569 | free(ad.ptr); | ||
570 | } | ||
571 | |||
572 | return (r); | ||
573 | } | ||
574 | |||
575 | int | ||
576 | u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms) | ||
577 | { | ||
578 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_MSG; | ||
579 | iso7816_apdu_t *apdu = NULL; | ||
580 | unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; | ||
581 | unsigned char reply[2048]; | ||
582 | int reply_len; | ||
583 | int found; | ||
584 | int r; | ||
585 | |||
586 | #ifdef FIDO_FUZZ | ||
587 | ms = 0; /* XXX */ | ||
588 | #endif | ||
589 | |||
590 | if (cred->rk == FIDO_OPT_TRUE || cred->uv == FIDO_OPT_TRUE) { | ||
591 | fido_log_debug("%s: rk=%d, uv=%d", __func__, cred->rk, | ||
592 | cred->uv); | ||
593 | return (FIDO_ERR_UNSUPPORTED_OPTION); | ||
594 | } | ||
595 | |||
596 | if (cred->type != COSE_ES256 || cred->cdh.ptr == NULL || | ||
597 | cred->rp.id == NULL || cred->cdh.len != SHA256_DIGEST_LENGTH) { | ||
598 | fido_log_debug("%s: type=%d, cdh=(%p,%zu)" , __func__, | ||
599 | cred->type, (void *)cred->cdh.ptr, cred->cdh.len); | ||
600 | return (FIDO_ERR_INVALID_ARGUMENT); | ||
601 | } | ||
602 | |||
603 | for (size_t i = 0; i < cred->excl.len; i++) { | ||
604 | if ((r = key_lookup(dev, cred->rp.id, &cred->excl.ptr[i], | ||
605 | &found, ms)) != FIDO_OK) { | ||
606 | fido_log_debug("%s: key_lookup", __func__); | ||
607 | return (r); | ||
608 | } | ||
609 | if (found) { | ||
610 | if ((r = send_dummy_register(dev, ms)) != FIDO_OK) { | ||
611 | fido_log_debug("%s: send_dummy_register", | ||
612 | __func__); | ||
613 | return (r); | ||
614 | } | ||
615 | return (FIDO_ERR_CREDENTIAL_EXCLUDED); | ||
616 | } | ||
617 | } | ||
618 | |||
619 | memset(&rp_id_hash, 0, sizeof(rp_id_hash)); | ||
620 | |||
621 | if (SHA256((const void *)cred->rp.id, strlen(cred->rp.id), | ||
622 | rp_id_hash) != rp_id_hash) { | ||
623 | fido_log_debug("%s: sha256", __func__); | ||
624 | return (FIDO_ERR_INTERNAL); | ||
625 | } | ||
626 | |||
627 | if ((apdu = iso7816_new(U2F_CMD_REGISTER, 0, 2 * | ||
628 | SHA256_DIGEST_LENGTH)) == NULL || | ||
629 | iso7816_add(apdu, cred->cdh.ptr, cred->cdh.len) < 0 || | ||
630 | iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) { | ||
631 | fido_log_debug("%s: iso7816", __func__); | ||
632 | r = FIDO_ERR_INTERNAL; | ||
633 | goto fail; | ||
634 | } | ||
635 | |||
636 | do { | ||
637 | if (fido_tx(dev, cmd, iso7816_ptr(apdu), | ||
638 | iso7816_len(apdu)) < 0) { | ||
639 | fido_log_debug("%s: fido_tx", __func__); | ||
640 | r = FIDO_ERR_TX; | ||
641 | goto fail; | ||
642 | } | ||
643 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), | ||
644 | ms)) < 2) { | ||
645 | fido_log_debug("%s: fido_rx", __func__); | ||
646 | r = FIDO_ERR_RX; | ||
647 | goto fail; | ||
648 | } | ||
649 | if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) { | ||
650 | fido_log_debug("%s: usleep", __func__); | ||
651 | r = FIDO_ERR_RX; | ||
652 | goto fail; | ||
653 | } | ||
654 | } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED); | ||
655 | |||
656 | if ((r = parse_register_reply(cred, reply, | ||
657 | (size_t)reply_len)) != FIDO_OK) { | ||
658 | fido_log_debug("%s: parse_register_reply", __func__); | ||
659 | goto fail; | ||
660 | } | ||
661 | fail: | ||
662 | iso7816_free(&apdu); | ||
663 | |||
664 | return (r); | ||
665 | } | ||
666 | |||
667 | static int | ||
668 | u2f_authenticate_single(fido_dev_t *dev, const fido_blob_t *key_id, | ||
669 | fido_assert_t *fa, size_t idx, int ms) | ||
670 | { | ||
671 | fido_blob_t sig; | ||
672 | fido_blob_t ad; | ||
673 | int found; | ||
674 | int r; | ||
675 | |||
676 | memset(&sig, 0, sizeof(sig)); | ||
677 | memset(&ad, 0, sizeof(ad)); | ||
678 | |||
679 | if ((r = key_lookup(dev, fa->rp_id, key_id, &found, ms)) != FIDO_OK) { | ||
680 | fido_log_debug("%s: key_lookup", __func__); | ||
681 | goto fail; | ||
682 | } | ||
683 | |||
684 | if (!found) { | ||
685 | fido_log_debug("%s: not found", __func__); | ||
686 | r = FIDO_ERR_CREDENTIAL_EXCLUDED; | ||
687 | goto fail; | ||
688 | } | ||
689 | |||
690 | if (fa->up == FIDO_OPT_FALSE) { | ||
691 | fido_log_debug("%s: checking for key existence only", __func__); | ||
692 | r = FIDO_ERR_USER_PRESENCE_REQUIRED; | ||
693 | goto fail; | ||
694 | } | ||
695 | |||
696 | if ((r = do_auth(dev, &fa->cdh, fa->rp_id, key_id, &sig, &ad, | ||
697 | ms)) != FIDO_OK) { | ||
698 | fido_log_debug("%s: do_auth", __func__); | ||
699 | goto fail; | ||
700 | } | ||
701 | |||
702 | if (fido_blob_set(&fa->stmt[idx].id, key_id->ptr, key_id->len) < 0 || | ||
703 | fido_assert_set_authdata(fa, idx, ad.ptr, ad.len) != FIDO_OK || | ||
704 | fido_assert_set_sig(fa, idx, sig.ptr, sig.len) != FIDO_OK) { | ||
705 | fido_log_debug("%s: fido_assert_set", __func__); | ||
706 | r = FIDO_ERR_INTERNAL; | ||
707 | goto fail; | ||
708 | } | ||
709 | |||
710 | r = FIDO_OK; | ||
711 | fail: | ||
712 | if (sig.ptr) { | ||
713 | explicit_bzero(sig.ptr, sig.len); | ||
714 | free(sig.ptr); | ||
715 | } | ||
716 | if (ad.ptr) { | ||
717 | explicit_bzero(ad.ptr, ad.len); | ||
718 | free(ad.ptr); | ||
719 | } | ||
720 | |||
721 | return (r); | ||
722 | } | ||
723 | |||
724 | int | ||
725 | u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms) | ||
726 | { | ||
727 | int nauth_ok = 0; | ||
728 | int r; | ||
729 | |||
730 | if (fa->uv == FIDO_OPT_TRUE || fa->allow_list.ptr == NULL) { | ||
731 | fido_log_debug("%s: uv=%d, allow_list=%p", __func__, fa->uv, | ||
732 | (void *)fa->allow_list.ptr); | ||
733 | return (FIDO_ERR_UNSUPPORTED_OPTION); | ||
734 | } | ||
735 | |||
736 | if ((r = fido_assert_set_count(fa, fa->allow_list.len)) != FIDO_OK) { | ||
737 | fido_log_debug("%s: fido_assert_set_count", __func__); | ||
738 | return (r); | ||
739 | } | ||
740 | |||
741 | for (size_t i = 0; i < fa->allow_list.len; i++) { | ||
742 | if ((r = u2f_authenticate_single(dev, &fa->allow_list.ptr[i], | ||
743 | fa, nauth_ok, ms)) == FIDO_OK) { | ||
744 | nauth_ok++; | ||
745 | } else if (r != FIDO_ERR_CREDENTIAL_EXCLUDED) { | ||
746 | fido_log_debug("%s: u2f_authenticate_single", __func__); | ||
747 | return (r); | ||
748 | } | ||
749 | /* ignore credentials that don't exist */ | ||
750 | } | ||
751 | |||
752 | fa->stmt_len = nauth_ok; | ||
753 | |||
754 | if (nauth_ok == 0) | ||
755 | return (FIDO_ERR_NO_CREDENTIALS); | ||
756 | |||
757 | return (FIDO_OK); | ||
758 | } | ||
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt new file mode 100644 index 0000000..5f27e88 --- /dev/null +++ b/tools/CMakeLists.txt | |||
@@ -0,0 +1,65 @@ | |||
1 | # Copyright (c) 2018 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 | list(APPEND COMPAT_SOURCES | ||
6 | ../openbsd-compat/explicit_bzero.c | ||
7 | ../openbsd-compat/strlcpy.c | ||
8 | ../openbsd-compat/strlcat.c | ||
9 | ) | ||
10 | |||
11 | if(WIN32) | ||
12 | list(APPEND COMPAT_SOURCES | ||
13 | ../openbsd-compat/bsd-getline.c | ||
14 | ../openbsd-compat/explicit_bzero_win32.c | ||
15 | ../openbsd-compat/getopt_long.c | ||
16 | ../openbsd-compat/posix_win.c | ||
17 | ../openbsd-compat/readpassphrase_win32.c | ||
18 | ) | ||
19 | else() | ||
20 | list(APPEND COMPAT_SOURCES ../openbsd-compat/readpassphrase.c) | ||
21 | endif() | ||
22 | |||
23 | add_executable(fido2-cred | ||
24 | fido2-cred.c | ||
25 | cred_make.c | ||
26 | cred_verify.c | ||
27 | base64.c | ||
28 | util.c | ||
29 | ${COMPAT_SOURCES} | ||
30 | ) | ||
31 | |||
32 | add_executable(fido2-assert | ||
33 | fido2-assert.c | ||
34 | assert_get.c | ||
35 | assert_verify.c | ||
36 | base64.c | ||
37 | util.c | ||
38 | ${COMPAT_SOURCES} | ||
39 | ) | ||
40 | |||
41 | add_executable(fido2-token | ||
42 | fido2-token.c | ||
43 | base64.c | ||
44 | bio.c | ||
45 | credman.c | ||
46 | pin.c | ||
47 | token.c | ||
48 | util.c | ||
49 | ${COMPAT_SOURCES} | ||
50 | ) | ||
51 | |||
52 | add_library(sk-libfido2 MODULE sk-libfido2.c) | ||
53 | set_target_properties(sk-libfido2 PROPERTIES | ||
54 | COMPILE_FLAGS "-DSK_STANDALONE -DWITH_OPENSSL" | ||
55 | OUTPUT_NAME sk-libfido2 | ||
56 | ) | ||
57 | |||
58 | target_link_libraries(fido2-cred ${CRYPTO_LIBRARIES} fido2_shared) | ||
59 | target_link_libraries(fido2-assert ${CRYPTO_LIBRARIES} fido2_shared) | ||
60 | target_link_libraries(fido2-token ${CRYPTO_LIBRARIES} fido2_shared) | ||
61 | target_link_libraries(sk-libfido2 ${CRYPTO_LIBRARIES} fido2_shared) | ||
62 | |||
63 | install(TARGETS fido2-cred fido2-assert fido2-token | ||
64 | DESTINATION ${CMAKE_INSTALL_BINDIR}) | ||
65 | install(TARGETS sk-libfido2 DESTINATION ${CMAKE_INSTALL_LIBDIR}) | ||
diff --git a/tools/assert_get.c b/tools/assert_get.c new file mode 100644 index 0000000..5e209cd --- /dev/null +++ b/tools/assert_get.c | |||
@@ -0,0 +1,233 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <fido.h> | ||
8 | #include <stdio.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | #ifdef HAVE_UNISTD_H | ||
12 | #include <unistd.h> | ||
13 | #endif | ||
14 | |||
15 | #include "../openbsd-compat/openbsd-compat.h" | ||
16 | #include "extern.h" | ||
17 | |||
18 | static fido_assert_t * | ||
19 | prepare_assert(FILE *in_f, int flags) | ||
20 | { | ||
21 | fido_assert_t *assert = NULL; | ||
22 | struct blob cdh; | ||
23 | struct blob id; | ||
24 | struct blob hmac_salt; | ||
25 | char *rpid = NULL; | ||
26 | int r; | ||
27 | |||
28 | memset(&cdh, 0, sizeof(cdh)); | ||
29 | memset(&id, 0, sizeof(id)); | ||
30 | memset(&hmac_salt, 0, sizeof(hmac_salt)); | ||
31 | |||
32 | r = base64_read(in_f, &cdh); | ||
33 | r |= string_read(in_f, &rpid); | ||
34 | if ((flags & FLAG_RK) == 0) | ||
35 | r |= base64_read(in_f, &id); | ||
36 | if (flags & FLAG_HMAC) | ||
37 | r |= base64_read(in_f, &hmac_salt); | ||
38 | if (r < 0) | ||
39 | errx(1, "input error"); | ||
40 | |||
41 | if (flags & FLAG_DEBUG) { | ||
42 | fprintf(stderr, "client data hash:\n"); | ||
43 | xxd(cdh.ptr, cdh.len); | ||
44 | fprintf(stderr, "relying party id: %s\n", rpid); | ||
45 | if ((flags & FLAG_RK) == 0) { | ||
46 | fprintf(stderr, "credential id:\n"); | ||
47 | xxd(id.ptr, id.len); | ||
48 | } | ||
49 | } | ||
50 | |||
51 | if ((assert = fido_assert_new()) == NULL) | ||
52 | errx(1, "fido_assert_new"); | ||
53 | |||
54 | if ((r = fido_assert_set_clientdata_hash(assert, cdh.ptr, | ||
55 | cdh.len)) != FIDO_OK || | ||
56 | (r = fido_assert_set_rp(assert, rpid)) != FIDO_OK) | ||
57 | errx(1, "fido_assert_set: %s", fido_strerr(r)); | ||
58 | |||
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) { | ||
68 | if ((r = fido_assert_set_extensions(assert, | ||
69 | FIDO_EXT_HMAC_SECRET)) != FIDO_OK) | ||
70 | errx(1, "fido_assert_set_extensions: %s", | ||
71 | fido_strerr(r)); | ||
72 | if ((r = fido_assert_set_hmac_salt(assert, hmac_salt.ptr, | ||
73 | hmac_salt.len)) != FIDO_OK) | ||
74 | errx(1, "fido_assert_set_hmac_salt: %s", | ||
75 | fido_strerr(r)); | ||
76 | } | ||
77 | if ((flags & FLAG_RK) == 0) { | ||
78 | if ((r = fido_assert_allow_cred(assert, id.ptr, | ||
79 | id.len)) != FIDO_OK) | ||
80 | errx(1, "fido_assert_allow_cred: %s", fido_strerr(r)); | ||
81 | } | ||
82 | |||
83 | free(hmac_salt.ptr); | ||
84 | free(cdh.ptr); | ||
85 | free(id.ptr); | ||
86 | free(rpid); | ||
87 | |||
88 | return (assert); | ||
89 | } | ||
90 | |||
91 | static void | ||
92 | print_assert(FILE *out_f, const fido_assert_t *assert, size_t idx, int flags) | ||
93 | { | ||
94 | char *cdh = NULL; | ||
95 | char *authdata = NULL; | ||
96 | char *sig = NULL; | ||
97 | char *user_id = NULL; | ||
98 | char *hmac_secret = NULL; | ||
99 | int r; | ||
100 | |||
101 | r = base64_encode(fido_assert_clientdata_hash_ptr(assert), | ||
102 | fido_assert_clientdata_hash_len(assert), &cdh); | ||
103 | r |= base64_encode(fido_assert_authdata_ptr(assert, idx), | ||
104 | fido_assert_authdata_len(assert, 0), &authdata); | ||
105 | r |= base64_encode(fido_assert_sig_ptr(assert, idx), | ||
106 | fido_assert_sig_len(assert, idx), &sig); | ||
107 | if (flags & FLAG_RK) | ||
108 | r |= base64_encode(fido_assert_user_id_ptr(assert, idx), | ||
109 | fido_assert_user_id_len(assert, idx), &user_id); | ||
110 | if (flags & FLAG_HMAC) | ||
111 | r |= base64_encode(fido_assert_hmac_secret_ptr(assert, idx), | ||
112 | fido_assert_hmac_secret_len(assert, idx), &hmac_secret); | ||
113 | if (r < 0) | ||
114 | errx(1, "output error"); | ||
115 | |||
116 | fprintf(out_f, "%s\n", cdh); | ||
117 | fprintf(out_f, "%s\n", fido_assert_rp_id(assert)); | ||
118 | fprintf(out_f, "%s\n", authdata); | ||
119 | fprintf(out_f, "%s\n", sig); | ||
120 | if (flags & FLAG_RK) | ||
121 | fprintf(out_f, "%s\n", user_id); | ||
122 | if (hmac_secret) { | ||
123 | fprintf(out_f, "%s\n", hmac_secret); | ||
124 | explicit_bzero(hmac_secret, strlen(hmac_secret)); | ||
125 | } | ||
126 | |||
127 | free(hmac_secret); | ||
128 | free(cdh); | ||
129 | free(authdata); | ||
130 | free(sig); | ||
131 | free(user_id); | ||
132 | } | ||
133 | |||
134 | int | ||
135 | assert_get(int argc, char **argv) | ||
136 | { | ||
137 | fido_dev_t *dev = NULL; | ||
138 | fido_assert_t *assert = NULL; | ||
139 | char pin[1024]; | ||
140 | char prompt[1024]; | ||
141 | char *in_path = NULL; | ||
142 | char *out_path = NULL; | ||
143 | FILE *in_f = NULL; | ||
144 | FILE *out_f = NULL; | ||
145 | int flags = 0; | ||
146 | int ch; | ||
147 | int r; | ||
148 | |||
149 | while ((ch = getopt(argc, argv, "dhi:o:pruv")) != -1) { | ||
150 | switch (ch) { | ||
151 | case 'd': | ||
152 | flags |= FLAG_DEBUG; | ||
153 | break; | ||
154 | case 'h': | ||
155 | flags |= FLAG_HMAC; | ||
156 | break; | ||
157 | case 'i': | ||
158 | in_path = optarg; | ||
159 | break; | ||
160 | case 'o': | ||
161 | out_path = optarg; | ||
162 | break; | ||
163 | case 'p': | ||
164 | flags |= FLAG_UP; | ||
165 | break; | ||
166 | case 'r': | ||
167 | flags |= FLAG_RK; | ||
168 | break; | ||
169 | case 'u': | ||
170 | flags |= FLAG_U2F; | ||
171 | break; | ||
172 | case 'v': | ||
173 | flags |= FLAG_UV; | ||
174 | break; | ||
175 | default: | ||
176 | usage(); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | argc -= optind; | ||
181 | argv += optind; | ||
182 | |||
183 | if (argc < 1) | ||
184 | usage(); | ||
185 | |||
186 | in_f = open_read(in_path); | ||
187 | out_f = open_write(out_path); | ||
188 | |||
189 | fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); | ||
190 | |||
191 | assert = prepare_assert(in_f, flags); | ||
192 | |||
193 | dev = open_dev(argv[0]); | ||
194 | if (flags & FLAG_U2F) | ||
195 | fido_dev_force_u2f(dev); | ||
196 | |||
197 | if (flags & FLAG_UV) { | ||
198 | r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", | ||
199 | argv[0]); | ||
200 | if (r < 0 || (size_t)r >= sizeof(prompt)) | ||
201 | errx(1, "snprintf"); | ||
202 | if (!readpassphrase(prompt, pin, sizeof(pin), RPP_ECHO_OFF)) | ||
203 | errx(1, "readpassphrase"); | ||
204 | r = fido_dev_get_assert(dev, assert, pin); | ||
205 | } else | ||
206 | r = fido_dev_get_assert(dev, assert, NULL); | ||
207 | |||
208 | explicit_bzero(pin, sizeof(pin)); | ||
209 | |||
210 | if (r != FIDO_OK) | ||
211 | errx(1, "fido_dev_get_assert: %s", fido_strerr(r)); | ||
212 | |||
213 | if (flags & FLAG_RK) { | ||
214 | for (size_t idx = 0; idx < fido_assert_count(assert); idx++) | ||
215 | print_assert(out_f, assert, idx, flags); | ||
216 | } else { | ||
217 | if (fido_assert_count(assert) != 1) | ||
218 | errx(1, "fido_assert_count: %zu", | ||
219 | fido_assert_count(assert)); | ||
220 | print_assert(out_f, assert, 0, flags); | ||
221 | } | ||
222 | |||
223 | fido_dev_close(dev); | ||
224 | fido_dev_free(&dev); | ||
225 | fido_assert_free(&assert); | ||
226 | |||
227 | fclose(in_f); | ||
228 | fclose(out_f); | ||
229 | in_f = NULL; | ||
230 | out_f = NULL; | ||
231 | |||
232 | exit(0); | ||
233 | } | ||
diff --git a/tools/assert_verify.c b/tools/assert_verify.c new file mode 100644 index 0000000..ccff57a --- /dev/null +++ b/tools/assert_verify.c | |||
@@ -0,0 +1,201 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <fido.h> | ||
8 | #include <fido/es256.h> | ||
9 | #include <fido/rs256.h> | ||
10 | #include <fido/eddsa.h> | ||
11 | |||
12 | #include <stdbool.h> | ||
13 | #include <stdio.h> | ||
14 | #include <stdlib.h> | ||
15 | #include <string.h> | ||
16 | #ifdef HAVE_UNISTD_H | ||
17 | #include <unistd.h> | ||
18 | #endif | ||
19 | |||
20 | #include "../openbsd-compat/openbsd-compat.h" | ||
21 | #include "extern.h" | ||
22 | |||
23 | static fido_assert_t * | ||
24 | prepare_assert(FILE *in_f, int flags) | ||
25 | { | ||
26 | fido_assert_t *assert = NULL; | ||
27 | struct blob cdh; | ||
28 | struct blob authdata; | ||
29 | struct blob sig; | ||
30 | char *rpid = NULL; | ||
31 | int r; | ||
32 | |||
33 | memset(&cdh, 0, sizeof(cdh)); | ||
34 | memset(&authdata, 0, sizeof(authdata)); | ||
35 | memset(&sig, 0, sizeof(sig)); | ||
36 | |||
37 | r = base64_read(in_f, &cdh); | ||
38 | r |= string_read(in_f, &rpid); | ||
39 | r |= base64_read(in_f, &authdata); | ||
40 | r |= base64_read(in_f, &sig); | ||
41 | if (r < 0) | ||
42 | errx(1, "input error"); | ||
43 | |||
44 | if (flags & FLAG_DEBUG) { | ||
45 | fprintf(stderr, "client data hash:\n"); | ||
46 | xxd(cdh.ptr, cdh.len); | ||
47 | fprintf(stderr, "relying party id: %s\n", rpid); | ||
48 | fprintf(stderr, "authenticator data:\n"); | ||
49 | xxd(authdata.ptr, authdata.len); | ||
50 | fprintf(stderr, "signature:\n"); | ||
51 | xxd(sig.ptr, sig.len); | ||
52 | } | ||
53 | |||
54 | if ((assert = fido_assert_new()) == NULL) | ||
55 | errx(1, "fido_assert_new"); | ||
56 | if ((r = fido_assert_set_count(assert, 1)) != FIDO_OK) | ||
57 | errx(1, "fido_assert_count: %s", fido_strerr(r)); | ||
58 | |||
59 | if ((r = fido_assert_set_clientdata_hash(assert, cdh.ptr, | ||
60 | cdh.len)) != FIDO_OK || | ||
61 | (r = fido_assert_set_rp(assert, rpid)) != FIDO_OK || | ||
62 | (r = fido_assert_set_authdata(assert, 0, authdata.ptr, | ||
63 | authdata.len)) != FIDO_OK || | ||
64 | (r = fido_assert_set_sig(assert, 0, sig.ptr, sig.len)) != FIDO_OK) | ||
65 | errx(1, "fido_assert_set: %s", fido_strerr(r)); | ||
66 | |||
67 | if (flags & FLAG_UP) { | ||
68 | if ((r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) | ||
69 | errx(1, "fido_assert_set_up: %s", fido_strerr(r)); | ||
70 | } | ||
71 | if (flags & FLAG_UV) { | ||
72 | if ((r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) | ||
73 | errx(1, "fido_assert_set_uv: %s", fido_strerr(r)); | ||
74 | } | ||
75 | if (flags & FLAG_HMAC) { | ||
76 | if ((r = fido_assert_set_extensions(assert, | ||
77 | FIDO_EXT_HMAC_SECRET)) != FIDO_OK) | ||
78 | errx(1, "fido_assert_set_extensions: %s", | ||
79 | fido_strerr(r)); | ||
80 | } | ||
81 | |||
82 | free(cdh.ptr); | ||
83 | free(authdata.ptr); | ||
84 | free(sig.ptr); | ||
85 | free(rpid); | ||
86 | |||
87 | return (assert); | ||
88 | } | ||
89 | |||
90 | static void * | ||
91 | load_pubkey(int type, const char *file) | ||
92 | { | ||
93 | EC_KEY *ec = NULL; | ||
94 | RSA *rsa = NULL; | ||
95 | EVP_PKEY *eddsa = NULL; | ||
96 | es256_pk_t *es256_pk = NULL; | ||
97 | rs256_pk_t *rs256_pk = NULL; | ||
98 | eddsa_pk_t *eddsa_pk = NULL; | ||
99 | void *pk = NULL; | ||
100 | |||
101 | if (type == COSE_ES256) { | ||
102 | if ((ec = read_ec_pubkey(file)) == NULL) | ||
103 | errx(1, "read_ec_pubkey"); | ||
104 | if ((es256_pk = es256_pk_new()) == NULL) | ||
105 | errx(1, "es256_pk_new"); | ||
106 | if (es256_pk_from_EC_KEY(es256_pk, ec) != FIDO_OK) | ||
107 | errx(1, "es256_pk_from_EC_KEY"); | ||
108 | |||
109 | pk = es256_pk; | ||
110 | EC_KEY_free(ec); | ||
111 | } else if (type == COSE_RS256) { | ||
112 | if ((rsa = read_rsa_pubkey(file)) == NULL) | ||
113 | errx(1, "read_rsa_pubkey"); | ||
114 | if ((rs256_pk = rs256_pk_new()) == NULL) | ||
115 | errx(1, "rs256_pk_new"); | ||
116 | if (rs256_pk_from_RSA(rs256_pk, rsa) != FIDO_OK) | ||
117 | errx(1, "rs256_pk_from_RSA"); | ||
118 | |||
119 | pk = rs256_pk; | ||
120 | RSA_free(rsa); | ||
121 | } else if (type == COSE_EDDSA) { | ||
122 | if ((eddsa = read_eddsa_pubkey(file)) == NULL) | ||
123 | errx(1, "read_eddsa_pubkey"); | ||
124 | if ((eddsa_pk = eddsa_pk_new()) == NULL) | ||
125 | errx(1, "eddsa_pk_new"); | ||
126 | if (eddsa_pk_from_EVP_PKEY(eddsa_pk, eddsa) != FIDO_OK) | ||
127 | errx(1, "eddsa_pk_from_EVP_PKEY"); | ||
128 | |||
129 | pk = eddsa_pk; | ||
130 | EVP_PKEY_free(eddsa); | ||
131 | } | ||
132 | |||
133 | return (pk); | ||
134 | } | ||
135 | |||
136 | int | ||
137 | assert_verify(int argc, char **argv) | ||
138 | { | ||
139 | fido_assert_t *assert = NULL; | ||
140 | void *pk = NULL; | ||
141 | char *in_path = NULL; | ||
142 | FILE *in_f = NULL; | ||
143 | int type = COSE_ES256; | ||
144 | int flags = 0; | ||
145 | int ch; | ||
146 | int r; | ||
147 | |||
148 | while ((ch = getopt(argc, argv, "dhi:pv")) != -1) { | ||
149 | switch (ch) { | ||
150 | case 'd': | ||
151 | flags |= FLAG_DEBUG; | ||
152 | break; | ||
153 | case 'h': | ||
154 | flags |= FLAG_HMAC; | ||
155 | break; | ||
156 | case 'i': | ||
157 | in_path = optarg; | ||
158 | break; | ||
159 | case 'p': | ||
160 | flags |= FLAG_UP; | ||
161 | break; | ||
162 | case 'v': | ||
163 | flags |= FLAG_UV; | ||
164 | break; | ||
165 | default: | ||
166 | usage(); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | argc -= optind; | ||
171 | argv += optind; | ||
172 | |||
173 | if (argc < 1 || argc > 2) | ||
174 | usage(); | ||
175 | |||
176 | in_f = open_read(in_path); | ||
177 | |||
178 | if (argc > 1) { | ||
179 | if (strcmp(argv[1], "es256") == 0) | ||
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 | |||
189 | fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); | ||
190 | |||
191 | pk = load_pubkey(type, argv[0]); | ||
192 | assert = prepare_assert(in_f, flags); | ||
193 | if ((r = fido_assert_verify(assert, 0, type, pk)) != FIDO_OK) | ||
194 | errx(1, "fido_assert_verify: %s", fido_strerr(r)); | ||
195 | fido_assert_free(&assert); | ||
196 | |||
197 | fclose(in_f); | ||
198 | in_f = NULL; | ||
199 | |||
200 | exit(0); | ||
201 | } | ||
diff --git a/tools/base64.c b/tools/base64.c new file mode 100644 index 0000000..9f31def --- /dev/null +++ b/tools/base64.c | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <openssl/bio.h> | ||
8 | #include <openssl/evp.h> | ||
9 | |||
10 | #include <fido.h> | ||
11 | #include <limits.h> | ||
12 | #include <stdint.h> | ||
13 | #include <string.h> | ||
14 | |||
15 | #include "../openbsd-compat/openbsd-compat.h" | ||
16 | #include "extern.h" | ||
17 | |||
18 | int | ||
19 | base64_encode(const void *ptr, size_t len, char **out) | ||
20 | { | ||
21 | BIO *bio_b64 = NULL; | ||
22 | BIO *bio_mem = NULL; | ||
23 | char *b64_ptr = NULL; | ||
24 | long b64_len; | ||
25 | int n; | ||
26 | int ok = -1; | ||
27 | |||
28 | if (ptr == NULL || out == NULL || len > INT_MAX) | ||
29 | return (-1); | ||
30 | |||
31 | *out = NULL; | ||
32 | |||
33 | if ((bio_b64 = BIO_new(BIO_f_base64())) == NULL) | ||
34 | goto fail; | ||
35 | if ((bio_mem = BIO_new(BIO_s_mem())) == NULL) | ||
36 | goto fail; | ||
37 | |||
38 | BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL); | ||
39 | BIO_push(bio_b64, bio_mem); | ||
40 | |||
41 | n = BIO_write(bio_b64, ptr, (int)len); | ||
42 | if (n < 0 || (size_t)n != len) | ||
43 | goto fail; | ||
44 | |||
45 | if (BIO_flush(bio_b64) < 0) | ||
46 | goto fail; | ||
47 | |||
48 | b64_len = BIO_get_mem_data(bio_b64, &b64_ptr); | ||
49 | if (b64_len < 0 || (size_t)b64_len == SIZE_MAX || b64_ptr == NULL) | ||
50 | goto fail; | ||
51 | if ((*out = calloc(1, (size_t)b64_len + 1)) == NULL) | ||
52 | goto fail; | ||
53 | |||
54 | memcpy(*out, b64_ptr, (size_t)b64_len); | ||
55 | ok = 0; | ||
56 | |||
57 | fail: | ||
58 | BIO_free(bio_b64); | ||
59 | BIO_free(bio_mem); | ||
60 | |||
61 | return (ok); | ||
62 | } | ||
63 | |||
64 | int | ||
65 | base64_decode(char *in, void **ptr, size_t *len) | ||
66 | { | ||
67 | BIO *bio_mem = NULL; | ||
68 | BIO *bio_b64 = NULL; | ||
69 | size_t alloc_len; | ||
70 | int n; | ||
71 | int ok = -1; | ||
72 | |||
73 | if (in == NULL || ptr == NULL || len == NULL || strlen(in) > INT_MAX) | ||
74 | return (-1); | ||
75 | |||
76 | *ptr = NULL; | ||
77 | *len = 0; | ||
78 | |||
79 | if ((bio_b64 = BIO_new(BIO_f_base64())) == NULL) | ||
80 | goto fail; | ||
81 | if ((bio_mem = BIO_new_mem_buf((void *)in, -1)) == NULL) | ||
82 | goto fail; | ||
83 | |||
84 | BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL); | ||
85 | BIO_push(bio_b64, bio_mem); | ||
86 | |||
87 | alloc_len = strlen(in); | ||
88 | if ((*ptr = calloc(1, alloc_len)) == NULL) | ||
89 | goto fail; | ||
90 | |||
91 | n = BIO_read(bio_b64, *ptr, (int)alloc_len); | ||
92 | if (n <= 0 || BIO_eof(bio_b64) == 0) | ||
93 | goto fail; | ||
94 | |||
95 | *len = (size_t)n; | ||
96 | ok = 0; | ||
97 | |||
98 | fail: | ||
99 | BIO_free(bio_b64); | ||
100 | BIO_free(bio_mem); | ||
101 | |||
102 | if (ok < 0) { | ||
103 | free(*ptr); | ||
104 | *ptr = NULL; | ||
105 | *len = 0; | ||
106 | } | ||
107 | |||
108 | return (ok); | ||
109 | } | ||
110 | |||
111 | int | ||
112 | base64_read(FILE *f, struct blob *out) | ||
113 | { | ||
114 | char *line = NULL; | ||
115 | size_t linesize = 0; | ||
116 | ssize_t n; | ||
117 | |||
118 | out->ptr = NULL; | ||
119 | out->len = 0; | ||
120 | |||
121 | if ((n = getline(&line, &linesize, f)) <= 0 || | ||
122 | (size_t)n != strlen(line)) { | ||
123 | free(line); /* XXX should be free'd _even_ if getline() fails */ | ||
124 | return (-1); | ||
125 | } | ||
126 | |||
127 | if (base64_decode(line, (void **)&out->ptr, &out->len) < 0) { | ||
128 | free(line); | ||
129 | return (-1); | ||
130 | } | ||
131 | |||
132 | free(line); | ||
133 | |||
134 | return (0); | ||
135 | } | ||
diff --git a/tools/bio.c b/tools/bio.c new file mode 100644 index 0000000..b8f9b38 --- /dev/null +++ b/tools/bio.c | |||
@@ -0,0 +1,270 @@ | |||
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 <fido.h> | ||
8 | #include <fido/bio.h> | ||
9 | |||
10 | #include <stdbool.h> | ||
11 | #include <stdio.h> | ||
12 | #include <stdlib.h> | ||
13 | #include <string.h> | ||
14 | #ifdef HAVE_UNISTD_H | ||
15 | #include <unistd.h> | ||
16 | #endif | ||
17 | |||
18 | #include "../openbsd-compat/openbsd-compat.h" | ||
19 | #include "extern.h" | ||
20 | |||
21 | static void | ||
22 | print_template(const fido_bio_template_array_t *ta, size_t idx) | ||
23 | { | ||
24 | char *id = NULL; | ||
25 | const fido_bio_template_t *t = NULL; | ||
26 | |||
27 | if ((t = fido_bio_template(ta, idx)) == NULL) | ||
28 | errx(1, "fido_bio_template"); | ||
29 | |||
30 | if (base64_encode(fido_bio_template_id_ptr(t), | ||
31 | fido_bio_template_id_len(t), &id) < 0) | ||
32 | errx(1, "output error"); | ||
33 | |||
34 | printf("%02u: %s %s\n", (unsigned)idx, id, fido_bio_template_name(t)); | ||
35 | |||
36 | free(id); | ||
37 | } | ||
38 | |||
39 | int | ||
40 | bio_list(char *path) | ||
41 | { | ||
42 | char pin[1024]; | ||
43 | fido_bio_template_array_t *ta = NULL; | ||
44 | fido_dev_t *dev = NULL; | ||
45 | int r; | ||
46 | |||
47 | if (path == NULL) | ||
48 | usage(); | ||
49 | if ((ta = fido_bio_template_array_new()) == NULL) | ||
50 | errx(1, "fido_bio_template_array_new"); | ||
51 | |||
52 | dev = open_dev(path); | ||
53 | read_pin(path, pin, sizeof(pin)); | ||
54 | r = fido_bio_dev_get_template_array(dev, ta, pin); | ||
55 | explicit_bzero(pin, sizeof(pin)); | ||
56 | |||
57 | if (r != FIDO_OK) | ||
58 | errx(1, "fido_bio_dev_get_template_array: %s", fido_strerr(r)); | ||
59 | for (size_t i = 0; i < fido_bio_template_array_count(ta); i++) | ||
60 | print_template(ta, i); | ||
61 | |||
62 | fido_bio_template_array_free(&ta); | ||
63 | fido_dev_close(dev); | ||
64 | fido_dev_free(&dev); | ||
65 | |||
66 | exit(0); | ||
67 | } | ||
68 | |||
69 | int | ||
70 | bio_set_name(char *path, char *id, char *name) | ||
71 | { | ||
72 | char pin[1024]; | ||
73 | fido_bio_template_t *t = NULL; | ||
74 | fido_dev_t *dev = NULL; | ||
75 | int r; | ||
76 | size_t id_blob_len = 0; | ||
77 | void *id_blob_ptr = NULL; | ||
78 | |||
79 | if (path == NULL) | ||
80 | usage(); | ||
81 | if ((t = fido_bio_template_new()) == NULL) | ||
82 | errx(1, "fido_bio_template_new"); | ||
83 | |||
84 | if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0) | ||
85 | errx(1, "base64_decode"); | ||
86 | |||
87 | if ((r = fido_bio_template_set_name(t, name)) != FIDO_OK) | ||
88 | errx(1, "fido_bio_template_set_name: %s", fido_strerr(r)); | ||
89 | if ((r = fido_bio_template_set_id(t, id_blob_ptr, | ||
90 | id_blob_len)) != FIDO_OK) | ||
91 | errx(1, "fido_bio_template_set_id: %s", fido_strerr(r)); | ||
92 | |||
93 | dev = open_dev(path); | ||
94 | read_pin(path, pin, sizeof(pin)); | ||
95 | r = fido_bio_dev_set_template_name(dev, t, pin); | ||
96 | explicit_bzero(pin, sizeof(pin)); | ||
97 | |||
98 | if (r != FIDO_OK) | ||
99 | errx(1, "fido_bio_dev_set_template_name: %s", fido_strerr(r)); | ||
100 | |||
101 | free(id_blob_ptr); | ||
102 | fido_bio_template_free(&t); | ||
103 | fido_dev_close(dev); | ||
104 | fido_dev_free(&dev); | ||
105 | |||
106 | exit(0); | ||
107 | } | ||
108 | |||
109 | static const char * | ||
110 | plural(uint8_t n) | ||
111 | { | ||
112 | if (n == 1) | ||
113 | return ""; | ||
114 | return "s"; | ||
115 | } | ||
116 | |||
117 | static const char * | ||
118 | enroll_strerr(uint8_t n) | ||
119 | { | ||
120 | switch (n) { | ||
121 | case FIDO_BIO_ENROLL_FP_GOOD: | ||
122 | return "Sample ok"; | ||
123 | case FIDO_BIO_ENROLL_FP_TOO_HIGH: | ||
124 | return "Sample too high"; | ||
125 | case FIDO_BIO_ENROLL_FP_TOO_LOW: | ||
126 | return "Sample too low"; | ||
127 | case FIDO_BIO_ENROLL_FP_TOO_LEFT: | ||
128 | return "Sample too left"; | ||
129 | case FIDO_BIO_ENROLL_FP_TOO_RIGHT: | ||
130 | return "Sample too right"; | ||
131 | case FIDO_BIO_ENROLL_FP_TOO_FAST: | ||
132 | return "Sample too fast"; | ||
133 | case FIDO_BIO_ENROLL_FP_TOO_SLOW: | ||
134 | return "Sample too slow"; | ||
135 | case FIDO_BIO_ENROLL_FP_POOR_QUALITY: | ||
136 | return "Poor quality sample"; | ||
137 | case FIDO_BIO_ENROLL_FP_TOO_SKEWED: | ||
138 | return "Sample too skewed"; | ||
139 | case FIDO_BIO_ENROLL_FP_TOO_SHORT: | ||
140 | return "Sample too short"; | ||
141 | case FIDO_BIO_ENROLL_FP_MERGE_FAILURE: | ||
142 | return "Sample merge failure"; | ||
143 | case FIDO_BIO_ENROLL_FP_EXISTS: | ||
144 | return "Sample exists"; | ||
145 | case FIDO_BIO_ENROLL_FP_DATABASE_FULL: | ||
146 | return "Fingerprint database full"; | ||
147 | case FIDO_BIO_ENROLL_NO_USER_ACTIVITY: | ||
148 | return "No user activity"; | ||
149 | case FIDO_BIO_ENROLL_NO_USER_PRESENCE_TRANSITION: | ||
150 | return "No user presence transition"; | ||
151 | default: | ||
152 | return "Unknown error"; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | int | ||
157 | bio_enroll(char *path) | ||
158 | { | ||
159 | char pin[1024]; | ||
160 | fido_bio_enroll_t *e = NULL; | ||
161 | fido_bio_template_t *t = NULL; | ||
162 | fido_dev_t *dev = NULL; | ||
163 | int r; | ||
164 | |||
165 | if (path == NULL) | ||
166 | usage(); | ||
167 | if ((t = fido_bio_template_new()) == NULL) | ||
168 | errx(1, "fido_bio_template_new"); | ||
169 | if ((e = fido_bio_enroll_new()) == NULL) | ||
170 | errx(1, "fido_bio_enroll_new"); | ||
171 | |||
172 | dev = open_dev(path); | ||
173 | read_pin(path, pin, sizeof(pin)); | ||
174 | |||
175 | printf("Touch your security key.\n"); | ||
176 | |||
177 | r = fido_bio_dev_enroll_begin(dev, t, e, 10000, pin); | ||
178 | explicit_bzero(pin, sizeof(pin)); | ||
179 | if (r != FIDO_OK) | ||
180 | errx(1, "fido_bio_dev_enroll_begin: %s", fido_strerr(r)); | ||
181 | |||
182 | printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e))); | ||
183 | |||
184 | while (fido_bio_enroll_remaining_samples(e) > 0) { | ||
185 | printf("Touch your security key (%u sample%s left).\n", | ||
186 | (unsigned)fido_bio_enroll_remaining_samples(e), | ||
187 | plural(fido_bio_enroll_remaining_samples(e))); | ||
188 | if ((r = fido_bio_dev_enroll_continue(dev, t, e, | ||
189 | 10000)) != FIDO_OK) { | ||
190 | errx(1, "fido_bio_dev_enroll_continue: %s", | ||
191 | fido_strerr(r)); | ||
192 | } | ||
193 | printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e))); | ||
194 | } | ||
195 | |||
196 | fido_bio_template_free(&t); | ||
197 | fido_bio_enroll_free(&e); | ||
198 | fido_dev_close(dev); | ||
199 | fido_dev_free(&dev); | ||
200 | |||
201 | exit(0); | ||
202 | } | ||
203 | |||
204 | int | ||
205 | bio_delete(fido_dev_t *dev, char *path, char *id) | ||
206 | { | ||
207 | char pin[1024]; | ||
208 | fido_bio_template_t *t = NULL; | ||
209 | int r; | ||
210 | size_t id_blob_len = 0; | ||
211 | void *id_blob_ptr = NULL; | ||
212 | |||
213 | if (path == NULL) | ||
214 | usage(); | ||
215 | if ((t = fido_bio_template_new()) == NULL) | ||
216 | errx(1, "fido_bio_template_new"); | ||
217 | |||
218 | if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0) | ||
219 | errx(1, "base64_decode"); | ||
220 | if ((r = fido_bio_template_set_id(t, id_blob_ptr, | ||
221 | id_blob_len)) != FIDO_OK) | ||
222 | errx(1, "fido_bio_template_set_id: %s", fido_strerr(r)); | ||
223 | |||
224 | read_pin(path, pin, sizeof(pin)); | ||
225 | r = fido_bio_dev_enroll_remove(dev, t, pin); | ||
226 | explicit_bzero(pin, sizeof(pin)); | ||
227 | |||
228 | if (r != FIDO_OK) | ||
229 | errx(1, "fido_bio_dev_enroll_remove: %s", fido_strerr(r)); | ||
230 | |||
231 | free(id_blob_ptr); | ||
232 | fido_bio_template_free(&t); | ||
233 | fido_dev_close(dev); | ||
234 | fido_dev_free(&dev); | ||
235 | |||
236 | exit(0); | ||
237 | } | ||
238 | |||
239 | static const char * | ||
240 | type_str(uint8_t t) | ||
241 | { | ||
242 | switch (t) { | ||
243 | case 1: | ||
244 | return "touch"; | ||
245 | case 2: | ||
246 | return "swipe"; | ||
247 | default: | ||
248 | return "unknown"; | ||
249 | } | ||
250 | } | ||
251 | |||
252 | void | ||
253 | bio_info(fido_dev_t *dev) | ||
254 | { | ||
255 | fido_bio_info_t *i = NULL; | ||
256 | int r; | ||
257 | |||
258 | if ((i = fido_bio_info_new()) == NULL) | ||
259 | errx(1, "fido_bio_info_new"); | ||
260 | if ((r = fido_bio_dev_get_info(dev, i)) != FIDO_OK) { | ||
261 | fido_bio_info_free(&i); | ||
262 | return; | ||
263 | } | ||
264 | |||
265 | printf("sensor type: %u (%s)\n", (unsigned)fido_bio_info_type(i), | ||
266 | type_str(fido_bio_info_type(i))); | ||
267 | printf("max samples: %u\n", (unsigned)fido_bio_info_max_samples(i)); | ||
268 | |||
269 | fido_bio_info_free(&i); | ||
270 | } | ||
diff --git a/tools/cred_make.c b/tools/cred_make.c new file mode 100644 index 0000000..380c67a --- /dev/null +++ b/tools/cred_make.c | |||
@@ -0,0 +1,221 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <fido.h> | ||
8 | #include <stdio.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | #ifdef HAVE_UNISTD_H | ||
12 | #include <unistd.h> | ||
13 | #endif | ||
14 | |||
15 | #include "../openbsd-compat/openbsd-compat.h" | ||
16 | #include "extern.h" | ||
17 | |||
18 | static fido_cred_t * | ||
19 | prepare_cred(FILE *in_f, int type, int flags) | ||
20 | { | ||
21 | fido_cred_t *cred = NULL; | ||
22 | struct blob cdh; | ||
23 | struct blob uid; | ||
24 | char *rpid = NULL; | ||
25 | char *uname = NULL; | ||
26 | int r; | ||
27 | |||
28 | memset(&cdh, 0, sizeof(cdh)); | ||
29 | memset(&uid, 0, sizeof(uid)); | ||
30 | |||
31 | r = base64_read(in_f, &cdh); | ||
32 | r |= string_read(in_f, &rpid); | ||
33 | r |= string_read(in_f, &uname); | ||
34 | r |= base64_read(in_f, &uid); | ||
35 | if (r < 0) | ||
36 | errx(1, "input error"); | ||
37 | |||
38 | if (flags & FLAG_DEBUG) { | ||
39 | fprintf(stderr, "client data hash:\n"); | ||
40 | xxd(cdh.ptr, cdh.len); | ||
41 | fprintf(stderr, "relying party id: %s\n", rpid); | ||
42 | fprintf(stderr, "user name: %s\n", uname); | ||
43 | fprintf(stderr, "user id:\n"); | ||
44 | xxd(uid.ptr, uid.len); | ||
45 | } | ||
46 | |||
47 | if ((cred = fido_cred_new()) == NULL) | ||
48 | errx(1, "fido_cred_new"); | ||
49 | |||
50 | if ((r = fido_cred_set_type(cred, type)) != FIDO_OK || | ||
51 | (r = fido_cred_set_clientdata_hash(cred, cdh.ptr, | ||
52 | cdh.len)) != FIDO_OK || | ||
53 | (r = fido_cred_set_rp(cred, rpid, NULL)) != FIDO_OK || | ||
54 | (r = fido_cred_set_user(cred, uid.ptr, uid.len, uname, NULL, | ||
55 | NULL)) != FIDO_OK) | ||
56 | errx(1, "fido_cred_set: %s", fido_strerr(r)); | ||
57 | |||
58 | if (flags & FLAG_RK) { | ||
59 | if ((r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK) | ||
60 | errx(1, "fido_cred_set_rk: %s", fido_strerr(r)); | ||
61 | } | ||
62 | if (flags & FLAG_UV) { | ||
63 | if ((r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) | ||
64 | errx(1, "fido_cred_set_uv: %s", fido_strerr(r)); | ||
65 | } | ||
66 | if (flags & FLAG_HMAC) { | ||
67 | if ((r = fido_cred_set_extensions(cred, | ||
68 | FIDO_EXT_HMAC_SECRET)) != FIDO_OK) | ||
69 | errx(1, "fido_cred_set_extensions: %s", fido_strerr(r)); | ||
70 | } | ||
71 | |||
72 | free(cdh.ptr); | ||
73 | free(uid.ptr); | ||
74 | free(rpid); | ||
75 | free(uname); | ||
76 | |||
77 | return (cred); | ||
78 | } | ||
79 | |||
80 | static void | ||
81 | print_attcred(FILE *out_f, const fido_cred_t *cred) | ||
82 | { | ||
83 | char *cdh = NULL; | ||
84 | char *authdata = NULL; | ||
85 | char *id = NULL; | ||
86 | char *sig = NULL; | ||
87 | char *x5c = NULL; | ||
88 | int r; | ||
89 | |||
90 | r = base64_encode(fido_cred_clientdata_hash_ptr(cred), | ||
91 | fido_cred_clientdata_hash_len(cred), &cdh); | ||
92 | r |= base64_encode(fido_cred_authdata_ptr(cred), | ||
93 | fido_cred_authdata_len(cred), &authdata); | ||
94 | r |= base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), | ||
95 | &id); | ||
96 | r |= base64_encode(fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), | ||
97 | &sig); | ||
98 | if (fido_cred_x5c_ptr(cred) != NULL) | ||
99 | r |= base64_encode(fido_cred_x5c_ptr(cred), | ||
100 | fido_cred_x5c_len(cred), &x5c); | ||
101 | if (r < 0) | ||
102 | errx(1, "output error"); | ||
103 | |||
104 | fprintf(out_f, "%s\n", cdh); | ||
105 | fprintf(out_f, "%s\n", fido_cred_rp_id(cred)); | ||
106 | fprintf(out_f, "%s\n", fido_cred_fmt(cred)); | ||
107 | fprintf(out_f, "%s\n", authdata); | ||
108 | fprintf(out_f, "%s\n", id); | ||
109 | fprintf(out_f, "%s\n", sig); | ||
110 | if (x5c != NULL) | ||
111 | fprintf(out_f, "%s\n", x5c); | ||
112 | |||
113 | free(cdh); | ||
114 | free(authdata); | ||
115 | free(id); | ||
116 | free(sig); | ||
117 | free(x5c); | ||
118 | } | ||
119 | |||
120 | int | ||
121 | cred_make(int argc, char **argv) | ||
122 | { | ||
123 | fido_dev_t *dev = NULL; | ||
124 | fido_cred_t *cred = NULL; | ||
125 | char prompt[1024]; | ||
126 | char pin[1024]; | ||
127 | char *in_path = NULL; | ||
128 | char *out_path = NULL; | ||
129 | FILE *in_f = NULL; | ||
130 | FILE *out_f = NULL; | ||
131 | int type = COSE_ES256; | ||
132 | int flags = 0; | ||
133 | int ch; | ||
134 | int r; | ||
135 | |||
136 | while ((ch = getopt(argc, argv, "dhi:o:qruv")) != -1) { | ||
137 | switch (ch) { | ||
138 | case 'd': | ||
139 | flags |= FLAG_DEBUG; | ||
140 | break; | ||
141 | case 'h': | ||
142 | flags |= FLAG_HMAC; | ||
143 | break; | ||
144 | case 'i': | ||
145 | in_path = optarg; | ||
146 | break; | ||
147 | case 'o': | ||
148 | out_path = optarg; | ||
149 | break; | ||
150 | case 'q': | ||
151 | flags |= FLAG_QUIET; | ||
152 | break; | ||
153 | case 'r': | ||
154 | flags |= FLAG_RK; | ||
155 | break; | ||
156 | case 'u': | ||
157 | flags |= FLAG_U2F; | ||
158 | break; | ||
159 | case 'v': | ||
160 | flags |= FLAG_UV; | ||
161 | break; | ||
162 | default: | ||
163 | usage(); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | argc -= optind; | ||
168 | argv += optind; | ||
169 | |||
170 | if (argc < 1 || argc > 2) | ||
171 | usage(); | ||
172 | |||
173 | in_f = open_read(in_path); | ||
174 | out_f = open_write(out_path); | ||
175 | |||
176 | if (argc > 1) { | ||
177 | if (strcmp(argv[1], "es256") == 0) | ||
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 | |||
187 | fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); | ||
188 | |||
189 | cred = prepare_cred(in_f, type, flags); | ||
190 | |||
191 | dev = open_dev(argv[0]); | ||
192 | if (flags & FLAG_U2F) | ||
193 | fido_dev_force_u2f(dev); | ||
194 | |||
195 | r = fido_dev_make_cred(dev, cred, NULL); | ||
196 | if (r == FIDO_ERR_PIN_REQUIRED && !(flags & FLAG_QUIET)) { | ||
197 | r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", | ||
198 | argv[0]); | ||
199 | if (r < 0 || (size_t)r >= sizeof(prompt)) | ||
200 | errx(1, "snprintf"); | ||
201 | if (!readpassphrase(prompt, pin, sizeof(pin), RPP_ECHO_OFF)) | ||
202 | errx(1, "readpassphrase"); | ||
203 | r = fido_dev_make_cred(dev, cred, pin); | ||
204 | } | ||
205 | |||
206 | explicit_bzero(pin, sizeof(pin)); | ||
207 | if (r != FIDO_OK) | ||
208 | errx(1, "fido_dev_make_cred: %s", fido_strerr(r)); | ||
209 | print_attcred(out_f, cred); | ||
210 | |||
211 | fido_dev_close(dev); | ||
212 | fido_dev_free(&dev); | ||
213 | fido_cred_free(&cred); | ||
214 | |||
215 | fclose(in_f); | ||
216 | fclose(out_f); | ||
217 | in_f = NULL; | ||
218 | out_f = NULL; | ||
219 | |||
220 | exit(0); | ||
221 | } | ||
diff --git a/tools/cred_verify.c b/tools/cred_verify.c new file mode 100644 index 0000000..3f7a400 --- /dev/null +++ b/tools/cred_verify.c | |||
@@ -0,0 +1,177 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <fido.h> | ||
8 | #include <stdio.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | #ifdef HAVE_UNISTD_H | ||
12 | #include <unistd.h> | ||
13 | #endif | ||
14 | |||
15 | #include "../openbsd-compat/openbsd-compat.h" | ||
16 | #include "extern.h" | ||
17 | |||
18 | static fido_cred_t * | ||
19 | prepare_cred(FILE *in_f, int type, int flags) | ||
20 | { | ||
21 | fido_cred_t *cred = NULL; | ||
22 | struct blob cdh; | ||
23 | struct blob authdata; | ||
24 | struct blob id; | ||
25 | struct blob sig; | ||
26 | struct blob x5c; | ||
27 | char *rpid = NULL; | ||
28 | char *fmt = NULL; | ||
29 | int r; | ||
30 | |||
31 | memset(&cdh, 0, sizeof(cdh)); | ||
32 | memset(&authdata, 0, sizeof(authdata)); | ||
33 | memset(&id, 0, sizeof(id)); | ||
34 | memset(&sig, 0, sizeof(sig)); | ||
35 | memset(&x5c, 0, sizeof(x5c)); | ||
36 | |||
37 | r = base64_read(in_f, &cdh); | ||
38 | r |= string_read(in_f, &rpid); | ||
39 | r |= string_read(in_f, &fmt); | ||
40 | r |= base64_read(in_f, &authdata); | ||
41 | r |= base64_read(in_f, &id); | ||
42 | r |= base64_read(in_f, &sig); | ||
43 | if (r < 0) | ||
44 | errx(1, "input error"); | ||
45 | |||
46 | (void)base64_read(in_f, &x5c); | ||
47 | |||
48 | if (flags & FLAG_DEBUG) { | ||
49 | fprintf(stderr, "client data hash:\n"); | ||
50 | xxd(cdh.ptr, cdh.len); | ||
51 | fprintf(stderr, "relying party id: %s\n", rpid); | ||
52 | fprintf(stderr, "format: %s\n", fmt); | ||
53 | fprintf(stderr, "authenticator data:\n"); | ||
54 | xxd(authdata.ptr, authdata.len); | ||
55 | fprintf(stderr, "credential id:\n"); | ||
56 | xxd(id.ptr, id.len); | ||
57 | fprintf(stderr, "signature:\n"); | ||
58 | xxd(sig.ptr, sig.len); | ||
59 | fprintf(stderr, "x509:\n"); | ||
60 | xxd(x5c.ptr, x5c.len); | ||
61 | } | ||
62 | |||
63 | if ((cred = fido_cred_new()) == NULL) | ||
64 | errx(1, "fido_cred_new"); | ||
65 | |||
66 | if ((r = fido_cred_set_type(cred, type)) != FIDO_OK || | ||
67 | (r = fido_cred_set_clientdata_hash(cred, cdh.ptr, | ||
68 | cdh.len)) != FIDO_OK || | ||
69 | (r = fido_cred_set_rp(cred, rpid, NULL)) != FIDO_OK || | ||
70 | (r = fido_cred_set_authdata(cred, authdata.ptr, | ||
71 | authdata.len)) != FIDO_OK || | ||
72 | (r = fido_cred_set_sig(cred, sig.ptr, sig.len)) != FIDO_OK || | ||
73 | (r = fido_cred_set_fmt(cred, fmt)) != FIDO_OK) | ||
74 | errx(1, "fido_cred_set: %s", fido_strerr(r)); | ||
75 | |||
76 | if (x5c.ptr != NULL) { | ||
77 | if ((r = fido_cred_set_x509(cred, x5c.ptr, x5c.len)) != FIDO_OK) | ||
78 | errx(1, "fido_cred_set_x509: %s", fido_strerr(r)); | ||
79 | } | ||
80 | |||
81 | if (flags & FLAG_UV) { | ||
82 | if ((r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) | ||
83 | errx(1, "fido_cred_set_uv: %s", fido_strerr(r)); | ||
84 | } | ||
85 | if (flags & FLAG_HMAC) { | ||
86 | if ((r = fido_cred_set_extensions(cred, | ||
87 | FIDO_EXT_HMAC_SECRET)) != FIDO_OK) | ||
88 | errx(1, "fido_cred_set_extensions: %s", fido_strerr(r)); | ||
89 | } | ||
90 | |||
91 | free(cdh.ptr); | ||
92 | free(authdata.ptr); | ||
93 | free(id.ptr); | ||
94 | free(sig.ptr); | ||
95 | free(x5c.ptr); | ||
96 | free(rpid); | ||
97 | free(fmt); | ||
98 | |||
99 | return (cred); | ||
100 | } | ||
101 | |||
102 | int | ||
103 | cred_verify(int argc, char **argv) | ||
104 | { | ||
105 | fido_cred_t *cred = NULL; | ||
106 | char *in_path = NULL; | ||
107 | char *out_path = NULL; | ||
108 | FILE *in_f = NULL; | ||
109 | FILE *out_f = NULL; | ||
110 | int type = COSE_ES256; | ||
111 | int flags = 0; | ||
112 | int ch; | ||
113 | int r; | ||
114 | |||
115 | while ((ch = getopt(argc, argv, "dhi:o:v")) != -1) { | ||
116 | switch (ch) { | ||
117 | case 'd': | ||
118 | flags |= FLAG_DEBUG; | ||
119 | break; | ||
120 | case 'h': | ||
121 | flags |= FLAG_HMAC; | ||
122 | break; | ||
123 | case 'i': | ||
124 | in_path = optarg; | ||
125 | break; | ||
126 | case 'o': | ||
127 | out_path = optarg; | ||
128 | break; | ||
129 | case 'v': | ||
130 | flags |= FLAG_UV; | ||
131 | break; | ||
132 | default: | ||
133 | usage(); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | argc -= optind; | ||
138 | argv += optind; | ||
139 | |||
140 | if (argc > 1) | ||
141 | usage(); | ||
142 | |||
143 | in_f = open_read(in_path); | ||
144 | out_f = open_write(out_path); | ||
145 | |||
146 | if (argc > 0) { | ||
147 | if (strcmp(argv[0], "es256") == 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 | |||
157 | fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); | ||
158 | cred = prepare_cred(in_f, type, flags); | ||
159 | |||
160 | if (fido_cred_x5c_ptr(cred) == NULL) { | ||
161 | if ((r = fido_cred_verify_self(cred)) != FIDO_OK) | ||
162 | errx(1, "fido_cred_verify_self: %s", fido_strerr(r)); | ||
163 | } else { | ||
164 | if ((r = fido_cred_verify(cred)) != FIDO_OK) | ||
165 | errx(1, "fido_cred_verify: %s", fido_strerr(r)); | ||
166 | } | ||
167 | |||
168 | print_cred(out_f, type, cred); | ||
169 | fido_cred_free(&cred); | ||
170 | |||
171 | fclose(in_f); | ||
172 | fclose(out_f); | ||
173 | in_f = NULL; | ||
174 | out_f = NULL; | ||
175 | |||
176 | exit(0); | ||
177 | } | ||
diff --git a/tools/credman.c b/tools/credman.c new file mode 100644 index 0000000..08c9eb8 --- /dev/null +++ b/tools/credman.c | |||
@@ -0,0 +1,237 @@ | |||
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 <fido.h> | ||
8 | #include <fido/credman.h> | ||
9 | |||
10 | #include <stdbool.h> | ||
11 | #include <stdio.h> | ||
12 | #include <stdlib.h> | ||
13 | #include <string.h> | ||
14 | #ifdef HAVE_UNISTD_H | ||
15 | #include <unistd.h> | ||
16 | #endif | ||
17 | |||
18 | #include "../openbsd-compat/openbsd-compat.h" | ||
19 | #include "extern.h" | ||
20 | |||
21 | int | ||
22 | credman_get_metadata(fido_dev_t *dev, const char *path) | ||
23 | { | ||
24 | fido_credman_metadata_t *metadata = NULL; | ||
25 | char pin[1024]; | ||
26 | int r; | ||
27 | |||
28 | if ((metadata = fido_credman_metadata_new()) == NULL) | ||
29 | errx(1, "fido_credman_metadata_new"); | ||
30 | |||
31 | read_pin(path, pin, sizeof(pin)); | ||
32 | r = fido_credman_get_dev_metadata(dev, metadata, pin); | ||
33 | explicit_bzero(pin, sizeof(pin)); | ||
34 | |||
35 | if (r != FIDO_OK) | ||
36 | errx(1, "fido_credman_get_dev_metadata: %s", fido_strerr(r)); | ||
37 | |||
38 | printf("existing rk(s): %u\n", | ||
39 | (unsigned)fido_credman_rk_existing(metadata)); | ||
40 | printf("possible rk(s): %u\n", | ||
41 | (unsigned)fido_credman_rk_remaining(metadata)); | ||
42 | |||
43 | fido_credman_metadata_free(&metadata); | ||
44 | fido_dev_close(dev); | ||
45 | fido_dev_free(&dev); | ||
46 | |||
47 | exit(0); | ||
48 | } | ||
49 | |||
50 | static void | ||
51 | print_rp(fido_credman_rp_t *rp, size_t idx) | ||
52 | { | ||
53 | char *rp_id_hash = NULL; | ||
54 | |||
55 | if (base64_encode(fido_credman_rp_id_hash_ptr(rp, idx), | ||
56 | fido_credman_rp_id_hash_len(rp, idx), &rp_id_hash) < 0) | ||
57 | errx(1, "output error"); | ||
58 | |||
59 | printf("%02u: %s %s\n", (unsigned)idx, rp_id_hash, | ||
60 | fido_credman_rp_id(rp, idx)); | ||
61 | |||
62 | free(rp_id_hash); | ||
63 | rp_id_hash = NULL; | ||
64 | } | ||
65 | |||
66 | int | ||
67 | credman_list_rp(char *path) | ||
68 | { | ||
69 | fido_dev_t *dev = NULL; | ||
70 | fido_credman_rp_t *rp = NULL; | ||
71 | char pin[1024]; | ||
72 | int r; | ||
73 | |||
74 | if (path == NULL) | ||
75 | usage(); | ||
76 | if ((rp = fido_credman_rp_new()) == NULL) | ||
77 | errx(1, "fido_credman_rp_new"); | ||
78 | |||
79 | dev = open_dev(path); | ||
80 | read_pin(path, pin, sizeof(pin)); | ||
81 | r = fido_credman_get_dev_rp(dev, rp, pin); | ||
82 | explicit_bzero(pin, sizeof(pin)); | ||
83 | |||
84 | if (r != FIDO_OK) | ||
85 | errx(1, "fido_credman_get_dev_rp: %s", fido_strerr(r)); | ||
86 | |||
87 | for (size_t i = 0; i < fido_credman_rp_count(rp); i++) | ||
88 | print_rp(rp, i); | ||
89 | |||
90 | fido_credman_rp_free(&rp); | ||
91 | fido_dev_close(dev); | ||
92 | fido_dev_free(&dev); | ||
93 | |||
94 | exit(0); | ||
95 | } | ||
96 | |||
97 | static void | ||
98 | print_rk(const fido_credman_rk_t *rk, size_t idx) | ||
99 | { | ||
100 | const fido_cred_t *cred; | ||
101 | char *id = NULL; | ||
102 | char *user_id = NULL; | ||
103 | const char *type; | ||
104 | |||
105 | if ((cred = fido_credman_rk(rk, idx)) == NULL) | ||
106 | errx(1, "fido_credman_rk"); | ||
107 | if (base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), | ||
108 | &id) < 0 || base64_encode(fido_cred_user_id_ptr(cred), | ||
109 | fido_cred_user_id_len(cred), &user_id) < 0) | ||
110 | errx(1, "output error"); | ||
111 | |||
112 | switch (fido_cred_type(cred)) { | ||
113 | case COSE_EDDSA: | ||
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 | |||
127 | printf("%02u: %s %s (%s) %s\n", (unsigned)idx, id, | ||
128 | fido_cred_display_name(cred), user_id, type); | ||
129 | |||
130 | free(user_id); | ||
131 | free(id); | ||
132 | user_id = NULL; | ||
133 | id = NULL; | ||
134 | } | ||
135 | |||
136 | int | ||
137 | credman_list_rk(char *path, const char *rp_id) | ||
138 | { | ||
139 | fido_dev_t *dev = NULL; | ||
140 | fido_credman_rk_t *rk = NULL; | ||
141 | char pin[1024]; | ||
142 | int r; | ||
143 | |||
144 | if (path == NULL) | ||
145 | usage(); | ||
146 | if ((rk = fido_credman_rk_new()) == NULL) | ||
147 | errx(1, "fido_credman_rk_new"); | ||
148 | |||
149 | dev = open_dev(path); | ||
150 | read_pin(path, pin, sizeof(pin)); | ||
151 | r = fido_credman_get_dev_rk(dev, rp_id, rk, pin); | ||
152 | explicit_bzero(pin, sizeof(pin)); | ||
153 | |||
154 | if (r != FIDO_OK) | ||
155 | errx(1, "fido_credman_get_dev_rk: %s", fido_strerr(r)); | ||
156 | for (size_t i = 0; i < fido_credman_rk_count(rk); i++) | ||
157 | print_rk(rk, i); | ||
158 | |||
159 | fido_credman_rk_free(&rk); | ||
160 | fido_dev_close(dev); | ||
161 | fido_dev_free(&dev); | ||
162 | |||
163 | exit(0); | ||
164 | } | ||
165 | |||
166 | int | ||
167 | credman_print_rk(fido_dev_t *dev, const char *path, char *rp_id, char *cred_id) | ||
168 | { | ||
169 | const fido_cred_t *cred = NULL; | ||
170 | fido_credman_rk_t *rk = NULL; | ||
171 | char pin[1024]; | ||
172 | void *cred_id_ptr = NULL; | ||
173 | size_t cred_id_len = 0; | ||
174 | int r; | ||
175 | |||
176 | if ((rk = fido_credman_rk_new()) == NULL) | ||
177 | errx(1, "fido_credman_rk_new"); | ||
178 | if (base64_decode(cred_id, &cred_id_ptr, &cred_id_len) < 0) | ||
179 | errx(1, "base64_decode"); | ||
180 | |||
181 | read_pin(path, pin, sizeof(pin)); | ||
182 | r = fido_credman_get_dev_rk(dev, rp_id, rk, pin); | ||
183 | explicit_bzero(pin, sizeof(pin)); | ||
184 | |||
185 | if (r != FIDO_OK) | ||
186 | errx(1, "fido_credman_get_dev_rk: %s", fido_strerr(r)); | ||
187 | |||
188 | for (size_t i = 0; i < fido_credman_rk_count(rk); i++) { | ||
189 | if ((cred = fido_credman_rk(rk, i)) == NULL || | ||
190 | fido_cred_id_ptr(cred) == NULL) | ||
191 | errx(1, "output error"); | ||
192 | if (cred_id_len != fido_cred_id_len(cred) || | ||
193 | memcmp(cred_id_ptr, fido_cred_id_ptr(cred), cred_id_len)) | ||
194 | continue; | ||
195 | print_cred(stdout, fido_cred_type(cred), cred); | ||
196 | goto out; | ||
197 | } | ||
198 | |||
199 | errx(1, "credential not found"); | ||
200 | |||
201 | out: | ||
202 | free(cred_id_ptr); | ||
203 | cred_id_ptr = NULL; | ||
204 | |||
205 | fido_credman_rk_free(&rk); | ||
206 | fido_dev_close(dev); | ||
207 | fido_dev_free(&dev); | ||
208 | |||
209 | exit(0); | ||
210 | } | ||
211 | |||
212 | int | ||
213 | credman_delete_rk(fido_dev_t *dev, const char *path, char *id) | ||
214 | { | ||
215 | char pin[1024]; | ||
216 | void *id_ptr = NULL; | ||
217 | size_t id_len = 0; | ||
218 | int r; | ||
219 | |||
220 | if (base64_decode(id, &id_ptr, &id_len) < 0) | ||
221 | errx(1, "base64_decode"); | ||
222 | |||
223 | read_pin(path, pin, sizeof(pin)); | ||
224 | r = fido_credman_del_dev_rk(dev, id_ptr, id_len, pin); | ||
225 | explicit_bzero(pin, sizeof(pin)); | ||
226 | |||
227 | if (r != FIDO_OK) | ||
228 | errx(1, "fido_credman_del_dev_rk: %s", fido_strerr(r)); | ||
229 | |||
230 | free(id_ptr); | ||
231 | id_ptr = NULL; | ||
232 | |||
233 | fido_dev_close(dev); | ||
234 | fido_dev_free(&dev); | ||
235 | |||
236 | exit(0); | ||
237 | } | ||
diff --git a/tools/extern.h b/tools/extern.h new file mode 100644 index 0000000..e79e6f0 --- /dev/null +++ b/tools/extern.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | #ifndef _EXTERN_H_ | ||
8 | #define _EXTERN_H_ | ||
9 | |||
10 | struct blob { | ||
11 | unsigned char *ptr; | ||
12 | size_t len; | ||
13 | }; | ||
14 | |||
15 | #define TOKEN_OPT "CDILPRSVbcdei:k:n:r" | ||
16 | |||
17 | #define FLAG_DEBUG 0x01 | ||
18 | #define FLAG_QUIET 0x02 | ||
19 | #define FLAG_RK 0x04 | ||
20 | #define FLAG_UV 0x08 | ||
21 | #define FLAG_U2F 0x10 | ||
22 | #define FLAG_HMAC 0x20 | ||
23 | #define FLAG_UP 0x40 | ||
24 | |||
25 | EC_KEY *read_ec_pubkey(const char *); | ||
26 | fido_dev_t *open_dev(const char *); | ||
27 | FILE *open_read(const char *); | ||
28 | FILE *open_write(const char *); | ||
29 | int assert_get(int, char **); | ||
30 | int assert_verify(int, char **); | ||
31 | int base64_decode(char *, void **, size_t *); | ||
32 | int base64_encode(const void *, size_t, char **); | ||
33 | int base64_read(FILE *, struct blob *); | ||
34 | int bio_delete(fido_dev_t *, char *, char *); | ||
35 | int bio_enroll(char *); | ||
36 | void bio_info(fido_dev_t *); | ||
37 | int bio_list(char *); | ||
38 | int bio_set_name(char *, char *, char *); | ||
39 | int cred_make(int, char **); | ||
40 | int cred_verify(int, char **); | ||
41 | int credman_delete_rk(fido_dev_t *, const char *, char *); | ||
42 | int credman_get_metadata(fido_dev_t *, const char *); | ||
43 | int credman_list_rk(char *, const char *); | ||
44 | int credman_list_rp(char *); | ||
45 | int credman_print_rk(fido_dev_t *, const char *, char *, char *); | ||
46 | int pin_change(char *); | ||
47 | int pin_set(char *); | ||
48 | int string_read(FILE *, char **); | ||
49 | int token_delete(int, char **, char *); | ||
50 | int token_info(int, char **, char *); | ||
51 | int token_list(int, char **, char *); | ||
52 | int token_reset(char *); | ||
53 | int token_set(int, char **, char *); | ||
54 | int write_ec_pubkey(FILE *, const void *, size_t); | ||
55 | int write_rsa_pubkey(FILE *, const void *, size_t); | ||
56 | RSA *read_rsa_pubkey(const char *); | ||
57 | EVP_PKEY *read_eddsa_pubkey(const char *); | ||
58 | int write_eddsa_pubkey(FILE *, const void *, size_t); | ||
59 | void print_cred(FILE *, int, const fido_cred_t *); | ||
60 | void read_pin(const char *, char *, size_t); | ||
61 | void usage(void); | ||
62 | void xxd(const void *, size_t); | ||
63 | |||
64 | #endif /* _EXTERN_H_ */ | ||
diff --git a/tools/fido2-assert.c b/tools/fido2-assert.c new file mode 100644 index 0000000..9ce537a --- /dev/null +++ b/tools/fido2-assert.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | /* | ||
8 | * Example usage: | ||
9 | * | ||
10 | * $ echo assertion challenge | openssl sha256 -binary | base64 > assert_param | ||
11 | * $ echo relying party >> assert_param | ||
12 | * $ head -1 cred >> assert_param # credential id | ||
13 | * $ tail -n +2 cred > pubkey # credential pubkey | ||
14 | * $ fido2-assert -G -i assert_param /dev/hidraw5 | fido2-assert -V pubkey rs256 | ||
15 | * | ||
16 | * See blurb in fido2-cred.c on how to obtain cred. | ||
17 | */ | ||
18 | |||
19 | #include <fido.h> | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | |||
24 | #include "../openbsd-compat/openbsd-compat.h" | ||
25 | #include "extern.h" | ||
26 | |||
27 | void | ||
28 | usage(void) | ||
29 | { | ||
30 | fprintf(stderr, | ||
31 | "usage: fido2-assert -G [-dhpruv] [-i input_file] [-o output_file] device\n" | ||
32 | " fido2-assert -V [-dhpv] [-i input_file] key_file [type]\n" | ||
33 | ); | ||
34 | |||
35 | exit(1); | ||
36 | } | ||
37 | |||
38 | int | ||
39 | main(int argc, char **argv) | ||
40 | { | ||
41 | if (argc < 2 || strlen(argv[1]) != 2 || argv[1][0] != '-') | ||
42 | usage(); | ||
43 | |||
44 | switch (argv[1][1]) { | ||
45 | case 'G': | ||
46 | return (assert_get(--argc, ++argv)); | ||
47 | case 'V': | ||
48 | return (assert_verify(--argc, ++argv)); | ||
49 | } | ||
50 | |||
51 | usage(); | ||
52 | |||
53 | /* NOTREACHED */ | ||
54 | } | ||
diff --git a/tools/fido2-cred.c b/tools/fido2-cred.c new file mode 100644 index 0000000..45efca0 --- /dev/null +++ b/tools/fido2-cred.c | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 | /* | ||
8 | * Example usage: | ||
9 | * | ||
10 | * $ echo credential challenge | openssl sha256 -binary | base64 > cred_param | ||
11 | * $ echo relying party >> cred_param | ||
12 | * $ echo user name >> 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 | ||
15 | */ | ||
16 | |||
17 | #include <fido.h> | ||
18 | #include <stdio.h> | ||
19 | #include <stdlib.h> | ||
20 | #include <string.h> | ||
21 | |||
22 | #include "../openbsd-compat/openbsd-compat.h" | ||
23 | #include "extern.h" | ||
24 | |||
25 | void | ||
26 | usage(void) | ||
27 | { | ||
28 | fprintf(stderr, | ||
29 | "usage: fido2-cred -M [-dhqruv] [-i input_file] [-o output_file] device [type]\n" | ||
30 | " fido2-cred -V [-dhv] [-i input_file] [-o output_file] [type]\n" | ||
31 | ); | ||
32 | |||
33 | exit(1); | ||
34 | } | ||
35 | |||
36 | int | ||
37 | main(int argc, char **argv) | ||
38 | { | ||
39 | if (argc < 2 || strlen(argv[1]) != 2 || argv[1][0] != '-') | ||
40 | usage(); | ||
41 | |||
42 | switch (argv[1][1]) { | ||
43 | case 'M': | ||
44 | return (cred_make(--argc, ++argv)); | ||
45 | case 'V': | ||
46 | return (cred_verify(--argc, ++argv)); | ||
47 | } | ||
48 | |||
49 | usage(); | ||
50 | |||
51 | /* NOTREACHED */ | ||
52 | } | ||
diff --git a/tools/fido2-token.c b/tools/fido2-token.c new file mode 100644 index 0000000..0b02fea --- /dev/null +++ b/tools/fido2-token.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <fido.h> | ||
8 | #include <stdio.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | |||
12 | #include "../openbsd-compat/openbsd-compat.h" | ||
13 | #include "extern.h" | ||
14 | |||
15 | static int action; | ||
16 | |||
17 | void | ||
18 | usage(void) | ||
19 | { | ||
20 | fprintf(stderr, | ||
21 | "usage: fido2-token [-CR] [-d] device\n" | ||
22 | " fido2-token -D [-de] -i 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" | ||
25 | " fido2-token -S [-de] [-i template_id -n template_name] device\n" | ||
26 | " fido2-token -V\n" | ||
27 | ); | ||
28 | |||
29 | exit(1); | ||
30 | } | ||
31 | |||
32 | static void | ||
33 | setaction(int ch) | ||
34 | { | ||
35 | if (action) | ||
36 | usage(); | ||
37 | action = ch; | ||
38 | } | ||
39 | |||
40 | int | ||
41 | main(int argc, char **argv) | ||
42 | { | ||
43 | int ch; | ||
44 | int flags = 0; | ||
45 | char *device; | ||
46 | |||
47 | while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) { | ||
48 | switch (ch) { | ||
49 | case 'b': | ||
50 | case 'c': | ||
51 | case 'e': | ||
52 | case 'i': | ||
53 | case 'k': | ||
54 | case 'n': | ||
55 | case 'r': | ||
56 | break; /* ignore */ | ||
57 | case 'd': | ||
58 | flags = FIDO_DEBUG; | ||
59 | break; | ||
60 | default: | ||
61 | setaction(ch); | ||
62 | break; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | if (argc - optind == 1) | ||
67 | device = argv[optind]; | ||
68 | else | ||
69 | device = NULL; | ||
70 | |||
71 | fido_init(flags); | ||
72 | |||
73 | switch (action) { | ||
74 | case 'C': | ||
75 | return (pin_change(device)); | ||
76 | case 'D': | ||
77 | return (token_delete(argc, argv, device)); | ||
78 | case 'I': | ||
79 | return (token_info(argc, argv, device)); | ||
80 | case 'L': | ||
81 | return (token_list(argc, argv, device)); | ||
82 | case 'R': | ||
83 | return (token_reset(device)); | ||
84 | case 'S': | ||
85 | return (token_set(argc, argv, device)); | ||
86 | case 'V': | ||
87 | fprintf(stderr, "%d.%d.%d\n", _FIDO_MAJOR, _FIDO_MINOR, | ||
88 | _FIDO_PATCH); | ||
89 | exit(0); | ||
90 | } | ||
91 | |||
92 | usage(); | ||
93 | |||
94 | /* NOTREACHED */ | ||
95 | } | ||
diff --git a/tools/pin.c b/tools/pin.c new file mode 100644 index 0000000..eab178a --- /dev/null +++ b/tools/pin.c | |||
@@ -0,0 +1,146 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <fido.h> | ||
8 | #include <stdbool.h> | ||
9 | #include <stdio.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <string.h> | ||
12 | #ifdef HAVE_UNISTD_H | ||
13 | #include <unistd.h> | ||
14 | #endif | ||
15 | |||
16 | #include "../openbsd-compat/openbsd-compat.h" | ||
17 | #include "extern.h" | ||
18 | |||
19 | int | ||
20 | pin_set(char *path) | ||
21 | { | ||
22 | fido_dev_t *dev = NULL; | ||
23 | char prompt[1024]; | ||
24 | char pin1[1024]; | ||
25 | char pin2[1024]; | ||
26 | int r; | ||
27 | int status = 1; | ||
28 | |||
29 | if (path == NULL) | ||
30 | usage(); | ||
31 | |||
32 | dev = open_dev(path); | ||
33 | |||
34 | r = snprintf(prompt, sizeof(prompt), "Enter new PIN for %s: ", path); | ||
35 | if (r < 0 || (size_t)r >= sizeof(prompt)) { | ||
36 | warnx("snprintf"); | ||
37 | goto out; | ||
38 | } | ||
39 | |||
40 | if (!readpassphrase(prompt, pin1, sizeof(pin1), RPP_ECHO_OFF)) { | ||
41 | warnx("readpassphrase"); | ||
42 | goto out; | ||
43 | } | ||
44 | |||
45 | r = snprintf(prompt, sizeof(prompt), "Enter the same PIN again: "); | ||
46 | if (r < 0 || (size_t)r >= sizeof(prompt)) { | ||
47 | warnx("snprintf"); | ||
48 | goto out; | ||
49 | } | ||
50 | |||
51 | if (!readpassphrase(prompt, pin2, sizeof(pin2), RPP_ECHO_OFF)) { | ||
52 | warnx("readpassphrase"); | ||
53 | goto out; | ||
54 | } | ||
55 | |||
56 | if (strcmp(pin1, pin2) != 0) { | ||
57 | fprintf(stderr, "PINs do not match. Try again.\n"); | ||
58 | goto out; | ||
59 | } | ||
60 | |||
61 | if ((r = fido_dev_set_pin(dev, pin1, NULL)) != FIDO_OK) { | ||
62 | warnx("fido_dev_set_pin: %s", fido_strerr(r)); | ||
63 | goto out; | ||
64 | } | ||
65 | |||
66 | fido_dev_close(dev); | ||
67 | fido_dev_free(&dev); | ||
68 | |||
69 | status = 0; | ||
70 | out: | ||
71 | explicit_bzero(pin1, sizeof(pin1)); | ||
72 | explicit_bzero(pin2, sizeof(pin2)); | ||
73 | |||
74 | exit(status); | ||
75 | } | ||
76 | |||
77 | int | ||
78 | pin_change(char *path) | ||
79 | { | ||
80 | fido_dev_t *dev = NULL; | ||
81 | char prompt[1024]; | ||
82 | char pin0[1024]; | ||
83 | char pin1[1024]; | ||
84 | char pin2[1024]; | ||
85 | int r; | ||
86 | int status = 1; | ||
87 | |||
88 | if (path == NULL) | ||
89 | usage(); | ||
90 | |||
91 | dev = open_dev(path); | ||
92 | |||
93 | r = snprintf(prompt, sizeof(prompt), "Enter current PIN for %s: ", path); | ||
94 | if (r < 0 || (size_t)r >= sizeof(prompt)) { | ||
95 | warnx("snprintf"); | ||
96 | goto out; | ||
97 | } | ||
98 | |||
99 | if (!readpassphrase(prompt, pin0, sizeof(pin0), RPP_ECHO_OFF)) { | ||
100 | warnx("readpassphrase"); | ||
101 | goto out; | ||
102 | } | ||
103 | |||
104 | r = snprintf(prompt, sizeof(prompt), "Enter new PIN for %s: ", path); | ||
105 | if (r < 0 || (size_t)r >= sizeof(prompt)) { | ||
106 | warnx("snprintf"); | ||
107 | goto out; | ||
108 | } | ||
109 | |||
110 | if (!readpassphrase(prompt, pin1, sizeof(pin1), RPP_ECHO_OFF)) { | ||
111 | warnx("readpassphrase"); | ||
112 | goto out; | ||
113 | } | ||
114 | |||
115 | r = snprintf(prompt, sizeof(prompt), "Enter the same PIN again: "); | ||
116 | if (r < 0 || (size_t)r >= sizeof(prompt)) { | ||
117 | warnx("snprintf"); | ||
118 | goto out; | ||
119 | } | ||
120 | |||
121 | if (!readpassphrase(prompt, pin2, sizeof(pin2), RPP_ECHO_OFF)) { | ||
122 | warnx("readpassphrase"); | ||
123 | goto out; | ||
124 | } | ||
125 | |||
126 | if (strcmp(pin1, pin2) != 0) { | ||
127 | fprintf(stderr, "PINs do not match. Try again.\n"); | ||
128 | goto out; | ||
129 | } | ||
130 | |||
131 | if ((r = fido_dev_set_pin(dev, pin1, pin0)) != FIDO_OK) { | ||
132 | warnx("fido_dev_set_pin: %s", fido_strerr(r)); | ||
133 | goto out; | ||
134 | } | ||
135 | |||
136 | fido_dev_close(dev); | ||
137 | fido_dev_free(&dev); | ||
138 | |||
139 | status = 0; | ||
140 | out: | ||
141 | explicit_bzero(pin0, sizeof(pin0)); | ||
142 | explicit_bzero(pin1, sizeof(pin1)); | ||
143 | explicit_bzero(pin2, sizeof(pin2)); | ||
144 | |||
145 | exit(status); | ||
146 | } | ||
diff --git a/tools/sk-libfido2.c b/tools/sk-libfido2.c new file mode 100644 index 0000000..15aa813 --- /dev/null +++ b/tools/sk-libfido2.c | |||
@@ -0,0 +1,784 @@ | |||
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 | |||
73 | struct 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 | |||
84 | struct 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 */ | ||
101 | uint32_t sk_api_version(void); | ||
102 | |||
103 | /* Enroll a U2F key (private key generation) */ | ||
104 | int 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 */ | ||
109 | int 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 | ||
114 | static void skdebug(const char *func, const char *fmt, ...) | ||
115 | __attribute__((__format__ (printf, 2, 3))); | ||
116 | |||
117 | static void | ||
118 | skdebug(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 | |||
143 | uint32_t | ||
144 | sk_api_version(void) | ||
145 | { | ||
146 | return SK_VERSION_MAJOR; | ||
147 | } | ||
148 | |||
149 | /* Select the first identified FIDO device attached to the system */ | ||
150 | static char * | ||
151 | pick_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) | ||
183 | static int | ||
184 | get_random_challenge(uint8_t *ptr, size_t len) | ||
185 | { | ||
186 | arc4random_buf(ptr, len); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | #elif defined(HAVE_GETENTROPY) | ||
191 | static int | ||
192 | get_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) | ||
202 | static int | ||
203 | get_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) | ||
224 | static int | ||
225 | get_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. */ | ||
241 | static int | ||
242 | try_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 */ | ||
290 | static fido_dev_t * | ||
291 | find_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 | */ | ||
354 | static int | ||
355 | pack_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 | |||
424 | static int | ||
425 | pack_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 | |||
455 | static int | ||
456 | pack_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 | |||
470 | int | ||
471 | sk_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 | ||
621 | static int | ||
622 | pack_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 | |||
659 | static int | ||
660 | pack_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 | |||
687 | static int | ||
688 | pack_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 | |||
702 | int | ||
703 | sk_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/tools/test.sh b/tools/test.sh new file mode 100755 index 0000000..8159a44 --- /dev/null +++ b/tools/test.sh | |||
@@ -0,0 +1,96 @@ | |||
1 | #!/bin/bash -e | ||
2 | # | ||
3 | # Copyright (c) 2018 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 | |||
7 | if [[ "$#" -ne 1 ]]; then | ||
8 | echo "usage: test.sh device" 1>&2 | ||
9 | exit 1 | ||
10 | fi | ||
11 | |||
12 | read -p "This script will reset the authenticator at $1, permanently erasing "\ | ||
13 | "its credentials. Are you *SURE* you want to proceed (yes/no)? " | ||
14 | if [[ "${REPLY}" != "yes" ]]; then | ||
15 | exit 1 | ||
16 | fi | ||
17 | |||
18 | echo "Resetting authenticator... (tap to continue!)" | ||
19 | fido2-token -R $1 | ||
20 | |||
21 | CRED_PARAM="$(mktemp /tmp/cred_param.XXXXXXXX)" | ||
22 | ASSERT_PARAM="$(mktemp /tmp/assert_param.XXXXXXXX)" | ||
23 | ASSERT_PUBKEY="$(mktemp /tmp/assert_pubkey.XXXXXXXX)" | ||
24 | ES256_CRED="$(mktemp /tmp/es256_cred.XXXXXXX)" | ||
25 | ES256_CRED_R="$(mktemp /tmp/es256_cred_r.XXXXXXXX)" | ||
26 | |||
27 | cleanup() { | ||
28 | echo "Cleaning up..." | ||
29 | [[ "${CRED_PARAM}" != "" ]] && rm "${CRED_PARAM}" | ||
30 | [[ "${ASSERT_PARAM}" != "" ]] && rm "${ASSERT_PARAM}" | ||
31 | [[ "${ASSERT_PUBKEY}" != "" ]] && rm "${ASSERT_PUBKEY}" | ||
32 | [[ "${ES256_CRED}" != "" ]] && rm "${ES256_CRED}" | ||
33 | [[ "${ES256_CRED_R}" != "" ]] && rm "${ES256_CRED_R}" | ||
34 | } | ||
35 | |||
36 | trap cleanup EXIT | ||
37 | |||
38 | dd if=/dev/urandom bs=1 count=32 2>/dev/null | base64 > "${CRED_PARAM}" | ||
39 | echo "Boring Relying Party" >> "${CRED_PARAM}" | ||
40 | echo "Boring User Name" >> "${CRED_PARAM}" | ||
41 | dd if=/dev/urandom bs=1 count=32 2>/dev/null | base64 >> "${CRED_PARAM}" | ||
42 | echo "Credential parameters:" | ||
43 | cat "${CRED_PARAM}" | ||
44 | |||
45 | echo "Generating non-resident ES256 credential... (tap to continue!)" | ||
46 | fido2-cred -M -i "${CRED_PARAM}" $1 | fido2-cred -V | tee "${ES256_CRED}" | ||
47 | echo "Generating resident ES256 credential... (tap to continue!)" | ||
48 | fido2-cred -M -r -i "${CRED_PARAM}" $1 | fido2-cred -V | tee "${ES256_CRED_R}" | ||
49 | |||
50 | PIN1="$(dd if=/dev/urandom | tr -cd '[:print:]' | fold -w50 | head -1)" | ||
51 | PIN2="$(dd if=/dev/urandom | tr -cd '[:print:]' | fold -w50 | head -1)" | ||
52 | |||
53 | echo "Setting ${PIN1} as the PIN..." | ||
54 | echo -e "${PIN1}\n${PIN1}" | setsid -w fido2-token -S $1 | ||
55 | echo "Changing PIN from ${PIN1} to ${PIN2}..." | ||
56 | echo -e "${PIN1}\n${PIN2}\n${PIN2}" | setsid -w fido2-token -C $1 | ||
57 | echo "" | ||
58 | |||
59 | echo "Testing non-resident ES256 credential..." | ||
60 | echo "Getting assertion without user presence verification..." | ||
61 | dd if=/dev/urandom bs=1 count=32 2>/dev/null | base64 > "${ASSERT_PARAM}" | ||
62 | echo "Boring Relying Party" >> "${ASSERT_PARAM}" | ||
63 | head -1 "${ES256_CRED}" >> "${ASSERT_PARAM}" | ||
64 | tail -n +2 "${ES256_CRED}" > "${ASSERT_PUBKEY}" | ||
65 | echo "Assertion parameters:" | ||
66 | cat "${ASSERT_PARAM}" | ||
67 | fido2-assert -G -i "${ASSERT_PARAM}" $1 | fido2-assert -V "${ASSERT_PUBKEY}" | ||
68 | echo "Checking that the user presence bit is observed..." | ||
69 | ! fido2-assert -G -i "${ASSERT_PARAM}" $1 | fido2-assert -V -p "${ASSERT_PUBKEY}" | ||
70 | echo "Checking that the user verification bit is observed..." | ||
71 | ! fido2-assert -G -i "${ASSERT_PARAM}" $1 | fido2-assert -V -v "${ASSERT_PUBKEY}" | ||
72 | echo "Getting assertion _with_ user presence verification... (tap to continue!)" | ||
73 | fido2-assert -G -p -i "${ASSERT_PARAM}" $1 | fido2-assert -V -p "${ASSERT_PUBKEY}" | ||
74 | echo "Getting assertion _with_ user verification..." | ||
75 | echo -e "${PIN2}\n" | setsid -w fido2-assert -G -v -i "${ASSERT_PARAM}" $1 | \ | ||
76 | fido2-assert -V -v "${ASSERT_PUBKEY}" | ||
77 | echo "" | ||
78 | |||
79 | echo "Testing resident ES256 credential..." | ||
80 | echo "Getting assertion without user presence verification..." | ||
81 | dd if=/dev/urandom bs=1 count=32 2>/dev/null | base64 > "${ASSERT_PARAM}" | ||
82 | echo "Boring Relying Party" >> "${ASSERT_PARAM}" | ||
83 | tail -n +2 "${ES256_CRED_R}" > "${ASSERT_PUBKEY}" | ||
84 | echo "Assertion parameters:" | ||
85 | cat "${ASSERT_PARAM}" | ||
86 | fido2-assert -G -r -i "${ASSERT_PARAM}" $1 | fido2-assert -V "${ASSERT_PUBKEY}" | ||
87 | echo "Checking that the user presence bit is observed..." | ||
88 | ! fido2-assert -G -r -i "${ASSERT_PARAM}" $1 | fido2-assert -V -p "${ASSERT_PUBKEY}" | ||
89 | echo "Checking that the user verification bit is observed..." | ||
90 | ! fido2-assert -G -r -i "${ASSERT_PARAM}" $1 | fido2-assert -V -v "${ASSERT_PUBKEY}" | ||
91 | echo "Getting assertion _with_ user presence verification... (tap to continue!)" | ||
92 | fido2-assert -G -r -p -i "${ASSERT_PARAM}" $1 | fido2-assert -V -p "${ASSERT_PUBKEY}" | ||
93 | echo "Getting assertion _with_ user verification..." | ||
94 | echo -e "${PIN2}\n" | setsid -w fido2-assert -G -v -r -i "${ASSERT_PARAM}" $1 | \ | ||
95 | fido2-assert -V -v "${ASSERT_PUBKEY}" | ||
96 | echo "" | ||
diff --git a/tools/token.c b/tools/token.c new file mode 100644 index 0000000..b149208 --- /dev/null +++ b/tools/token.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <fido.h> | ||
8 | #include <stdbool.h> | ||
9 | #include <stdio.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <string.h> | ||
12 | #ifdef HAVE_UNISTD_H | ||
13 | #include <unistd.h> | ||
14 | #endif | ||
15 | |||
16 | #include "../openbsd-compat/openbsd-compat.h" | ||
17 | #include "extern.h" | ||
18 | |||
19 | static void | ||
20 | format_flags(char *ret, size_t retlen, uint8_t flags) | ||
21 | { | ||
22 | memset(ret, 0, retlen); | ||
23 | |||
24 | if (flags & FIDO_CAP_WINK) { | ||
25 | if (strlcat(ret, "wink,", retlen) >= retlen) | ||
26 | goto toolong; | ||
27 | } else { | ||
28 | if (strlcat(ret, "nowink,", retlen) >= retlen) | ||
29 | goto toolong; | ||
30 | } | ||
31 | |||
32 | if (flags & FIDO_CAP_CBOR) { | ||
33 | if (strlcat(ret, " cbor,", retlen) >= retlen) | ||
34 | goto toolong; | ||
35 | } else { | ||
36 | if (strlcat(ret, " nocbor,", retlen) >= retlen) | ||
37 | goto toolong; | ||
38 | } | ||
39 | |||
40 | if (flags & FIDO_CAP_NMSG) { | ||
41 | if (strlcat(ret, " nomsg", retlen) >= retlen) | ||
42 | goto toolong; | ||
43 | } else { | ||
44 | if (strlcat(ret, " msg", retlen) >= retlen) | ||
45 | goto toolong; | ||
46 | } | ||
47 | |||
48 | return; | ||
49 | toolong: | ||
50 | strlcpy(ret, "toolong", retlen); | ||
51 | } | ||
52 | |||
53 | static void | ||
54 | print_attr(const fido_dev_t *dev) | ||
55 | { | ||
56 | char flags_txt[128]; | ||
57 | |||
58 | printf("proto: 0x%02x\n", fido_dev_protocol(dev)); | ||
59 | printf("major: 0x%02x\n", fido_dev_major(dev)); | ||
60 | printf("minor: 0x%02x\n", fido_dev_minor(dev)); | ||
61 | printf("build: 0x%02x\n", fido_dev_build(dev)); | ||
62 | |||
63 | format_flags(flags_txt, sizeof(flags_txt), fido_dev_flags(dev)); | ||
64 | printf("caps: 0x%02x (%s)\n", fido_dev_flags(dev), flags_txt); | ||
65 | } | ||
66 | |||
67 | static void | ||
68 | print_str_array(const char *label, char * const *sa, size_t len) | ||
69 | { | ||
70 | if (len == 0) | ||
71 | return; | ||
72 | |||
73 | printf("%s strings: ", label); | ||
74 | |||
75 | for (size_t i = 0; i < len; i++) | ||
76 | printf("%s%s", i > 0 ? ", " : "", sa[i]); | ||
77 | |||
78 | printf("\n"); | ||
79 | } | ||
80 | |||
81 | static void | ||
82 | print_opt_array(const char *label, char * const *name, const bool *value, | ||
83 | size_t len) | ||
84 | { | ||
85 | if (len == 0) | ||
86 | return; | ||
87 | |||
88 | printf("%s: ", label); | ||
89 | |||
90 | for (size_t i = 0; i < len; i++) | ||
91 | printf("%s%s%s", i > 0 ? ", " : "", | ||
92 | value[i] ? "" : "no", name[i]); | ||
93 | |||
94 | printf("\n"); | ||
95 | } | ||
96 | |||
97 | static void | ||
98 | print_aaguid(const unsigned char *buf, size_t buflen) | ||
99 | { | ||
100 | printf("aaguid: "); | ||
101 | |||
102 | while (buflen--) | ||
103 | printf("%02x", *buf++); | ||
104 | |||
105 | printf("\n"); | ||
106 | } | ||
107 | |||
108 | static void | ||
109 | print_maxmsgsiz(uint64_t maxmsgsiz) | ||
110 | { | ||
111 | printf("maxmsgsiz: %d\n", (int)maxmsgsiz); | ||
112 | } | ||
113 | |||
114 | static void | ||
115 | print_byte_array(const char *label, const uint8_t *ba, size_t len) | ||
116 | { | ||
117 | if (len == 0) | ||
118 | return; | ||
119 | |||
120 | printf("%s: ", label); | ||
121 | |||
122 | for (size_t i = 0; i < len; i++) | ||
123 | printf("%s%u", i > 0 ? ", " : "", (unsigned)ba[i]); | ||
124 | |||
125 | printf("\n"); | ||
126 | } | ||
127 | |||
128 | int | ||
129 | token_info(int argc, char **argv, char *path) | ||
130 | { | ||
131 | char *cred_id = NULL; | ||
132 | char *rp_id = NULL; | ||
133 | fido_cbor_info_t *ci = NULL; | ||
134 | fido_dev_t *dev = NULL; | ||
135 | int ch; | ||
136 | int credman = 0; | ||
137 | int r; | ||
138 | int retrycnt; | ||
139 | |||
140 | optind = 1; | ||
141 | |||
142 | while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) { | ||
143 | switch (ch) { | ||
144 | case 'c': | ||
145 | credman = 1; | ||
146 | break; | ||
147 | case 'i': | ||
148 | cred_id = optarg; | ||
149 | break; | ||
150 | case 'k': | ||
151 | rp_id = optarg; | ||
152 | break; | ||
153 | default: | ||
154 | break; /* ignore */ | ||
155 | } | ||
156 | } | ||
157 | |||
158 | if (path == NULL || (credman && (cred_id != NULL || rp_id != NULL))) | ||
159 | usage(); | ||
160 | |||
161 | dev = open_dev(path); | ||
162 | |||
163 | if (credman) | ||
164 | return (credman_get_metadata(dev, path)); | ||
165 | if (cred_id && rp_id) | ||
166 | return (credman_print_rk(dev, path, rp_id, cred_id)); | ||
167 | if (cred_id || rp_id) | ||
168 | usage(); | ||
169 | |||
170 | print_attr(dev); | ||
171 | |||
172 | if (fido_dev_is_fido2(dev) == false) | ||
173 | goto end; | ||
174 | if ((ci = fido_cbor_info_new()) == NULL) | ||
175 | errx(1, "fido_cbor_info_new"); | ||
176 | if ((r = fido_dev_get_cbor_info(dev, ci)) != FIDO_OK) | ||
177 | errx(1, "fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r); | ||
178 | |||
179 | /* print supported protocol versions */ | ||
180 | print_str_array("version", fido_cbor_info_versions_ptr(ci), | ||
181 | fido_cbor_info_versions_len(ci)); | ||
182 | |||
183 | /* print supported extensions */ | ||
184 | print_str_array("extension", fido_cbor_info_extensions_ptr(ci), | ||
185 | fido_cbor_info_extensions_len(ci)); | ||
186 | |||
187 | /* print aaguid */ | ||
188 | print_aaguid(fido_cbor_info_aaguid_ptr(ci), | ||
189 | fido_cbor_info_aaguid_len(ci)); | ||
190 | |||
191 | /* print supported options */ | ||
192 | print_opt_array("options", fido_cbor_info_options_name_ptr(ci), | ||
193 | fido_cbor_info_options_value_ptr(ci), | ||
194 | fido_cbor_info_options_len(ci)); | ||
195 | |||
196 | /* print maximum message size */ | ||
197 | print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci)); | ||
198 | |||
199 | /* print supported pin protocols */ | ||
200 | print_byte_array("pin protocols", fido_cbor_info_protocols_ptr(ci), | ||
201 | fido_cbor_info_protocols_len(ci)); | ||
202 | |||
203 | if ((r = fido_dev_get_retry_count(dev, &retrycnt)) != FIDO_OK) | ||
204 | printf("pin retries: undefined\n"); | ||
205 | else | ||
206 | printf("pin retries: %d\n", retrycnt); | ||
207 | |||
208 | bio_info(dev); | ||
209 | |||
210 | fido_cbor_info_free(&ci); | ||
211 | end: | ||
212 | fido_dev_close(dev); | ||
213 | fido_dev_free(&dev); | ||
214 | |||
215 | exit(0); | ||
216 | } | ||
217 | |||
218 | int | ||
219 | token_reset(char *path) | ||
220 | { | ||
221 | fido_dev_t *dev = NULL; | ||
222 | int r; | ||
223 | |||
224 | if (path == NULL) | ||
225 | usage(); | ||
226 | |||
227 | dev = open_dev(path); | ||
228 | if ((r = fido_dev_reset(dev)) != FIDO_OK) | ||
229 | errx(1, "fido_dev_reset: %s", fido_strerr(r)); | ||
230 | |||
231 | fido_dev_close(dev); | ||
232 | fido_dev_free(&dev); | ||
233 | |||
234 | exit(0); | ||
235 | } | ||
236 | |||
237 | int | ||
238 | token_set(int argc, char **argv, char *path) | ||
239 | { | ||
240 | char *id = NULL; | ||
241 | char *name = NULL; | ||
242 | int ch; | ||
243 | int enroll = 0; | ||
244 | |||
245 | optind = 1; | ||
246 | |||
247 | while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) { | ||
248 | switch (ch) { | ||
249 | case 'e': | ||
250 | enroll = 1; | ||
251 | break; | ||
252 | case 'i': | ||
253 | id = optarg; | ||
254 | break; | ||
255 | case 'n': | ||
256 | name = optarg; | ||
257 | break; | ||
258 | default: | ||
259 | break; /* ignore */ | ||
260 | } | ||
261 | } | ||
262 | |||
263 | if (enroll) { | ||
264 | if (id && name) | ||
265 | return (bio_set_name(path, id, name)); | ||
266 | if (!id && !name) | ||
267 | return (bio_enroll(path)); | ||
268 | usage(); | ||
269 | } | ||
270 | |||
271 | return (pin_set(path)); | ||
272 | } | ||
273 | |||
274 | int | ||
275 | token_list(int argc, char **argv, char *path) | ||
276 | { | ||
277 | fido_dev_info_t *devlist; | ||
278 | size_t ndevs; | ||
279 | const char *rp_id = NULL; | ||
280 | int enrolls = 0; | ||
281 | int keys = 0; | ||
282 | int rplist = 0; | ||
283 | int ch; | ||
284 | int r; | ||
285 | |||
286 | optind = 1; | ||
287 | |||
288 | while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) { | ||
289 | switch (ch) { | ||
290 | case 'e': | ||
291 | enrolls = 1; | ||
292 | break; | ||
293 | case 'k': | ||
294 | keys = 1; | ||
295 | rp_id = optarg; | ||
296 | break; | ||
297 | case 'r': | ||
298 | rplist = 1; | ||
299 | break; | ||
300 | default: | ||
301 | break; /* ignore */ | ||
302 | } | ||
303 | } | ||
304 | |||
305 | if (enrolls) | ||
306 | return (bio_list(path)); | ||
307 | if (keys) | ||
308 | return (credman_list_rk(path, rp_id)); | ||
309 | if (rplist) | ||
310 | return (credman_list_rp(path)); | ||
311 | |||
312 | if ((devlist = fido_dev_info_new(64)) == NULL) | ||
313 | errx(1, "fido_dev_info_new"); | ||
314 | if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK) | ||
315 | errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r); | ||
316 | |||
317 | for (size_t i = 0; i < ndevs; i++) { | ||
318 | const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i); | ||
319 | printf("%s: vendor=0x%04x, product=0x%04x (%s %s)\n", | ||
320 | fido_dev_info_path(di), | ||
321 | (uint16_t)fido_dev_info_vendor(di), | ||
322 | (uint16_t)fido_dev_info_product(di), | ||
323 | fido_dev_info_manufacturer_string(di), | ||
324 | fido_dev_info_product_string(di)); | ||
325 | } | ||
326 | |||
327 | fido_dev_info_free(&devlist, ndevs); | ||
328 | |||
329 | exit(0); | ||
330 | } | ||
331 | |||
332 | int | ||
333 | token_delete(int argc, char **argv, char *path) | ||
334 | { | ||
335 | char *id = NULL; | ||
336 | fido_dev_t *dev = NULL; | ||
337 | int ch; | ||
338 | int enroll = 0; | ||
339 | |||
340 | optind = 1; | ||
341 | |||
342 | while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) { | ||
343 | switch (ch) { | ||
344 | case 'e': | ||
345 | enroll = 1; | ||
346 | break; | ||
347 | case 'i': | ||
348 | id = optarg; | ||
349 | break; | ||
350 | default: | ||
351 | break; /* ignore */ | ||
352 | } | ||
353 | } | ||
354 | |||
355 | if (path == NULL || id == NULL) | ||
356 | usage(); | ||
357 | |||
358 | dev = open_dev(path); | ||
359 | |||
360 | if (id && !enroll) | ||
361 | return (credman_delete_rk(dev, path, id)); | ||
362 | |||
363 | return (bio_delete(dev, path, id)); | ||
364 | } | ||
diff --git a/tools/util.c b/tools/util.c new file mode 100644 index 0000000..de70388 --- /dev/null +++ b/tools/util.c | |||
@@ -0,0 +1,364 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2018 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 <sys/types.h> | ||
8 | #include <sys/stat.h> | ||
9 | |||
10 | #include <openssl/ec.h> | ||
11 | #include <openssl/evp.h> | ||
12 | #include <openssl/pem.h> | ||
13 | |||
14 | #include <fido.h> | ||
15 | #include <fido/es256.h> | ||
16 | #include <fido/rs256.h> | ||
17 | #include <fido/eddsa.h> | ||
18 | |||
19 | #include <fcntl.h> | ||
20 | #include <stdint.h> | ||
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <string.h> | ||
24 | |||
25 | #include "../openbsd-compat/openbsd-compat.h" | ||
26 | #ifdef _MSC_VER | ||
27 | #include "../openbsd-compat/posix_win.h" | ||
28 | #endif | ||
29 | |||
30 | #include "extern.h" | ||
31 | |||
32 | void | ||
33 | read_pin(const char *path, char *buf, size_t len) | ||
34 | { | ||
35 | char prompt[1024]; | ||
36 | int r; | ||
37 | |||
38 | r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", path); | ||
39 | if (r < 0 || (size_t)r >= sizeof(prompt)) | ||
40 | errx(1, "snprintf"); | ||
41 | if (!readpassphrase(prompt, buf, len, RPP_ECHO_OFF)) | ||
42 | errx(1, "readpassphrase"); | ||
43 | } | ||
44 | |||
45 | FILE * | ||
46 | open_write(const char *file) | ||
47 | { | ||
48 | int fd; | ||
49 | FILE *f; | ||
50 | |||
51 | if (file == NULL || strcmp(file, "-") == 0) | ||
52 | return (stdout); | ||
53 | if ((fd = open(file, O_WRONLY | O_CREAT, 0600)) < 0) | ||
54 | err(1, "open %s", file); | ||
55 | if ((f = fdopen(fd, "w")) == NULL) | ||
56 | err(1, "fdopen %s", file); | ||
57 | |||
58 | return (f); | ||
59 | } | ||
60 | |||
61 | FILE * | ||
62 | open_read(const char *file) | ||
63 | { | ||
64 | int fd; | ||
65 | FILE *f; | ||
66 | |||
67 | if (file == NULL || strcmp(file, "-") == 0) { | ||
68 | #ifdef FIDO_FUZZ | ||
69 | setvbuf(stdin, NULL, _IONBF, 0); | ||
70 | #endif | ||
71 | return (stdin); | ||
72 | } | ||
73 | if ((fd = open(file, O_RDONLY)) < 0) | ||
74 | err(1, "open %s", file); | ||
75 | if ((f = fdopen(fd, "r")) == NULL) | ||
76 | err(1, "fdopen %s", file); | ||
77 | |||
78 | return (f); | ||
79 | } | ||
80 | |||
81 | void | ||
82 | xxd(const void *buf, size_t count) | ||
83 | { | ||
84 | const uint8_t *ptr = buf; | ||
85 | size_t i; | ||
86 | |||
87 | fprintf(stderr, " "); | ||
88 | |||
89 | for (i = 0; i < count; i++) { | ||
90 | fprintf(stderr, "%02x ", *ptr++); | ||
91 | if ((i + 1) % 16 == 0 && i + 1 < count) | ||
92 | fprintf(stderr, "\n "); | ||
93 | } | ||
94 | |||
95 | fprintf(stderr, "\n"); | ||
96 | fflush(stderr); | ||
97 | } | ||
98 | |||
99 | int | ||
100 | string_read(FILE *f, char **out) | ||
101 | { | ||
102 | char *line = NULL; | ||
103 | size_t linesize = 0; | ||
104 | ssize_t n; | ||
105 | |||
106 | *out = NULL; | ||
107 | |||
108 | if ((n = getline(&line, &linesize, f)) <= 0 || | ||
109 | (size_t)n != strlen(line)) { | ||
110 | free(line); | ||
111 | return (-1); | ||
112 | } | ||
113 | |||
114 | line[n - 1] = '\0'; /* trim \n */ | ||
115 | *out = line; | ||
116 | |||
117 | return (0); | ||
118 | } | ||
119 | |||
120 | fido_dev_t * | ||
121 | open_dev(const char *path) | ||
122 | { | ||
123 | fido_dev_t *dev; | ||
124 | int r; | ||
125 | |||
126 | if ((dev = fido_dev_new()) == NULL) | ||
127 | errx(1, "fido_dev_new"); | ||
128 | |||
129 | r = fido_dev_open(dev, path); | ||
130 | if (r != FIDO_OK) | ||
131 | errx(1, "fido_dev_open %s: %s", path, fido_strerr(r)); | ||
132 | |||
133 | return (dev); | ||
134 | } | ||
135 | |||
136 | EC_KEY * | ||
137 | read_ec_pubkey(const char *path) | ||
138 | { | ||
139 | FILE *fp = NULL; | ||
140 | EVP_PKEY *pkey = NULL; | ||
141 | EC_KEY *ec = NULL; | ||
142 | |||
143 | if ((fp = fopen(path, "r")) == NULL) { | ||
144 | warn("fopen"); | ||
145 | goto fail; | ||
146 | } | ||
147 | |||
148 | if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { | ||
149 | warnx("PEM_read_PUBKEY"); | ||
150 | goto fail; | ||
151 | } | ||
152 | if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { | ||
153 | warnx("EVP_PKEY_get1_EC_KEY"); | ||
154 | goto fail; | ||
155 | } | ||
156 | |||
157 | fail: | ||
158 | if (fp) { | ||
159 | fclose(fp); | ||
160 | } | ||
161 | if (pkey) { | ||
162 | EVP_PKEY_free(pkey); | ||
163 | } | ||
164 | |||
165 | return (ec); | ||
166 | } | ||
167 | |||
168 | int | ||
169 | write_ec_pubkey(FILE *f, const void *ptr, size_t len) | ||
170 | { | ||
171 | EVP_PKEY *pkey = NULL; | ||
172 | es256_pk_t *pk = NULL; | ||
173 | int ok = -1; | ||
174 | |||
175 | if ((pk = es256_pk_new()) == NULL) { | ||
176 | warnx("es256_pk_new"); | ||
177 | goto fail; | ||
178 | } | ||
179 | |||
180 | if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { | ||
181 | warnx("es256_pk_from_ptr"); | ||
182 | goto fail; | ||
183 | } | ||
184 | |||
185 | if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) { | ||
186 | warnx("es256_pk_to_EVP_PKEY"); | ||
187 | goto fail; | ||
188 | } | ||
189 | |||
190 | if (PEM_write_PUBKEY(f, pkey) == 0) { | ||
191 | warnx("PEM_write_PUBKEY"); | ||
192 | goto fail; | ||
193 | } | ||
194 | |||
195 | ok = 0; | ||
196 | fail: | ||
197 | es256_pk_free(&pk); | ||
198 | |||
199 | if (pkey != NULL) { | ||
200 | EVP_PKEY_free(pkey); | ||
201 | } | ||
202 | |||
203 | return (ok); | ||
204 | } | ||
205 | |||
206 | RSA * | ||
207 | read_rsa_pubkey(const char *path) | ||
208 | { | ||
209 | FILE *fp = NULL; | ||
210 | EVP_PKEY *pkey = NULL; | ||
211 | RSA *rsa = NULL; | ||
212 | |||
213 | if ((fp = fopen(path, "r")) == NULL) { | ||
214 | warn("fopen"); | ||
215 | goto fail; | ||
216 | } | ||
217 | |||
218 | if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { | ||
219 | warnx("PEM_read_PUBKEY"); | ||
220 | goto fail; | ||
221 | } | ||
222 | if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) { | ||
223 | warnx("EVP_PKEY_get1_RSA"); | ||
224 | goto fail; | ||
225 | } | ||
226 | |||
227 | fail: | ||
228 | if (fp) { | ||
229 | fclose(fp); | ||
230 | } | ||
231 | if (pkey) { | ||
232 | EVP_PKEY_free(pkey); | ||
233 | } | ||
234 | |||
235 | return (rsa); | ||
236 | } | ||
237 | |||
238 | int | ||
239 | write_rsa_pubkey(FILE *f, const void *ptr, size_t len) | ||
240 | { | ||
241 | EVP_PKEY *pkey = NULL; | ||
242 | rs256_pk_t *pk = NULL; | ||
243 | int ok = -1; | ||
244 | |||
245 | if ((pk = rs256_pk_new()) == NULL) { | ||
246 | warnx("rs256_pk_new"); | ||
247 | goto fail; | ||
248 | } | ||
249 | |||
250 | if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { | ||
251 | warnx("rs256_pk_from_ptr"); | ||
252 | goto fail; | ||
253 | } | ||
254 | |||
255 | if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) { | ||
256 | warnx("rs256_pk_to_EVP_PKEY"); | ||
257 | goto fail; | ||
258 | } | ||
259 | |||
260 | if (PEM_write_PUBKEY(f, pkey) == 0) { | ||
261 | warnx("PEM_write_PUBKEY"); | ||
262 | goto fail; | ||
263 | } | ||
264 | |||
265 | ok = 0; | ||
266 | fail: | ||
267 | rs256_pk_free(&pk); | ||
268 | |||
269 | if (pkey != NULL) { | ||
270 | EVP_PKEY_free(pkey); | ||
271 | } | ||
272 | |||
273 | return (ok); | ||
274 | } | ||
275 | |||
276 | EVP_PKEY * | ||
277 | read_eddsa_pubkey(const char *path) | ||
278 | { | ||
279 | FILE *fp = NULL; | ||
280 | EVP_PKEY *pkey = NULL; | ||
281 | |||
282 | if ((fp = fopen(path, "r")) == NULL) { | ||
283 | warn("fopen"); | ||
284 | goto fail; | ||
285 | } | ||
286 | |||
287 | if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { | ||
288 | warnx("PEM_read_PUBKEY"); | ||
289 | goto fail; | ||
290 | } | ||
291 | |||
292 | fail: | ||
293 | if (fp) { | ||
294 | fclose(fp); | ||
295 | } | ||
296 | |||
297 | return (pkey); | ||
298 | } | ||
299 | |||
300 | int | ||
301 | write_eddsa_pubkey(FILE *f, const void *ptr, size_t len) | ||
302 | { | ||
303 | EVP_PKEY *pkey = NULL; | ||
304 | eddsa_pk_t *pk = NULL; | ||
305 | int ok = -1; | ||
306 | |||
307 | if ((pk = eddsa_pk_new()) == NULL) { | ||
308 | warnx("eddsa_pk_new"); | ||
309 | goto fail; | ||
310 | } | ||
311 | |||
312 | if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) { | ||
313 | warnx("eddsa_pk_from_ptr"); | ||
314 | goto fail; | ||
315 | } | ||
316 | |||
317 | if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { | ||
318 | warnx("eddsa_pk_to_EVP_PKEY"); | ||
319 | goto fail; | ||
320 | } | ||
321 | |||
322 | if (PEM_write_PUBKEY(f, pkey) == 0) { | ||
323 | warnx("PEM_write_PUBKEY"); | ||
324 | goto fail; | ||
325 | } | ||
326 | |||
327 | ok = 0; | ||
328 | fail: | ||
329 | eddsa_pk_free(&pk); | ||
330 | |||
331 | if (pkey != NULL) { | ||
332 | EVP_PKEY_free(pkey); | ||
333 | } | ||
334 | |||
335 | return (ok); | ||
336 | } | ||
337 | |||
338 | void | ||
339 | print_cred(FILE *out_f, int type, const fido_cred_t *cred) | ||
340 | { | ||
341 | char *id; | ||
342 | int r; | ||
343 | |||
344 | r = base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &id); | ||
345 | if (r < 0) | ||
346 | errx(1, "output error"); | ||
347 | |||
348 | fprintf(out_f, "%s\n", id); | ||
349 | |||
350 | if (type == COSE_ES256) { | ||
351 | write_ec_pubkey(out_f, fido_cred_pubkey_ptr(cred), | ||
352 | fido_cred_pubkey_len(cred)); | ||
353 | } else if (type == COSE_RS256) { | ||
354 | write_rsa_pubkey(out_f, fido_cred_pubkey_ptr(cred), | ||
355 | fido_cred_pubkey_len(cred)); | ||
356 | } else if (type == COSE_EDDSA) { | ||
357 | write_eddsa_pubkey(out_f, fido_cred_pubkey_ptr(cred), | ||
358 | fido_cred_pubkey_len(cred)); | ||
359 | } else { | ||
360 | errx(1, "print_cred: unknown type"); | ||
361 | } | ||
362 | |||
363 | free(id); | ||
364 | } | ||
diff --git a/udev/70-u2f.rules b/udev/70-u2f.rules new file mode 100644 index 0000000..8dc20a1 --- /dev/null +++ b/udev/70-u2f.rules | |||
@@ -0,0 +1,72 @@ | |||
1 | # Copyright (c) 2018 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 | # this udev file should be used with udev 188 and newer | ||
6 | ACTION!="add|change", GOTO="u2f_end" | ||
7 | |||
8 | # Yubico YubiKey | ||
9 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0113|0114|0115|0116|0120|0121|0200|0402|0403|0406|0407|0410", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
10 | |||
11 | # Happlink (formerly Plug-Up) Security KEY | ||
12 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2581", ATTRS{idProduct}=="f1d0", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
13 | |||
14 | # Neowave Keydo and Keydo AES | ||
15 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1e0d", ATTRS{idProduct}=="f1d0|f1ae", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
16 | |||
17 | # HyperSecu HyperFIDO | ||
18 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e|2ccf", ATTRS{idProduct}=="0880", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
19 | |||
20 | # Feitian ePass FIDO, BioPass FIDO2 | ||
21 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0850|0852|0853|0854|0856|0858|085a|085b|085d", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
22 | |||
23 | # JaCarta U2F | ||
24 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="24dc", ATTRS{idProduct}=="0101|0501", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
25 | |||
26 | # U2F Zero | ||
27 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
28 | |||
29 | # VASCO SecureClick | ||
30 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1a44", ATTRS{idProduct}=="00bb", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
31 | |||
32 | # Bluink Key | ||
33 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2abe", ATTRS{idProduct}=="1002", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
34 | |||
35 | # Thetis Key | ||
36 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1ea8", ATTRS{idProduct}=="f025", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
37 | |||
38 | # Nitrokey FIDO U2F | ||
39 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4287", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
40 | |||
41 | # Google Titan U2F | ||
42 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="5026", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
43 | |||
44 | # Tomu board + chopstx U2F + SoloKeys | ||
45 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="cdab|a2ca", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
46 | |||
47 | # SoloKeys | ||
48 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="5070|50b0", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
49 | |||
50 | # Trezor | ||
51 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="534c", ATTRS{idProduct}=="0001", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
52 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="53c1", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
53 | |||
54 | # Infineon FIDO | ||
55 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="058b", ATTRS{idProduct}=="022d", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
56 | |||
57 | # Ledger Nano S and Nano X | ||
58 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0001|0004", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
59 | |||
60 | # Kensington VeriMark | ||
61 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="06cb", ATTRS{idProduct}=="0088", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
62 | |||
63 | # Longmai mFIDO | ||
64 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="4c4d", ATTRS{idProduct}=="f703", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
65 | |||
66 | # eWBM FIDO2 - Goldengate 310, 320, 500, 450 | ||
67 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="4a1a|4c2a|5c2f|f47c", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
68 | |||
69 | # OnlyKey (FIDO2 / U2F) | ||
70 | KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="60fc", TAG+="uaccess", GROUP="plugdev", MODE="0660" | ||
71 | |||
72 | LABEL="u2f_end" | ||
diff --git a/udev/CMakeLists.txt b/udev/CMakeLists.txt new file mode 100644 index 0000000..29a9d41 --- /dev/null +++ b/udev/CMakeLists.txt | |||
@@ -0,0 +1,7 @@ | |||
1 | # Copyright (c) 2018 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 | if(UDEV_RULES_DIR) | ||
6 | install(FILES 70-u2f.rules DESTINATION ${UDEV_RULES_DIR}) | ||
7 | endif() | ||
diff --git a/windows/build.ps1 b/windows/build.ps1 new file mode 100644 index 0000000..aaa848d --- /dev/null +++ b/windows/build.ps1 | |||
@@ -0,0 +1,204 @@ | |||
1 | param( | ||
2 | [string]$CMakePath = "C:\Program Files\CMake\bin\cmake.exe", | ||
3 | [string]$GitPath = "C:\Program Files\Git\bin\git.exe", | ||
4 | [string]$SevenZPath = "C:\Program Files\7-Zip\7z.exe", | ||
5 | [string]$GPGPath = "C:\Program Files (x86)\GnuPG\bin\gpg.exe" | ||
6 | ) | ||
7 | |||
8 | $ErrorActionPreference = "Continue" | ||
9 | |||
10 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 | ||
11 | |||
12 | # LibreSSL coordinates. | ||
13 | New-Variable -Name 'LIBRESSL_URL' ` | ||
14 | -Value 'https://ftp.openbsd.org/pub/OpenBSD/LibreSSL' -Option Constant | ||
15 | New-Variable -Name 'LIBRESSL' -Value 'libressl-3.0.2' -Option Constant | ||
16 | |||
17 | # libcbor coordinates. | ||
18 | New-Variable -Name 'LIBCBOR' -Value 'libcbor-0.5.0' -Option Constant | ||
19 | New-Variable -Name 'LIBCBOR_BRANCH' -Value 'v0.5.0' -Option Constant | ||
20 | New-Variable -Name 'LIBCBOR_GIT' -Value 'https://github.com/pjk/libcbor' ` | ||
21 | -Option Constant | ||
22 | |||
23 | # Work directories. | ||
24 | New-Variable -Name 'BUILD' -Value "$PSScriptRoot\..\build" -Option Constant | ||
25 | New-Variable -Name 'OUTPUT' -Value "$PSScriptRoot\..\output" -Option Constant | ||
26 | |||
27 | # Find CMake. | ||
28 | $CMake = $(Get-Command cmake -ErrorAction Ignore | Select-Object -ExpandProperty Source) | ||
29 | if([string]::IsNullOrEmpty($CMake)) { | ||
30 | $CMake = $CMakePath | ||
31 | } | ||
32 | |||
33 | # Find Git. | ||
34 | $Git = $(Get-Command git -ErrorAction Ignore | Select-Object -ExpandProperty Source) | ||
35 | if([string]::IsNullOrEmpty($Git)) { | ||
36 | $Git = $GitPath | ||
37 | } | ||
38 | |||
39 | # Find 7z. | ||
40 | $SevenZ = $(Get-Command 7z -ErrorAction Ignore | Select-Object -ExpandProperty Source) | ||
41 | if([string]::IsNullOrEmpty($SevenZ)) { | ||
42 | $SevenZ = $SevenZPath | ||
43 | } | ||
44 | |||
45 | # Find GPG. | ||
46 | $GPG = $(Get-Command gpg -ErrorAction Ignore | Select-Object -ExpandProperty Source) | ||
47 | if([string]::IsNullOrEmpty($GPG)) { | ||
48 | $GPG = $GPGPath | ||
49 | } | ||
50 | |||
51 | if(-Not (Test-Path $CMake)) { | ||
52 | throw "Unable to find CMake at $CMake" | ||
53 | } | ||
54 | |||
55 | if(-Not (Test-Path $Git)) { | ||
56 | throw "Unable to find Git at $Git" | ||
57 | } | ||
58 | |||
59 | if(-Not (Test-Path $SevenZ)) { | ||
60 | throw "Unable to find 7z at $SevenZ" | ||
61 | } | ||
62 | |||
63 | if(-Not (Test-Path $GPG)) { | ||
64 | throw "Unable to find GPG at $GPG" | ||
65 | } | ||
66 | |||
67 | Write-Host "Git: $Git" | ||
68 | Write-Host "CMake: $CMake" | ||
69 | Write-Host "7z: $SevenZ" | ||
70 | Write-Host "GPG: $GPG" | ||
71 | |||
72 | New-Item -Type Directory ${BUILD} | ||
73 | New-Item -Type Directory ${BUILD}\32 | ||
74 | New-Item -Type Directory ${BUILD}\64 | ||
75 | New-Item -Type Directory ${OUTPUT} | ||
76 | New-Item -Type Directory ${OUTPUT}\pkg\Win64\Release\v142\dynamic | ||
77 | New-Item -Type Directory ${OUTPUT}\pkg\Win32\Release\v142\dynamic | ||
78 | |||
79 | Push-Location ${BUILD} | ||
80 | |||
81 | try { | ||
82 | if (Test-Path .\${LIBRESSL}) { | ||
83 | Remove-Item .\${LIBRESSL} -Recurse -ErrorAction Stop | ||
84 | } | ||
85 | |||
86 | if(-Not (Test-Path .\${LIBRESSL}.tar.gz -PathType leaf)) { | ||
87 | Invoke-WebRequest ${LIBRESSL_URL}/${LIBRESSL}.tar.gz ` | ||
88 | -OutFile .\${LIBRESSL}.tar.gz | ||
89 | } | ||
90 | if(-Not (Test-Path .\${LIBRESSL}.tar.gz.asc -PathType leaf)) { | ||
91 | Invoke-WebRequest ${LIBRESSL_URL}/${LIBRESSL}.tar.gz.asc ` | ||
92 | -OutFile .\${LIBRESSL}.tar.gz.asc | ||
93 | } | ||
94 | |||
95 | Copy-Item "$PSScriptRoot\libressl.gpg" -Destination "${BUILD}" | ||
96 | & $GPG --list-keys | ||
97 | & $GPG -v --no-default-keyring --keyring ./libressl.gpg ` | ||
98 | --verify .\${LIBRESSL}.tar.gz.asc .\${LIBRESSL}.tar.gz | ||
99 | if ($LastExitCode -ne 0) { | ||
100 | throw "GPG signature verification failed" | ||
101 | } | ||
102 | |||
103 | & $SevenZ e .\${LIBRESSL}.tar.gz | ||
104 | & $SevenZ x .\${LIBRESSL}.tar | ||
105 | Remove-Item -Force .\${LIBRESSL}.tar | ||
106 | |||
107 | if(-Not (Test-Path .\${LIBCBOR})) { | ||
108 | Write-Host "Cloning ${LIBCBOR}..." | ||
109 | & $Git clone --branch ${LIBCBOR_BRANCH} ${LIBCBOR_GIT} ` | ||
110 | .\${LIBCBOR} | ||
111 | } | ||
112 | } catch { | ||
113 | throw "Failed to fetch and verify dependencies" | ||
114 | } finally { | ||
115 | Pop-Location | ||
116 | } | ||
117 | |||
118 | Function Build(${OUTPUT}, ${GENERATOR}, ${ARCH}) { | ||
119 | if(-Not (Test-Path .\${LIBRESSL})) { | ||
120 | New-Item -Type Directory .\${LIBRESSL} -ErrorAction Stop | ||
121 | } | ||
122 | |||
123 | Push-Location .\${LIBRESSL} | ||
124 | & $CMake ..\..\${LIBRESSL} -G "${GENERATOR}" -A "${ARCH}" ` | ||
125 | -DCMAKE_C_FLAGS_RELEASE="/Zi" ` | ||
126 | -DCMAKE_INSTALL_PREFIX="${OUTPUT}" -DBUILD_SHARED_LIBS=ON ` | ||
127 | -DLIBRESSL_TESTS=OFF | ||
128 | & $CMake --build . --config Release | ||
129 | & $CMake --build . --config Release --target install | ||
130 | Pop-Location | ||
131 | |||
132 | if(-Not (Test-Path .\${LIBCBOR})) { | ||
133 | New-Item -Type Directory .\${LIBCBOR} -ErrorAction Stop | ||
134 | } | ||
135 | |||
136 | Push-Location .\${LIBCBOR} | ||
137 | & $CMake ..\..\${LIBCBOR} -G "${GENERATOR}" -A "${ARCH}" ` | ||
138 | -DCMAKE_C_FLAGS_RELEASE="/Zi" ` | ||
139 | -DCMAKE_INSTALL_PREFIX="${OUTPUT}" | ||
140 | & $CMake --build . --config Release | ||
141 | & $CMake --build . --config Release --target install | ||
142 | Pop-Location | ||
143 | |||
144 | & $CMake ..\.. -G "${GENERATOR}" -A "${ARCH}" ` | ||
145 | -DCBOR_INCLUDE_DIRS="${OUTPUT}\include" ` | ||
146 | -DCBOR_LIBRARY_DIRS="${OUTPUT}\lib" ` | ||
147 | -DCRYPTO_INCLUDE_DIRS="${OUTPUT}\include" ` | ||
148 | -DCRYPTO_LIBRARY_DIRS="${OUTPUT}\lib" ` | ||
149 | -DCMAKE_INSTALL_PREFIX="${OUTPUT}" | ||
150 | & $CMake --build . --config Release | ||
151 | & $CMake --build . --config Release --target install | ||
152 | "cbor.dll", "crypto-45.dll" | %{ Copy-Item "${OUTPUT}\bin\$_" ` | ||
153 | -Destination "examples\Release" } | ||
154 | } | ||
155 | |||
156 | Function Package-Headers() { | ||
157 | Copy-Item "${OUTPUT}\64\include" -Destination "${OUTPUT}\pkg" ` | ||
158 | -Recurse -ErrorAction Stop | ||
159 | } | ||
160 | |||
161 | Function Package-Libraries(${SRC}, ${DEST}) { | ||
162 | Copy-Item "${SRC}\bin\cbor.dll" "${DEST}" -ErrorAction Stop | ||
163 | Copy-Item "${SRC}\lib\cbor.lib" "${DEST}" -ErrorAction Stop | ||
164 | Copy-Item "${SRC}\bin\crypto-45.dll" "${DEST}" -ErrorAction Stop | ||
165 | Copy-Item "${SRC}\lib\crypto-45.lib" "${DEST}" -ErrorAction Stop | ||
166 | Copy-Item "${SRC}\lib\fido2.dll" "${DEST}" -ErrorAction Stop | ||
167 | Copy-Item "${SRC}\lib\fido2.lib" "${DEST}" -ErrorAction Stop | ||
168 | } | ||
169 | |||
170 | Function Package-PDBs(${SRC}, ${DEST}) { | ||
171 | Copy-Item "${SRC}\${LIBRESSL}\crypto\crypto.dir\Release\vc142.pdb" ` | ||
172 | "${DEST}\crypto-45.pdb" -ErrorAction Stop | ||
173 | Copy-Item "${SRC}\${LIBCBOR}\src\cbor_shared.dir\Release\vc142.pdb" ` | ||
174 | "${DEST}\cbor.pdb" -ErrorAction Stop | ||
175 | Copy-Item "${SRC}\src\fido2_shared.dir\Release\vc142.pdb" ` | ||
176 | "${DEST}\fido2.pdb" -ErrorAction Stop | ||
177 | } | ||
178 | |||
179 | Function Package-Tools(${SRC}, ${DEST}) { | ||
180 | Copy-Item "${SRC}\tools\Release\fido2-assert.exe" ` | ||
181 | "${DEST}\fido2-assert.exe" -ErrorAction stop | ||
182 | Copy-Item "${SRC}\tools\Release\fido2-cred.exe" ` | ||
183 | "${DEST}\fido2-cred.exe" -ErrorAction stop | ||
184 | Copy-Item "${SRC}\tools\Release\fido2-token.exe" ` | ||
185 | "${DEST}\fido2-token.exe" -ErrorAction stop | ||
186 | } | ||
187 | |||
188 | Push-Location ${BUILD}\64 | ||
189 | Build ${OUTPUT}\64 "Visual Studio 16 2019" "x64" | ||
190 | Pop-Location | ||
191 | |||
192 | Push-Location ${BUILD}\32 | ||
193 | Build ${OUTPUT}\32 "Visual Studio 16 2019" "Win32" | ||
194 | Pop-Location | ||
195 | |||
196 | Package-Headers | ||
197 | |||
198 | Package-Libraries ${OUTPUT}\64 ${OUTPUT}\pkg\Win64\Release\v142\dynamic | ||
199 | Package-PDBs ${BUILD}\64 ${OUTPUT}\pkg\Win64\Release\v142\dynamic | ||
200 | Package-Tools ${BUILD}\64 ${OUTPUT}\pkg\Win64\Release\v142\dynamic | ||
201 | |||
202 | Package-Libraries ${OUTPUT}\32 ${OUTPUT}\pkg\Win32\Release\v142\dynamic | ||
203 | Package-PDBs ${BUILD}\32 ${OUTPUT}\pkg\Win32\Release\v142\dynamic | ||
204 | Package-Tools ${BUILD}\32 ${OUTPUT}\pkg\Win32\Release\v142\dynamic | ||
diff --git a/windows/libressl.gpg b/windows/libressl.gpg new file mode 100644 index 0000000..87d5dad --- /dev/null +++ b/windows/libressl.gpg | |||
Binary files differ | |||