diff --git a/contrib/libfido2/CMakeLists.txt b/contrib/libfido2/CMakeLists.txt index 101b7b33e2fc..d775a98c5b48 100644 --- a/contrib/libfido2/CMakeLists.txt +++ b/contrib/libfido2/CMakeLists.txt @@ -1,418 +1,415 @@ -# Copyright (c) 2018 Yubico AB. All rights reserved. +# Copyright (c) 2018-2021 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. # detect AppleClang; needs to come before project() cmake_policy(SET CMP0025 NEW) project(libfido2 C) cmake_minimum_required(VERSION 3.0) # Set PIE flags for POSITION_INDEPENDENT_CODE targets, added in CMake 3.14. if(POLICY CMP0083) cmake_policy(SET CMP0083 NEW) endif() include(CheckCCompilerFlag) include(CheckFunctionExists) include(CheckLibraryExists) include(CheckSymbolExists) include(CheckIncludeFiles) include(CheckTypeSize) include(GNUInstallDirs) include(CheckPIESupported OPTIONAL RESULT_VARIABLE CHECK_PIE_SUPPORTED) if(CHECK_PIE_SUPPORTED) check_pie_supported(LANGUAGES C) endif() set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_COLOR_MAKEFILE OFF) set(CMAKE_VERBOSE_MAKEFILE ON) set(FIDO_MAJOR "1") -set(FIDO_MINOR "8") +set(FIDO_MINOR "9") set(FIDO_PATCH "0") set(FIDO_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}.${FIDO_PATCH}) option(BUILD_EXAMPLES "Build example programs" ON) option(BUILD_MANPAGES "Build man pages" ON) option(BUILD_SHARED_LIBS "Build the shared library" ON) option(BUILD_STATIC_LIBS "Build the static library" ON) option(BUILD_TOOLS "Build tool programs" ON) option(FUZZ "Enable fuzzing instrumentation" OFF) option(LIBFUZZER "Build libfuzzer harnesses" OFF) option(USE_HIDAPI "Use hidapi as the HID backend" OFF) option(USE_WINHELLO "Abstract Windows Hello as a FIDO device" OFF) option(NFC_LINUX "Experimental NFC support on Linux" OFF) add_definitions(-D_FIDO_MAJOR=${FIDO_MAJOR}) add_definitions(-D_FIDO_MINOR=${FIDO_MINOR}) add_definitions(-D_FIDO_PATCH=${FIDO_PATCH}) if(CYGWIN OR MSYS) set(WIN32 1) add_definitions(-DWINVER=0x0a00) endif() if(WIN32) add_definitions(-DWIN32_LEAN_AND_MEAN -D_WIN32_WINNT=0x0600) endif() if(APPLE) set(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") endif() if(NOT MSVC) set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_POSIX_C_SOURCE=200809L") set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_BSD_SOURCE") if(APPLE) set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_DARWIN_C_SOURCE") set(FIDO_CFLAGS "${FIDO_CFLAGS} -D__STDC_WANT_LIB_EXT1__=1") elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") - set(NFC_LINUX OFF) + set(NFC_LINUX ON) set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_GNU_SOURCE") set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_DEFAULT_SOURCE") - elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR + CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD") set(FIDO_CFLAGS "${FIDO_CFLAGS} -D__BSD_VISIBLE=1") endif() set(FIDO_CFLAGS "${FIDO_CFLAGS} -std=c99") set(CMAKE_C_FLAGS "${FIDO_CFLAGS} ${CMAKE_C_FLAGS}") endif() check_c_compiler_flag("-Wshorten-64-to-32" HAVE_SHORTEN_64_TO_32) -check_c_compiler_flag("-fstack-protector-all" HAVE_STACK_PROTECTOR_ALL) +check_c_compiler_flag("-Werror -fstack-protector-all" HAVE_STACK_PROTECTOR_ALL) check_include_files(cbor.h HAVE_CBOR_H) check_include_files(endian.h HAVE_ENDIAN_H) check_include_files(err.h HAVE_ERR_H) check_include_files(openssl/opensslv.h HAVE_OPENSSLV_H) check_include_files(signal.h HAVE_SIGNAL_H) check_include_files(sys/random.h HAVE_SYS_RANDOM_H) check_include_files(unistd.h HAVE_UNISTD_H) -check_include_files("windows.h;webauthn.h" HAVE_WEBAUTHN_H) check_symbol_exists(arc4random_buf stdlib.h HAVE_ARC4RANDOM_BUF) check_symbol_exists(clock_gettime time.h HAVE_CLOCK_GETTIME) check_symbol_exists(explicit_bzero string.h HAVE_EXPLICIT_BZERO) check_symbol_exists(freezero stdlib.h HAVE_FREEZERO) check_symbol_exists(getline stdio.h HAVE_GETLINE) check_symbol_exists(getopt unistd.h HAVE_GETOPT) check_symbol_exists(getpagesize unistd.h HAVE_GETPAGESIZE) check_symbol_exists(getrandom sys/random.h HAVE_GETRANDOM) check_symbol_exists(memset_s string.h HAVE_MEMSET_S) check_symbol_exists(readpassphrase readpassphrase.h HAVE_READPASSPHRASE) check_symbol_exists(recallocarray stdlib.h HAVE_RECALLOCARRAY) -check_symbol_exists(sigaction signal.h HAVE_SIGACTION) check_symbol_exists(strlcat string.h HAVE_STRLCAT) check_symbol_exists(strlcpy string.h HAVE_STRLCPY) +check_symbol_exists(strsep string.h HAVE_STRSEP) check_symbol_exists(sysconf unistd.h HAVE_SYSCONF) check_symbol_exists(timespecsub sys/time.h HAVE_TIMESPECSUB) check_symbol_exists(timingsafe_bcmp string.h HAVE_TIMINGSAFE_BCMP) -set(CMAKE_EXTRA_INCLUDE_FILES signal.h) -check_type_size("sig_atomic_t" HAVE_SIG_ATOMIC_T) -set(CMAKE_EXTRA_INCLUDE_FILES) - set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) try_compile(HAVE_POSIX_IOCTL "${CMAKE_CURRENT_BINARY_DIR}/posix_ioctl_check.o" "${CMAKE_CURRENT_SOURCE_DIR}/openbsd-compat/posix_ioctl_check.c" COMPILE_DEFINITIONS "-Werror -Woverflow -Wsign-conversion") list(APPEND CHECK_VARIABLES HAVE_ARC4RANDOM_BUF HAVE_CBOR_H HAVE_CLOCK_GETTIME HAVE_ENDIAN_H HAVE_ERR_H HAVE_FREEZERO HAVE_GETLINE HAVE_GETOPT HAVE_GETPAGESIZE HAVE_GETRANDOM HAVE_MEMSET_S HAVE_OPENSSLV_H HAVE_POSIX_IOCTL HAVE_READPASSPHRASE HAVE_RECALLOCARRAY - HAVE_SIGACTION HAVE_SIGNAL_H HAVE_STRLCAT HAVE_STRLCPY + HAVE_STRSEP HAVE_SYSCONF HAVE_SYS_RANDOM_H HAVE_TIMESPECSUB HAVE_TIMINGSAFE_BCMP HAVE_UNISTD_H - HAVE_WEBAUTHN_H ) foreach(v ${CHECK_VARIABLES}) if (${v}) add_definitions(-D${v}) endif() endforeach() if(HAVE_EXPLICIT_BZERO AND NOT LIBFUZZER) add_definitions(-DHAVE_EXPLICIT_BZERO) endif() -if(HAVE_SIGACTION AND (NOT HAVE_SIG_ATOMIC_T STREQUAL "")) - add_definitions(-DSIGNAL_EXAMPLE) -endif() - if(UNIX) add_definitions(-DHAVE_DEV_URANDOM) endif() if(MSVC) if((NOT CBOR_INCLUDE_DIRS) OR (NOT CBOR_LIBRARY_DIRS) OR - (NOT CRYPTO_INCLUDE_DIRS) OR (NOT CRYPTO_LIBRARY_DIRS) OR - (NOT ZLIB_INCLUDE_DIRS) OR (NOT ZLIB_LIBRARY_DIRS)) - message(FATAL_ERROR "please provide definitions for " - "{CBOR,CRYPTO,ZLIB}_{INCLUDE,LIBRARY}_DIRS when building " - "under msvc") + (NOT CBOR_BIN_DIRS) OR (NOT CRYPTO_INCLUDE_DIRS) OR + (NOT CRYPTO_LIBRARY_DIRS) OR (NOT CRYPTO_BIN_DIRS) OR + (NOT ZLIB_INCLUDE_DIRS) OR (NOT ZLIB_LIBRARY_DIRS) OR + (NOT ZLIB_BIN_DIRS)) + message(FATAL_ERROR "please define " + "{CBOR,CRYPTO,ZLIB}_{INCLUDE,LIBRARY,BIN}_DIRS when " + "building under msvc") endif() set(CBOR_LIBRARIES cbor) set(ZLIB_LIBRARIES zlib) set(CRYPTO_LIBRARIES crypto-46) set(MSVC_DISABLED_WARNINGS_LIST + "C4152" # nonstandard extension used: function/data pointer + # conversion in expression; "C4200" # nonstandard extension used: zero-sized array in # struct/union; "C4204" # nonstandard extension used: non-constant aggregate # initializer; "C4706" # assignment within conditional expression; "C4996" # The POSIX name for this item is deprecated. Instead, # use the ISO C and C++ conformant name; "C6287" # redundant code: the left and right subexpressions are identical ) # The construction in the following 3 lines was taken from LibreSSL's # CMakeLists.txt. string(REPLACE "C" " -wd" MSVC_DISABLED_WARNINGS_STR ${MSVC_DISABLED_WARNINGS_LIST}) string(REGEX REPLACE "[/-]W[1234][ ]?" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MP -W4 -WX ${MSVC_DISABLED_WARNINGS_STR}") - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Z7 /guard:cf /sdl /RTCcsu") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Od /Z7 /guard:cf /sdl /RTCcsu") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi /guard:cf /sdl") - if (HAVE_WEBAUTHN_H) - add_definitions(-DUSE_WINHELLO) - set(USE_WINHELLO ON) - endif() + add_definitions(-DUSE_WINHELLO) + set(USE_WINHELLO ON) else() include(FindPkgConfig) pkg_search_module(CBOR libcbor) pkg_search_module(CRYPTO libcrypto) pkg_search_module(ZLIB zlib) if(NOT CBOR_FOUND AND NOT HAVE_CBOR_H) message(FATAL_ERROR "could not find libcbor") endif() if(NOT CRYPTO_FOUND AND NOT HAVE_OPENSSLV_H) message(FATAL_ERROR "could not find libcrypto") endif() if(NOT ZLIB_FOUND) message(FATAL_ERROR "could not find zlib") endif() set(CBOR_LIBRARIES "cbor") set(CRYPTO_LIBRARIES "crypto") if(CMAKE_SYSTEM_NAME STREQUAL "Linux") pkg_search_module(UDEV libudev REQUIRED) set(UDEV_NAME "udev") # If using hidapi, use hidapi-hidraw. set(HIDAPI_SUFFIX -hidraw) if(NOT HAVE_CLOCK_GETTIME) # Look for clock_gettime in librt. check_library_exists(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME) if (HAVE_CLOCK_GETTIME) add_definitions(-DHAVE_CLOCK_GETTIME) set(BASE_LIBRARIES ${BASE_LIBRARIES} rt) endif() endif() endif() if(MINGW) # MinGW is stuck with a flavour of C89. add_definitions(-DFIDO_NO_DIAGNOSTIC) add_definitions(-DWC_ERR_INVALID_CHARS=0x80) add_compile_options(-Wno-unused-parameter) endif() if(USE_HIDAPI) add_definitions(-DUSE_HIDAPI) pkg_search_module(HIDAPI hidapi${HIDAPI_SUFFIX} REQUIRED) set(HIDAPI_LIBRARIES hidapi${HIDAPI_SUFFIX}) endif() if(FUZZ) set(NFC_LINUX ON) endif() if(NFC_LINUX) add_definitions(-DNFC_LINUX) endif() add_compile_options(-Wall) add_compile_options(-Wextra) add_compile_options(-Werror) add_compile_options(-Wshadow) add_compile_options(-Wcast-qual) add_compile_options(-Wwrite-strings) add_compile_options(-Wmissing-prototypes) add_compile_options(-Wbad-function-cast) add_compile_options(-pedantic) add_compile_options(-pedantic-errors) if(HAVE_SHORTEN_64_TO_32) add_compile_options(-Wshorten-64-to-32) endif() if(HAVE_STACK_PROTECTOR_ALL) add_compile_options(-fstack-protector-all) endif() set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g2") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -D_FORTIFY_SOURCE=2") + if(CRYPTO_VERSION VERSION_GREATER_EQUAL 3.0) + add_definitions(-DOPENSSL_API_COMPAT=0x10100000L) + endif() + if(FUZZ) add_definitions(-DFIDO_FUZZ) endif() + if(LIBFUZZER) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=fuzzer-no-link") endif() endif() # Avoid https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 if(CMAKE_COMPILER_IS_GNUCC) add_compile_options(-Wno-unused-result) endif() # Decide which keyword to use for thread-local storage. if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang") set(TLS "__thread") elseif(WIN32) set(TLS "__declspec(thread)") endif() add_definitions(-DTLS=${TLS}) # export list if(APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang")) # clang + lld string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} " -exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/src/export.llvm") elseif(NOT MSVC) # clang/gcc + gnu ld if(FUZZ) string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} " -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/fuzz/export.gnu") else() string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} " -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/export.gnu") endif() if(NOT WIN32) string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} " -Wl,-z,noexecstack -Wl,-z,relro,-z,now") string(CONCAT CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} " -Wl,-z,noexecstack -Wl,-z,relro,-z,now") if(FUZZ) file(STRINGS fuzz/wrapped.sym WRAPPED_SYMBOLS) foreach(s ${WRAPPED_SYMBOLS}) string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} " -Wl,--wrap=${s}") endforeach() endif() endif() else() string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} " /def:\"${CMAKE_CURRENT_SOURCE_DIR}/src/export.msvc\"") endif() include_directories(${CMAKE_SOURCE_DIR}/src) include_directories(${CBOR_INCLUDE_DIRS}) include_directories(${CRYPTO_INCLUDE_DIRS}) include_directories(${HIDAPI_INCLUDE_DIRS}) include_directories(${UDEV_INCLUDE_DIRS}) include_directories(${ZLIB_INCLUDE_DIRS}) link_directories(${CBOR_LIBRARY_DIRS}) link_directories(${CRYPTO_LIBRARY_DIRS}) link_directories(${HIDAPI_LIBRARY_DIRS}) link_directories(${UDEV_LIBRARY_DIRS}) link_directories(${ZLIB_LIBRARY_DIRS}) message(STATUS "BASE_LIBRARIES: ${BASE_LIBRARIES}") message(STATUS "BUILD_EXAMPLES: ${BUILD_EXAMPLES}") message(STATUS "BUILD_MANPAGES: ${BUILD_MANPAGES}") message(STATUS "BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}") message(STATUS "BUILD_STATIC_LIBS: ${BUILD_STATIC_LIBS}") message(STATUS "BUILD_TOOLS: ${BUILD_TOOLS}") message(STATUS "CBOR_INCLUDE_DIRS: ${CBOR_INCLUDE_DIRS}") message(STATUS "CBOR_LIBRARIES: ${CBOR_LIBRARIES}") message(STATUS "CBOR_LIBRARY_DIRS: ${CBOR_LIBRARY_DIRS}") message(STATUS "CBOR_VERSION: ${CBOR_VERSION}") message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}") message(STATUS "CMAKE_C_COMPILER_ID: ${CMAKE_C_COMPILER_ID}") message(STATUS "CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}") message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}") message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}") message(STATUS "CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}") message(STATUS "CMAKE_SYSTEM_VERSION: ${CMAKE_SYSTEM_VERSION}") message(STATUS "CRYPTO_INCLUDE_DIRS: ${CRYPTO_INCLUDE_DIRS}") message(STATUS "CRYPTO_LIBRARIES: ${CRYPTO_LIBRARIES}") message(STATUS "CRYPTO_LIBRARY_DIRS: ${CRYPTO_LIBRARY_DIRS}") message(STATUS "CRYPTO_VERSION: ${CRYPTO_VERSION}") message(STATUS "FIDO_VERSION: ${FIDO_VERSION}") message(STATUS "FUZZ: ${FUZZ}") message(STATUS "ZLIB_INCLUDE_DIRS: ${ZLIB_INCLUDE_DIRS}") message(STATUS "ZLIB_LIBRARIES: ${ZLIB_LIBRARIES}") message(STATUS "ZLIB_LIBRARY_DIRS: ${ZLIB_LIBRARY_DIRS}") message(STATUS "ZLIB_VERSION: ${ZLIB_VERSION}") if(USE_HIDAPI) message(STATUS "HIDAPI_INCLUDE_DIRS: ${HIDAPI_INCLUDE_DIRS}") message(STATUS "HIDAPI_LIBRARIES: ${HIDAPI_LIBRARIES}") message(STATUS "HIDAPI_LIBRARY_DIRS: ${HIDAPI_LIBRARY_DIRS}") message(STATUS "HIDAPI_VERSION: ${HIDAPI_VERSION}") endif() message(STATUS "LIBFUZZER: ${LIBFUZZER}") message(STATUS "TLS: ${TLS}") message(STATUS "UDEV_INCLUDE_DIRS: ${UDEV_INCLUDE_DIRS}") message(STATUS "UDEV_LIBRARIES: ${UDEV_LIBRARIES}") message(STATUS "UDEV_LIBRARY_DIRS: ${UDEV_LIBRARY_DIRS}") message(STATUS "UDEV_RULES_DIR: ${UDEV_RULES_DIR}") message(STATUS "UDEV_VERSION: ${UDEV_VERSION}") message(STATUS "USE_HIDAPI: ${USE_HIDAPI}") message(STATUS "USE_WINHELLO: ${USE_WINHELLO}") message(STATUS "NFC_LINUX: ${NFC_LINUX}") subdirs(src) if(BUILD_EXAMPLES) subdirs(examples) endif() if(BUILD_TOOLS) subdirs(tools) endif() if(BUILD_MANPAGES) subdirs(man) endif() if(NOT WIN32) - if(CMAKE_BUILD_TYPE STREQUAL "Debug") - if(NOT LIBFUZZER AND NOT FUZZ) - subdirs(regress) - endif() + if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT FUZZ) + enable_testing() + subdirs(regress) endif() if(FUZZ) subdirs(fuzz) endif() if(CMAKE_SYSTEM_NAME STREQUAL "Linux") subdirs(udev) endif() endif() diff --git a/contrib/libfido2/NEWS b/contrib/libfido2/NEWS index a89766b72e89..04cda4e0e83a 100644 --- a/contrib/libfido2/NEWS +++ b/contrib/libfido2/NEWS @@ -1,179 +1,201 @@ +* Version 1.9.0 (2021-10-27) + ** Enabled NFC support on Linux. + ** Added OpenSSL 3.0 compatibility. + ** Removed OpenSSL 1.0 compatibility. + ** Support for FIDO 2.1 "minPinLength" extension. + ** Support for COSE_EDDSA, COSE_ES256, and COSE_RS1 attestation. + ** Support for TPM 2.0 attestation. + ** Support for device timeouts; see fido_dev_set_timeout(). + ** New API calls: + - es256_pk_from_EVP_PKEY; + - fido_cred_attstmt_len; + - fido_cred_attstmt_ptr; + - fido_cred_pin_minlen; + - fido_cred_set_attstmt; + - fido_cred_set_pin_minlen; + - fido_dev_set_pin_minlen_rpid; + - fido_dev_set_timeout; + - rs256_pk_from_EVP_PKEY. + ** Reliability and portability fixes. + ** Better handling of HID devices without identification strings; gh#381. + ** Fixed detection of Windows's native webauthn API; gh#382. + * Version 1.8.0 (2021-07-22) ** Dropped 'Requires.private' entry from pkg-config file. ** Better support for FIDO 2.1 authenticators. ** Support for Windows's native webauthn API. ** Support for attestation format 'none'. ** New API calls: - fido_assert_set_clientdata; - fido_cbor_info_algorithm_cose; - fido_cbor_info_algorithm_count; - fido_cbor_info_algorithm_type; - fido_cbor_info_transports_len; - fido_cbor_info_transports_ptr; - fido_cred_set_clientdata; - fido_cred_set_id; - fido_credman_set_dev_rk; - fido_dev_is_winhello. ** fido2-token: new -Sc option to update a resident credential. ** Documentation and reliability fixes. ** HID access serialisation on Linux. * Version 1.7.0 (2021-03-29) ** New dependency on zlib. ** Fixed musl build; gh#259. ** hid_win: detect devices with vendor or product IDs > 0x7fff; gh#264. ** Support for FIDO 2.1 authenticator configuration. ** Support for FIDO 2.1 UV token permissions. ** Support for FIDO 2.1 "credBlobs" and "largeBlobs" extensions. ** New API calls: - fido_assert_blob_len; - fido_assert_blob_ptr; - fido_assert_largeblob_key_len; - fido_assert_largeblob_key_ptr; - fido_assert_set_hmac_secret; - fido_cbor_info_maxcredbloblen; - fido_cred_largeblob_key_len; - fido_cred_largeblob_key_ptr; - fido_cred_set_blob; - fido_dev_enable_entattest; - fido_dev_force_pin_change; - fido_dev_has_uv; - fido_dev_largeblob_get; - fido_dev_largeblob_get_array; - fido_dev_largeblob_remove; - fido_dev_largeblob_set; - fido_dev_largeblob_set_array; - fido_dev_set_pin_minlen; - fido_dev_set_sigmask; - fido_dev_supports_credman; - fido_dev_supports_permissions; - fido_dev_supports_uv; - fido_dev_toggle_always_uv. ** New fido_init flag to disable fido_dev_open's U2F fallback; gh#282. ** Experimental NFC support on Linux; enable with -DNFC_LINUX. * Version 1.6.0 (2020-12-22) ** Fix OpenSSL 1.0 and Cygwin builds. ** hid_linux: fix build on 32-bit systems. ** hid_osx: allow reads from spawned threads. ** Documentation and reliability fixes. ** New API calls: - fido_cred_authdata_raw_len; - fido_cred_authdata_raw_ptr; - fido_cred_sigcount; - fido_dev_get_uv_retry_count; - fido_dev_supports_credman. ** Hardened Windows build. ** Native FreeBSD and NetBSD support. ** Use CTAP2 canonical CBOR when combining hmac-secret and credProtect. * Version 1.5.0 (2020-09-01) ** hid_linux: return FIDO_OK if no devices are found. ** hid_osx: - repair communication with U2F tokens, gh#166; - reliability fixes. ** fido2-{assert,cred}: new options to explicitly toggle UP, UV. ** Support for configurable report lengths. ** New API calls: - fido_cbor_info_maxcredcntlst; - fido_cbor_info_maxcredidlen; - fido_cred_aaguid_len; - fido_cred_aaguid_ptr; - fido_dev_get_touch_begin; - fido_dev_get_touch_status. ** Use COSE_ECDH_ES256 with CTAP_CBOR_CLIENT_PIN; gh#154. ** Allow CTAP messages up to 2048 bytes; gh#171. ** Ensure we only list USB devices by default. * Version 1.4.0 (2020-04-15) ** hid_hidapi: hidapi backend; enable with -DUSE_HIDAPI=1. ** Fall back to U2F if the key claims to, but does not support FIDO2. ** FIDO2 credential protection (credprot) support. ** New API calls: - fido_cbor_info_fwversion; - fido_cred_prot; - fido_cred_set_prot; - fido_dev_set_transport_functions; - fido_set_log_handler. ** Support for FreeBSD. ** Support for C++. ** Support for MSYS. ** Fixed EdDSA and RSA self-attestation. * Version 1.3.1 (2020-02-19) ** fix zero-ing of le1 and le2 when talking to a U2F device. ** dropping sk-libfido2 middleware, please find it in the openssh tree. * Version 1.3.0 (2019-11-28) ** assert/hmac: encode public key as per spec, gh#60. ** fido2-cred: fix creation of resident keys. ** fido2-{assert,cred}: support for hmac-secret extension. ** hid_osx: detect device removal, gh#56. ** hid_osx: fix device detection in MacOS Catalina. ** New API calls: - fido_assert_set_authdata_raw; - fido_assert_sigcount; - fido_cred_set_authdata_raw; - fido_dev_cancel. ** Middleware library for use by OpenSSH. ** Support for biometric enrollment. ** Support for OpenBSD. ** Support for self-attestation. * Version 1.2.0 (released 2019-07-26) ** Credential management support. ** New API reflecting FIDO's 3-state booleans (true, false, absent): - fido_assert_set_up; - fido_assert_set_uv; - fido_cred_set_rk; - fido_cred_set_uv. ** Command-line tools for Windows. ** Documentation and reliability fixes. ** fido_{assert,cred}_set_options() are now marked as deprecated. * Version 1.1.0 (released 2019-05-08) ** MacOS: fix IOKit crash on HID read. ** Windows: fix contents of release file. ** EdDSA (Ed25519) support. ** fido_dev_make_cred: fix order of CBOR map keys. ** fido_dev_get_assert: plug memory leak when operating on U2F devices. * Version 1.0.0 (released 2019-03-21) ** Native HID support on Linux, MacOS, and Windows. ** fido2-{assert,cred}: new -u option to force U2F on dual authenticators. ** fido2-assert: support for multiple resident keys with the same RP. ** Strict checks for CTAP2 compliance on received CBOR payloads. ** Better fuzzing harnesses. ** Documentation and reliability fixes. * Version 0.4.0 (released 2019-01-07) ** fido2-assert: print the user id for resident credentials. ** Fix encoding of COSE algorithms when making a credential. ** Rework purpose of fido_cred_set_type; no ABI change. ** Minor documentation and code fixes. * Version 0.3.0 (released 2018-09-11) ** Various reliability fixes. ** Merged fuzzing instrumentation. ** Added regress tests. ** Added support for FIDO 2's hmac-secret extension. ** New API calls: - fido_assert_hmac_secret_len; - fido_assert_hmac_secret_ptr; - fido_assert_set_extensions; - fido_assert_set_hmac_salt; - fido_cred_set_extensions; - fido_dev_force_fido2. ** Support for native builds with Microsoft Visual Studio 17. * Version 0.2.0 (released 2018-06-20) ** Added command-line tools. ** Added a couple of missing get functions. * Version 0.1.1 (released 2018-06-05) ** Added documentation. ** Added OpenSSL 1.0 support. ** Minor fixes. * Version 0.1.0 (released 2018-05-18) ** First beta release. diff --git a/contrib/libfido2/README.adoc b/contrib/libfido2/README.adoc index f5ffa7e4e602..a0e188bf8774 100644 --- a/contrib/libfido2/README.adoc +++ b/contrib/libfido2/README.adoc @@ -1,93 +1,96 @@ == libfido2 image:https://github.com/yubico/libfido2/workflows/linux/badge.svg["Linux Build Status (github actions)", link="https://github.com/Yubico/libfido2/actions"] image:https://github.com/yubico/libfido2/workflows/macos/badge.svg["macOS Build Status (github actions)", link="https://github.com/Yubico/libfido2/actions"] image:https://github.com/yubico/libfido2/workflows/windows/badge.svg["Windows Build Status (github actions)", link="https://github.com/Yubico/libfido2/actions"] image:https://github.com/yubico/libfido2/workflows/fuzzer/badge.svg["Fuzz Status (github actions)", link="https://github.com/Yubico/libfido2/actions"] image:https://oss-fuzz-build-logs.storage.googleapis.com/badges/libfido2.svg["Fuzz Status (oss-fuzz)", link="https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:libfido2"] *libfido2* provides library functionality and command-line tools to communicate with a FIDO device over USB, and to verify attestation and assertion signatures. *libfido2* supports the FIDO U2F (CTAP 1) and FIDO 2.0 (CTAP 2) protocols. For usage, see the `examples/` directory. === License *libfido2* is licensed under the BSD 2-clause license. See the LICENSE file for the full license text. === Supported Platforms *libfido2* is known to work on Linux, macOS, Windows, OpenBSD, and FreeBSD. +NFC support is available on Linux and Windows. + === Documentation Documentation is available in troff and HTML formats. An https://developers.yubico.com/libfido2/Manuals/[online mirror of *libfido2*'s documentation] is also available. === Bindings * .NET: https://github.com/borrrden/Fido2Net[Fido2Net] * Go: https://github.com/keys-pub/go-libfido2[go-libfido2] * Perl: https://github.com/jacquesg/p5-FIDO-Raw[p5-FIDO-Raw] * Rust: https://github.com/PvdBerg1998/libfido2[libfido2] === Installation ==== Releases -The current release of *libfido2* is 1.8.0. Please consult Yubico's +The current release of *libfido2* is 1.9.0. Please consult Yubico's https://developers.yubico.com/libfido2/Releases[release page] for source and binary releases. ==== Ubuntu 20.04 (Focal) $ sudo apt install libfido2-1 $ sudo apt install libfido2-dev $ sudo apt install libfido2-doc Alternatively, newer versions of *libfido2* are available in Yubico's PPA. Follow the instructions for Ubuntu 18.04 (Bionic) below. ==== Ubuntu 18.04 (Bionic) $ sudo apt install software-properties-common $ sudo apt-add-repository ppa:yubico/stable $ sudo apt update $ sudo apt install libfido2-dev ==== macOS $ brew install libfido2 Or from source, on UNIX-like systems: - $ (rm -rf build && mkdir build && cd build && cmake ..) + $ cmake -B build $ make -C build $ sudo make -C build install Depending on the platform, https://www.freedesktop.org/wiki/Software/pkg-config/[pkg-config] may need to be installed, or the PKG_CONFIG_PATH environment variable set. *libfido2* depends on https://github.com/pjk/libcbor[libcbor], -https://www.openssl.org[OpenSSL], and https://zlib.net[zlib]. On Linux, libudev +https://www.openssl.org[OpenSSL] 1.1 or newer, and https://zlib.net[zlib]. +On Linux, libudev (part of https://www.freedesktop.org/wiki/Software/systemd[systemd]) is also required. For complete, OS-specific installation instructions, please refer to the `.actions/` (Linux, macOS) and `windows/` directories. On Linux, you will need to add a udev rule to be able to access the FIDO device, or run as root. For example, the udev rule may contain the following: ---- #udev rule for allowing HID access to Yubico devices for FIDO support. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", \ MODE="0664", GROUP="plugdev", ATTRS{idVendor}=="1050" ---- diff --git a/contrib/libfido2/examples/assert.c b/contrib/libfido2/examples/assert.c index dc3fda3ac447..8b0dbd9f6eb2 100644 --- a/contrib/libfido2/examples/assert.c +++ b/contrib/libfido2/examples/assert.c @@ -1,342 +1,328 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" -static const unsigned char cdh[32] = { +static const unsigned char cd[32] = { 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7, 0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56, 0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52, 0x35, 0x2d, 0xa2, 0x62, 0x4a, 0xbe, 0x89, 0x76, }; static void usage(void) { fprintf(stderr, "usage: assert [-t ecdsa|rsa|eddsa] [-a cred_id] " "[-h hmac_secret] [-s hmac_salt] [-P pin] [-T seconds] " "[-b blobkey] [-puv] \n"); exit(EXIT_FAILURE); } static void verify_assert(int type, const unsigned char *authdata_ptr, size_t authdata_len, const unsigned char *sig_ptr, size_t sig_len, bool up, bool uv, int ext, const char *key) { fido_assert_t *assert = NULL; EC_KEY *ec = NULL; RSA *rsa = NULL; EVP_PKEY *eddsa = NULL; es256_pk_t *es256_pk = NULL; rs256_pk_t *rs256_pk = NULL; eddsa_pk_t *eddsa_pk = NULL; void *pk; int r; /* credential pubkey */ switch (type) { case COSE_ES256: if ((ec = read_ec_pubkey(key)) == NULL) errx(1, "read_ec_pubkey"); if ((es256_pk = es256_pk_new()) == NULL) errx(1, "es256_pk_new"); if (es256_pk_from_EC_KEY(es256_pk, ec) != FIDO_OK) errx(1, "es256_pk_from_EC_KEY"); pk = es256_pk; EC_KEY_free(ec); ec = NULL; break; case COSE_RS256: if ((rsa = read_rsa_pubkey(key)) == NULL) errx(1, "read_rsa_pubkey"); if ((rs256_pk = rs256_pk_new()) == NULL) errx(1, "rs256_pk_new"); if (rs256_pk_from_RSA(rs256_pk, rsa) != FIDO_OK) errx(1, "rs256_pk_from_RSA"); pk = rs256_pk; RSA_free(rsa); rsa = NULL; break; case COSE_EDDSA: if ((eddsa = read_eddsa_pubkey(key)) == NULL) errx(1, "read_eddsa_pubkey"); if ((eddsa_pk = eddsa_pk_new()) == NULL) errx(1, "eddsa_pk_new"); if (eddsa_pk_from_EVP_PKEY(eddsa_pk, eddsa) != FIDO_OK) errx(1, "eddsa_pk_from_EVP_PKEY"); pk = eddsa_pk; EVP_PKEY_free(eddsa); eddsa = NULL; break; default: errx(1, "unknown credential type %d", type); } if ((assert = fido_assert_new()) == NULL) errx(1, "fido_assert_new"); /* client data hash */ - r = fido_assert_set_clientdata_hash(assert, cdh, sizeof(cdh)); + r = fido_assert_set_clientdata(assert, cd, sizeof(cd)); if (r != FIDO_OK) - errx(1, "fido_assert_set_clientdata_hash: %s (0x%x)", - fido_strerr(r), r); + errx(1, "fido_assert_set_clientdata: %s (0x%x)", fido_strerr(r), r); /* relying party */ r = fido_assert_set_rp(assert, "localhost"); if (r != FIDO_OK) errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r); /* authdata */ r = fido_assert_set_count(assert, 1); if (r != FIDO_OK) errx(1, "fido_assert_set_count: %s (0x%x)", fido_strerr(r), r); r = fido_assert_set_authdata(assert, 0, authdata_ptr, authdata_len); if (r != FIDO_OK) errx(1, "fido_assert_set_authdata: %s (0x%x)", fido_strerr(r), r); /* extension */ r = fido_assert_set_extensions(assert, ext); if (r != FIDO_OK) errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r), r); /* user presence */ if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r); /* user verification */ if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r); /* sig */ r = fido_assert_set_sig(assert, 0, sig_ptr, sig_len); if (r != FIDO_OK) errx(1, "fido_assert_set_sig: %s (0x%x)", fido_strerr(r), r); r = fido_assert_verify(assert, 0, type, pk); if (r != FIDO_OK) errx(1, "fido_assert_verify: %s (0x%x)", fido_strerr(r), r); es256_pk_free(&es256_pk); rs256_pk_free(&rs256_pk); eddsa_pk_free(&eddsa_pk); fido_assert_free(&assert); } int main(int argc, char **argv) { bool up = false; bool uv = false; bool u2f = false; fido_dev_t *dev = NULL; fido_assert_t *assert = NULL; const char *pin = NULL; const char *blobkey_out = NULL; const char *hmac_out = NULL; unsigned char *body = NULL; - long long seconds = 0; + long long ms = 0; size_t len; int type = COSE_ES256; int ext = 0; int ch; int r; if ((assert = fido_assert_new()) == NULL) errx(1, "fido_assert_new"); while ((ch = getopt(argc, argv, "P:T:a:b:h:ps:t:uv")) != -1) { switch (ch) { case 'P': pin = optarg; break; case 'T': -#ifndef SIGNAL_EXAMPLE - (void)seconds; - errx(1, "-T not supported"); -#else - if (base10(optarg, &seconds) < 0) + if (base10(optarg, &ms) < 0) errx(1, "base10: %s", optarg); - if (seconds <= 0 || seconds > 30) + if (ms <= 0 || ms > 30) errx(1, "-T: %s must be in (0,30]", optarg); + ms *= 1000; /* seconds to milliseconds */ break; -#endif case 'a': if (read_blob(optarg, &body, &len) < 0) errx(1, "read_blob: %s", optarg); if ((r = fido_assert_allow_cred(assert, body, len)) != FIDO_OK) errx(1, "fido_assert_allow_cred: %s (0x%x)", fido_strerr(r), r); free(body); body = NULL; break; case 'b': ext |= FIDO_EXT_LARGEBLOB_KEY; blobkey_out = optarg; break; case 'h': hmac_out = optarg; break; case 'p': up = true; break; case 's': ext |= FIDO_EXT_HMAC_SECRET; if (read_blob(optarg, &body, &len) < 0) errx(1, "read_blob: %s", optarg); if ((r = fido_assert_set_hmac_salt(assert, body, len)) != FIDO_OK) errx(1, "fido_assert_set_hmac_salt: %s (0x%x)", fido_strerr(r), r); free(body); body = NULL; break; case 't': if (strcmp(optarg, "ecdsa") == 0) type = COSE_ES256; else if (strcmp(optarg, "rsa") == 0) type = COSE_RS256; else if (strcmp(optarg, "eddsa") == 0) type = COSE_EDDSA; else errx(1, "unknown type %s", optarg); break; case 'u': u2f = true; break; case 'v': uv = true; break; default: usage(); } } argc -= optind; argv += optind; if (argc != 2) usage(); fido_init(0); if ((dev = fido_dev_new()) == NULL) errx(1, "fido_dev_new"); r = fido_dev_open(dev, argv[1]); if (r != FIDO_OK) errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); if (u2f) fido_dev_force_u2f(dev); /* client data hash */ - r = fido_assert_set_clientdata_hash(assert, cdh, sizeof(cdh)); + r = fido_assert_set_clientdata(assert, cd, sizeof(cd)); if (r != FIDO_OK) - errx(1, "fido_assert_set_clientdata_hash: %s (0x%x)", - fido_strerr(r), r); + errx(1, "fido_assert_set_clientdata: %s (0x%x)", fido_strerr(r), r); /* relying party */ r = fido_assert_set_rp(assert, "localhost"); if (r != FIDO_OK) errx(1, "fido_assert_set_rp: %s (0x%x)", fido_strerr(r), r); /* extensions */ r = fido_assert_set_extensions(assert, ext); if (r != FIDO_OK) errx(1, "fido_assert_set_extensions: %s (0x%x)", fido_strerr(r), r); /* user presence */ if (up && (r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_assert_set_up: %s (0x%x)", fido_strerr(r), r); /* user verification */ if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r); -#ifdef SIGNAL_EXAMPLE - prepare_signal_handler(SIGINT); - if (seconds) { - prepare_signal_handler(SIGALRM); - alarm((unsigned)seconds); - } -#endif + /* timeout */ + if (ms != 0 && (r = fido_dev_set_timeout(dev, (int)ms)) != FIDO_OK) + errx(1, "fido_dev_set_timeout: %s (0x%x)", fido_strerr(r), r); - r = fido_dev_get_assert(dev, assert, pin); - if (r != FIDO_OK) { -#ifdef SIGNAL_EXAMPLE - if (got_signal) - fido_dev_cancel(dev); -#endif + if ((r = fido_dev_get_assert(dev, assert, pin)) != FIDO_OK) { + fido_dev_cancel(dev); errx(1, "fido_dev_get_assert: %s (0x%x)", fido_strerr(r), r); } r = fido_dev_close(dev); if (r != FIDO_OK) errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); fido_dev_free(&dev); if (fido_assert_count(assert) != 1) errx(1, "fido_assert_count: %d signatures returned", (int)fido_assert_count(assert)); /* when verifying, pin implies uv */ if (pin) uv = true; verify_assert(type, fido_assert_authdata_ptr(assert, 0), fido_assert_authdata_len(assert, 0), fido_assert_sig_ptr(assert, 0), fido_assert_sig_len(assert, 0), up, uv, ext, argv[0]); if (hmac_out != NULL) { /* extract the hmac secret */ if (write_blob(hmac_out, fido_assert_hmac_secret_ptr(assert, 0), fido_assert_hmac_secret_len(assert, 0)) < 0) errx(1, "write_blob"); } if (blobkey_out != NULL) { /* extract the hmac secret */ if (write_blob(blobkey_out, fido_assert_largeblob_key_ptr(assert, 0), fido_assert_largeblob_key_len(assert, 0)) < 0) errx(1, "write_blob"); } fido_assert_free(&assert); exit(0); } diff --git a/contrib/libfido2/examples/cred.c b/contrib/libfido2/examples/cred.c index 74145c761380..4a9d8bf4b25a 100644 --- a/contrib/libfido2/examples/cred.c +++ b/contrib/libfido2/examples/cred.c @@ -1,346 +1,300 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" -static const unsigned char cdh[32] = { +static const unsigned char cd[32] = { 0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb, 0xdd, 0xd7, 0xfb, 0x06, 0x37, 0x62, 0xea, 0x26, 0x20, 0x44, 0x8e, 0x69, 0x7c, 0x03, 0xf2, 0x31, 0x2f, 0x99, 0xdc, 0xaf, 0x3e, 0x8a, 0x91, 0x6b, }; static const unsigned char user_id[32] = { 0x78, 0x1c, 0x78, 0x60, 0xad, 0x88, 0xd2, 0x63, 0x32, 0x62, 0x2a, 0xf1, 0x74, 0x5d, 0xed, 0xb2, 0xe7, 0xa4, 0x2b, 0x44, 0x89, 0x29, 0x39, 0xc5, 0x56, 0x64, 0x01, 0x27, 0x0d, 0xbb, 0xc4, 0x49, }; static void usage(void) { fprintf(stderr, "usage: cred [-t ecdsa|rsa|eddsa] [-k pubkey] " "[-ei cred_id] [-P pin] [-T seconds] [-b blobkey] [-hruv] " "\n"); exit(EXIT_FAILURE); } static void verify_cred(int type, const char *fmt, const unsigned char *authdata_ptr, - size_t authdata_len, const unsigned char *x509_ptr, size_t x509_len, - const unsigned char *sig_ptr, size_t sig_len, bool rk, bool uv, int ext, - const char *key_out, const char *id_out) + size_t authdata_len, const unsigned char *attstmt_ptr, size_t attstmt_len, + bool rk, bool uv, int ext, const char *key_out, const char *id_out) { fido_cred_t *cred; int r; if ((cred = fido_cred_new()) == NULL) errx(1, "fido_cred_new"); /* type */ r = fido_cred_set_type(cred, type); if (r != FIDO_OK) errx(1, "fido_cred_set_type: %s (0x%x)", fido_strerr(r), r); - /* client data hash */ - r = fido_cred_set_clientdata_hash(cred, cdh, sizeof(cdh)); + /* client data */ + r = fido_cred_set_clientdata(cred, cd, sizeof(cd)); if (r != FIDO_OK) - errx(1, "fido_cred_set_clientdata_hash: %s (0x%x)", - fido_strerr(r), r); + errx(1, "fido_cred_set_clientdata: %s (0x%x)", fido_strerr(r), r); /* relying party */ r = fido_cred_set_rp(cred, "localhost", "sweet home localhost"); if (r != FIDO_OK) errx(1, "fido_cred_set_rp: %s (0x%x)", fido_strerr(r), r); /* authdata */ r = fido_cred_set_authdata(cred, authdata_ptr, authdata_len); if (r != FIDO_OK) errx(1, "fido_cred_set_authdata: %s (0x%x)", fido_strerr(r), r); /* extensions */ r = fido_cred_set_extensions(cred, ext); if (r != FIDO_OK) errx(1, "fido_cred_set_extensions: %s (0x%x)", fido_strerr(r), r); /* resident key */ if (rk && (r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_cred_set_rk: %s (0x%x)", fido_strerr(r), r); /* user verification */ if (uv && (r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_cred_set_uv: %s (0x%x)", fido_strerr(r), r); /* fmt */ r = fido_cred_set_fmt(cred, fmt); if (r != FIDO_OK) errx(1, "fido_cred_set_fmt: %s (0x%x)", fido_strerr(r), r); if (!strcmp(fido_cred_fmt(cred), "none")) { warnx("no attestation data, skipping credential verification"); goto out; } - /* x509 */ - r = fido_cred_set_x509(cred, x509_ptr, x509_len); + /* attestation statement */ + r = fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len); if (r != FIDO_OK) - errx(1, "fido_cred_set_x509: %s (0x%x)", fido_strerr(r), r); - - /* sig */ - r = fido_cred_set_sig(cred, sig_ptr, sig_len); - if (r != FIDO_OK) - errx(1, "fido_cred_set_sig: %s (0x%x)", fido_strerr(r), r); + errx(1, "fido_cred_set_attstmt: %s (0x%x)", fido_strerr(r), r); r = fido_cred_verify(cred); if (r != FIDO_OK) errx(1, "fido_cred_verify: %s (0x%x)", fido_strerr(r), r); out: if (key_out != NULL) { /* extract the credential pubkey */ if (type == COSE_ES256) { if (write_ec_pubkey(key_out, fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)) < 0) errx(1, "write_ec_pubkey"); } else if (type == COSE_RS256) { if (write_rsa_pubkey(key_out, fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)) < 0) errx(1, "write_rsa_pubkey"); } else if (type == COSE_EDDSA) { if (write_eddsa_pubkey(key_out, fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)) < 0) errx(1, "write_eddsa_pubkey"); } } if (id_out != NULL) { /* extract the credential id */ if (write_blob(id_out, fido_cred_id_ptr(cred), fido_cred_id_len(cred)) < 0) errx(1, "write_blob"); } fido_cred_free(&cred); } -static fido_dev_t * -open_from_manifest(const fido_dev_info_t *dev_infos, size_t len, - const char *path) -{ - size_t i; - fido_dev_t *dev; - - for (i = 0; i < len; i++) { - const fido_dev_info_t *curr = fido_dev_info_ptr(dev_infos, i); - if (path == NULL || - strcmp(path, fido_dev_info_path(curr)) == 0) { - dev = fido_dev_new_with_info(curr); - if (fido_dev_open_with_info(dev) == FIDO_OK) - return (dev); - fido_dev_free(&dev); - } - } - - return (NULL); -} - int main(int argc, char **argv) { bool rk = false; bool uv = false; bool u2f = false; fido_dev_t *dev; fido_cred_t *cred = NULL; const char *pin = NULL; const char *blobkey_out = NULL; const char *key_out = NULL; const char *id_out = NULL; - const char *path = NULL; unsigned char *body = NULL; - long long seconds = 0; + long long ms = 0; size_t len; int type = COSE_ES256; int ext = 0; int ch; int r; - fido_dev_info_t *dev_infos = NULL; - size_t dev_infos_len = 0; if ((cred = fido_cred_new()) == NULL) errx(1, "fido_cred_new"); while ((ch = getopt(argc, argv, "P:T:b:e:hi:k:rt:uv")) != -1) { switch (ch) { case 'P': pin = optarg; break; case 'T': -#ifndef SIGNAL_EXAMPLE - (void)seconds; - errx(1, "-T not supported"); -#else - if (base10(optarg, &seconds) < 0) + if (base10(optarg, &ms) < 0) errx(1, "base10: %s", optarg); - if (seconds <= 0 || seconds > 30) + if (ms <= 0 || ms > 30) errx(1, "-T: %s must be in (0,30]", optarg); + ms *= 1000; /* seconds to milliseconds */ break; -#endif case 'b': ext |= FIDO_EXT_LARGEBLOB_KEY; blobkey_out = optarg; break; case 'e': if (read_blob(optarg, &body, &len) < 0) errx(1, "read_blob: %s", optarg); r = fido_cred_exclude(cred, body, len); if (r != FIDO_OK) errx(1, "fido_cred_exclude: %s (0x%x)", fido_strerr(r), r); free(body); body = NULL; break; case 'h': ext |= FIDO_EXT_HMAC_SECRET; break; case 'i': id_out = optarg; break; case 'k': key_out = optarg; break; case 'r': rk = true; break; case 't': if (strcmp(optarg, "ecdsa") == 0) type = COSE_ES256; else if (strcmp(optarg, "rsa") == 0) type = COSE_RS256; else if (strcmp(optarg, "eddsa") == 0) type = COSE_EDDSA; else errx(1, "unknown type %s", optarg); break; case 'u': u2f = true; break; case 'v': uv = true; break; default: usage(); } } - fido_init(0); - argc -= optind; argv += optind; - if (argc > 1) + if (argc != 1) usage(); - dev_infos = fido_dev_info_new(16); - fido_dev_info_manifest(dev_infos, 16, &dev_infos_len); - if (argc == 1) - path = argv[0]; - if ((dev = open_from_manifest(dev_infos, dev_infos_len, path)) == NULL) - errx(1, "open_from_manifest"); + fido_init(0); + + if ((dev = fido_dev_new()) == NULL) + errx(1, "fido_dev_new"); + r = fido_dev_open(dev, argv[0]); + if (r != FIDO_OK) + errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); if (u2f) fido_dev_force_u2f(dev); /* type */ r = fido_cred_set_type(cred, type); if (r != FIDO_OK) errx(1, "fido_cred_set_type: %s (0x%x)", fido_strerr(r), r); - /* client data hash */ - r = fido_cred_set_clientdata_hash(cred, cdh, sizeof(cdh)); + /* client data */ + r = fido_cred_set_clientdata(cred, cd, sizeof(cd)); if (r != FIDO_OK) - errx(1, "fido_cred_set_clientdata_hash: %s (0x%x)", - fido_strerr(r), r); + errx(1, "fido_cred_set_clientdata: %s (0x%x)", fido_strerr(r), r); /* relying party */ r = fido_cred_set_rp(cred, "localhost", "sweet home localhost"); if (r != FIDO_OK) errx(1, "fido_cred_set_rp: %s (0x%x)", fido_strerr(r), r); /* user */ r = fido_cred_set_user(cred, user_id, sizeof(user_id), "john smith", "jsmith", NULL); if (r != FIDO_OK) errx(1, "fido_cred_set_user: %s (0x%x)", fido_strerr(r), r); /* extensions */ r = fido_cred_set_extensions(cred, ext); if (r != FIDO_OK) errx(1, "fido_cred_set_extensions: %s (0x%x)", fido_strerr(r), r); /* resident key */ if (rk && (r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_cred_set_rk: %s (0x%x)", fido_strerr(r), r); /* user verification */ if (uv && (r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_cred_set_uv: %s (0x%x)", fido_strerr(r), r); -#ifdef SIGNAL_EXAMPLE - prepare_signal_handler(SIGINT); - if (seconds) { - prepare_signal_handler(SIGALRM); - alarm((unsigned)seconds); - } -#endif + /* timeout */ + if (ms != 0 && (r = fido_dev_set_timeout(dev, (int)ms)) != FIDO_OK) + errx(1, "fido_dev_set_timeout: %s (0x%x)", fido_strerr(r), r); - r = fido_dev_make_cred(dev, cred, pin); - if (r != FIDO_OK) { -#ifdef SIGNAL_EXAMPLE - if (got_signal) - fido_dev_cancel(dev); -#endif + if ((r = fido_dev_make_cred(dev, cred, pin)) != FIDO_OK) { + fido_dev_cancel(dev); errx(1, "fido_makecred: %s (0x%x)", fido_strerr(r), r); } r = fido_dev_close(dev); if (r != FIDO_OK) errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); fido_dev_free(&dev); /* when verifying, pin implies uv */ if (pin) uv = true; verify_cred(type, fido_cred_fmt(cred), fido_cred_authdata_ptr(cred), - fido_cred_authdata_len(cred), fido_cred_x5c_ptr(cred), - fido_cred_x5c_len(cred), fido_cred_sig_ptr(cred), - fido_cred_sig_len(cred), rk, uv, ext, key_out, id_out); + fido_cred_authdata_len(cred), fido_cred_attstmt_ptr(cred), + fido_cred_attstmt_len(cred), rk, uv, ext, key_out, id_out); if (blobkey_out != NULL) { /* extract the "largeBlob" key */ if (write_blob(blobkey_out, fido_cred_largeblob_key_ptr(cred), fido_cred_largeblob_key_len(cred)) < 0) errx(1, "write_blob"); } fido_cred_free(&cred); exit(0); } diff --git a/contrib/libfido2/examples/extern.h b/contrib/libfido2/examples/extern.h index 0ea68c4fb585..5633b23d2003 100644 --- a/contrib/libfido2/examples/extern.h +++ b/contrib/libfido2/examples/extern.h @@ -1,33 +1,25 @@ /* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _EXTERN_H_ #define _EXTERN_H_ #include #include #include -#ifdef HAVE_SIGNAL_H -#include -#endif - /* util.c */ EC_KEY *read_ec_pubkey(const char *); RSA *read_rsa_pubkey(const char *); EVP_PKEY *read_eddsa_pubkey(const char *); int base10(const char *, long long *); int read_blob(const char *, unsigned char **, size_t *); int write_blob(const char *, const unsigned char *, size_t); int write_ec_pubkey(const char *, const void *, size_t); int write_rsa_pubkey(const char *, const void *, size_t); int write_eddsa_pubkey(const char *, const void *, size_t); -#ifdef SIGNAL_EXAMPLE -void prepare_signal_handler(int); -extern volatile sig_atomic_t got_signal; -#endif #endif /* _EXTERN_H_ */ diff --git a/contrib/libfido2/examples/reset.c b/contrib/libfido2/examples/reset.c index eb341c26c0cd..b429d05f0fe4 100644 --- a/contrib/libfido2/examples/reset.c +++ b/contrib/libfido2/examples/reset.c @@ -1,55 +1,48 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ /* * Perform a factory reset on a given authenticator. */ #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" int main(int argc, char **argv) { fido_dev_t *dev; int r; if (argc != 2) { fprintf(stderr, "usage: reset \n"); exit(EXIT_FAILURE); } fido_init(0); if ((dev = fido_dev_new()) == NULL) errx(1, "fido_dev_new"); if ((r = fido_dev_open(dev, argv[1])) != FIDO_OK) errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); -#ifdef SIGNAL_EXAMPLE - prepare_signal_handler(SIGINT); -#endif - if ((r = fido_dev_reset(dev)) != FIDO_OK) { -#ifdef SIGNAL_EXAMPLE - if (got_signal) - fido_dev_cancel(dev); -#endif - errx(1, "fido_reset: %s (0x%x)", fido_strerr(r), r); + fido_dev_cancel(dev); + errx(1, "fido_dev_reset: %s (0x%x)", fido_strerr(r), r); } if ((r = fido_dev_close(dev)) != FIDO_OK) errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); fido_dev_free(&dev); exit(0); } diff --git a/contrib/libfido2/examples/util.c b/contrib/libfido2/examples/util.c index caa68aa880ee..8b360af21c7a 100644 --- a/contrib/libfido2/examples/util.c +++ b/contrib/libfido2/examples/util.c @@ -1,413 +1,385 @@ /* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#ifdef HAVE_SIGNAL_H -#include -#endif #ifdef HAVE_UNISTD_H #include #endif #ifdef _MSC_VER #include "../openbsd-compat/posix_win.h" #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" -#ifdef SIGNAL_EXAMPLE -volatile sig_atomic_t got_signal = 0; - -static void -signal_handler(int signo) -{ - (void)signo; - got_signal = 1; -} - -void -prepare_signal_handler(int signo) -{ - struct sigaction sa; - - memset(&sa, 0, sizeof(sa)); - - sigemptyset(&sa.sa_mask); - sa.sa_handler = signal_handler; - - if (sigaction(signo, &sa, NULL) < 0) - err(1, "sigaction"); -} -#endif - int base10(const char *str, long long *ll) { char *ep; *ll = strtoll(str, &ep, 10); if (str == ep || *ep != '\0') return (-1); else if (*ll == LLONG_MIN && errno == ERANGE) return (-1); else if (*ll == LLONG_MAX && errno == ERANGE) return (-1); return (0); } int write_blob(const char *path, const unsigned char *ptr, size_t len) { int fd, ok = -1; ssize_t n; if ((fd = open(path, O_WRONLY | O_CREAT, 0600)) < 0) { warn("open %s", path); goto fail; } if ((n = write(fd, ptr, len)) < 0) { warn("write"); goto fail; } if ((size_t)n != len) { warnx("write"); goto fail; } ok = 0; fail: if (fd != -1) { close(fd); } return (ok); } int read_blob(const char *path, unsigned char **ptr, size_t *len) { int fd, ok = -1; struct stat st; ssize_t n; *ptr = NULL; *len = 0; if ((fd = open(path, O_RDONLY)) < 0) { warn("open %s", path); goto fail; } if (fstat(fd, &st) < 0) { warn("stat %s", path); goto fail; } if (st.st_size < 0) { warnx("stat %s: invalid size", path); goto fail; } *len = (size_t)st.st_size; if ((*ptr = malloc(*len)) == NULL) { warn("malloc"); goto fail; } if ((n = read(fd, *ptr, *len)) < 0) { warn("read"); goto fail; } if ((size_t)n != *len) { warnx("read"); goto fail; } ok = 0; fail: if (fd != -1) { close(fd); } if (ok < 0) { free(*ptr); *ptr = NULL; *len = 0; } return (ok); } EC_KEY * read_ec_pubkey(const char *path) { FILE *fp = NULL; EVP_PKEY *pkey = NULL; EC_KEY *ec = NULL; if ((fp = fopen(path, "r")) == NULL) { warn("fopen"); goto fail; } if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { warnx("PEM_read_PUBKEY"); goto fail; } if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { warnx("EVP_PKEY_get1_EC_KEY"); goto fail; } fail: if (fp != NULL) { fclose(fp); } if (pkey != NULL) { EVP_PKEY_free(pkey); } return (ec); } int write_ec_pubkey(const char *path, const void *ptr, size_t len) { FILE *fp = NULL; EVP_PKEY *pkey = NULL; es256_pk_t *pk = NULL; int fd = -1; int ok = -1; if ((pk = es256_pk_new()) == NULL) { warnx("es256_pk_new"); goto fail; } if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { warnx("es256_pk_from_ptr"); goto fail; } if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) { warn("open %s", path); goto fail; } if ((fp = fdopen(fd, "w")) == NULL) { warn("fdopen"); goto fail; } fd = -1; /* owned by fp now */ if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) { warnx("es256_pk_to_EVP_PKEY"); goto fail; } if (PEM_write_PUBKEY(fp, pkey) == 0) { warnx("PEM_write_PUBKEY"); goto fail; } ok = 0; fail: es256_pk_free(&pk); if (fp != NULL) { fclose(fp); } if (fd != -1) { close(fd); } if (pkey != NULL) { EVP_PKEY_free(pkey); } return (ok); } RSA * read_rsa_pubkey(const char *path) { FILE *fp = NULL; EVP_PKEY *pkey = NULL; RSA *rsa = NULL; if ((fp = fopen(path, "r")) == NULL) { warn("fopen"); goto fail; } if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { warnx("PEM_read_PUBKEY"); goto fail; } if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) { warnx("EVP_PKEY_get1_RSA"); goto fail; } fail: if (fp != NULL) { fclose(fp); } if (pkey != NULL) { EVP_PKEY_free(pkey); } return (rsa); } int write_rsa_pubkey(const char *path, const void *ptr, size_t len) { FILE *fp = NULL; EVP_PKEY *pkey = NULL; rs256_pk_t *pk = NULL; int fd = -1; int ok = -1; if ((pk = rs256_pk_new()) == NULL) { warnx("rs256_pk_new"); goto fail; } if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) { warnx("rs256_pk_from_ptr"); goto fail; } if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) { warn("open %s", path); goto fail; } if ((fp = fdopen(fd, "w")) == NULL) { warn("fdopen"); goto fail; } fd = -1; /* owned by fp now */ if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) { warnx("rs256_pk_to_EVP_PKEY"); goto fail; } if (PEM_write_PUBKEY(fp, pkey) == 0) { warnx("PEM_write_PUBKEY"); goto fail; } ok = 0; fail: rs256_pk_free(&pk); if (fp != NULL) { fclose(fp); } if (fd != -1) { close(fd); } if (pkey != NULL) { EVP_PKEY_free(pkey); } return (ok); } EVP_PKEY * read_eddsa_pubkey(const char *path) { FILE *fp = NULL; EVP_PKEY *pkey = NULL; if ((fp = fopen(path, "r")) == NULL) { warn("fopen"); goto fail; } if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { warnx("PEM_read_PUBKEY"); goto fail; } fail: if (fp) { fclose(fp); } return (pkey); } int write_eddsa_pubkey(const char *path, const void *ptr, size_t len) { FILE *fp = NULL; EVP_PKEY *pkey = NULL; eddsa_pk_t *pk = NULL; int fd = -1; int ok = -1; if ((pk = eddsa_pk_new()) == NULL) { warnx("eddsa_pk_new"); goto fail; } if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) { warnx("eddsa_pk_from_ptr"); goto fail; } if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) { warn("open %s", path); goto fail; } if ((fp = fdopen(fd, "w")) == NULL) { warn("fdopen"); goto fail; } fd = -1; /* owned by fp now */ if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { warnx("eddsa_pk_to_EVP_PKEY"); goto fail; } if (PEM_write_PUBKEY(fp, pkey) == 0) { warnx("PEM_write_PUBKEY"); goto fail; } ok = 0; fail: eddsa_pk_free(&pk); if (fp != NULL) { fclose(fp); } if (fd != -1) { close(fd); } if (pkey != NULL) { EVP_PKEY_free(pkey); } return (ok); } diff --git a/contrib/libfido2/fuzz/Dockerfile b/contrib/libfido2/fuzz/Dockerfile index 895da69e4c4c..f175991d0462 100644 --- a/contrib/libfido2/fuzz/Dockerfile +++ b/contrib/libfido2/fuzz/Dockerfile @@ -1,12 +1,12 @@ -# Copyright (c) 2019 Yubico AB. All rights reserved. +# Copyright (c) 2019-2021 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. FROM ubuntu:focal ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update -RUN apt-get install -y clang-11 cmake git libssl-dev libudev-dev make pkg-config +RUN apt-get install -y clang-12 cmake git libssl-dev libudev-dev make pkg-config RUN apt-get install -y zlib1g-dev RUN git clone --branch v0.8.0 https://github.com/PJK/libcbor RUN git clone https://github.com/yubico/libfido2 -RUN CC=clang-11 CXX=clang++-11 /libfido2/fuzz/build-coverage /libcbor /libfido2 +RUN CC=clang-12 CXX=clang++-12 /libfido2/fuzz/build-coverage /libcbor /libfido2 diff --git a/contrib/libfido2/fuzz/Makefile b/contrib/libfido2/fuzz/Makefile index 4b067c23aac2..1a974a2bf557 100644 --- a/contrib/libfido2/fuzz/Makefile +++ b/contrib/libfido2/fuzz/Makefile @@ -1,79 +1,81 @@ -# Copyright (c) 2019 Yubico AB. All rights reserved. +# Copyright (c) 2019-2021 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. -IMAGE := libfido2-coverage:1.8.0 +IMAGE := libfido2-coverage:1.9.1 RUNNER := libfido2-runner -PROFDATA := llvm-profdata-11 -COV := llvm-cov-11 +PROFDATA := llvm-profdata-12 +COV := llvm-cov-12 TARGETS := fuzz_assert fuzz_bio fuzz_cred fuzz_credman fuzz_hid \ fuzz_largeblob fuzz_netlink fuzz_mgmt CORPORA := $(foreach f,${TARGETS},${f}/corpus) MINIFY := $(foreach f,${TARGETS},/minify/${f}/corpus) REMOTE := gs://libfido2-corpus.clusterfuzz-external.appspot.com .DEFAULT_GOAL := all all: ${TARGETS} build: docker build -t ${IMAGE} - < Dockerfile run: build -docker run -it -d --name ${RUNNER} ${IMAGE} docker start ${RUNNER} sync: run tar Ccf .. - src fuzz | docker exec -i ${RUNNER} tar Cxf /libfido2 - docker exec ${RUNNER} make -C libfido2/build corpus: sync docker exec ${RUNNER} /bin/sh -c 'cd /libfido2/fuzz && rm -rf ${TARGETS}' docker exec ${RUNNER} tar Czxf /libfido2/fuzz /libfido2/fuzz/corpus.tgz ${TARGETS}: corpus sync docker exec -e LLVM_PROFILE_FILE=/profraw/$@ ${RUNNER} \ /bin/sh -c 'rm -f /profraw/$@ && /libfido2/build/fuzz/$@ \ -runs=1 /libfido2/fuzz/$@' ${MINIFY}: /minify/%/corpus: % docker exec ${RUNNER} /bin/sh -c 'rm -rf $@ && mkdir -p $@ && \ /libfido2/build/fuzz/$< -use_value_profile=1 -merge=1 $@ \ /libfido2/fuzz/$ $@ profdata: run docker exec ${RUNNER} /bin/sh -c 'rm -f /$@ && ${PROFDATA} \ merge -sparse profraw/* -o $@' report.tgz: profdata docker exec ${RUNNER} /bin/sh -c 'rm -rf /report && mkdir /report && \ ${COV} show -format=html -tab-size=8 -instr-profile=/$< \ - -output-dir=/report /libfido2/build/src/libfido2.so' + --show-branch-summary=false -output-dir=/report \ + /libfido2/build/src/libfido2.so' docker exec -i ${RUNNER} tar Czcf / - report > $@ summary.txt: profdata docker exec ${RUNNER} ${COV} report -use-color=false \ - /libfido2/build/src/libfido2.so -instr-profile=/$< > $@ + --show-branch-summary=false /libfido2/build/src/libfido2.so \ + -instr-profile=/$< > $@ functions.txt: profdata docker exec ${RUNNER} /bin/sh -c '${COV} report -use-color=false \ - -show-functions -instr-profile=/$< \ + -show-functions --show-branch-summary=false -instr-profile=/$< \ /libfido2/build/src/libfido2.so /libfido2/src/*.[ch]' > $@ clean: run docker exec ${RUNNER} /bin/sh -c 'rm -rf /profraw /profdata && \ make -C /libfido2/build clean' -docker stop ${RUNNER} rm -rf ${TARGETS} ${CORPORA}: -mkdir -p $@ gsutil -q -m rsync -d -r ${REMOTE}/libFuzzer/libfido2_$(@:/corpus=) $@ corpus.tgz: ${CORPORA} tar zcf $@ ${TARGETS} .PHONY: build run sync corpus ${TARGETS} ${CORPORA} .PHONY: report.tgz summary.txt functions.txt diff --git a/contrib/libfido2/fuzz/clock.c b/contrib/libfido2/fuzz/clock.c new file mode 100644 index 000000000000..23803c2ee3e5 --- /dev/null +++ b/contrib/libfido2/fuzz/clock.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + +#include +#include + +#include "mutator_aux.h" + +/* + * A pseudo-random monotonic clock with a probabilistic discontinuity to + * the end of time (as measured by struct timespec). + */ + +extern int prng_up; +extern int __wrap_clock_gettime(clockid_t, struct timespec *); +extern int __real_clock_gettime(clockid_t, struct timespec *); +extern int __wrap_usleep(unsigned int); +static TLS struct timespec fuzz_clock; + +static void +tick(unsigned int usec) +{ + long long drift; + + /* + * Simulate a jump to the end of time with 0.125% probability. + * This condition should be gracefully handled by callers of + * clock_gettime(). + */ + if (uniform_random(800) < 1) { + fuzz_clock.tv_sec = LLONG_MAX; + fuzz_clock.tv_nsec = LONG_MAX; + return; + } + + drift = usec * 1000LL + (long long)uniform_random(10000000); /* 10ms */ + if (LLONG_MAX - drift < (long long)fuzz_clock.tv_nsec) { + fuzz_clock_reset(); /* Not much we can do here. */ + } else if (drift + (long long)fuzz_clock.tv_nsec < 1000000000) { + fuzz_clock.tv_nsec += (long)(drift); + } else { + fuzz_clock.tv_sec += (long)(drift / 1000000000); + fuzz_clock.tv_nsec += (long)(drift % 1000000000); + } +} + +int +__wrap_clock_gettime(clockid_t clk_id, struct timespec *tp) +{ + if (!prng_up || clk_id != CLOCK_MONOTONIC) + return __real_clock_gettime(clk_id, tp); + if (uniform_random(400) < 1) + return -1; + + tick(0); + *tp = fuzz_clock; + + return 0; +} + +int +__wrap_usleep(unsigned int usec) +{ + if (uniform_random(400) < 1) + return -1; + + tick(usec); + + return 0; +} + +void +fuzz_clock_reset(void) +{ + memset(&fuzz_clock, 0, sizeof(fuzz_clock)); +} diff --git a/contrib/libfido2/fuzz/dummy.h b/contrib/libfido2/fuzz/dummy.h index 981cceec37b5..95744eba634b 100644 --- a/contrib/libfido2/fuzz/dummy.h +++ b/contrib/libfido2/fuzz/dummy.h @@ -1,96 +1,179 @@ /* * Copyright (c) 2020 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _DUMMY_H #define _DUMMY_H #include const char dummy_name[] = "finger1"; const char dummy_pin1[] = "skepp cg0u3;Y.."; const char dummy_pin2[] = "bastilha 6rJrfQZI."; const char dummy_pin[] = "9}4gT:8d=A37Dh}U"; const char dummy_rp_id[] = "localhost"; const char dummy_rp_name[] = "sweet home localhost"; const char dummy_user_icon[] = "an icon"; const char dummy_user_name[] = "john smith"; const char dummy_user_nick[] = "jsmith"; const uint8_t dummy_id[] = { 0x5e, 0xd2 }; const uint8_t dummy_user_id[] = { 0x78, 0x1c, 0x78, 0x60, 0xad, 0x88, 0xd2, 0x63, 0x32, 0x62, 0x2a, 0xf1, 0x74, 0x5d, 0xed, 0xb2, 0xe7, 0xa4, 0x2b, 0x44, 0x89, 0x29, 0x39, 0xc5, 0x56, 0x64, 0x01, 0x27, 0x0d, 0xbb, 0xc4, 0x49, }; const uint8_t dummy_cred_id[] = { 0x4f, 0x72, 0x98, 0x42, 0x4a, 0xe1, 0x17, 0xa5, 0x85, 0xa0, 0xef, 0x3b, 0x11, 0x24, 0x4a, 0x3d, }; const uint8_t dummy_cdh[] = { 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7, 0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56, 0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52, 0x35, 0x2d, 0xa2, 0x62, 0x4a, 0xbe, 0x89, 0x76, }; const uint8_t dummy_es256[] = { 0xcc, 0x1b, 0x50, 0xac, 0xc4, 0x19, 0xf8, 0x3a, 0xee, 0x0a, 0x77, 0xd6, 0xf3, 0x53, 0xdb, 0xef, 0xf2, 0xb9, 0x5c, 0x2d, 0x8b, 0x1e, 0x52, 0x58, 0x88, 0xf4, 0x0b, 0x85, 0x1f, 0x40, 0x6d, 0x18, 0x15, 0xb3, 0xcc, 0x25, 0x7c, 0x38, 0x3d, 0xec, 0xdf, 0xad, 0xbd, 0x46, 0x91, 0xc3, 0xac, 0x30, 0x94, 0x2a, 0xf7, 0x78, 0x35, 0x70, 0x59, 0x6f, 0x28, 0xcb, 0x8e, 0x07, 0x85, 0xb5, 0x91, 0x96, }; const uint8_t dummy_rs256[] = { 0xd2, 0xa8, 0xc0, 0x11, 0x82, 0x9e, 0x57, 0x2e, 0x60, 0xae, 0x8c, 0xb0, 0x09, 0xe1, 0x58, 0x2b, 0x99, 0xec, 0xc3, 0x11, 0x1b, 0xef, 0x81, 0x49, 0x34, 0x53, 0x6a, 0x01, 0x65, 0x2c, 0x24, 0x09, 0x30, 0x87, 0x98, 0x51, 0x6e, 0x30, 0x4f, 0x60, 0xbd, 0x54, 0xd2, 0x54, 0xbd, 0x94, 0x42, 0xdd, 0x63, 0xe5, 0x2c, 0xc6, 0x04, 0x32, 0xc0, 0x8f, 0x72, 0xd5, 0xb4, 0xf0, 0x4f, 0x42, 0xe5, 0xb0, 0xa2, 0x95, 0x11, 0xfe, 0xd8, 0xb0, 0x65, 0x34, 0xff, 0xfb, 0x44, 0x97, 0x52, 0xfc, 0x67, 0x23, 0x0b, 0xad, 0xf3, 0x3a, 0x82, 0xd4, 0x96, 0x10, 0x87, 0x6b, 0xfa, 0xd6, 0x51, 0x60, 0x3e, 0x1c, 0xae, 0x19, 0xb8, 0xce, 0x08, 0xae, 0x9a, 0xee, 0x78, 0x16, 0x22, 0xcc, 0x92, 0xcb, 0xa8, 0x95, 0x34, 0xe5, 0xb9, 0x42, 0x6a, 0xf0, 0x2e, 0x82, 0x1f, 0x4c, 0x7d, 0x84, 0x94, 0x68, 0x7b, 0x97, 0x2b, 0xf7, 0x7d, 0x67, 0x83, 0xbb, 0xc7, 0x8a, 0x31, 0x5a, 0xf3, 0x2a, 0x95, 0xdf, 0x63, 0xe7, 0x4e, 0xee, 0x26, 0xda, 0x87, 0x00, 0xe2, 0x23, 0x4a, 0x33, 0x9a, 0xa0, 0x1b, 0xce, 0x60, 0x1f, 0x98, 0xa1, 0xb0, 0xdb, 0xbf, 0x20, 0x59, 0x27, 0xf2, 0x06, 0xd9, 0xbe, 0x37, 0xa4, 0x03, 0x6b, 0x6a, 0x4e, 0xaf, 0x22, 0x68, 0xf3, 0xff, 0x28, 0x59, 0x05, 0xc9, 0xf1, 0x28, 0xf4, 0xbb, 0x35, 0xe0, 0xc2, 0x68, 0xc2, 0xaa, 0x54, 0xac, 0x8c, 0xc1, 0x69, 0x9e, 0x4b, 0x32, 0xfc, 0x53, 0x58, 0x85, 0x7d, 0x3f, 0x51, 0xd1, 0xc9, 0x03, 0x02, 0x13, 0x61, 0x62, 0xda, 0xf8, 0xfe, 0x3e, 0xc8, 0x95, 0x12, 0xfb, 0x0c, 0xdf, 0x06, 0x65, 0x6f, 0x23, 0xc7, 0x83, 0x7c, 0x50, 0x2d, 0x27, 0x25, 0x4d, 0xbf, 0x94, 0xf0, 0x89, 0x04, 0xb9, 0x2d, 0xc4, 0xa5, 0x32, 0xa9, 0x25, 0x0a, 0x99, 0x59, 0x01, 0x00, 0x01, }; const uint8_t dummy_eddsa[] = { 0xfe, 0x8b, 0x61, 0x50, 0x31, 0x7a, 0xe6, 0xdf, 0xb1, 0x04, 0x9d, 0x4d, 0xb5, 0x7a, 0x5e, 0x96, 0x4c, 0xb2, 0xf9, 0x5f, 0x72, 0x47, 0xb5, 0x18, 0xe2, 0x39, 0xdf, 0x2f, 0x87, 0x19, 0xb3, 0x02, }; +const uint8_t dummy_netlink_wiredata[] = { + 0xd8, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9d, 0x2e, 0x00, 0x00, + 0x01, 0x02, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x6e, 0x66, 0x63, 0x00, 0x06, 0x00, 0x01, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x05, 0x00, + 0x1f, 0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0x00, + 0x14, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x03, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x04, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x05, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x06, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x07, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x08, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x09, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0a, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0e, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x10, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x11, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, + 0x08, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x13, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x07, 0x00, + 0x18, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x9d, 0x2e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x9d, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9d, 0x2e, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, + 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x05, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x06, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00, + 0x93, 0xb9, 0x25, 0x00 +}; + #endif /* !_DUMMY_H */ diff --git a/contrib/libfido2/fuzz/export.gnu b/contrib/libfido2/fuzz/export.gnu index bd70d1c7eaac..0c712b30a429 100644 --- a/contrib/libfido2/fuzz/export.gnu +++ b/contrib/libfido2/fuzz/export.gnu @@ -1,242 +1,254 @@ { global: eddsa_pk_free; eddsa_pk_from_EVP_PKEY; eddsa_pk_from_ptr; eddsa_pk_new; eddsa_pk_to_EVP_PKEY; es256_pk_free; es256_pk_from_EC_KEY; + es256_pk_from_EVP_PKEY; es256_pk_from_ptr; es256_pk_new; es256_pk_to_EVP_PKEY; fido_assert_allow_cred; fido_assert_authdata_len; fido_assert_authdata_ptr; fido_assert_blob_len; fido_assert_blob_ptr; fido_assert_clientdata_hash_len; fido_assert_clientdata_hash_ptr; fido_assert_count; fido_assert_flags; fido_assert_free; fido_assert_hmac_secret_len; fido_assert_hmac_secret_ptr; fido_assert_id_len; fido_assert_id_ptr; fido_assert_largeblob_key_len; fido_assert_largeblob_key_ptr; fido_assert_new; fido_assert_rp_id; fido_assert_set_authdata; fido_assert_set_authdata_raw; + fido_assert_set_clientdata; fido_assert_set_clientdata_hash; fido_assert_set_count; fido_assert_set_extensions; fido_assert_set_hmac_salt; fido_assert_set_hmac_secret; fido_assert_set_options; fido_assert_set_rp; fido_assert_set_sig; fido_assert_set_up; fido_assert_set_uv; fido_assert_sigcount; fido_assert_sig_len; fido_assert_sig_ptr; fido_assert_user_display_name; fido_assert_user_icon; fido_assert_user_id_len; fido_assert_user_id_ptr; fido_assert_user_name; fido_assert_verify; fido_bio_dev_enroll_begin; fido_bio_dev_enroll_cancel; fido_bio_dev_enroll_continue; fido_bio_dev_enroll_remove; fido_bio_dev_get_info; fido_bio_dev_get_template_array; fido_bio_dev_set_template_name; fido_bio_enroll_free; fido_bio_enroll_last_status; fido_bio_enroll_new; fido_bio_enroll_remaining_samples; fido_bio_info_free; fido_bio_info_max_samples; fido_bio_info_new; fido_bio_info_type; fido_bio_template; fido_bio_template_array_count; fido_bio_template_array_free; fido_bio_template_array_new; fido_bio_template_free; fido_bio_template_id_len; fido_bio_template_id_ptr; fido_bio_template_name; fido_bio_template_new; fido_bio_template_set_id; fido_bio_template_set_name; fido_cbor_info_aaguid_len; fido_cbor_info_aaguid_ptr; fido_cbor_info_algorithm_cose; fido_cbor_info_algorithm_count; fido_cbor_info_algorithm_type; fido_cbor_info_extensions_len; fido_cbor_info_extensions_ptr; fido_cbor_info_free; fido_cbor_info_maxmsgsiz; fido_cbor_info_maxcredbloblen; fido_cbor_info_maxcredcntlst; fido_cbor_info_maxcredidlen; fido_cbor_info_fwversion; fido_cbor_info_new; fido_cbor_info_options_len; fido_cbor_info_options_name_ptr; fido_cbor_info_options_value_ptr; fido_cbor_info_protocols_len; fido_cbor_info_protocols_ptr; fido_cbor_info_transports_len; fido_cbor_info_transports_ptr; fido_cbor_info_versions_len; fido_cbor_info_versions_ptr; + fido_cred_attstmt_len; + fido_cred_attstmt_ptr; fido_cred_authdata_len; fido_cred_authdata_ptr; fido_cred_authdata_raw_len; fido_cred_authdata_raw_ptr; fido_cred_clientdata_hash_len; fido_cred_clientdata_hash_ptr; fido_cred_display_name; fido_cred_exclude; fido_cred_flags; fido_cred_largeblob_key_len; fido_cred_largeblob_key_ptr; fido_cred_sigcount; fido_cred_fmt; fido_cred_free; fido_cred_id_len; fido_cred_id_ptr; fido_cred_aaguid_len; fido_cred_aaguid_ptr; fido_credman_del_dev_rk; fido_credman_get_dev_metadata; fido_credman_get_dev_rk; fido_credman_get_dev_rp; fido_credman_metadata_free; fido_credman_metadata_new; fido_credman_rk; fido_credman_rk_count; fido_credman_rk_existing; fido_credman_rk_free; fido_credman_rk_new; fido_credman_rk_remaining; fido_credman_rp_count; fido_credman_rp_free; fido_credman_rp_id; fido_credman_rp_id_hash_len; fido_credman_rp_id_hash_ptr; fido_credman_rp_name; fido_credman_rp_new; fido_credman_set_dev_rk; fido_cred_new; + fido_cred_pin_minlen; fido_cred_prot; fido_cred_pubkey_len; fido_cred_pubkey_ptr; fido_cred_rp_id; fido_cred_rp_name; + fido_cred_set_attstmt; fido_cred_set_authdata; fido_cred_set_authdata_raw; fido_cred_set_blob; + fido_cred_set_clientdata; fido_cred_set_clientdata_hash; fido_cred_set_extensions; fido_cred_set_fmt; fido_cred_set_id; fido_cred_set_options; + fido_cred_set_pin_minlen; fido_cred_set_prot; fido_cred_set_rk; fido_cred_set_rp; fido_cred_set_sig; fido_cred_set_type; fido_cred_set_user; fido_cred_set_uv; fido_cred_set_x509; fido_cred_sig_len; fido_cred_sig_ptr; fido_cred_type; fido_cred_user_id_len; fido_cred_user_id_ptr; fido_cred_user_name; fido_cred_verify; fido_cred_verify_self; fido_cred_x5c_len; fido_cred_x5c_ptr; fido_dev_build; fido_dev_cancel; fido_dev_close; fido_dev_enable_entattest; fido_dev_flags; fido_dev_force_fido2; fido_dev_force_pin_change; fido_dev_force_u2f; fido_dev_free; fido_dev_get_assert; fido_dev_get_cbor_info; fido_dev_get_retry_count; fido_dev_get_uv_retry_count; fido_dev_get_touch_begin; fido_dev_get_touch_status; fido_dev_has_pin; fido_dev_has_uv; fido_dev_info_free; fido_dev_info_manifest; fido_dev_info_manufacturer_string; fido_dev_info_new; fido_dev_info_path; fido_dev_info_product; fido_dev_info_product_string; fido_dev_info_ptr; fido_dev_info_vendor; fido_dev_is_fido2; fido_dev_major; fido_dev_make_cred; fido_dev_minor; fido_dev_new; fido_dev_open; fido_dev_protocol; fido_dev_reset; fido_dev_set_io_functions; fido_dev_set_pin; fido_dev_set_pin_minlen; + fido_dev_set_pin_minlen_rpid; + fido_dev_set_timeout; fido_dev_set_transport_functions; fido_dev_supports_cred_prot; fido_dev_supports_credman; fido_dev_supports_permissions; fido_dev_supports_pin; fido_dev_supports_uv; fido_dev_toggle_always_uv; fido_dev_largeblob_get; fido_dev_largeblob_get_array; fido_dev_largeblob_remove; fido_dev_largeblob_set; fido_dev_largeblob_set_array; fido_hid_get_report_len; fido_hid_get_usage; fido_init; fido_nfc_rx; fido_nfc_tx; fido_nl_free; fido_nl_get_nfc_target; fido_nl_new; fido_nl_power_nfc; fido_set_log_handler; fido_strerr; rs256_pk_free; rs256_pk_from_ptr; + rs256_pk_from_EVP_PKEY; rs256_pk_from_RSA; rs256_pk_new; rs256_pk_to_EVP_PKEY; prng_init; + fuzz_clock_reset; set_netlink_io_functions; set_udev_parameters; uniform_random; local: *; }; diff --git a/contrib/libfido2/fuzz/functions.txt b/contrib/libfido2/fuzz/functions.txt index 28fe4f6af17b..886893b1d11d 100644 --- a/contrib/libfido2/fuzz/functions.txt +++ b/contrib/libfido2/fuzz/functions.txt @@ -1,807 +1,866 @@ File '/libfido2/src/aes256.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------- +-------------------------------------------------------------------------------------------------------- aes256_cbc_enc 3 0 100.00% 4 0 100.00% aes256_cbc_dec 3 0 100.00% 4 0 100.00% aes256_gcm_enc 1 0 100.00% 3 0 100.00% aes256_gcm_dec 1 0 100.00% 3 0 100.00% -aes256.c:aes256_cbc_fips 26 2 92.31% 45 7 84.44% -aes256.c:aes256_cbc 29 1 96.55% 40 3 92.50% -aes256.c:aes256_cbc_proto1 1 0 100.00% 7 0 100.00% -aes256.c:aes256_gcm 51 1 98.04% 69 4 94.20% ------------------------------------------------------------------------------- -TOTAL 115 4 96.52% 175 14 92.00% +aes256.c:aes256_cbc_fips 26 2 92.31% 42 7 83.33% +aes256.c:aes256_cbc 29 1 96.55% 36 3 91.67% +aes256.c:aes256_cbc_proto1 1 0 100.00% 5 0 100.00% +aes256.c:aes256_gcm 51 1 98.04% 60 4 93.33% +-------------------------------------------------------------------------------------------------------- +TOTAL 115 4 96.52% 157 14 91.08% File '/libfido2/src/assert.c': Name Regions Miss Cover Lines Miss Cover ---------------------------------------------------------------------------------------- -fido_dev_get_assert 40 0 100.00% 41 0 100.00% -fido_check_flags 13 0 100.00% 18 0 100.00% -fido_get_signed_hash 32 0 100.00% 46 0 100.00% -fido_verify_sig_es256 17 2 88.24% 31 7 77.42% -fido_verify_sig_rs256 17 2 88.24% 31 7 77.42% -fido_verify_sig_eddsa 23 2 91.30% 43 7 83.72% -fido_assert_verify 48 4 91.67% 79 5 93.67% -fido_assert_set_clientdata 12 12 0.00% 12 12 0.00% -fido_assert_set_clientdata_hash 8 0 100.00% 7 0 100.00% -fido_assert_set_hmac_salt 10 0 100.00% 7 0 100.00% -fido_assert_set_hmac_secret 12 12 0.00% 8 8 0.00% -fido_assert_set_rp 12 0 100.00% 14 0 100.00% -fido_assert_allow_cred 13 2 84.62% 29 3 89.66% -fido_assert_set_extensions 14 0 100.00% 11 0 100.00% -fido_assert_set_options 6 6 0.00% 6 6 0.00% -fido_assert_set_up 2 0 100.00% 5 0 100.00% -fido_assert_set_uv 2 0 100.00% 5 0 100.00% +----------------------------------------------------------------------------------------------------------------- +fido_dev_get_assert 40 0 100.00% 35 0 100.00% +fido_check_flags 13 0 100.00% 15 0 100.00% +fido_get_signed_hash 36 0 100.00% 46 0 100.00% +fido_assert_verify 48 4 91.67% 67 5 92.54% +fido_assert_set_clientdata 12 12 0.00% 11 11 0.00% +fido_assert_set_clientdata_hash 8 0 100.00% 6 0 100.00% +fido_assert_set_hmac_salt 10 0 100.00% 6 0 100.00% +fido_assert_set_hmac_secret 12 12 0.00% 7 7 0.00% +fido_assert_set_rp 12 0 100.00% 11 0 100.00% +fido_assert_allow_cred 13 2 84.62% 22 3 86.36% +fido_assert_set_extensions 14 0 100.00% 10 0 100.00% +fido_assert_set_options 6 6 0.00% 5 5 0.00% +fido_assert_set_up 2 0 100.00% 4 0 100.00% +fido_assert_set_uv 2 0 100.00% 4 0 100.00% fido_assert_clientdata_hash_ptr 1 0 100.00% 3 0 100.00% fido_assert_clientdata_hash_len 1 0 100.00% 3 0 100.00% fido_assert_new 1 0 100.00% 3 0 100.00% fido_assert_reset_tx 1 0 100.00% 12 0 100.00% fido_assert_reset_rx 4 0 100.00% 19 0 100.00% -fido_assert_free 6 0 100.00% 10 0 100.00% +fido_assert_free 6 0 100.00% 9 0 100.00% fido_assert_count 1 0 100.00% 3 0 100.00% fido_assert_rp_id 1 0 100.00% 3 0 100.00% -fido_assert_flags 4 0 100.00% 6 0 100.00% -fido_assert_sigcount 4 0 100.00% 6 0 100.00% -fido_assert_authdata_ptr 4 0 100.00% 6 0 100.00% -fido_assert_authdata_len 4 0 100.00% 6 0 100.00% -fido_assert_sig_ptr 4 0 100.00% 6 0 100.00% -fido_assert_sig_len 4 0 100.00% 6 0 100.00% -fido_assert_id_ptr 4 0 100.00% 6 0 100.00% -fido_assert_id_len 4 0 100.00% 6 0 100.00% -fido_assert_user_id_ptr 4 0 100.00% 6 0 100.00% -fido_assert_user_id_len 4 0 100.00% 6 0 100.00% -fido_assert_user_icon 4 0 100.00% 6 0 100.00% -fido_assert_user_name 4 0 100.00% 6 0 100.00% -fido_assert_user_display_name 4 0 100.00% 6 0 100.00% -fido_assert_hmac_secret_ptr 4 0 100.00% 6 0 100.00% -fido_assert_hmac_secret_len 4 0 100.00% 6 0 100.00% -fido_assert_largeblob_key_ptr 4 0 100.00% 6 0 100.00% -fido_assert_largeblob_key_len 4 0 100.00% 6 0 100.00% -fido_assert_blob_ptr 4 0 100.00% 6 0 100.00% -fido_assert_blob_len 4 0 100.00% 6 0 100.00% -fido_assert_set_authdata 24 0 100.00% 35 0 100.00% -fido_assert_set_authdata_raw 24 0 100.00% 34 0 100.00% -fido_assert_set_sig 14 0 100.00% 8 0 100.00% -fido_assert_set_count 10 0 100.00% 21 0 100.00% -assert.c:fido_dev_get_assert_wait 21 0 100.00% 16 0 100.00% -assert.c:fido_dev_get_assert_tx 56 2 96.43% 77 5 93.51% -assert.c:fido_dev_get_assert_rx 19 0 100.00% 38 0 100.00% -assert.c:adjust_assert_count 24 0 100.00% 33 0 100.00% -assert.c:parse_assert_reply 12 0 100.00% 26 0 100.00% -assert.c:fido_get_next_assert_tx 8 0 100.00% 10 0 100.00% -assert.c:fido_get_next_assert_rx 15 2 86.67% 26 4 84.62% -assert.c:decrypt_hmac_secrets 9 0 100.00% 16 0 100.00% -assert.c:check_extensions 5 0 100.00% 11 0 100.00% +fido_assert_flags 4 0 100.00% 5 0 100.00% +fido_assert_sigcount 4 0 100.00% 5 0 100.00% +fido_assert_authdata_ptr 4 0 100.00% 5 0 100.00% +fido_assert_authdata_len 4 0 100.00% 5 0 100.00% +fido_assert_sig_ptr 4 0 100.00% 5 0 100.00% +fido_assert_sig_len 4 0 100.00% 5 0 100.00% +fido_assert_id_ptr 4 0 100.00% 5 0 100.00% +fido_assert_id_len 4 0 100.00% 5 0 100.00% +fido_assert_user_id_ptr 4 0 100.00% 5 0 100.00% +fido_assert_user_id_len 4 0 100.00% 5 0 100.00% +fido_assert_user_icon 4 0 100.00% 5 0 100.00% +fido_assert_user_name 4 0 100.00% 5 0 100.00% +fido_assert_user_display_name 4 0 100.00% 5 0 100.00% +fido_assert_hmac_secret_ptr 4 0 100.00% 5 0 100.00% +fido_assert_hmac_secret_len 4 0 100.00% 5 0 100.00% +fido_assert_largeblob_key_ptr 4 0 100.00% 5 0 100.00% +fido_assert_largeblob_key_len 4 0 100.00% 5 0 100.00% +fido_assert_blob_ptr 4 0 100.00% 5 0 100.00% +fido_assert_blob_len 4 0 100.00% 5 0 100.00% +fido_assert_set_authdata 24 0 100.00% 28 0 100.00% +fido_assert_set_authdata_raw 24 0 100.00% 27 0 100.00% +fido_assert_set_sig 14 0 100.00% 7 0 100.00% +fido_assert_set_count 10 0 100.00% 17 0 100.00% +assert.c:fido_dev_get_assert_wait 21 0 100.00% 14 0 100.00% +assert.c:fido_dev_get_assert_tx 56 2 96.43% 62 5 91.94% +assert.c:fido_dev_get_assert_rx 19 0 100.00% 27 0 100.00% +assert.c:adjust_assert_count 24 0 100.00% 26 0 100.00% +assert.c:parse_assert_reply 12 0 100.00% 24 0 100.00% +assert.c:fido_get_next_assert_tx 8 0 100.00% 8 0 100.00% +assert.c:fido_get_next_assert_rx 15 2 86.67% 21 4 80.95% +assert.c:decrypt_hmac_secrets 9 0 100.00% 15 0 100.00% +assert.c:check_extensions 5 0 100.00% 9 0 100.00% assert.c:fido_assert_reset_extattr 1 0 100.00% 5 0 100.00% assert.c:fido_assert_clean_authdata 1 0 100.00% 5 0 100.00% ---------------------------------------------------------------------------------------- -TOTAL 616 46 92.53% 924 64 93.07% +----------------------------------------------------------------------------------------------------------------- +TOTAL 563 40 92.90% 694 40 94.24% File '/libfido2/src/authkey.c': Name Regions Miss Cover Lines Miss Cover ---------------------------------------------------------------------------------------- +----------------------------------------------------------------------------------------------------------------- fido_dev_authkey 1 0 100.00% 3 0 100.00% -authkey.c:fido_dev_authkey_wait 10 0 100.00% 9 0 100.00% -authkey.c:fido_dev_authkey_tx 19 0 100.00% 33 0 100.00% -authkey.c:fido_dev_authkey_rx 6 0 100.00% 18 0 100.00% -authkey.c:parse_authkey 8 0 100.00% 12 0 100.00% ---------------------------------------------------------------------------------------- -TOTAL 44 0 100.00% 75 0 100.00% +authkey.c:fido_dev_authkey_wait 10 0 100.00% 7 0 100.00% +authkey.c:fido_dev_authkey_tx 19 0 100.00% 25 0 100.00% +authkey.c:fido_dev_authkey_rx 6 0 100.00% 14 0 100.00% +authkey.c:parse_authkey 8 0 100.00% 10 0 100.00% +----------------------------------------------------------------------------------------------------------------- +TOTAL 44 0 100.00% 59 0 100.00% File '/libfido2/src/bio.c': Name Regions Miss Cover Lines Miss Cover ---------------------------------------------------------------------------------------- +----------------------------------------------------------------------------------------------------------------- fido_bio_dev_get_template_array 5 2 60.00% 6 0 100.00% fido_bio_dev_set_template_name 7 0 100.00% 6 0 100.00% -fido_bio_dev_enroll_begin 25 2 92.00% 37 0 100.00% +fido_bio_dev_enroll_begin 25 2 92.00% 31 0 100.00% fido_bio_dev_enroll_continue 5 2 60.00% 6 0 100.00% -fido_bio_dev_enroll_cancel 1 1 0.00% 3 3 0.00% -fido_bio_dev_enroll_remove 1 0 100.00% 3 0 100.00% -fido_bio_dev_get_info 1 0 100.00% 3 0 100.00% +fido_bio_dev_enroll_cancel 1 1 0.00% 4 4 0.00% +fido_bio_dev_enroll_remove 1 0 100.00% 4 0 100.00% +fido_bio_dev_get_info 1 0 100.00% 4 0 100.00% fido_bio_template_name 1 0 100.00% 3 0 100.00% fido_bio_template_id_ptr 1 0 100.00% 3 0 100.00% fido_bio_template_id_len 1 0 100.00% 3 0 100.00% fido_bio_template_array_count 1 0 100.00% 3 0 100.00% fido_bio_template_array_new 1 0 100.00% 3 0 100.00% fido_bio_template_new 1 0 100.00% 3 0 100.00% -fido_bio_template_array_free 6 0 100.00% 10 0 100.00% -fido_bio_template_free 6 0 100.00% 10 0 100.00% -fido_bio_template_set_name 8 0 100.00% 9 0 100.00% -fido_bio_template_set_id 8 0 100.00% 8 0 100.00% -fido_bio_template 4 0 100.00% 6 0 100.00% +fido_bio_template_array_free 6 0 100.00% 8 0 100.00% +fido_bio_template_free 6 0 100.00% 8 0 100.00% +fido_bio_template_set_name 8 0 100.00% 7 0 100.00% +fido_bio_template_set_id 8 0 100.00% 6 0 100.00% +fido_bio_template 4 0 100.00% 5 0 100.00% fido_bio_enroll_new 1 0 100.00% 3 0 100.00% fido_bio_info_new 1 0 100.00% 3 0 100.00% fido_bio_info_type 1 0 100.00% 3 0 100.00% fido_bio_info_max_samples 1 0 100.00% 3 0 100.00% -fido_bio_enroll_free 6 0 100.00% 11 0 100.00% -fido_bio_info_free 6 0 100.00% 9 0 100.00% +fido_bio_enroll_free 6 0 100.00% 8 0 100.00% +fido_bio_info_free 6 0 100.00% 7 0 100.00% fido_bio_enroll_remaining_samples 1 0 100.00% 3 0 100.00% fido_bio_enroll_last_status 1 0 100.00% 3 0 100.00% -bio.c:bio_get_template_array_wait 11 0 100.00% 9 0 100.00% -bio.c:bio_tx 43 0 100.00% 66 0 100.00% -bio.c:bio_prepare_hmac 18 0 100.00% 36 0 100.00% -bio.c:bio_rx_template_array 11 0 100.00% 21 0 100.00% -bio.c:bio_parse_template_array 26 1 96.15% 34 4 88.24% -bio.c:decode_template_array 12 1 91.67% 23 3 86.96% -bio.c:decode_template 9 0 100.00% 18 0 100.00% -bio.c:bio_set_template_name_wait 19 0 100.00% 24 0 100.00% -bio.c:bio_enroll_begin_wait 17 0 100.00% 24 0 100.00% -bio.c:bio_rx_enroll_begin 15 0 100.00% 29 0 100.00% -bio.c:bio_parse_enroll_status 20 0 100.00% 31 0 100.00% -bio.c:bio_parse_template_id 8 0 100.00% 12 0 100.00% -bio.c:bio_enroll_continue_wait 19 0 100.00% 25 0 100.00% -bio.c:bio_rx_enroll_continue 11 0 100.00% 22 0 100.00% -bio.c:bio_enroll_cancel_wait 11 11 0.00% 12 12 0.00% -bio.c:bio_enroll_remove_wait 17 0 100.00% 24 0 100.00% -bio.c:bio_get_info_wait 11 0 100.00% 11 0 100.00% -bio.c:bio_rx_info 11 0 100.00% 21 0 100.00% +bio.c:bio_get_template_array_wait 11 0 100.00% 7 0 100.00% +bio.c:bio_tx 43 0 100.00% 55 0 100.00% +bio.c:bio_prepare_hmac 18 0 100.00% 29 0 100.00% +bio.c:bio_rx_template_array 11 0 100.00% 17 0 100.00% +bio.c:bio_parse_template_array 26 1 96.15% 27 4 85.19% +bio.c:decode_template_array 12 1 91.67% 18 3 83.33% +bio.c:decode_template 9 0 100.00% 15 0 100.00% +bio.c:bio_set_template_name_wait 19 0 100.00% 20 0 100.00% +bio.c:bio_enroll_begin_wait 17 0 100.00% 19 0 100.00% +bio.c:bio_rx_enroll_begin 15 0 100.00% 24 0 100.00% +bio.c:bio_parse_enroll_status 20 0 100.00% 28 0 100.00% +bio.c:bio_parse_template_id 8 0 100.00% 10 0 100.00% +bio.c:bio_enroll_continue_wait 19 0 100.00% 20 0 100.00% +bio.c:bio_rx_enroll_continue 11 0 100.00% 18 0 100.00% +bio.c:bio_enroll_cancel_wait 11 11 0.00% 10 10 0.00% +bio.c:bio_enroll_remove_wait 17 0 100.00% 19 0 100.00% +bio.c:bio_get_info_wait 11 0 100.00% 10 0 100.00% +bio.c:bio_rx_info 11 0 100.00% 17 0 100.00% bio.c:bio_reset_info 1 0 100.00% 4 0 100.00% -bio.c:bio_parse_info 20 0 100.00% 31 0 100.00% -bio.c:bio_reset_template_array 4 0 100.00% 8 0 100.00% +bio.c:bio_parse_info 20 0 100.00% 28 0 100.00% +bio.c:bio_reset_template_array 4 0 100.00% 7 0 100.00% bio.c:bio_reset_template 1 0 100.00% 5 0 100.00% -bio.c:bio_reset_enroll 3 0 100.00% 7 0 100.00% ---------------------------------------------------------------------------------------- -TOTAL 419 20 95.23% 660 22 96.67% +bio.c:bio_reset_enroll 3 0 100.00% 6 0 100.00% +----------------------------------------------------------------------------------------------------------------- +TOTAL 419 20 95.23% 559 21 96.24% File '/libfido2/src/blob.c': Name Regions Miss Cover Lines Miss Cover ---------------------------------------------------------------------------------------- +----------------------------------------------------------------------------------------------------------------- fido_blob_new 1 0 100.00% 3 0 100.00% fido_blob_reset 1 0 100.00% 4 0 100.00% -fido_blob_set 9 0 100.00% 19 0 100.00% -fido_blob_append 12 2 83.33% 22 6 72.73% -fido_blob_free 6 0 100.00% 10 0 100.00% -fido_free_blob_array 7 0 100.00% 14 0 100.00% -fido_blob_encode 6 0 100.00% 6 0 100.00% +fido_blob_set 9 0 100.00% 15 0 100.00% +fido_blob_append 12 1 91.67% 20 3 85.00% +fido_blob_free 6 0 100.00% 8 0 100.00% +fido_free_blob_array 7 0 100.00% 12 0 100.00% +fido_blob_encode 6 0 100.00% 5 0 100.00% fido_blob_decode 1 0 100.00% 3 0 100.00% fido_blob_is_empty 3 0 100.00% 3 0 100.00% -fido_blob_serialise 7 1 85.71% 12 1 91.67% ---------------------------------------------------------------------------------------- -TOTAL 53 3 94.34% 96 7 92.71% +fido_blob_serialise 7 1 85.71% 10 1 90.00% +----------------------------------------------------------------------------------------------------------------- +TOTAL 53 2 96.23% 83 4 95.18% File '/libfido2/src/buf.c': Name Regions Miss Cover Lines Miss Cover ---------------------------------------------------------------------------------------- -fido_buf_read 4 0 100.00% 10 0 100.00% -fido_buf_write 4 1 75.00% 10 1 90.00% ---------------------------------------------------------------------------------------- -TOTAL 8 1 87.50% 20 1 95.00% +----------------------------------------------------------------------------------------------------------------- +fido_buf_read 4 0 100.00% 8 0 100.00% +fido_buf_write 4 1 75.00% 8 1 87.50% +----------------------------------------------------------------------------------------------------------------- +TOTAL 8 1 87.50% 16 1 93.75% File '/libfido2/src/cbor.c': Name Regions Miss Cover Lines Miss Cover ----------------------------------------------------------------------------------------- -cbor_map_iter 20 1 95.00% 30 4 86.67% -cbor_array_iter 12 0 100.00% 20 0 100.00% -cbor_parse_reply 27 0 100.00% 43 0 100.00% +------------------------------------------------------------------------------------------------------------------ +cbor_map_iter 20 1 95.00% 26 4 84.62% +cbor_array_iter 12 0 100.00% 16 0 100.00% +cbor_parse_reply 27 0 100.00% 36 0 100.00% cbor_vector_free 6 0 100.00% 5 0 100.00% -cbor_bytestring_copy 14 0 100.00% 22 0 100.00% -cbor_string_copy 14 0 100.00% 23 0 100.00% -cbor_add_bytestring 14 0 100.00% 26 0 100.00% -cbor_add_string 14 0 100.00% 26 0 100.00% -cbor_add_bool 14 0 100.00% 26 0 100.00% -cbor_flatten_vector 14 1 92.86% 21 1 95.24% -cbor_build_frame 15 0 100.00% 32 0 100.00% -cbor_encode_rp_entity 13 0 100.00% 14 0 100.00% -cbor_encode_user_entity 21 0 100.00% 18 0 100.00% -cbor_encode_pubkey_param 36 0 100.00% 48 0 100.00% -cbor_encode_pubkey 10 0 100.00% 13 0 100.00% -cbor_encode_pubkey_list 18 0 100.00% 23 0 100.00% -cbor_encode_cred_ext 46 0 100.00% 46 0 100.00% -cbor_encode_cred_opt 13 0 100.00% 13 0 100.00% -cbor_encode_assert_opt 13 0 100.00% 13 0 100.00% -cbor_encode_pin_auth 20 1 95.00% 30 3 90.00% -cbor_encode_pin_opt 4 0 100.00% 10 0 100.00% -cbor_encode_change_pin_auth 33 1 96.97% 49 3 93.88% -cbor_encode_assert_ext 33 0 100.00% 35 0 100.00% -cbor_decode_fmt 11 0 100.00% 19 0 100.00% -cbor_decode_pubkey 21 1 95.24% 32 2 93.75% -cbor_decode_cred_authdata 31 1 96.77% 45 3 93.33% -cbor_decode_assert_authdata 21 0 100.00% 42 0 100.00% -cbor_decode_attstmt 8 0 100.00% 10 0 100.00% -cbor_decode_uint64 4 0 100.00% 10 0 100.00% -cbor_decode_cred_id 8 0 100.00% 10 0 100.00% -cbor_decode_user 8 0 100.00% 10 0 100.00% -cbor_decode_rp_entity 8 0 100.00% 10 0 100.00% -cbor_build_uint 10 4 60.00% 10 5 50.00% -cbor_array_append 17 0 100.00% 23 0 100.00% -cbor_array_drop 18 2 88.89% 19 3 84.21% -cbor.c:ctap_check_cbor 28 0 100.00% 32 0 100.00% -cbor.c:check_key_type 8 0 100.00% 9 0 100.00% -cbor.c:cbor_add_arg 13 0 100.00% 28 0 100.00% -cbor.c:cbor_add_uint8 14 0 100.00% 26 0 100.00% -cbor.c:cbor_encode_largeblob_key_ext 6 0 100.00% 7 0 100.00% -cbor.c:cbor_encode_hmac_secret_param 53 2 96.23% 75 4 94.67% -cbor.c:get_cose_alg 36 0 100.00% 48 0 100.00% -cbor.c:find_cose_alg 35 0 100.00% 40 0 100.00% -cbor.c:decode_attcred 25 0 100.00% 56 0 100.00% -cbor.c:decode_cred_extensions 14 0 100.00% 31 0 100.00% -cbor.c:decode_cred_extension 40 3 92.50% 45 9 80.00% -cbor.c:decode_assert_extensions 14 0 100.00% 29 0 100.00% -cbor.c:decode_assert_extension 19 0 100.00% 31 0 100.00% -cbor.c:decode_attstmt_entry 38 0 100.00% 44 0 100.00% -cbor.c:decode_x5c 4 0 100.00% 8 0 100.00% -cbor.c:decode_cred_id_entry 10 0 100.00% 23 0 100.00% -cbor.c:decode_user_entry 25 0 100.00% 39 0 100.00% -cbor.c:decode_rp_entity_entry 15 0 100.00% 29 0 100.00% ----------------------------------------------------------------------------------------- -TOTAL 986 17 98.28% 1426 37 97.41% +cbor_bytestring_copy 14 0 100.00% 18 0 100.00% +cbor_string_copy 14 1 92.86% 18 3 83.33% +cbor_add_bytestring 14 0 100.00% 21 0 100.00% +cbor_add_string 14 0 100.00% 21 0 100.00% +cbor_add_bool 14 0 100.00% 21 0 100.00% +cbor_flatten_vector 14 1 92.86% 16 1 93.75% +cbor_build_frame 15 0 100.00% 25 0 100.00% +cbor_encode_rp_entity 13 0 100.00% 11 0 100.00% +cbor_encode_user_entity 21 0 100.00% 15 0 100.00% +cbor_encode_pubkey_param 36 0 100.00% 39 0 100.00% +cbor_encode_pubkey 10 0 100.00% 11 0 100.00% +cbor_encode_pubkey_list 18 0 100.00% 19 0 100.00% +cbor_encode_str_array 18 0 100.00% 19 0 100.00% +cbor_encode_cred_ext 55 0 100.00% 50 0 100.00% +cbor_encode_cred_opt 13 0 100.00% 11 0 100.00% +cbor_encode_assert_opt 13 0 100.00% 11 0 100.00% +cbor_encode_pin_auth 20 1 95.00% 22 3 86.36% +cbor_encode_pin_opt 4 0 100.00% 8 0 100.00% +cbor_encode_change_pin_auth 31 1 96.77% 36 3 91.67% +cbor_encode_assert_ext 33 0 100.00% 32 0 100.00% +cbor_decode_fmt 13 0 100.00% 15 0 100.00% +cbor_decode_pubkey 21 1 95.24% 30 2 93.33% +cbor_decode_cred_authdata 31 1 96.77% 35 3 91.43% +cbor_decode_assert_authdata 21 0 100.00% 32 0 100.00% +cbor_decode_attstmt 13 0 100.00% 16 0 100.00% +cbor_decode_uint64 4 0 100.00% 8 0 100.00% +cbor_decode_cred_id 8 0 100.00% 9 0 100.00% +cbor_decode_user 8 0 100.00% 9 0 100.00% +cbor_decode_rp_entity 8 0 100.00% 9 0 100.00% +cbor_build_uint 10 4 60.00% 9 4 55.56% +cbor_array_append 17 0 100.00% 21 0 100.00% +cbor_array_drop 18 2 88.89% 17 3 82.35% +cbor.c:ctap_check_cbor 28 0 100.00% 26 0 100.00% +cbor.c:check_key_type 8 0 100.00% 7 0 100.00% +cbor.c:cbor_add_arg 13 0 100.00% 21 0 100.00% +cbor.c:cbor_add_uint8 14 0 100.00% 21 0 100.00% +cbor.c:cbor_encode_largeblob_key_ext 6 0 100.00% 6 0 100.00% +cbor.c:cbor_encode_hmac_secret_param 59 4 93.22% 66 8 87.88% +cbor.c:get_cose_alg 36 1 97.22% 38 3 92.11% +cbor.c:find_cose_alg 35 0 100.00% 33 0 100.00% +cbor.c:decode_attcred 25 0 100.00% 44 0 100.00% +cbor.c:decode_cred_extensions 14 0 100.00% 24 0 100.00% +cbor.c:decode_cred_extension 49 10 79.59% 49 17 65.31% +cbor.c:decode_assert_extensions 14 0 100.00% 23 0 100.00% +cbor.c:decode_assert_extension 19 0 100.00% 27 0 100.00% +cbor.c:decode_attstmt_entry 52 0 100.00% 50 0 100.00% +cbor.c:decode_x5c 4 0 100.00% 6 0 100.00% +cbor.c:decode_cred_id_entry 10 0 100.00% 19 0 100.00% +cbor.c:decode_user_entry 25 0 100.00% 35 0 100.00% +cbor.c:decode_rp_entity_entry 15 0 100.00% 25 0 100.00% +------------------------------------------------------------------------------------------------------------------ +TOTAL 1047 28 97.33% 1237 54 95.63% File '/libfido2/src/compress.c': Name Regions Miss Cover Lines Miss Cover ----------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------ fido_compress 1 0 100.00% 3 0 100.00% fido_uncompress 1 0 100.00% 3 0 100.00% -compress.c:do_compress 32 4 87.50% 24 3 87.50% ----------------------------------------------------------------------------------------- -TOTAL 34 4 88.24% 30 3 90.00% +compress.c:do_compress 32 4 87.50% 22 3 86.36% +------------------------------------------------------------------------------------------------------------------ +TOTAL 34 4 88.24% 28 3 89.29% File '/libfido2/src/config.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ -fido_dev_enable_entattest 1 0 100.00% 3 0 100.00% -fido_dev_toggle_always_uv 1 0 100.00% 3 0 100.00% -fido_dev_set_pin_minlen 1 0 100.00% 3 0 100.00% -fido_dev_force_pin_change 1 0 100.00% 3 0 100.00% -config.c:config_enable_entattest_wait 6 0 100.00% 8 0 100.00% -config.c:config_tx 37 0 100.00% 57 0 100.00% -config.c:config_prepare_hmac 8 1 87.50% 22 3 86.36% -config.c:config_toggle_always_uv_wait 6 0 100.00% 8 0 100.00% -config.c:config_pin_minlen 5 0 100.00% 8 0 100.00% -config.c:config_pin_minlen_tx 28 0 100.00% 31 0 100.00% ------------------------------------------------------------------------------------------ -TOTAL 94 1 98.94% 146 3 97.95% +------------------------------------------------------------------------------------------------------------------- +fido_dev_enable_entattest 1 0 100.00% 4 0 100.00% +fido_dev_toggle_always_uv 1 0 100.00% 4 0 100.00% +fido_dev_set_pin_minlen 1 0 100.00% 4 0 100.00% +fido_dev_force_pin_change 1 0 100.00% 4 0 100.00% +fido_dev_set_pin_minlen_rpid 6 0 100.00% 15 0 100.00% +config.c:config_enable_entattest_wait 6 0 100.00% 7 0 100.00% +config.c:config_tx 37 0 100.00% 48 0 100.00% +config.c:config_prepare_hmac 8 0 100.00% 19 0 100.00% +config.c:config_toggle_always_uv_wait 6 0 100.00% 7 0 100.00% +config.c:config_pin_minlen 5 0 100.00% 7 0 100.00% +config.c:config_pin_minlen_tx 36 0 100.00% 32 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 108 0 100.00% 151 0 100.00% File '/libfido2/src/cred.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------------------- fido_dev_make_cred 12 0 100.00% 10 0 100.00% -fido_check_rp_id 4 0 100.00% 14 0 100.00% -fido_cred_verify 50 4 92.00% 75 8 89.33% -fido_cred_verify_self 58 6 89.66% 94 10 89.36% +fido_check_rp_id 4 0 100.00% 11 0 100.00% +fido_cred_verify 56 2 96.43% 72 5 93.06% +fido_cred_verify_self 58 4 93.10% 83 5 93.98% fido_cred_new 1 0 100.00% 3 0 100.00% -fido_cred_reset_tx 1 0 100.00% 22 0 100.00% -fido_cred_reset_rx 1 0 100.00% 8 0 100.00% -fido_cred_free 6 0 100.00% 10 0 100.00% -fido_cred_set_authdata 23 0 100.00% 37 0 100.00% -fido_cred_set_authdata_raw 25 0 100.00% 38 0 100.00% -fido_cred_set_id 6 0 100.00% 6 0 100.00% -fido_cred_set_x509 6 0 100.00% 6 0 100.00% -fido_cred_set_sig 6 0 100.00% 6 0 100.00% -fido_cred_exclude 14 2 85.71% 25 3 88.00% -fido_cred_set_clientdata 12 12 0.00% 12 12 0.00% -fido_cred_set_clientdata_hash 8 0 100.00% 7 0 100.00% -fido_cred_set_rp 18 0 100.00% 26 0 100.00% -fido_cred_set_user 32 0 100.00% 46 0 100.00% -fido_cred_set_extensions 15 0 100.00% 11 0 100.00% -fido_cred_set_options 6 6 0.00% 6 6 0.00% -fido_cred_set_rk 2 0 100.00% 5 0 100.00% -fido_cred_set_uv 2 0 100.00% 5 0 100.00% -fido_cred_set_prot 21 0 100.00% 16 0 100.00% -fido_cred_set_blob 13 2 84.62% 10 1 90.00% -fido_cred_set_fmt 18 4 77.78% 16 1 93.75% -fido_cred_set_type 17 0 100.00% 9 0 100.00% +fido_cred_reset_tx 1 0 100.00% 19 0 100.00% +fido_cred_reset_rx 1 0 100.00% 7 0 100.00% +fido_cred_free 6 0 100.00% 9 0 100.00% +fido_cred_set_authdata 23 0 100.00% 28 0 100.00% +fido_cred_set_authdata_raw 25 0 100.00% 29 0 100.00% +fido_cred_set_id 6 0 100.00% 5 0 100.00% +fido_cred_set_x509 6 0 100.00% 5 0 100.00% +fido_cred_set_sig 6 0 100.00% 5 0 100.00% +fido_cred_set_attstmt 20 0 100.00% 23 0 100.00% +fido_cred_exclude 14 2 85.71% 19 3 84.21% +fido_cred_set_clientdata 12 12 0.00% 11 11 0.00% +fido_cred_set_clientdata_hash 8 0 100.00% 6 0 100.00% +fido_cred_set_rp 18 0 100.00% 22 0 100.00% +fido_cred_set_user 32 0 100.00% 41 0 100.00% +fido_cred_set_extensions 16 0 100.00% 10 0 100.00% +fido_cred_set_options 6 6 0.00% 5 5 0.00% +fido_cred_set_rk 2 0 100.00% 4 0 100.00% +fido_cred_set_uv 2 0 100.00% 4 0 100.00% +fido_cred_set_prot 21 0 100.00% 14 0 100.00% +fido_cred_set_pin_minlen 7 0 100.00% 8 0 100.00% +fido_cred_set_blob 13 2 84.62% 8 1 87.50% +fido_cred_set_fmt 20 4 80.00% 12 1 91.67% +fido_cred_set_type 17 0 100.00% 7 0 100.00% fido_cred_type 1 0 100.00% 3 0 100.00% fido_cred_flags 1 0 100.00% 3 0 100.00% fido_cred_sigcount 1 0 100.00% 3 0 100.00% fido_cred_clientdata_hash_ptr 1 0 100.00% 3 0 100.00% fido_cred_clientdata_hash_len 1 0 100.00% 3 0 100.00% fido_cred_x5c_ptr 1 0 100.00% 3 0 100.00% fido_cred_x5c_len 1 0 100.00% 3 0 100.00% fido_cred_sig_ptr 1 0 100.00% 3 0 100.00% fido_cred_sig_len 1 0 100.00% 3 0 100.00% fido_cred_authdata_ptr 1 0 100.00% 3 0 100.00% fido_cred_authdata_len 1 0 100.00% 3 0 100.00% fido_cred_authdata_raw_ptr 1 0 100.00% 3 0 100.00% fido_cred_authdata_raw_len 1 0 100.00% 3 0 100.00% -fido_cred_pubkey_ptr 9 0 100.00% 20 0 100.00% -fido_cred_pubkey_len 9 0 100.00% 20 0 100.00% +fido_cred_attstmt_ptr 1 0 100.00% 3 0 100.00% +fido_cred_attstmt_len 1 0 100.00% 3 0 100.00% +fido_cred_pubkey_ptr 9 0 100.00% 18 0 100.00% +fido_cred_pubkey_len 9 0 100.00% 18 0 100.00% fido_cred_id_ptr 1 0 100.00% 3 0 100.00% fido_cred_id_len 1 0 100.00% 3 0 100.00% fido_cred_aaguid_ptr 1 0 100.00% 3 0 100.00% fido_cred_aaguid_len 1 0 100.00% 3 0 100.00% fido_cred_prot 1 0 100.00% 3 0 100.00% +fido_cred_pin_minlen 1 0 100.00% 3 0 100.00% fido_cred_fmt 1 0 100.00% 3 0 100.00% fido_cred_rp_id 1 0 100.00% 3 0 100.00% fido_cred_rp_name 1 0 100.00% 3 0 100.00% fido_cred_user_name 1 0 100.00% 3 0 100.00% fido_cred_display_name 1 0 100.00% 3 0 100.00% fido_cred_user_id_ptr 1 0 100.00% 3 0 100.00% fido_cred_user_id_len 1 0 100.00% 3 0 100.00% fido_cred_largeblob_key_ptr 1 0 100.00% 3 0 100.00% fido_cred_largeblob_key_len 1 0 100.00% 3 0 100.00% -cred.c:fido_dev_make_cred_wait 10 0 100.00% 9 0 100.00% -cred.c:fido_dev_make_cred_tx 64 0 100.00% 85 0 100.00% -cred.c:fido_dev_make_cred_rx 19 0 100.00% 27 0 100.00% -cred.c:parse_makecred_reply 14 0 100.00% 29 0 100.00% -cred.c:check_extensions 2 0 100.00% 9 0 100.00% -cred.c:get_signed_hash_u2f 22 0 100.00% 20 0 100.00% -cred.c:verify_sig 27 2 92.59% 40 7 82.50% -cred.c:fido_cred_clean_authdata 1 0 100.00% 9 0 100.00% ------------------------------------------------------------------------------------------ -TOTAL 581 38 93.46% 872 48 94.50% +cred.c:fido_dev_make_cred_wait 10 0 100.00% 7 0 100.00% +cred.c:fido_dev_make_cred_tx 64 0 100.00% 70 0 100.00% +cred.c:fido_dev_make_cred_rx 29 0 100.00% 32 0 100.00% +cred.c:parse_makecred_reply 14 0 100.00% 27 0 100.00% +cred.c:check_extensions 2 0 100.00% 6 0 100.00% +cred.c:get_signed_hash_u2f 27 0 100.00% 26 0 100.00% +cred.c:verify_attstmt 23 2 91.30% 40 5 87.50% +cred.c:fido_cred_clean_authdata 1 0 100.00% 8 0 100.00% +cred.c:fido_cred_clean_attstmt 1 0 100.00% 8 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 632 34 94.62% 830 36 95.66% File '/libfido2/src/credman.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ -fido_credman_get_dev_metadata 1 0 100.00% 3 0 100.00% -fido_credman_get_dev_rk 1 0 100.00% 3 0 100.00% -fido_credman_del_dev_rk 1 0 100.00% 3 0 100.00% -fido_credman_get_dev_rp 1 0 100.00% 3 0 100.00% -fido_credman_set_dev_rk 1 0 100.00% 3 0 100.00% +------------------------------------------------------------------------------------------------------------------- +fido_credman_get_dev_metadata 1 0 100.00% 4 0 100.00% +fido_credman_get_dev_rk 1 0 100.00% 4 0 100.00% +fido_credman_del_dev_rk 1 0 100.00% 4 0 100.00% +fido_credman_get_dev_rp 1 0 100.00% 4 0 100.00% +fido_credman_set_dev_rk 1 0 100.00% 4 0 100.00% fido_credman_rk_new 1 0 100.00% 3 0 100.00% -fido_credman_rk_free 6 1 83.33% 10 0 100.00% +fido_credman_rk_free 6 1 83.33% 8 0 100.00% fido_credman_rk_count 1 0 100.00% 3 0 100.00% -fido_credman_rk 4 0 100.00% 6 0 100.00% +fido_credman_rk 4 0 100.00% 5 0 100.00% fido_credman_metadata_new 1 0 100.00% 3 0 100.00% -fido_credman_metadata_free 6 1 83.33% 9 0 100.00% +fido_credman_metadata_free 6 1 83.33% 7 0 100.00% fido_credman_rk_existing 1 0 100.00% 3 0 100.00% fido_credman_rk_remaining 1 0 100.00% 3 0 100.00% fido_credman_rp_new 1 0 100.00% 3 0 100.00% -fido_credman_rp_free 6 1 83.33% 10 0 100.00% +fido_credman_rp_free 6 1 83.33% 8 0 100.00% fido_credman_rp_count 1 0 100.00% 3 0 100.00% -fido_credman_rp_id 4 0 100.00% 6 0 100.00% -fido_credman_rp_name 4 0 100.00% 6 0 100.00% -fido_credman_rp_id_hash_len 4 0 100.00% 6 0 100.00% -fido_credman_rp_id_hash_ptr 4 0 100.00% 6 0 100.00% -credman.c:credman_get_metadata_wait 11 0 100.00% 10 0 100.00% -credman.c:credman_tx 36 0 100.00% 60 0 100.00% -credman.c:credman_prepare_hmac 31 1 96.77% 56 2 96.43% -credman.c:credman_rx_metadata 11 0 100.00% 21 0 100.00% -credman.c:credman_parse_metadata 9 0 100.00% 19 0 100.00% -credman.c:credman_get_rk_wait 27 0 100.00% 28 0 100.00% -credman.c:credman_rx_rk 19 0 100.00% 36 0 100.00% -credman.c:credman_parse_rk_count 16 0 100.00% 25 0 100.00% -credman.c:credman_grow_array 17 2 88.24% 28 5 82.14% -credman.c:credman_parse_rk 23 0 100.00% 33 0 100.00% -credman.c:credman_rx_next_rk 15 2 86.67% 26 4 84.62% -credman.c:credman_del_rk_wait 16 0 100.00% 20 0 100.00% -credman.c:credman_get_rp_wait 23 0 100.00% 18 0 100.00% -credman.c:credman_rx_rp 19 0 100.00% 36 0 100.00% -credman.c:credman_parse_rp_count 16 0 100.00% 25 0 100.00% -credman.c:credman_parse_rp 9 0 100.00% 19 0 100.00% -credman.c:credman_rx_next_rp 15 2 86.67% 26 4 84.62% -credman.c:credman_set_dev_rk_wait 11 0 100.00% 10 0 100.00% -credman.c:credman_reset_rk 4 0 100.00% 10 0 100.00% -credman.c:credman_reset_rp 4 0 100.00% 13 0 100.00% ------------------------------------------------------------------------------------------ -TOTAL 382 10 97.38% 614 15 97.56% +fido_credman_rp_id 4 0 100.00% 5 0 100.00% +fido_credman_rp_name 4 0 100.00% 5 0 100.00% +fido_credman_rp_id_hash_len 4 0 100.00% 5 0 100.00% +fido_credman_rp_id_hash_ptr 4 0 100.00% 5 0 100.00% +credman.c:credman_get_metadata_wait 11 0 100.00% 8 0 100.00% +credman.c:credman_tx 36 0 100.00% 50 0 100.00% +credman.c:credman_prepare_hmac 31 1 96.77% 50 2 96.00% +credman.c:credman_rx_metadata 11 0 100.00% 17 0 100.00% +credman.c:credman_parse_metadata 9 0 100.00% 17 0 100.00% +credman.c:credman_get_rk_wait 27 0 100.00% 23 0 100.00% +credman.c:credman_rx_rk 19 0 100.00% 27 0 100.00% +credman.c:credman_parse_rk_count 16 0 100.00% 20 0 100.00% +credman.c:credman_grow_array 17 2 88.24% 21 5 76.19% +credman.c:credman_parse_rk 23 0 100.00% 31 0 100.00% +credman.c:credman_rx_next_rk 15 2 86.67% 21 4 80.95% +credman.c:credman_del_rk_wait 16 0 100.00% 15 0 100.00% +credman.c:credman_get_rp_wait 23 0 100.00% 15 0 100.00% +credman.c:credman_rx_rp 19 0 100.00% 27 0 100.00% +credman.c:credman_parse_rp_count 16 0 100.00% 20 0 100.00% +credman.c:credman_parse_rp 9 0 100.00% 17 0 100.00% +credman.c:credman_rx_next_rp 15 2 86.67% 21 4 80.95% +credman.c:credman_set_dev_rk_wait 11 0 100.00% 8 0 100.00% +credman.c:credman_reset_rk 4 0 100.00% 9 0 100.00% +credman.c:credman_reset_rp 4 0 100.00% 12 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 382 10 97.38% 518 15 97.10% File '/libfido2/src/dev.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ -fido_dev_register_manifest_func 10 2 80.00% 18 3 83.33% -fido_dev_unregister_manifest_func 7 7 0.00% 13 13 0.00% -fido_dev_info_manifest 22 4 81.82% 28 0 100.00% +------------------------------------------------------------------------------------------------------------------- +fido_dev_register_manifest_func 10 2 80.00% 14 3 78.57% +fido_dev_unregister_manifest_func 7 7 0.00% 11 11 0.00% +fido_dev_info_manifest 22 4 81.82% 24 0 100.00% fido_dev_open_with_info 5 5 0.00% 6 6 0.00% -fido_dev_open 11 5 54.55% 26 12 53.85% -fido_dev_close 9 2 77.78% 10 0 100.00% -fido_dev_set_sigmask 12 12 0.00% 10 10 0.00% +fido_dev_open 5 1 80.00% 19 12 36.84% +fido_dev_close 9 2 77.78% 8 0 100.00% +fido_dev_set_sigmask 18 18 0.00% 11 11 0.00% fido_dev_cancel 11 0 100.00% 8 0 100.00% -fido_dev_get_touch_begin 50 0 100.00% 68 0 100.00% -fido_dev_get_touch_status 17 0 100.00% 25 0 100.00% -fido_dev_set_io_functions 18 4 77.78% 17 6 64.71% -fido_dev_set_transport_functions 6 2 66.67% 11 3 72.73% -fido_init 8 1 87.50% 6 0 100.00% -fido_dev_new 5 0 100.00% 16 0 100.00% -fido_dev_new_with_info 10 10 0.00% 20 20 0.00% -fido_dev_free 6 0 100.00% 11 0 100.00% +fido_dev_get_touch_begin 50 0 100.00% 59 0 100.00% +fido_dev_get_touch_status 17 0 100.00% 20 0 100.00% +fido_dev_set_io_functions 18 4 77.78% 14 6 57.14% +fido_dev_set_transport_functions 6 2 66.67% 9 3 66.67% +fido_init 8 1 87.50% 5 0 100.00% +fido_dev_new 5 0 100.00% 14 0 100.00% +fido_dev_new_with_info 10 10 0.00% 16 16 0.00% +fido_dev_free 6 0 100.00% 8 0 100.00% fido_dev_protocol 1 0 100.00% 3 0 100.00% fido_dev_major 1 0 100.00% 3 0 100.00% fido_dev_minor 1 0 100.00% 3 0 100.00% fido_dev_build 1 0 100.00% 3 0 100.00% fido_dev_flags 1 0 100.00% 3 0 100.00% fido_dev_is_fido2 2 0 100.00% 3 0 100.00% fido_dev_is_winhello 2 2 0.00% 3 3 0.00% fido_dev_supports_pin 3 0 100.00% 3 0 100.00% fido_dev_has_pin 2 0 100.00% 3 0 100.00% fido_dev_supports_cred_prot 2 0 100.00% 3 0 100.00% fido_dev_supports_credman 2 0 100.00% 3 0 100.00% fido_dev_supports_uv 3 0 100.00% 3 0 100.00% fido_dev_has_uv 2 0 100.00% 3 0 100.00% fido_dev_supports_permissions 2 0 100.00% 3 0 100.00% fido_dev_force_u2f 2 0 100.00% 4 0 100.00% fido_dev_force_fido2 2 2 0.00% 3 3 0.00% -fido_dev_get_pin_protocol 11 0 100.00% 8 0 100.00% +fido_dev_get_pin_protocol 11 0 100.00% 7 0 100.00% fido_dev_maxmsgsize 1 0 100.00% 3 0 100.00% -dev.c:find_manifest_func_node 5 0 100.00% 9 0 100.00% -dev.c:fido_dev_open_wait 10 0 100.00% 9 0 100.00% -dev.c:fido_dev_open_tx 56 15 73.21% 67 26 61.19% +fido_dev_set_timeout 6 2 66.67% 6 1 83.33% +dev.c:find_manifest_func_node 5 0 100.00% 8 0 100.00% +dev.c:fido_dev_open_wait 10 0 100.00% 7 0 100.00% +dev.c:fido_dev_open_tx 56 15 73.21% 56 26 53.57% dev.c:set_random_report_len 11 0 100.00% 6 0 100.00% -dev.c:fido_dev_open_rx 36 1 97.22% 62 1 98.39% +dev.c:fido_dev_open_rx 36 1 97.22% 53 1 98.11% dev.c:fido_dev_set_flags 1 0 100.00% 5 0 100.00% -dev.c:fido_dev_set_extension_flags 7 0 100.00% 8 0 100.00% -dev.c:fido_dev_set_option_flags 29 0 100.00% 19 0 100.00% -dev.c:fido_dev_set_protocol_flags 11 0 100.00% 18 0 100.00% ------------------------------------------------------------------------------------------ -TOTAL 414 74 82.13% 556 106 80.94% +dev.c:fido_dev_set_extension_flags 7 0 100.00% 7 0 100.00% +dev.c:fido_dev_set_option_flags 29 0 100.00% 18 0 100.00% +dev.c:fido_dev_set_protocol_flags 11 0 100.00% 17 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 420 78 81.43% 488 102 79.10% File '/libfido2/src/ecdh.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ -fido_do_ecdh 29 0 100.00% 40 0 100.00% -ecdh.c:do_ecdh 37 0 100.00% 48 0 100.00% -ecdh.c:kdf 19 1 94.74% 32 2 93.75% -ecdh.c:hkdf_sha256 32 1 96.88% 41 3 92.68% ------------------------------------------------------------------------------------------ -TOTAL 117 2 98.29% 161 5 96.89% +------------------------------------------------------------------------------------------------------------------- +fido_do_ecdh 29 0 100.00% 36 0 100.00% +ecdh.c:do_ecdh 37 0 100.00% 44 0 100.00% +ecdh.c:kdf 19 1 94.74% 28 2 92.86% +ecdh.c:hkdf_sha256 32 1 96.88% 38 3 92.11% +------------------------------------------------------------------------------------------------------------------- +TOTAL 117 2 98.29% 146 5 96.58% File '/libfido2/src/eddsa.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ -eddsa_pk_decode 8 0 100.00% 10 0 100.00% +------------------------------------------------------------------------------------------------------------------- +eddsa_pk_decode 8 0 100.00% 9 0 100.00% eddsa_pk_new 1 0 100.00% 3 0 100.00% -eddsa_pk_free 6 0 100.00% 9 0 100.00% -eddsa_pk_from_ptr 6 0 100.00% 8 0 100.00% -eddsa_pk_to_EVP_PKEY 3 0 100.00% 9 0 100.00% -eddsa_pk_from_EVP_PKEY 14 0 100.00% 12 0 100.00% -eddsa.c:decode_pubkey_point 8 0 100.00% 14 0 100.00% -eddsa.c:decode_coord 8 0 100.00% 12 0 100.00% ------------------------------------------------------------------------------------------ -TOTAL 54 0 100.00% 77 0 100.00% +eddsa_pk_free 6 0 100.00% 7 0 100.00% +eddsa_pk_from_ptr 6 0 100.00% 6 0 100.00% +eddsa_pk_to_EVP_PKEY 3 0 100.00% 7 0 100.00% +eddsa_pk_from_EVP_PKEY 14 0 100.00% 10 0 100.00% +eddsa_verify_sig 19 2 89.47% 30 6 80.00% +eddsa_pk_verify_sig 7 1 85.71% 13 2 84.62% +eddsa.c:decode_pubkey_point 8 0 100.00% 11 0 100.00% +eddsa.c:decode_coord 8 0 100.00% 10 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 80 3 96.25% 106 8 92.45% File '/libfido2/src/err.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------------------- fido_strerr 122 10 91.80% 126 10 92.06% ------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------------------- TOTAL 122 10 91.80% 126 10 92.06% File '/libfido2/src/es256.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ -es256_pk_decode 8 0 100.00% 10 0 100.00% -es256_pk_encode 56 0 100.00% 70 0 100.00% +------------------------------------------------------------------------------------------------------------------- +es256_pk_decode 8 0 100.00% 9 0 100.00% +es256_pk_encode 56 0 100.00% 48 0 100.00% es256_sk_new 1 0 100.00% 3 0 100.00% -es256_sk_free 6 0 100.00% 9 0 100.00% +es256_sk_free 6 0 100.00% 7 0 100.00% es256_pk_new 1 0 100.00% 3 0 100.00% -es256_pk_free 6 0 100.00% 9 0 100.00% -es256_pk_from_ptr 11 0 100.00% 13 0 100.00% -es256_pk_set_x 1 0 100.00% 5 0 100.00% -es256_pk_set_y 1 0 100.00% 5 0 100.00% -es256_sk_create 39 0 100.00% 46 0 100.00% -es256_pk_to_EVP_PKEY 42 0 100.00% 66 0 100.00% -es256_pk_from_EC_KEY 38 0 100.00% 43 0 100.00% -es256_sk_to_EVP_PKEY 28 0 100.00% 50 0 100.00% -es256_derive_pk 25 0 100.00% 34 0 100.00% -es256.c:decode_pubkey_point 9 0 100.00% 16 0 100.00% -es256.c:decode_coord 8 0 100.00% 12 0 100.00% ------------------------------------------------------------------------------------------ -TOTAL 280 0 100.00% 394 0 100.00% +es256_pk_free 6 0 100.00% 7 0 100.00% +es256_pk_from_ptr 11 0 100.00% 10 0 100.00% +es256_pk_set_x 1 0 100.00% 4 0 100.00% +es256_pk_set_y 1 0 100.00% 4 0 100.00% +es256_sk_create 39 0 100.00% 41 0 100.00% +es256_pk_to_EVP_PKEY 42 0 100.00% 54 0 100.00% +es256_pk_from_EC_KEY 38 0 100.00% 36 0 100.00% +es256_pk_from_EVP_PKEY 7 2 71.43% 7 0 100.00% +es256_sk_to_EVP_PKEY 28 0 100.00% 40 0 100.00% +es256_derive_pk 25 0 100.00% 30 0 100.00% +es256_verify_sig 12 2 83.33% 19 5 73.68% +es256_pk_verify_sig 7 1 85.71% 13 2 84.62% +es256.c:decode_pubkey_point 9 0 100.00% 13 0 100.00% +es256.c:decode_coord 8 0 100.00% 10 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 306 5 98.37% 358 7 98.04% File '/libfido2/src/extern.h': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------------------- File '/libfido2/src/fido.h': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------------------- File '/libfido2/src/hid.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ -fido_hid_get_usage 13 0 100.00% 28 0 100.00% -fido_hid_get_report_len 19 0 100.00% 33 0 100.00% +------------------------------------------------------------------------------------------------------------------- +fido_hid_get_usage 13 0 100.00% 22 0 100.00% +fido_hid_get_report_len 19 0 100.00% 27 0 100.00% fido_dev_info_new 1 0 100.00% 3 0 100.00% -fido_dev_info_free 9 0 100.00% 18 0 100.00% +fido_dev_info_free 9 0 100.00% 14 0 100.00% fido_dev_info_ptr 1 0 100.00% 3 0 100.00% fido_dev_info_path 1 0 100.00% 3 0 100.00% fido_dev_info_vendor 1 0 100.00% 3 0 100.00% fido_dev_info_product 1 0 100.00% 3 0 100.00% fido_dev_info_manufacturer_string 1 0 100.00% 3 0 100.00% fido_dev_info_product_string 1 0 100.00% 3 0 100.00% -hid.c:get_key_len 6 0 100.00% 14 0 100.00% -hid.c:get_key_val 6 0 100.00% 20 0 100.00% ------------------------------------------------------------------------------------------ -TOTAL 60 0 100.00% 134 0 100.00% +hid.c:get_key_len 6 0 100.00% 12 0 100.00% +hid.c:get_key_val 6 0 100.00% 18 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 60 0 100.00% 114 0 100.00% File '/libfido2/src/hid_linux.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ -fido_hid_manifest 35 4 88.57% 50 1 98.00% -fido_hid_open 27 27 0.00% 44 44 0.00% -fido_hid_close 3 3 0.00% 8 8 0.00% -fido_hid_set_sigmask 2 2 0.00% 8 8 0.00% -fido_hid_read 15 15 0.00% 26 26 0.00% -fido_hid_write 12 12 0.00% 21 21 0.00% -fido_hid_report_in_len 1 1 0.00% 5 5 0.00% -fido_hid_report_out_len 1 1 0.00% 5 5 0.00% -hid_linux.c:copy_info 34 0 100.00% 53 0 100.00% -hid_linux.c:is_fido 10 2 80.00% 19 2 89.47% -hid_linux.c:get_parent_attr 6 0 100.00% 11 0 100.00% -hid_linux.c:parse_uevent 12 0 100.00% 28 0 100.00% +------------------------------------------------------------------------------------------------------------------- +fido_hid_manifest 35 4 88.57% 41 1 97.56% +fido_hid_open 27 27 0.00% 40 40 0.00% +fido_hid_close 3 3 0.00% 6 6 0.00% +fido_hid_set_sigmask 2 2 0.00% 6 6 0.00% +fido_hid_read 15 15 0.00% 21 21 0.00% +fido_hid_write 12 12 0.00% 17 17 0.00% +fido_hid_report_in_len 1 1 0.00% 4 4 0.00% +fido_hid_report_out_len 1 1 0.00% 4 4 0.00% +hid_linux.c:copy_info 34 0 100.00% 44 0 100.00% +hid_linux.c:is_fido 10 2 80.00% 14 2 85.71% +hid_linux.c:get_parent_attr 6 0 100.00% 9 0 100.00% +hid_linux.c:parse_uevent 12 0 100.00% 24 0 100.00% hid_linux.c:get_usb_attr 1 0 100.00% 3 0 100.00% -hid_linux.c:get_report_descriptor 14 1 92.86% 22 3 86.36% ------------------------------------------------------------------------------------------ -TOTAL 173 68 60.69% 303 123 59.41% +hid_linux.c:get_report_descriptor 14 1 92.86% 17 3 82.35% +------------------------------------------------------------------------------------------------------------------- +TOTAL 173 68 60.69% 250 104 58.40% File '/libfido2/src/hid_unix.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ -fido_hid_unix_open 18 11 38.89% 26 14 46.15% -fido_hid_unix_wait 12 9 25.00% 26 14 46.15% ------------------------------------------------------------------------------------------ -TOTAL 30 20 33.33% 52 28 46.15% +------------------------------------------------------------------------------------------------------------------- +fido_hid_unix_open 18 11 38.89% 22 14 36.36% +fido_hid_unix_wait 10 9 10.00% 21 10 52.38% +------------------------------------------------------------------------------------------------------------------- +TOTAL 28 20 28.57% 43 24 44.19% File '/libfido2/src/info.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ -fido_dev_get_cbor_info_wait 10 0 100.00% 9 0 100.00% -fido_dev_get_cbor_info 1 0 100.00% 3 0 100.00% +------------------------------------------------------------------------------------------------------------------- +fido_dev_get_cbor_info_wait 10 0 100.00% 7 0 100.00% +fido_dev_get_cbor_info 1 0 100.00% 4 0 100.00% fido_cbor_info_new 1 0 100.00% 3 0 100.00% fido_cbor_info_reset 1 0 100.00% 8 0 100.00% -fido_cbor_info_free 6 0 100.00% 9 0 100.00% +fido_cbor_info_free 6 0 100.00% 8 0 100.00% fido_cbor_info_versions_ptr 1 0 100.00% 3 0 100.00% fido_cbor_info_versions_len 1 0 100.00% 3 0 100.00% fido_cbor_info_extensions_ptr 1 0 100.00% 3 0 100.00% fido_cbor_info_extensions_len 1 0 100.00% 3 0 100.00% fido_cbor_info_transports_ptr 1 0 100.00% 3 0 100.00% fido_cbor_info_transports_len 1 0 100.00% 3 0 100.00% fido_cbor_info_aaguid_ptr 1 0 100.00% 3 0 100.00% fido_cbor_info_aaguid_len 1 0 100.00% 3 0 100.00% fido_cbor_info_options_name_ptr 1 0 100.00% 3 0 100.00% fido_cbor_info_options_value_ptr 1 0 100.00% 3 0 100.00% fido_cbor_info_options_len 1 0 100.00% 3 0 100.00% fido_cbor_info_maxcredbloblen 1 0 100.00% 3 0 100.00% fido_cbor_info_maxmsgsiz 1 0 100.00% 3 0 100.00% fido_cbor_info_maxcredcntlst 1 0 100.00% 3 0 100.00% fido_cbor_info_maxcredidlen 1 0 100.00% 3 0 100.00% fido_cbor_info_fwversion 1 0 100.00% 3 0 100.00% fido_cbor_info_protocols_ptr 1 0 100.00% 3 0 100.00% fido_cbor_info_protocols_len 1 0 100.00% 3 0 100.00% fido_cbor_info_algorithm_count 1 0 100.00% 3 0 100.00% -fido_cbor_info_algorithm_type 4 0 100.00% 6 0 100.00% -fido_cbor_info_algorithm_cose 4 0 100.00% 6 0 100.00% -info.c:fido_dev_get_cbor_info_tx 8 0 100.00% 12 0 100.00% -info.c:fido_dev_get_cbor_info_rx 6 0 100.00% 18 0 100.00% -info.c:parse_reply_element 19 0 100.00% 39 0 100.00% -info.c:decode_string_array 12 0 100.00% 21 0 100.00% -info.c:decode_string 4 0 100.00% 14 0 100.00% -info.c:decode_aaguid 8 0 100.00% 12 0 100.00% -info.c:decode_options 11 0 100.00% 18 0 100.00% -info.c:decode_option 11 0 100.00% 22 0 100.00% -info.c:decode_protocols 12 0 100.00% 21 0 100.00% -info.c:decode_protocol 6 0 100.00% 16 0 100.00% -info.c:decode_algorithms 12 0 100.00% 21 0 100.00% -info.c:decode_algorithm 9 0 100.00% 23 0 100.00% -info.c:decode_algorithm_entry 20 0 100.00% 31 0 100.00% -info.c:free_algo 1 0 100.00% 5 0 100.00% -info.c:free_str_array 4 0 100.00% 8 0 100.00% -info.c:free_opt_array 4 0 100.00% 9 0 100.00% -info.c:free_byte_array 1 0 100.00% 6 0 100.00% -info.c:free_algo_array 4 0 100.00% 8 0 100.00% ------------------------------------------------------------------------------------------ -TOTAL 198 0 100.00% 405 0 100.00% +fido_cbor_info_algorithm_type 4 0 100.00% 5 0 100.00% +fido_cbor_info_algorithm_cose 4 0 100.00% 5 0 100.00% +info.c:fido_dev_get_cbor_info_tx 8 0 100.00% 9 0 100.00% +info.c:fido_dev_get_cbor_info_rx 6 0 100.00% 14 0 100.00% +info.c:parse_reply_element 19 0 100.00% 37 0 100.00% +info.c:decode_string_array 12 0 100.00% 17 0 100.00% +info.c:decode_string 4 0 100.00% 10 0 100.00% +info.c:decode_aaguid 8 0 100.00% 10 0 100.00% +info.c:decode_options 11 0 100.00% 15 0 100.00% +info.c:decode_option 11 0 100.00% 17 0 100.00% +info.c:decode_protocols 12 0 100.00% 17 0 100.00% +info.c:decode_protocol 6 0 100.00% 12 0 100.00% +info.c:decode_algorithms 12 0 100.00% 17 0 100.00% +info.c:decode_algorithm 9 0 100.00% 17 0 100.00% +info.c:decode_algorithm_entry 20 0 100.00% 27 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 184 0 100.00% 316 0 100.00% File '/libfido2/src/io.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ -fido_tx 13 0 100.00% 13 0 100.00% -fido_rx 13 1 92.31% 17 3 82.35% -fido_rx_cbor_status 8 0 100.00% 12 0 100.00% -io.c:tx_empty 9 0 100.00% 17 0 100.00% -io.c:tx 13 0 100.00% 21 0 100.00% -io.c:tx_preamble 16 1 93.75% 24 1 95.83% -io.c:tx_frame 15 1 93.33% 22 1 95.45% -io.c:rx 40 2 95.00% 65 1 98.46% -io.c:rx_preamble 23 2 91.30% 26 5 80.77% -io.c:rx_frame 8 0 100.00% 11 0 100.00% ------------------------------------------------------------------------------------------ -TOTAL 158 7 95.57% 228 11 95.18% +------------------------------------------------------------------------------------------------------------------- +fido_tx 13 0 100.00% 11 0 100.00% +fido_rx 13 1 92.31% 14 3 78.57% +fido_rx_cbor_status 8 0 100.00% 10 0 100.00% +io.c:transport_tx 7 0 100.00% 10 0 100.00% +io.c:tx_empty 9 0 100.00% 14 0 100.00% +io.c:tx_pkt 7 0 100.00% 10 0 100.00% +io.c:tx 13 0 100.00% 19 0 100.00% +io.c:tx_preamble 16 1 93.75% 20 1 95.00% +io.c:tx_frame 15 1 93.33% 18 1 94.44% +io.c:transport_rx 7 0 100.00% 10 0 100.00% +io.c:rx 40 2 95.00% 52 1 98.08% +io.c:rx_preamble 23 2 91.30% 22 5 77.27% +io.c:rx_frame 11 0 100.00% 11 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 182 7 96.15% 221 11 95.02% File '/libfido2/src/iso7816.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ -iso7816_new 4 0 100.00% 18 0 100.00% -iso7816_free 6 0 100.00% 8 0 100.00% -iso7816_add 6 1 83.33% 9 0 100.00% +------------------------------------------------------------------------------------------------------------------- +iso7816_new 4 0 100.00% 16 0 100.00% +iso7816_free 6 0 100.00% 7 0 100.00% +iso7816_add 6 1 83.33% 8 0 100.00% iso7816_ptr 1 0 100.00% 3 0 100.00% iso7816_len 1 0 100.00% 4 0 100.00% ------------------------------------------------------------------------------------------ -TOTAL 18 1 94.44% 42 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 18 1 94.44% 38 0 100.00% File '/libfido2/src/largeblob.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ -fido_dev_largeblob_get 26 2 92.31% 41 4 90.24% -fido_dev_largeblob_set 27 0 100.00% 39 0 100.00% -fido_dev_largeblob_remove 12 0 100.00% 21 0 100.00% -fido_dev_largeblob_get_array 15 2 86.67% 30 4 86.67% -fido_dev_largeblob_set_array 14 0 100.00% 21 0 100.00% -largeblob.c:largeblob_get_array 32 0 100.00% 39 0 100.00% -largeblob.c:get_chunklen 9 1 88.89% 11 0 100.00% -largeblob.c:largeblob_get_tx 19 0 100.00% 28 0 100.00% -largeblob.c:largeblob_get_rx 15 0 100.00% 23 0 100.00% -largeblob.c:parse_largeblob_reply 8 0 100.00% 10 0 100.00% -largeblob.c:largeblob_array_check 7 0 100.00% 18 0 100.00% -largeblob.c:largeblob_array_digest 10 0 100.00% 11 0 100.00% -largeblob.c:largeblob_array_load 14 2 85.71% 21 7 66.67% -largeblob.c:largeblob_array_lookup 25 0 100.00% 36 0 100.00% -largeblob.c:largeblob_decode 16 2 87.50% 17 6 64.71% -largeblob.c:largeblob_do_decode 27 3 88.89% 32 5 84.38% -largeblob.c:largeblob_decrypt 15 0 100.00% 28 0 100.00% -largeblob.c:largeblob_aad 1 0 100.00% 12 0 100.00% +------------------------------------------------------------------------------------------------------------------- +fido_dev_largeblob_get 26 2 92.31% 38 4 89.47% +fido_dev_largeblob_set 27 2 92.59% 36 4 88.89% +fido_dev_largeblob_remove 12 0 100.00% 18 0 100.00% +fido_dev_largeblob_get_array 15 2 86.67% 27 4 85.19% +fido_dev_largeblob_set_array 14 0 100.00% 19 0 100.00% +largeblob.c:largeblob_get_array 32 0 100.00% 36 0 100.00% +largeblob.c:get_chunklen 9 1 88.89% 9 0 100.00% +largeblob.c:largeblob_get_tx 19 0 100.00% 24 0 100.00% +largeblob.c:largeblob_get_rx 15 0 100.00% 21 0 100.00% +largeblob.c:parse_largeblob_reply 8 0 100.00% 9 0 100.00% +largeblob.c:largeblob_array_check 7 0 100.00% 16 0 100.00% +largeblob.c:largeblob_array_digest 10 0 100.00% 9 0 100.00% +largeblob.c:largeblob_array_load 14 2 85.71% 19 7 63.16% +largeblob.c:largeblob_array_lookup 25 0 100.00% 33 0 100.00% +largeblob.c:largeblob_decode 16 2 87.50% 16 6 62.50% +largeblob.c:largeblob_do_decode 27 3 88.89% 30 5 83.33% +largeblob.c:largeblob_decrypt 15 0 100.00% 24 0 100.00% +largeblob.c:largeblob_aad 1 0 100.00% 10 0 100.00% largeblob.c:largeblob_reset 1 0 100.00% 5 0 100.00% -largeblob.c:largeblob_encode 16 0 100.00% 23 0 100.00% +largeblob.c:largeblob_encode 16 0 100.00% 21 0 100.00% largeblob.c:largeblob_new 1 0 100.00% 3 0 100.00% -largeblob.c:largeblob_seal 20 0 100.00% 35 0 100.00% -largeblob.c:largeblob_get_nonce 8 1 87.50% 19 3 84.21% -largeblob.c:largeblob_free 6 0 100.00% 9 0 100.00% -largeblob.c:largeblob_add 27 2 92.59% 40 3 92.50% -largeblob.c:largeblob_drop 21 0 100.00% 30 0 100.00% -largeblob.c:largeblob_set_array 54 2 96.30% 64 4 93.75% -largeblob.c:largeblob_get_uv_token 19 0 100.00% 27 0 100.00% -largeblob.c:largeblob_set_tx 35 0 100.00% 40 0 100.00% -largeblob.c:prepare_hmac 13 2 84.62% 26 7 73.08% ------------------------------------------------------------------------------------------ -TOTAL 513 19 96.30% 759 43 94.33% +largeblob.c:largeblob_seal 20 0 100.00% 32 0 100.00% +largeblob.c:largeblob_get_nonce 8 1 87.50% 16 3 81.25% +largeblob.c:largeblob_free 6 0 100.00% 8 0 100.00% +largeblob.c:largeblob_add 27 2 92.59% 35 3 91.43% +largeblob.c:largeblob_drop 21 0 100.00% 27 0 100.00% +largeblob.c:largeblob_set_array 54 2 96.30% 61 4 93.44% +largeblob.c:largeblob_get_uv_token 19 0 100.00% 23 0 100.00% +largeblob.c:largeblob_set_tx 35 0 100.00% 36 0 100.00% +largeblob.c:prepare_hmac 13 2 84.62% 23 7 69.57% +------------------------------------------------------------------------------------------------------------------- +TOTAL 513 21 95.91% 684 47 93.13% File '/libfido2/src/log.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------------------- fido_log_init 1 0 100.00% 4 0 100.00% -fido_log_debug 6 1 83.33% 10 0 100.00% -fido_log_xxd 16 1 93.75% 27 0 100.00% -fido_log_error 8 2 75.00% 13 1 92.31% +fido_log_debug 6 1 83.33% 8 0 100.00% +fido_log_xxd 16 1 93.75% 24 0 100.00% +fido_log_error 8 2 75.00% 11 1 90.91% fido_set_log_handler 3 0 100.00% 4 0 100.00% log.c:log_on_stderr 1 1 0.00% 3 3 0.00% -log.c:do_log 4 0 100.00% 12 0 100.00% ------------------------------------------------------------------------------------------ -TOTAL 39 5 87.18% 73 4 94.52% +log.c:do_log 4 0 100.00% 9 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 39 5 87.18% 63 4 93.65% File '/libfido2/src/netlink.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ -fido_nl_power_nfc 18 1 94.44% 26 3 88.46% -fido_nl_get_nfc_target 16 1 93.75% 33 3 90.91% -fido_nl_free 10 2 80.00% 11 1 90.91% -fido_nl_new 16 2 87.50% 29 6 79.31% +------------------------------------------------------------------------------------------------------------------- +fido_nl_power_nfc 18 1 94.44% 24 3 87.50% +fido_nl_get_nfc_target 17 1 94.12% 31 3 90.32% +fido_nl_free 10 2 80.00% 9 1 88.89% +fido_nl_new 16 1 93.75% 26 3 88.46% set_netlink_io_functions 1 0 100.00% 4 0 100.00% -netlink.c:nlmsg_new 8 0 100.00% 18 0 100.00% -netlink.c:nlmsg_set_genl 1 0 100.00% 9 0 100.00% -netlink.c:nlmsg_write 6 1 83.33% 9 1 88.89% +netlink.c:nlmsg_new 8 0 100.00% 15 0 100.00% +netlink.c:nlmsg_set_genl 1 0 100.00% 7 0 100.00% +netlink.c:nlmsg_write 6 1 83.33% 7 1 85.71% netlink.c:nlmsg_set_u32 1 0 100.00% 3 0 100.00% -netlink.c:nlmsg_setattr 14 1 92.86% 21 0 100.00% -netlink.c:nlmsg_tx 10 1 90.00% 15 3 80.00% +netlink.c:nlmsg_setattr 14 1 92.86% 17 0 100.00% +netlink.c:nlmsg_tx 10 1 90.00% 13 3 76.92% netlink.c:nlmsg_ptr 1 0 100.00% 3 0 100.00% netlink.c:nlmsg_len 1 0 100.00% 3 0 100.00% -netlink.c:nlmsg_rx 11 3 72.73% 19 9 52.63% -netlink.c:nl_parse_reply 20 0 100.00% 30 0 100.00% -netlink.c:nlmsg_from_buf 15 0 100.00% 22 0 100.00% +netlink.c:nlmsg_rx 11 3 72.73% 17 9 47.06% +netlink.c:nl_parse_reply 20 0 100.00% 28 0 100.00% +netlink.c:nlmsg_from_buf 15 0 100.00% 17 0 100.00% netlink.c:nlmsg_type 1 0 100.00% 3 0 100.00% -netlink.c:nlmsg_get_status 8 0 100.00% 10 0 100.00% -netlink.c:nlmsg_read 6 0 100.00% 9 0 100.00% -netlink.c:nlmsg_get_genl 6 0 100.00% 10 0 100.00% -netlink.c:nlmsg_iter 6 0 100.00% 15 0 100.00% +netlink.c:nlmsg_get_status 8 0 100.00% 8 0 100.00% +netlink.c:nlmsg_read 6 0 100.00% 7 0 100.00% +netlink.c:nlmsg_get_genl 6 0 100.00% 7 0 100.00% +netlink.c:nlmsg_iter 6 0 100.00% 13 0 100.00% netlink.c:nlmsg_getattr 1 0 100.00% 3 0 100.00% -netlink.c:nla_from_buf 17 0 100.00% 26 0 100.00% -netlink.c:nl_nfc_poll 18 1 94.44% 27 3 88.89% -netlink.c:parse_nfc_event 10 0 100.00% 19 0 100.00% +netlink.c:nla_from_buf 17 0 100.00% 21 0 100.00% +netlink.c:nl_nfc_poll 18 1 94.44% 25 3 88.00% +netlink.c:parse_nfc_event 10 0 100.00% 17 0 100.00% netlink.c:nla_type 1 0 100.00% 3 0 100.00% netlink.c:nla_get_u32 1 0 100.00% 3 0 100.00% -netlink.c:nla_read 6 0 100.00% 9 0 100.00% -netlink.c:nl_dump_nfc_target 19 1 94.74% 33 3 90.91% -netlink.c:parse_target 9 0 100.00% 15 0 100.00% -netlink.c:nl_get_nfc_family 23 1 95.65% 35 3 91.43% +netlink.c:nla_read 6 0 100.00% 7 0 100.00% +netlink.c:nl_dump_nfc_target 19 1 94.74% 31 3 90.32% +netlink.c:parse_target 9 0 100.00% 13 0 100.00% +netlink.c:nl_get_nfc_family 23 1 95.65% 33 3 90.91% netlink.c:nlmsg_set_u16 1 0 100.00% 3 0 100.00% netlink.c:nlmsg_set_str 1 0 100.00% 3 0 100.00% -netlink.c:parse_family 10 0 100.00% 20 0 100.00% +netlink.c:parse_family 10 0 100.00% 17 0 100.00% netlink.c:nla_get_u16 1 0 100.00% 3 0 100.00% -netlink.c:nla_iter 6 0 100.00% 15 0 100.00% +netlink.c:nla_iter 6 0 100.00% 13 0 100.00% netlink.c:nla_getattr 1 0 100.00% 3 0 100.00% netlink.c:parse_mcastgrps 1 0 100.00% 3 0 100.00% -netlink.c:parse_mcastgrp 15 0 100.00% 27 0 100.00% -netlink.c:nla_get_str 10 0 100.00% 13 0 100.00% ------------------------------------------------------------------------------------------ -TOTAL 327 15 95.41% 565 35 93.81% +netlink.c:parse_mcastgrp 15 0 100.00% 24 0 100.00% +netlink.c:nla_get_str 10 0 100.00% 11 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 328 14 95.73% 498 32 93.57% File '/libfido2/src/nfc_linux.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------ -fido_nfc_tx 28 0 100.00% 48 0 100.00% +------------------------------------------------------------------------------------------------------------------- +fido_nfc_tx 28 0 100.00% 43 0 100.00% fido_nfc_rx 8 1 87.50% 13 3 76.92% -fido_nfc_manifest 35 2 94.29% 54 0 100.00% -fido_nfc_open 14 14 0.00% 21 21 0.00% -fido_nfc_close 1 1 0.00% 5 5 0.00% -fido_nfc_set_sigmask 2 2 0.00% 8 8 0.00% -fido_nfc_read 14 14 0.00% 34 34 0.00% -fido_nfc_write 12 12 0.00% 21 21 0.00% -nfc_linux.c:nfc_do_tx 20 2 90.00% 30 6 80.00% -nfc_linux.c:tx_short_apdu 14 0 100.00% 37 0 100.00% -nfc_linux.c:rx_init 25 6 76.00% 34 5 85.29% -nfc_linux.c:rx_cbor 4 0 100.00% 8 0 100.00% -nfc_linux.c:rx_msg 18 2 88.89% 28 6 78.57% -nfc_linux.c:rx_apdu 8 1 87.50% 22 3 86.36% -nfc_linux.c:tx_get_response 4 0 100.00% 14 0 100.00% -nfc_linux.c:copy_info 30 6 80.00% 42 0 100.00% +fido_nfc_manifest 35 5 85.71% 45 13 71.11% +fido_nfc_open 20 3 85.00% 23 5 78.26% +fido_nfc_close 1 1 0.00% 4 4 0.00% +fido_nfc_set_sigmask 2 2 0.00% 6 6 0.00% +fido_nfc_read 14 14 0.00% 30 30 0.00% +fido_nfc_write 12 12 0.00% 18 18 0.00% +nfc_linux.c:nfc_do_tx 20 2 90.00% 25 6 76.00% +nfc_linux.c:tx_short_apdu 14 0 100.00% 32 0 100.00% +nfc_linux.c:rx_init 25 6 76.00% 27 5 81.48% +nfc_linux.c:rx_cbor 4 0 100.00% 6 0 100.00% +nfc_linux.c:rx_msg 18 2 88.89% 23 6 73.91% +nfc_linux.c:rx_apdu 14 1 92.86% 22 3 86.36% +nfc_linux.c:tx_get_response 4 0 100.00% 11 0 100.00% +nfc_linux.c:copy_info 41 9 78.05% 44 3 93.18% nfc_linux.c:get_usb_attr 1 0 100.00% 3 0 100.00% -nfc_linux.c:get_parent_attr 6 0 100.00% 11 0 100.00% -nfc_linux.c:to_int 21 21 0.00% 16 16 0.00% -nfc_linux.c:sysnum_from_syspath 12 12 0.00% 20 20 0.00% -nfc_linux.c:nfc_new 6 6 0.00% 14 14 0.00% -nfc_linux.c:nfc_target_connect 9 9 0.00% 24 24 0.00% -nfc_linux.c:nfc_free 12 12 0.00% 13 13 0.00% ------------------------------------------------------------------------------------------ -TOTAL 304 123 59.54% 520 199 61.73% +nfc_linux.c:get_parent_attr 6 0 100.00% 9 0 100.00% +nfc_linux.c:to_int 21 6 71.43% 14 1 92.86% +nfc_linux.c:sysnum_from_syspath 12 0 100.00% 17 0 100.00% +nfc_linux.c:nfc_new 6 0 100.00% 11 0 100.00% +nfc_linux.c:nfc_target_connect 9 9 0.00% 21 21 0.00% +nfc_linux.c:nfc_free 12 0 100.00% 11 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 327 73 77.68% 458 124 72.93% File '/libfido2/src/pin.c': Name Regions Miss Cover Lines Miss Cover -------------------------------------------------------------------------------------------- -fido_sha256 7 0 100.00% 13 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +fido_sha256 7 0 100.00% 10 0 100.00% fido_dev_get_uv_token 1 0 100.00% 3 0 100.00% -fido_dev_set_pin 1 0 100.00% 3 0 100.00% -fido_dev_get_retry_count 1 0 100.00% 3 0 100.00% -fido_dev_get_uv_retry_count 1 0 100.00% 3 0 100.00% -cbor_add_uv_params 17 0 100.00% 28 0 100.00% -pin.c:uv_token_wait 14 2 85.71% 14 0 100.00% -pin.c:ctap21_uv_token_tx 49 0 100.00% 59 0 100.00% -pin.c:pin_sha256_enc 19 0 100.00% 30 0 100.00% +fido_dev_set_pin 1 0 100.00% 4 0 100.00% +fido_dev_get_retry_count 1 0 100.00% 4 0 100.00% +fido_dev_get_uv_retry_count 1 0 100.00% 4 0 100.00% +cbor_add_uv_params 17 0 100.00% 23 0 100.00% +pin.c:uv_token_wait 14 2 85.71% 12 0 100.00% +pin.c:ctap21_uv_token_tx 49 0 100.00% 53 0 100.00% +pin.c:pin_sha256_enc 19 0 100.00% 24 0 100.00% pin.c:encode_uv_permission 20 1 95.00% 19 3 84.21% -pin.c:ctap20_uv_token_tx 37 0 100.00% 53 0 100.00% -pin.c:uv_token_rx 20 0 100.00% 36 0 100.00% -pin.c:parse_uv_token 8 0 100.00% 12 0 100.00% -pin.c:fido_dev_set_pin_wait 21 0 100.00% 27 0 100.00% -pin.c:fido_dev_change_pin_tx 45 0 100.00% 68 0 100.00% -pin.c:pin_pad64_enc 15 0 100.00% 26 0 100.00% -pin.c:pad64 18 0 100.00% 24 0 100.00% -pin.c:fido_dev_set_pin_tx 33 0 100.00% 48 0 100.00% -pin.c:fido_dev_get_pin_retry_count_wait 10 0 100.00% 9 0 100.00% -pin.c:fido_dev_get_retry_count_tx 19 0 100.00% 28 0 100.00% -pin.c:fido_dev_get_pin_retry_count_rx 11 0 100.00% 21 0 100.00% +pin.c:ctap20_uv_token_tx 37 0 100.00% 45 0 100.00% +pin.c:uv_token_rx 20 0 100.00% 30 0 100.00% +pin.c:parse_uv_token 8 0 100.00% 10 0 100.00% +pin.c:fido_dev_set_pin_wait 21 0 100.00% 24 0 100.00% +pin.c:fido_dev_change_pin_tx 45 0 100.00% 56 0 100.00% +pin.c:pin_pad64_enc 15 0 100.00% 21 0 100.00% +pin.c:pad64 18 0 100.00% 19 0 100.00% +pin.c:fido_dev_set_pin_tx 33 0 100.00% 41 0 100.00% +pin.c:fido_dev_get_pin_retry_count_wait 10 0 100.00% 7 0 100.00% +pin.c:fido_dev_get_retry_count_tx 19 0 100.00% 23 0 100.00% +pin.c:fido_dev_get_pin_retry_count_rx 11 0 100.00% 17 0 100.00% pin.c:parse_pin_retry_count 1 0 100.00% 3 0 100.00% -pin.c:parse_retry_count 13 0 100.00% 20 0 100.00% -pin.c:fido_dev_get_uv_retry_count_wait 10 0 100.00% 9 0 100.00% -pin.c:fido_dev_get_uv_retry_count_rx 11 0 100.00% 21 0 100.00% +pin.c:parse_retry_count 13 0 100.00% 16 0 100.00% +pin.c:fido_dev_get_uv_retry_count_wait 10 0 100.00% 7 0 100.00% +pin.c:fido_dev_get_uv_retry_count_rx 11 0 100.00% 17 0 100.00% pin.c:parse_uv_retry_count 1 0 100.00% 3 0 100.00% -------------------------------------------------------------------------------------------- -TOTAL 403 3 99.26% 583 3 99.49% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 403 3 99.26% 495 3 99.39% File '/libfido2/src/random.c': Name Regions Miss Cover Lines Miss Cover -------------------------------------------------------------------------------------------- -fido_get_random 6 1 83.33% 8 1 87.50% -------------------------------------------------------------------------------------------- -TOTAL 6 1 83.33% 8 1 87.50% +--------------------------------------------------------------------------------------------------------------------- +fido_get_random 6 1 83.33% 6 1 83.33% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 6 1 83.33% 6 1 83.33% File '/libfido2/src/reset.c': Name Regions Miss Cover Lines Miss Cover -------------------------------------------------------------------------------------------- -fido_dev_reset 1 0 100.00% 3 0 100.00% -reset.c:fido_dev_reset_wait 15 0 100.00% 14 0 100.00% -reset.c:fido_dev_reset_tx 8 0 100.00% 10 0 100.00% -------------------------------------------------------------------------------------------- -TOTAL 24 0 100.00% 27 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +fido_dev_reset 1 0 100.00% 4 0 100.00% +reset.c:fido_dev_reset_wait 15 0 100.00% 11 0 100.00% +reset.c:fido_dev_reset_tx 8 0 100.00% 8 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 24 0 100.00% 23 0 100.00% + +File '/libfido2/src/rs1.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +rs1_verify_sig 20 1 95.00% 30 3 90.00% +rs1.c:rs1_get_EVP_MD 4 0 100.00% 6 0 100.00% +rs1.c:rs1_free_EVP_MD 1 0 100.00% 3 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 25 1 96.00% 39 3 92.31% File '/libfido2/src/rs256.c': Name Regions Miss Cover Lines Miss Cover -------------------------------------------------------------------------------------------- -rs256_pk_decode 8 0 100.00% 10 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +rs256_pk_decode 8 0 100.00% 9 0 100.00% rs256_pk_new 1 0 100.00% 3 0 100.00% -rs256_pk_free 6 0 100.00% 9 0 100.00% -rs256_pk_from_ptr 6 0 100.00% 8 0 100.00% -rs256_pk_to_EVP_PKEY 32 0 100.00% 48 0 100.00% -rs256_pk_from_RSA 32 4 87.50% 32 6 81.25% -rs256.c:decode_rsa_pubkey 9 0 100.00% 16 0 100.00% -rs256.c:decode_bignum 8 0 100.00% 12 0 100.00% -------------------------------------------------------------------------------------------- -TOTAL 102 4 96.08% 138 6 95.65% +rs256_pk_free 6 0 100.00% 7 0 100.00% +rs256_pk_from_ptr 6 0 100.00% 6 0 100.00% +rs256_pk_to_EVP_PKEY 32 0 100.00% 39 0 100.00% +rs256_pk_from_RSA 32 4 87.50% 26 6 76.92% +rs256_pk_from_EVP_PKEY 7 2 71.43% 7 0 100.00% +rs256_verify_sig 20 1 95.00% 30 2 93.33% +rs256_pk_verify_sig 7 1 85.71% 13 2 84.62% +rs256.c:decode_rsa_pubkey 9 0 100.00% 13 0 100.00% +rs256.c:decode_bignum 8 0 100.00% 10 0 100.00% +rs256.c:rs256_get_EVP_MD 4 0 100.00% 6 0 100.00% +rs256.c:rs256_free_EVP_MD 1 0 100.00% 3 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 141 8 94.33% 172 10 94.19% + +File '/libfido2/src/time.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +fido_time_now 4 0 100.00% 7 0 100.00% +fido_time_delta 23 1 95.65% 23 0 100.00% +time.c:timespec_to_ms 16 2 87.50% 13 1 92.31% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 43 3 93.02% 43 1 97.67% + +File '/libfido2/src/tpm.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +fido_get_signed_hash_tpm 20 0 100.00% 25 0 100.00% +tpm.c:check_rsa2048_pubarea 16 0 100.00% 28 0 100.00% +tpm.c:bswap_rsa2048_pubarea 1 0 100.00% 10 0 100.00% +tpm.c:check_sha1_certinfo 14 0 100.00% 38 0 100.00% +tpm.c:get_signed_sha1 17 0 100.00% 19 0 100.00% +tpm.c:get_signed_name 7 0 100.00% 10 0 100.00% +tpm.c:bswap_sha1_certinfo 1 0 100.00% 8 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 76 0 100.00% 138 0 100.00% + +File '/libfido2/src/types.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +fido_str_array_free 4 0 100.00% 7 0 100.00% +fido_opt_array_free 4 0 100.00% 8 0 100.00% +fido_byte_array_free 1 0 100.00% 5 0 100.00% +fido_algo_free 1 0 100.00% 5 0 100.00% +fido_algo_array_free 4 0 100.00% 7 0 100.00% +fido_str_array_pack 11 0 100.00% 14 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 25 0 100.00% 46 0 100.00% File '/libfido2/src/u2f.c': Name Regions Miss Cover Lines Miss Cover -------------------------------------------------------------------------------------------- -u2f_register 70 1 98.57% 88 0 100.00% -u2f_authenticate 32 0 100.00% 44 0 100.00% -u2f_get_touch_begin 30 0 100.00% 46 0 100.00% -u2f_get_touch_status 18 0 100.00% 29 0 100.00% -u2f.c:key_lookup 44 0 100.00% 69 0 100.00% -u2f.c:send_dummy_register 31 1 96.77% 49 0 100.00% -u2f.c:parse_register_reply 49 0 100.00% 71 0 100.00% -u2f.c:x5c_get 21 1 95.24% 34 3 91.18% -u2f.c:sig_get 6 0 100.00% 11 0 100.00% -u2f.c:encode_cred_authdata 33 2 93.94% 76 6 92.11% -u2f.c:cbor_blob_from_ec_point 22 0 100.00% 39 0 100.00% -u2f.c:u2f_authenticate_single 32 0 100.00% 52 0 100.00% -u2f.c:do_auth 50 1 98.00% 71 0 100.00% -u2f.c:parse_auth_reply 23 0 100.00% 29 0 100.00% -u2f.c:authdata_fake 12 0 100.00% 34 0 100.00% -------------------------------------------------------------------------------------------- -TOTAL 473 6 98.73% 742 9 98.79% +--------------------------------------------------------------------------------------------------------------------- +u2f_register 69 0 100.00% 75 0 100.00% +u2f_authenticate 32 0 100.00% 36 0 100.00% +u2f_get_touch_begin 30 0 100.00% 39 0 100.00% +u2f_get_touch_status 18 0 100.00% 26 0 100.00% +u2f.c:key_lookup 44 0 100.00% 59 0 100.00% +u2f.c:send_dummy_register 30 0 100.00% 39 0 100.00% +u2f.c:delay_ms 13 1 92.31% 15 3 80.00% +u2f.c:parse_register_reply 49 0 100.00% 62 0 100.00% +u2f.c:x5c_get 21 1 95.24% 26 3 88.46% +u2f.c:sig_get 6 0 100.00% 10 0 100.00% +u2f.c:encode_cred_attstmt 45 0 100.00% 52 0 100.00% +u2f.c:encode_cred_authdata 33 2 93.94% 61 6 90.16% +u2f.c:cbor_blob_from_ec_point 22 0 100.00% 31 0 100.00% +u2f.c:u2f_authenticate_single 32 0 100.00% 43 0 100.00% +u2f.c:do_auth 49 0 100.00% 61 0 100.00% +u2f.c:parse_auth_reply 23 0 100.00% 23 0 100.00% +u2f.c:authdata_fake 12 0 100.00% 27 0 100.00% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 528 4 99.24% 685 12 98.25% diff --git a/contrib/libfido2/fuzz/fuzz_assert.c b/contrib/libfido2/fuzz/fuzz_assert.c index 1ecbde38bd0a..4331148b5e06 100644 --- a/contrib/libfido2/fuzz/fuzz_assert.c +++ b/contrib/libfido2/fuzz/fuzz_assert.c @@ -1,471 +1,495 @@ /* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "mutator_aux.h" #include "wiredata_fido2.h" #include "wiredata_u2f.h" #include "dummy.h" #include "../openbsd-compat/openbsd-compat.h" /* Parameter set defining a FIDO2 get assertion operation. */ struct param { char pin[MAXSTR]; char rp_id[MAXSTR]; int ext; int seed; struct blob cdh; struct blob cred; struct blob es256; struct blob rs256; struct blob eddsa; struct blob wire_data; uint8_t cred_count; uint8_t type; uint8_t opt; uint8_t up; uint8_t uv; }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * get assertion using the example parameters above. */ static const uint8_t dummy_wire_data_fido[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_AUTHKEY, WIREDATA_CTAP_CBOR_PINTOKEN, WIREDATA_CTAP_CBOR_ASSERT, }; /* * Collection of HID reports from an authenticator issued with a U2F * authentication using the example parameters above. */ static const uint8_t dummy_wire_data_u2f[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_U2F_6985, WIREDATA_CTAP_U2F_6985, WIREDATA_CTAP_U2F_6985, WIREDATA_CTAP_U2F_6985, WIREDATA_CTAP_U2F_AUTH, }; struct param * unpack(const uint8_t *ptr, size_t len) { cbor_item_t *item = NULL, **v; struct cbor_load_result cbor; struct param *p; int ok = -1; if ((p = calloc(1, sizeof(*p))) == NULL || (item = cbor_load(ptr, len, &cbor)) == NULL || cbor.read != len || cbor_isa_array(item) == false || cbor_array_is_definite(item) == false || cbor_array_size(item) != 15 || (v = cbor_array_handle(item)) == NULL) goto fail; if (unpack_byte(v[0], &p->uv) < 0 || unpack_byte(v[1], &p->up) < 0 || unpack_byte(v[2], &p->opt) < 0 || unpack_byte(v[3], &p->type) < 0 || unpack_byte(v[4], &p->cred_count) < 0 || unpack_int(v[5], &p->ext) < 0 || unpack_int(v[6], &p->seed) < 0 || unpack_string(v[7], p->rp_id) < 0 || unpack_string(v[8], p->pin) < 0 || unpack_blob(v[9], &p->wire_data) < 0 || unpack_blob(v[10], &p->rs256) < 0 || unpack_blob(v[11], &p->es256) < 0 || unpack_blob(v[12], &p->eddsa) < 0 || unpack_blob(v[13], &p->cred) < 0 || unpack_blob(v[14], &p->cdh) < 0) goto fail; ok = 0; fail: if (ok < 0) { free(p); p = NULL; } if (item) cbor_decref(&item); return p; } size_t pack(uint8_t *ptr, size_t len, const struct param *p) { cbor_item_t *argv[15], *array = NULL; size_t cbor_alloc_len, cbor_len = 0; unsigned char *cbor = NULL; memset(argv, 0, sizeof(argv)); if ((array = cbor_new_definite_array(15)) == NULL || (argv[0] = pack_byte(p->uv)) == NULL || (argv[1] = pack_byte(p->up)) == NULL || (argv[2] = pack_byte(p->opt)) == NULL || (argv[3] = pack_byte(p->type)) == NULL || (argv[4] = pack_byte(p->cred_count)) == NULL || (argv[5] = pack_int(p->ext)) == NULL || (argv[6] = pack_int(p->seed)) == NULL || (argv[7] = pack_string(p->rp_id)) == NULL || (argv[8] = pack_string(p->pin)) == NULL || (argv[9] = pack_blob(&p->wire_data)) == NULL || (argv[10] = pack_blob(&p->rs256)) == NULL || (argv[11] = pack_blob(&p->es256)) == NULL || (argv[12] = pack_blob(&p->eddsa)) == NULL || (argv[13] = pack_blob(&p->cred)) == NULL || (argv[14] = pack_blob(&p->cdh)) == NULL) goto fail; for (size_t i = 0; i < 15; i++) if (cbor_array_push(array, argv[i]) == false) goto fail; if ((cbor_len = cbor_serialize_alloc(array, &cbor, &cbor_alloc_len)) > len) { cbor_len = 0; goto fail; } memcpy(ptr, cbor, cbor_len); fail: for (size_t i = 0; i < 15; i++) if (argv[i]) cbor_decref(&argv[i]); if (array) cbor_decref(&array); free(cbor); return cbor_len; } size_t pack_dummy(uint8_t *ptr, size_t len) { struct param dummy; uint8_t blob[4096]; size_t blob_len; memset(&dummy, 0, sizeof(dummy)); dummy.type = 1; /* rsa */ dummy.ext = FIDO_EXT_HMAC_SECRET; strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); dummy.cred.len = sizeof(dummy_cdh); /* XXX */ dummy.cdh.len = sizeof(dummy_cdh); dummy.es256.len = sizeof(dummy_es256); dummy.rs256.len = sizeof(dummy_rs256); dummy.eddsa.len = sizeof(dummy_eddsa); dummy.wire_data.len = sizeof(dummy_wire_data_fido); memcpy(&dummy.cred.body, &dummy_cdh, dummy.cred.len); /* XXX */ memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, dummy.wire_data.len); memcpy(&dummy.es256.body, &dummy_es256, dummy.es256.len); memcpy(&dummy.rs256.body, &dummy_rs256, dummy.rs256.len); memcpy(&dummy.eddsa.body, &dummy_eddsa, dummy.eddsa.len); assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); if (blob_len > len) { memcpy(ptr, blob, len); return len; } memcpy(ptr, blob, blob_len); return blob_len; } static void get_assert(fido_assert_t *assert, uint8_t opt, const struct blob *cdh, const char *rp_id, int ext, uint8_t up, uint8_t uv, const char *pin, uint8_t cred_count, const struct blob *cred) { fido_dev_t *dev; if ((dev = open_dev(opt & 2)) == NULL) return; if (opt & 1) fido_dev_force_u2f(dev); if (ext & FIDO_EXT_HMAC_SECRET) fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET); if (ext & FIDO_EXT_CRED_BLOB) fido_assert_set_extensions(assert, FIDO_EXT_CRED_BLOB); if (ext & FIDO_EXT_LARGEBLOB_KEY) fido_assert_set_extensions(assert, FIDO_EXT_LARGEBLOB_KEY); if (up & 1) fido_assert_set_up(assert, FIDO_OPT_TRUE); else if (opt & 1) fido_assert_set_up(assert, FIDO_OPT_FALSE); if (uv & 1) fido_assert_set_uv(assert, FIDO_OPT_TRUE); for (uint8_t i = 0; i < cred_count; i++) fido_assert_allow_cred(assert, cred->body, cred->len); fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len); fido_assert_set_rp(assert, rp_id); /* XXX reuse cred as hmac salt */ fido_assert_set_hmac_salt(assert, cred->body, cred->len); /* repeat memory operations to trigger reallocation paths */ fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len); fido_assert_set_rp(assert, rp_id); fido_assert_set_hmac_salt(assert, cred->body, cred->len); if (strlen(pin) == 0) pin = NULL; fido_dev_get_assert(dev, assert, (opt & 1) ? NULL : pin); fido_dev_cancel(dev); fido_dev_close(dev); fido_dev_free(&dev); } static void verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len, const char *rp_id, const unsigned char *authdata_ptr, size_t authdata_len, const unsigned char *sig_ptr, size_t sig_len, uint8_t up, uint8_t uv, int ext, void *pk) { fido_assert_t *assert = NULL; + int r; if ((assert = fido_assert_new()) == NULL) return; fido_assert_set_clientdata_hash(assert, cdh_ptr, cdh_len); fido_assert_set_rp(assert, rp_id); fido_assert_set_count(assert, 1); if (fido_assert_set_authdata(assert, 0, authdata_ptr, authdata_len) != FIDO_OK) { fido_assert_set_authdata_raw(assert, 0, authdata_ptr, authdata_len); } if (up & 1) fido_assert_set_up(assert, FIDO_OPT_TRUE); if (uv & 1) fido_assert_set_uv(assert, FIDO_OPT_TRUE); fido_assert_set_extensions(assert, ext); fido_assert_set_sig(assert, 0, sig_ptr, sig_len); /* repeat memory operations to trigger reallocation paths */ if (fido_assert_set_authdata(assert, 0, authdata_ptr, authdata_len) != FIDO_OK) { fido_assert_set_authdata_raw(assert, 0, authdata_ptr, authdata_len); } fido_assert_set_sig(assert, 0, sig_ptr, sig_len); - assert(fido_assert_verify(assert, 0, type, pk) != FIDO_OK); + r = fido_assert_verify(assert, 0, type, pk); + consume(&r, sizeof(r)); fido_assert_free(&assert); } /* - * Do a dummy conversion to exercise rs256_pk_from_RSA(). + * Do a dummy conversion to exercise es256_pk_from_EVP_PKEY(). + */ +static void +es256_convert(const es256_pk_t *k) +{ + EVP_PKEY *pkey = NULL; + es256_pk_t *pk = NULL; + int r; + + if ((pkey = es256_pk_to_EVP_PKEY(k)) == NULL || + (pk = es256_pk_new()) == NULL) + goto out; + + r = es256_pk_from_EVP_PKEY(pk, pkey); + consume(&r, sizeof(r)); +out: + es256_pk_free(&pk); + EVP_PKEY_free(pkey); +} + +/* + * Do a dummy conversion to exercise rs256_pk_from_EVP_PKEY(). */ static void rs256_convert(const rs256_pk_t *k) { EVP_PKEY *pkey = NULL; rs256_pk_t *pk = NULL; - RSA *rsa = NULL; - volatile int r; + int r; if ((pkey = rs256_pk_to_EVP_PKEY(k)) == NULL || - (pk = rs256_pk_new()) == NULL || - (rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) + (pk = rs256_pk_new()) == NULL) goto out; - r = rs256_pk_from_RSA(pk, rsa); + r = rs256_pk_from_EVP_PKEY(pk, pkey); + consume(&r, sizeof(r)); out: - if (pk) - rs256_pk_free(&pk); - if (pkey) - EVP_PKEY_free(pkey); + rs256_pk_free(&pk); + EVP_PKEY_free(pkey); } /* * Do a dummy conversion to exercise eddsa_pk_from_EVP_PKEY(). */ static void eddsa_convert(const eddsa_pk_t *k) { EVP_PKEY *pkey = NULL; eddsa_pk_t *pk = NULL; - volatile int r; + int r; if ((pkey = eddsa_pk_to_EVP_PKEY(k)) == NULL || (pk = eddsa_pk_new()) == NULL) goto out; r = eddsa_pk_from_EVP_PKEY(pk, pkey); + consume(&r, sizeof(r)); out: if (pk) eddsa_pk_free(&pk); if (pkey) EVP_PKEY_free(pkey); } void test(const struct param *p) { fido_assert_t *assert = NULL; es256_pk_t *es256_pk = NULL; rs256_pk_t *rs256_pk = NULL; eddsa_pk_t *eddsa_pk = NULL; uint8_t flags; uint32_t sigcount; int cose_alg = 0; void *pk; prng_init((unsigned int)p->seed); + fuzz_clock_reset(); fido_init(FIDO_DEBUG); fido_set_log_handler(consume_str); switch (p->type & 3) { case 0: cose_alg = COSE_ES256; if ((es256_pk = es256_pk_new()) == NULL) return; es256_pk_from_ptr(es256_pk, p->es256.body, p->es256.len); pk = es256_pk; + es256_convert(pk); + break; case 1: cose_alg = COSE_RS256; if ((rs256_pk = rs256_pk_new()) == NULL) return; rs256_pk_from_ptr(rs256_pk, p->rs256.body, p->rs256.len); pk = rs256_pk; rs256_convert(pk); break; default: cose_alg = COSE_EDDSA; if ((eddsa_pk = eddsa_pk_new()) == NULL) return; eddsa_pk_from_ptr(eddsa_pk, p->eddsa.body, p->eddsa.len); pk = eddsa_pk; eddsa_convert(pk); break; } if ((assert = fido_assert_new()) == NULL) goto out; set_wire_data(p->wire_data.body, p->wire_data.len); get_assert(assert, p->opt, &p->cdh, p->rp_id, p->ext, p->up, p->uv, p->pin, p->cred_count, &p->cred); /* XXX +1 on purpose */ for (size_t i = 0; i <= fido_assert_count(assert); i++) { verify_assert(cose_alg, fido_assert_clientdata_hash_ptr(assert), fido_assert_clientdata_hash_len(assert), fido_assert_rp_id(assert), fido_assert_authdata_ptr(assert, i), fido_assert_authdata_len(assert, i), fido_assert_sig_ptr(assert, i), fido_assert_sig_len(assert, i), p->up, p->uv, p->ext, pk); consume(fido_assert_id_ptr(assert, i), fido_assert_id_len(assert, i)); consume(fido_assert_user_id_ptr(assert, i), fido_assert_user_id_len(assert, i)); consume(fido_assert_hmac_secret_ptr(assert, i), fido_assert_hmac_secret_len(assert, i)); consume_str(fido_assert_user_icon(assert, i)); consume_str(fido_assert_user_name(assert, i)); consume_str(fido_assert_user_display_name(assert, i)); consume(fido_assert_blob_ptr(assert, i), fido_assert_blob_len(assert, i)); consume(fido_assert_largeblob_key_ptr(assert, i), fido_assert_largeblob_key_len(assert, i)); flags = fido_assert_flags(assert, i); consume(&flags, sizeof(flags)); sigcount = fido_assert_sigcount(assert, i); consume(&sigcount, sizeof(sigcount)); } out: es256_pk_free(&es256_pk); rs256_pk_free(&rs256_pk); eddsa_pk_free(&eddsa_pk); fido_assert_free(&assert); } void mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN { if (flags & MUTATE_SEED) p->seed = (int)seed; if (flags & MUTATE_PARAM) { mutate_byte(&p->uv); mutate_byte(&p->up); mutate_byte(&p->opt); mutate_byte(&p->type); mutate_byte(&p->cred_count); mutate_int(&p->ext); mutate_blob(&p->rs256); mutate_blob(&p->es256); mutate_blob(&p->eddsa); mutate_blob(&p->cred); mutate_blob(&p->cdh); mutate_string(p->rp_id); mutate_string(p->pin); } if (flags & MUTATE_WIREDATA) { if (p->opt & 1) { p->wire_data.len = sizeof(dummy_wire_data_u2f); memcpy(&p->wire_data.body, &dummy_wire_data_u2f, p->wire_data.len); } else { p->wire_data.len = sizeof(dummy_wire_data_fido); memcpy(&p->wire_data.body, &dummy_wire_data_fido, p->wire_data.len); } mutate_blob(&p->wire_data); } } diff --git a/contrib/libfido2/fuzz/fuzz_bio.c b/contrib/libfido2/fuzz/fuzz_bio.c index ed3deec93693..49a50932a543 100644 --- a/contrib/libfido2/fuzz/fuzz_bio.c +++ b/contrib/libfido2/fuzz/fuzz_bio.c @@ -1,440 +1,441 @@ /* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "mutator_aux.h" #include "wiredata_fido2.h" #include "dummy.h" #include "../openbsd-compat/openbsd-compat.h" /* Parameter set defining a FIDO2 credential management operation. */ struct param { char pin[MAXSTR]; char name[MAXSTR]; int seed; struct blob id; struct blob info_wire_data; struct blob enroll_wire_data; struct blob list_wire_data; struct blob set_name_wire_data; struct blob remove_wire_data; }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'getFingerprintSensorInfo' bio enrollment command. */ static const uint8_t dummy_info_wire_data[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_BIO_INFO, }; /* * Collection of HID reports from an authenticator issued with FIDO2 * 'enrollBegin' + 'enrollCaptureNextSample' bio enrollment commands. */ static const uint8_t dummy_enroll_wire_data[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_AUTHKEY, WIREDATA_CTAP_CBOR_PINTOKEN, WIREDATA_CTAP_CBOR_BIO_ENROLL, }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'enumerateEnrollments' bio enrollment command. */ static const uint8_t dummy_list_wire_data[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_AUTHKEY, WIREDATA_CTAP_CBOR_PINTOKEN, WIREDATA_CTAP_CBOR_BIO_ENUM, }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'setFriendlyName' bio enrollment command. */ static const uint8_t dummy_set_name_wire_data[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_AUTHKEY, WIREDATA_CTAP_CBOR_PINTOKEN, WIREDATA_CTAP_CBOR_STATUS, }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'removeEnrollment' bio enrollment command. */ static const uint8_t dummy_remove_wire_data[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_AUTHKEY, WIREDATA_CTAP_CBOR_PINTOKEN, WIREDATA_CTAP_CBOR_STATUS, }; struct param * unpack(const uint8_t *ptr, size_t len) { cbor_item_t *item = NULL, **v; struct cbor_load_result cbor; struct param *p; int ok = -1; if ((p = calloc(1, sizeof(*p))) == NULL || (item = cbor_load(ptr, len, &cbor)) == NULL || cbor.read != len || cbor_isa_array(item) == false || cbor_array_is_definite(item) == false || cbor_array_size(item) != 9 || (v = cbor_array_handle(item)) == NULL) goto fail; if (unpack_int(v[0], &p->seed) < 0 || unpack_string(v[1], p->pin) < 0 || unpack_string(v[2], p->name) < 0 || unpack_blob(v[3], &p->id) < 0 || unpack_blob(v[4], &p->info_wire_data) < 0 || unpack_blob(v[5], &p->enroll_wire_data) < 0 || unpack_blob(v[6], &p->list_wire_data) < 0 || unpack_blob(v[7], &p->set_name_wire_data) < 0 || unpack_blob(v[8], &p->remove_wire_data) < 0) goto fail; ok = 0; fail: if (ok < 0) { free(p); p = NULL; } if (item) cbor_decref(&item); return p; } size_t pack(uint8_t *ptr, size_t len, const struct param *p) { cbor_item_t *argv[9], *array = NULL; size_t cbor_alloc_len, cbor_len = 0; unsigned char *cbor = NULL; memset(argv, 0, sizeof(argv)); if ((array = cbor_new_definite_array(9)) == NULL || (argv[0] = pack_int(p->seed)) == NULL || (argv[1] = pack_string(p->pin)) == NULL || (argv[2] = pack_string(p->name)) == NULL || (argv[3] = pack_blob(&p->id)) == NULL || (argv[4] = pack_blob(&p->info_wire_data)) == NULL || (argv[5] = pack_blob(&p->enroll_wire_data)) == NULL || (argv[6] = pack_blob(&p->list_wire_data)) == NULL || (argv[7] = pack_blob(&p->set_name_wire_data)) == NULL || (argv[8] = pack_blob(&p->remove_wire_data)) == NULL) goto fail; for (size_t i = 0; i < 9; i++) if (cbor_array_push(array, argv[i]) == false) goto fail; if ((cbor_len = cbor_serialize_alloc(array, &cbor, &cbor_alloc_len)) > len) { cbor_len = 0; goto fail; } memcpy(ptr, cbor, cbor_len); fail: for (size_t i = 0; i < 9; i++) if (argv[i]) cbor_decref(&argv[i]); if (array) cbor_decref(&array); free(cbor); return cbor_len; } size_t pack_dummy(uint8_t *ptr, size_t len) { struct param dummy; uint8_t blob[4096]; size_t blob_len; memset(&dummy, 0, sizeof(dummy)); strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); strlcpy(dummy.name, dummy_name, sizeof(dummy.name)); dummy.info_wire_data.len = sizeof(dummy_info_wire_data); dummy.enroll_wire_data.len = sizeof(dummy_enroll_wire_data); dummy.list_wire_data.len = sizeof(dummy_list_wire_data); dummy.set_name_wire_data.len = sizeof(dummy_set_name_wire_data); dummy.remove_wire_data.len = sizeof(dummy_remove_wire_data); dummy.id.len = sizeof(dummy_id); memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data, dummy.info_wire_data.len); memcpy(&dummy.enroll_wire_data.body, &dummy_enroll_wire_data, dummy.enroll_wire_data.len); memcpy(&dummy.list_wire_data.body, &dummy_list_wire_data, dummy.list_wire_data.len); memcpy(&dummy.set_name_wire_data.body, &dummy_set_name_wire_data, dummy.set_name_wire_data.len); memcpy(&dummy.remove_wire_data.body, &dummy_remove_wire_data, dummy.remove_wire_data.len); memcpy(&dummy.id.body, &dummy_id, dummy.id.len); assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); if (blob_len > len) { memcpy(ptr, blob, len); return len; } memcpy(ptr, blob, blob_len); return blob_len; } static fido_dev_t * prepare_dev(void) { fido_dev_t *dev; bool x; if ((dev = open_dev(0)) == NULL) return NULL; x = fido_dev_is_fido2(dev); consume(&x, sizeof(x)); x = fido_dev_supports_pin(dev); consume(&x, sizeof(x)); x = fido_dev_has_pin(dev); consume(&x, sizeof(x)); x = fido_dev_supports_uv(dev); consume(&x, sizeof(x)); x = fido_dev_has_uv(dev); consume(&x, sizeof(x)); return dev; } static void get_info(const struct param *p) { fido_dev_t *dev = NULL; fido_bio_info_t *i = NULL; uint8_t type; uint8_t max_samples; int r; set_wire_data(p->info_wire_data.body, p->info_wire_data.len); if ((dev = prepare_dev()) == NULL || (i = fido_bio_info_new()) == NULL) goto done; r = fido_bio_dev_get_info(dev, i); consume_str(fido_strerr(r)); type = fido_bio_info_type(i); max_samples = fido_bio_info_max_samples(i); consume(&type, sizeof(type)); consume(&max_samples, sizeof(max_samples)); done: if (dev) fido_dev_close(dev); fido_dev_free(&dev); fido_bio_info_free(&i); } static void consume_template(const fido_bio_template_t *t) { consume_str(fido_bio_template_name(t)); consume(fido_bio_template_id_ptr(t), fido_bio_template_id_len(t)); } static void consume_enroll(fido_bio_enroll_t *e) { uint8_t last_status; uint8_t remaining_samples; last_status = fido_bio_enroll_last_status(e); remaining_samples = fido_bio_enroll_remaining_samples(e); consume(&last_status, sizeof(last_status)); consume(&remaining_samples, sizeof(remaining_samples)); } static void enroll(const struct param *p) { fido_dev_t *dev = NULL; fido_bio_template_t *t = NULL; fido_bio_enroll_t *e = NULL; size_t cnt = 0; set_wire_data(p->enroll_wire_data.body, p->enroll_wire_data.len); if ((dev = prepare_dev()) == NULL || (t = fido_bio_template_new()) == NULL || (e = fido_bio_enroll_new()) == NULL) goto done; fido_bio_dev_enroll_begin(dev, t, e, (uint32_t)p->seed, p->pin); consume_template(t); consume_enroll(e); while (fido_bio_enroll_remaining_samples(e) > 0 && cnt++ < 5) { fido_bio_dev_enroll_continue(dev, t, e, p->seed); consume_template(t); consume_enroll(e); } done: if (dev) fido_dev_close(dev); fido_dev_free(&dev); fido_bio_template_free(&t); fido_bio_enroll_free(&e); } static void list(const struct param *p) { fido_dev_t *dev = NULL; fido_bio_template_array_t *ta = NULL; const fido_bio_template_t *t = NULL; set_wire_data(p->list_wire_data.body, p->list_wire_data.len); if ((dev = prepare_dev()) == NULL || (ta = fido_bio_template_array_new()) == NULL) goto done; fido_bio_dev_get_template_array(dev, ta, p->pin); /* +1 on purpose */ for (size_t i = 0; i < fido_bio_template_array_count(ta) + 1; i++) if ((t = fido_bio_template(ta, i)) != NULL) consume_template(t); done: if (dev) fido_dev_close(dev); fido_dev_free(&dev); fido_bio_template_array_free(&ta); } static void set_name(const struct param *p) { fido_dev_t *dev = NULL; fido_bio_template_t *t = NULL; set_wire_data(p->set_name_wire_data.body, p->set_name_wire_data.len); if ((dev = prepare_dev()) == NULL || (t = fido_bio_template_new()) == NULL) goto done; fido_bio_template_set_name(t, p->name); fido_bio_template_set_id(t, p->id.body, p->id.len); consume_template(t); fido_bio_dev_set_template_name(dev, t, p->pin); done: if (dev) fido_dev_close(dev); fido_dev_free(&dev); fido_bio_template_free(&t); } static void del(const struct param *p) { fido_dev_t *dev = NULL; fido_bio_template_t *t = NULL; int r; set_wire_data(p->remove_wire_data.body, p->remove_wire_data.len); if ((dev = prepare_dev()) == NULL || (t = fido_bio_template_new()) == NULL) goto done; r = fido_bio_template_set_id(t, p->id.body, p->id.len); consume_template(t); consume_str(fido_strerr(r)); fido_bio_dev_enroll_remove(dev, t, p->pin); done: if (dev) fido_dev_close(dev); fido_dev_free(&dev); fido_bio_template_free(&t); } void test(const struct param *p) { prng_init((unsigned int)p->seed); + fuzz_clock_reset(); fido_init(FIDO_DEBUG); fido_set_log_handler(consume_str); get_info(p); enroll(p); list(p); set_name(p); del(p); } void mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN { if (flags & MUTATE_SEED) p->seed = (int)seed; if (flags & MUTATE_PARAM) { mutate_blob(&p->id); mutate_string(p->pin); mutate_string(p->name); } if (flags & MUTATE_WIREDATA) { mutate_blob(&p->info_wire_data); mutate_blob(&p->enroll_wire_data); mutate_blob(&p->list_wire_data); mutate_blob(&p->set_name_wire_data); mutate_blob(&p->remove_wire_data); } } diff --git a/contrib/libfido2/fuzz/fuzz_cred.c b/contrib/libfido2/fuzz/fuzz_cred.c index 004852d3451a..d7b630224054 100644 --- a/contrib/libfido2/fuzz/fuzz_cred.c +++ b/contrib/libfido2/fuzz/fuzz_cred.c @@ -1,455 +1,478 @@ /* - * Copyright (c) 2019 Yubico AB. All rights reserved. + * Copyright (c) 2019-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "mutator_aux.h" #include "wiredata_fido2.h" #include "wiredata_u2f.h" #include "dummy.h" #include "../openbsd-compat/openbsd-compat.h" /* Parameter set defining a FIDO2 make credential operation. */ struct param { char pin[MAXSTR]; char rp_id[MAXSTR]; char rp_name[MAXSTR]; char user_icon[MAXSTR]; char user_name[MAXSTR]; char user_nick[MAXSTR]; int ext; int seed; struct blob cdh; struct blob excl_cred; struct blob user_id; struct blob wire_data; uint8_t excl_count; uint8_t rk; uint8_t type; uint8_t opt; uint8_t uv; }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * make credential using the example parameters above. */ static const uint8_t dummy_wire_data_fido[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_AUTHKEY, WIREDATA_CTAP_CBOR_PINTOKEN, WIREDATA_CTAP_KEEPALIVE, WIREDATA_CTAP_KEEPALIVE, WIREDATA_CTAP_KEEPALIVE, WIREDATA_CTAP_CBOR_CRED, }; /* * Collection of HID reports from an authenticator issued with a U2F * registration using the example parameters above. */ static const uint8_t dummy_wire_data_u2f[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_U2F_6985, WIREDATA_CTAP_U2F_6985, WIREDATA_CTAP_U2F_6985, WIREDATA_CTAP_U2F_6985, WIREDATA_CTAP_U2F_6985, WIREDATA_CTAP_U2F_REGISTER, }; struct param * unpack(const uint8_t *ptr, size_t len) { cbor_item_t *item = NULL, **v; struct cbor_load_result cbor; struct param *p; int ok = -1; if ((p = calloc(1, sizeof(*p))) == NULL || (item = cbor_load(ptr, len, &cbor)) == NULL || cbor.read != len || cbor_isa_array(item) == false || cbor_array_is_definite(item) == false || cbor_array_size(item) != 17 || (v = cbor_array_handle(item)) == NULL) goto fail; if (unpack_byte(v[0], &p->rk) < 0 || unpack_byte(v[1], &p->type) < 0 || unpack_byte(v[2], &p->opt) < 0 || unpack_byte(v[3], &p->uv) < 0 || unpack_byte(v[4], &p->excl_count) < 0 || unpack_int(v[5], &p->ext) < 0 || unpack_int(v[6], &p->seed) < 0 || unpack_string(v[7], p->pin) < 0 || unpack_string(v[8], p->rp_id) < 0 || unpack_string(v[9], p->rp_name) < 0 || unpack_string(v[10], p->user_icon) < 0 || unpack_string(v[11], p->user_name) < 0 || unpack_string(v[12], p->user_nick) < 0 || unpack_blob(v[13], &p->cdh) < 0 || unpack_blob(v[14], &p->user_id) < 0 || unpack_blob(v[15], &p->wire_data) < 0 || unpack_blob(v[16], &p->excl_cred) < 0) goto fail; ok = 0; fail: if (ok < 0) { free(p); p = NULL; } if (item) cbor_decref(&item); return p; } size_t pack(uint8_t *ptr, size_t len, const struct param *p) { cbor_item_t *argv[17], *array = NULL; size_t cbor_alloc_len, cbor_len = 0; unsigned char *cbor = NULL; memset(argv, 0, sizeof(argv)); if ((array = cbor_new_definite_array(17)) == NULL || (argv[0] = pack_byte(p->rk)) == NULL || (argv[1] = pack_byte(p->type)) == NULL || (argv[2] = pack_byte(p->opt)) == NULL || (argv[3] = pack_byte(p->uv)) == NULL || (argv[4] = pack_byte(p->excl_count)) == NULL || (argv[5] = pack_int(p->ext)) == NULL || (argv[6] = pack_int(p->seed)) == NULL || (argv[7] = pack_string(p->pin)) == NULL || (argv[8] = pack_string(p->rp_id)) == NULL || (argv[9] = pack_string(p->rp_name)) == NULL || (argv[10] = pack_string(p->user_icon)) == NULL || (argv[11] = pack_string(p->user_name)) == NULL || (argv[12] = pack_string(p->user_nick)) == NULL || (argv[13] = pack_blob(&p->cdh)) == NULL || (argv[14] = pack_blob(&p->user_id)) == NULL || (argv[15] = pack_blob(&p->wire_data)) == NULL || (argv[16] = pack_blob(&p->excl_cred)) == NULL) goto fail; for (size_t i = 0; i < 17; i++) if (cbor_array_push(array, argv[i]) == false) goto fail; if ((cbor_len = cbor_serialize_alloc(array, &cbor, &cbor_alloc_len)) > len) { cbor_len = 0; goto fail; } memcpy(ptr, cbor, cbor_len); fail: for (size_t i = 0; i < 17; i++) if (argv[i]) cbor_decref(&argv[i]); if (array) cbor_decref(&array); free(cbor); return cbor_len; } size_t pack_dummy(uint8_t *ptr, size_t len) { struct param dummy; uint8_t blob[4096]; size_t blob_len; memset(&dummy, 0, sizeof(dummy)); dummy.type = 1; dummy.ext = FIDO_EXT_HMAC_SECRET; strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); strlcpy(dummy.rp_name, dummy_rp_name, sizeof(dummy.rp_name)); strlcpy(dummy.user_icon, dummy_user_icon, sizeof(dummy.user_icon)); strlcpy(dummy.user_name, dummy_user_name, sizeof(dummy.user_name)); strlcpy(dummy.user_nick, dummy_user_nick, sizeof(dummy.user_nick)); dummy.cdh.len = sizeof(dummy_cdh); dummy.user_id.len = sizeof(dummy_user_id); dummy.wire_data.len = sizeof(dummy_wire_data_fido); memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len); memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, dummy.wire_data.len); assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); if (blob_len > len) { memcpy(ptr, blob, len); return len; } memcpy(ptr, blob, blob_len); return blob_len; } static void make_cred(fido_cred_t *cred, uint8_t opt, int type, const struct blob *cdh, const char *rp_id, const char *rp_name, const struct blob *user_id, const char *user_name, const char *user_nick, const char *user_icon, int ext, uint8_t rk, uint8_t uv, const char *pin, uint8_t excl_count, const struct blob *excl_cred) { fido_dev_t *dev; if ((dev = open_dev(opt & 2)) == NULL) return; if (opt & 1) fido_dev_force_u2f(dev); for (uint8_t i = 0; i < excl_count; i++) fido_cred_exclude(cred, excl_cred->body, excl_cred->len); fido_cred_set_type(cred, type); fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len); fido_cred_set_rp(cred, rp_id, rp_name); fido_cred_set_user(cred, user_id->body, user_id->len, user_name, user_nick, user_icon); + if (ext & FIDO_EXT_HMAC_SECRET) fido_cred_set_extensions(cred, FIDO_EXT_HMAC_SECRET); if (ext & FIDO_EXT_CRED_BLOB) fido_cred_set_blob(cred, user_id->body, user_id->len); if (ext & FIDO_EXT_LARGEBLOB_KEY) fido_cred_set_extensions(cred, FIDO_EXT_LARGEBLOB_KEY); + if (ext & FIDO_EXT_MINPINLEN) + fido_cred_set_pin_minlen(cred, strlen(pin)); if (rk & 1) fido_cred_set_rk(cred, FIDO_OPT_TRUE); if (uv & 1) fido_cred_set_uv(cred, FIDO_OPT_TRUE); if (user_id->len) fido_cred_set_prot(cred, user_id->body[0] & 0x03); /* repeat memory operations to trigger reallocation paths */ fido_cred_set_type(cred, type); fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len); fido_cred_set_rp(cred, rp_id, rp_name); fido_cred_set_user(cred, user_id->body, user_id->len, user_name, user_nick, user_icon); if (strlen(pin) == 0) pin = NULL; fido_dev_make_cred(dev, cred, (opt & 1) ? NULL : pin); fido_dev_cancel(dev); fido_dev_close(dev); fido_dev_free(&dev); } static void verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len, const char *rp_id, const char *rp_name, const unsigned char *authdata_ptr, size_t authdata_len, const unsigned char *authdata_raw_ptr, size_t authdata_raw_len, int ext, uint8_t rk, uint8_t uv, const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr, - size_t sig_len, const char *fmt, int prot) + size_t sig_len, const unsigned char *attstmt_ptr, size_t attstmt_len, + const char *fmt, int prot, size_t minpinlen) { fido_cred_t *cred; uint8_t flags; uint32_t sigcount; + int r; if ((cred = fido_cred_new()) == NULL) return; fido_cred_set_type(cred, type); fido_cred_set_clientdata_hash(cred, cdh_ptr, cdh_len); fido_cred_set_rp(cred, rp_id, rp_name); consume(authdata_ptr, authdata_len); consume(authdata_raw_ptr, authdata_raw_len); + consume(x5c_ptr, x5c_len); + consume(sig_ptr, sig_len); + consume(attstmt_ptr, attstmt_len); if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK) fido_cred_set_authdata_raw(cred, authdata_raw_ptr, authdata_raw_len); fido_cred_set_extensions(cred, ext); - fido_cred_set_x509(cred, x5c_ptr, x5c_len); - fido_cred_set_sig(cred, sig_ptr, sig_len); + if (fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len) != FIDO_OK) { + fido_cred_set_x509(cred, x5c_ptr, x5c_len); + fido_cred_set_sig(cred, sig_ptr, sig_len); + } fido_cred_set_prot(cred, prot); + fido_cred_set_pin_minlen(cred, minpinlen); if (rk & 1) fido_cred_set_rk(cred, FIDO_OPT_TRUE); if (uv & 1) fido_cred_set_uv(cred, FIDO_OPT_TRUE); if (fmt) fido_cred_set_fmt(cred, fmt); /* repeat memory operations to trigger reallocation paths */ if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK) - fido_cred_set_authdata_raw(cred, authdata_ptr, authdata_len); + fido_cred_set_authdata_raw(cred, authdata_raw_ptr, + authdata_raw_len); + if (fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len) != FIDO_OK) { + fido_cred_set_x509(cred, x5c_ptr, x5c_len); + fido_cred_set_sig(cred, sig_ptr, sig_len); + } fido_cred_set_x509(cred, x5c_ptr, x5c_len); fido_cred_set_sig(cred, sig_ptr, sig_len); - assert(fido_cred_verify(cred) != FIDO_OK); - assert(fido_cred_verify_self(cred) != FIDO_OK); + r = fido_cred_verify(cred); + consume(&r, sizeof(r)); + r = fido_cred_verify_self(cred); + consume(&r, sizeof(r)); consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); consume(fido_cred_aaguid_ptr(cred), fido_cred_aaguid_len(cred)); consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred)); consume_str(fido_cred_user_name(cred)); consume_str(fido_cred_display_name(cred)); consume(fido_cred_largeblob_key_ptr(cred), fido_cred_largeblob_key_len(cred)); flags = fido_cred_flags(cred); consume(&flags, sizeof(flags)); sigcount = fido_cred_sigcount(cred); consume(&sigcount, sizeof(sigcount)); type = fido_cred_type(cred); consume(&type, sizeof(type)); + minpinlen = fido_cred_pin_minlen(cred); + consume(&minpinlen, sizeof(minpinlen)); fido_cred_free(&cred); } static void test_cred(const struct param *p) { fido_cred_t *cred = NULL; int cose_alg = 0; if ((cred = fido_cred_new()) == NULL) return; switch (p->type & 3) { case 0: cose_alg = COSE_ES256; break; case 1: cose_alg = COSE_RS256; break; default: cose_alg = COSE_EDDSA; break; } set_wire_data(p->wire_data.body, p->wire_data.len); make_cred(cred, p->opt, cose_alg, &p->cdh, p->rp_id, p->rp_name, &p->user_id, p->user_name, p->user_nick, p->user_icon, p->ext, p->rk, p->uv, p->pin, p->excl_count, &p->excl_cred); verify_cred(cose_alg, fido_cred_clientdata_hash_ptr(cred), fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred), fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred), fido_cred_authdata_len(cred), fido_cred_authdata_raw_ptr(cred), fido_cred_authdata_raw_len(cred), p->ext, p->rk, p->uv, fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred), fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), - fido_cred_fmt(cred), fido_cred_prot(cred)); + fido_cred_attstmt_ptr(cred), fido_cred_attstmt_len(cred), + fido_cred_fmt(cred), fido_cred_prot(cred), + fido_cred_pin_minlen(cred)); fido_cred_free(&cred); } static void test_touch(const struct param *p) { fido_dev_t *dev; int r; int touched; set_wire_data(p->wire_data.body, p->wire_data.len); if ((dev = open_dev(p->opt & 2)) == NULL) return; if (p->opt & 1) fido_dev_force_u2f(dev); r = fido_dev_get_touch_begin(dev); consume_str(fido_strerr(r)); r = fido_dev_get_touch_status(dev, &touched, -1); consume_str(fido_strerr(r)); consume(&touched, sizeof(touched)); fido_dev_cancel(dev); fido_dev_close(dev); fido_dev_free(&dev); } static void test_misc(const struct param *p) { fido_cred_t *cred = NULL; if ((cred = fido_cred_new()) == NULL) return; /* reuse user id as credential id */ fido_cred_set_id(cred, p->user_id.body, p->user_id.len); consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); fido_cred_free(&cred); } void test(const struct param *p) { prng_init((unsigned int)p->seed); + fuzz_clock_reset(); fido_init(FIDO_DEBUG); fido_set_log_handler(consume_str); test_cred(p); test_touch(p); test_misc(p); } void mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN { if (flags & MUTATE_SEED) p->seed = (int)seed; if (flags & MUTATE_PARAM) { mutate_byte(&p->rk); mutate_byte(&p->type); mutate_byte(&p->opt); mutate_byte(&p->uv); mutate_byte(&p->excl_count); mutate_int(&p->ext); mutate_blob(&p->cdh); mutate_blob(&p->user_id); mutate_blob(&p->excl_cred); mutate_string(p->pin); mutate_string(p->user_icon); mutate_string(p->user_name); mutate_string(p->user_nick); mutate_string(p->rp_id); mutate_string(p->rp_name); } if (flags & MUTATE_WIREDATA) { if (p->opt & 1) { p->wire_data.len = sizeof(dummy_wire_data_u2f); memcpy(&p->wire_data.body, &dummy_wire_data_u2f, p->wire_data.len); } else { p->wire_data.len = sizeof(dummy_wire_data_fido); memcpy(&p->wire_data.body, &dummy_wire_data_fido, p->wire_data.len); } mutate_blob(&p->wire_data); } } diff --git a/contrib/libfido2/fuzz/fuzz_credman.c b/contrib/libfido2/fuzz/fuzz_credman.c index 89a37379d87f..fb34f22f8147 100644 --- a/contrib/libfido2/fuzz/fuzz_credman.c +++ b/contrib/libfido2/fuzz/fuzz_credman.c @@ -1,405 +1,406 @@ /* * Copyright (c) 2019-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "mutator_aux.h" #include "wiredata_fido2.h" #include "dummy.h" #include "../openbsd-compat/openbsd-compat.h" /* Parameter set defining a FIDO2 credential management operation. */ struct param { char pin[MAXSTR]; char rp_id[MAXSTR]; int seed; struct blob cred_id; struct blob del_wire_data; struct blob meta_wire_data; struct blob rk_wire_data; struct blob rp_wire_data; }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'getCredsMetadata' credential management command. */ static const uint8_t dummy_meta_wire_data[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_AUTHKEY, WIREDATA_CTAP_CBOR_PINTOKEN, WIREDATA_CTAP_CBOR_CREDMAN_META, }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'enumerateRPsBegin' credential management command. */ static const uint8_t dummy_rp_wire_data[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_AUTHKEY, WIREDATA_CTAP_CBOR_PINTOKEN, WIREDATA_CTAP_CBOR_CREDMAN_RPLIST, }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'enumerateCredentialsBegin' credential management command. */ static const uint8_t dummy_rk_wire_data[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_AUTHKEY, WIREDATA_CTAP_CBOR_PINTOKEN, WIREDATA_CTAP_CBOR_CREDMAN_RKLIST, }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'deleteCredential' credential management command. */ static const uint8_t dummy_del_wire_data[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_AUTHKEY, WIREDATA_CTAP_CBOR_PINTOKEN, WIREDATA_CTAP_CBOR_STATUS, }; struct param * unpack(const uint8_t *ptr, size_t len) { cbor_item_t *item = NULL, **v; struct cbor_load_result cbor; struct param *p; int ok = -1; if ((p = calloc(1, sizeof(*p))) == NULL || (item = cbor_load(ptr, len, &cbor)) == NULL || cbor.read != len || cbor_isa_array(item) == false || cbor_array_is_definite(item) == false || cbor_array_size(item) != 8 || (v = cbor_array_handle(item)) == NULL) goto fail; if (unpack_int(v[0], &p->seed) < 0 || unpack_string(v[1], p->pin) < 0 || unpack_string(v[2], p->rp_id) < 0 || unpack_blob(v[3], &p->cred_id) < 0 || unpack_blob(v[4], &p->meta_wire_data) < 0 || unpack_blob(v[5], &p->rp_wire_data) < 0 || unpack_blob(v[6], &p->rk_wire_data) < 0 || unpack_blob(v[7], &p->del_wire_data) < 0) goto fail; ok = 0; fail: if (ok < 0) { free(p); p = NULL; } if (item) cbor_decref(&item); return p; } size_t pack(uint8_t *ptr, size_t len, const struct param *p) { cbor_item_t *argv[8], *array = NULL; size_t cbor_alloc_len, cbor_len = 0; unsigned char *cbor = NULL; memset(argv, 0, sizeof(argv)); if ((array = cbor_new_definite_array(8)) == NULL || (argv[0] = pack_int(p->seed)) == NULL || (argv[1] = pack_string(p->pin)) == NULL || (argv[2] = pack_string(p->rp_id)) == NULL || (argv[3] = pack_blob(&p->cred_id)) == NULL || (argv[4] = pack_blob(&p->meta_wire_data)) == NULL || (argv[5] = pack_blob(&p->rp_wire_data)) == NULL || (argv[6] = pack_blob(&p->rk_wire_data)) == NULL || (argv[7] = pack_blob(&p->del_wire_data)) == NULL) goto fail; for (size_t i = 0; i < 8; i++) if (cbor_array_push(array, argv[i]) == false) goto fail; if ((cbor_len = cbor_serialize_alloc(array, &cbor, &cbor_alloc_len)) > len) { cbor_len = 0; goto fail; } memcpy(ptr, cbor, cbor_len); fail: for (size_t i = 0; i < 8; i++) if (argv[i]) cbor_decref(&argv[i]); if (array) cbor_decref(&array); free(cbor); return cbor_len; } size_t pack_dummy(uint8_t *ptr, size_t len) { struct param dummy; uint8_t blob[4096]; size_t blob_len; memset(&dummy, 0, sizeof(dummy)); strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); dummy.meta_wire_data.len = sizeof(dummy_meta_wire_data); dummy.rp_wire_data.len = sizeof(dummy_rp_wire_data); dummy.rk_wire_data.len = sizeof(dummy_rk_wire_data); dummy.del_wire_data.len = sizeof(dummy_del_wire_data); dummy.cred_id.len = sizeof(dummy_cred_id); memcpy(&dummy.meta_wire_data.body, &dummy_meta_wire_data, dummy.meta_wire_data.len); memcpy(&dummy.rp_wire_data.body, &dummy_rp_wire_data, dummy.rp_wire_data.len); memcpy(&dummy.rk_wire_data.body, &dummy_rk_wire_data, dummy.rk_wire_data.len); memcpy(&dummy.del_wire_data.body, &dummy_del_wire_data, dummy.del_wire_data.len); memcpy(&dummy.cred_id.body, &dummy_cred_id, dummy.cred_id.len); assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); if (blob_len > len) { memcpy(ptr, blob, len); return len; } memcpy(ptr, blob, blob_len); return blob_len; } static fido_dev_t * prepare_dev(void) { fido_dev_t *dev; bool x; if ((dev = open_dev(0)) == NULL) return NULL; x = fido_dev_is_fido2(dev); consume(&x, sizeof(x)); x = fido_dev_supports_cred_prot(dev); consume(&x, sizeof(x)); x = fido_dev_supports_credman(dev); consume(&x, sizeof(x)); return dev; } static void get_metadata(const struct param *p) { fido_dev_t *dev; fido_credman_metadata_t *metadata; uint64_t existing; uint64_t remaining; set_wire_data(p->meta_wire_data.body, p->meta_wire_data.len); if ((dev = prepare_dev()) == NULL) return; if ((metadata = fido_credman_metadata_new()) == NULL) { fido_dev_close(dev); fido_dev_free(&dev); return; } fido_credman_get_dev_metadata(dev, metadata, p->pin); existing = fido_credman_rk_existing(metadata); remaining = fido_credman_rk_remaining(metadata); consume(&existing, sizeof(existing)); consume(&remaining, sizeof(remaining)); fido_credman_metadata_free(&metadata); fido_dev_close(dev); fido_dev_free(&dev); } static void get_rp_list(const struct param *p) { fido_dev_t *dev; fido_credman_rp_t *rp; set_wire_data(p->rp_wire_data.body, p->rp_wire_data.len); if ((dev = prepare_dev()) == NULL) return; if ((rp = fido_credman_rp_new()) == NULL) { fido_dev_close(dev); fido_dev_free(&dev); return; } fido_credman_get_dev_rp(dev, rp, p->pin); /* +1 on purpose */ for (size_t i = 0; i < fido_credman_rp_count(rp) + 1; i++) { consume(fido_credman_rp_id_hash_ptr(rp, i), fido_credman_rp_id_hash_len(rp, i)); consume_str(fido_credman_rp_id(rp, i)); consume_str(fido_credman_rp_name(rp, i)); } fido_credman_rp_free(&rp); fido_dev_close(dev); fido_dev_free(&dev); } static void get_rk_list(const struct param *p) { fido_dev_t *dev; fido_credman_rk_t *rk; const fido_cred_t *cred; int val; set_wire_data(p->rk_wire_data.body, p->rk_wire_data.len); if ((dev = prepare_dev()) == NULL) return; if ((rk = fido_credman_rk_new()) == NULL) { fido_dev_close(dev); fido_dev_free(&dev); return; } fido_credman_get_dev_rk(dev, p->rp_id, rk, p->pin); /* +1 on purpose */ for (size_t i = 0; i < fido_credman_rk_count(rk) + 1; i++) { if ((cred = fido_credman_rk(rk, i)) == NULL) { assert(i >= fido_credman_rk_count(rk)); continue; } val = fido_cred_type(cred); consume(&val, sizeof(val)); consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred)); consume_str(fido_cred_user_name(cred)); consume_str(fido_cred_display_name(cred)); val = fido_cred_prot(cred); consume(&val, sizeof(val)); } fido_credman_rk_free(&rk); fido_dev_close(dev); fido_dev_free(&dev); } static void del_rk(const struct param *p) { fido_dev_t *dev; set_wire_data(p->del_wire_data.body, p->del_wire_data.len); if ((dev = prepare_dev()) == NULL) return; fido_credman_del_dev_rk(dev, p->cred_id.body, p->cred_id.len, p->pin); fido_dev_close(dev); fido_dev_free(&dev); } static void set_rk(const struct param *p) { fido_dev_t *dev = NULL; fido_cred_t *cred = NULL; const char *pin = p->pin; int r0, r1, r2; set_wire_data(p->del_wire_data.body, p->del_wire_data.len); if ((dev = prepare_dev()) == NULL) return; if ((cred = fido_cred_new()) == NULL) goto out; r0 = fido_cred_set_id(cred, p->cred_id.body, p->cred_id.len); r1 = fido_cred_set_user(cred, p->cred_id.body, p->cred_id.len, p->rp_id, NULL, NULL); if (strlen(pin) == 0) pin = NULL; r2 = fido_credman_set_dev_rk(dev, cred, pin); consume(&r0, sizeof(r0)); consume(&r1, sizeof(r1)); consume(&r2, sizeof(r2)); out: fido_dev_close(dev); fido_dev_free(&dev); fido_cred_free(&cred); } void test(const struct param *p) { prng_init((unsigned int)p->seed); + fuzz_clock_reset(); fido_init(FIDO_DEBUG); fido_set_log_handler(consume_str); get_metadata(p); get_rp_list(p); get_rk_list(p); del_rk(p); set_rk(p); } void mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN { if (flags & MUTATE_SEED) p->seed = (int)seed; if (flags & MUTATE_PARAM) { mutate_blob(&p->cred_id); mutate_string(p->pin); mutate_string(p->rp_id); } if (flags & MUTATE_WIREDATA) { mutate_blob(&p->meta_wire_data); mutate_blob(&p->rp_wire_data); mutate_blob(&p->rk_wire_data); mutate_blob(&p->del_wire_data); } } diff --git a/contrib/libfido2/fuzz/fuzz_hid.c b/contrib/libfido2/fuzz/fuzz_hid.c index 6aca7ef5da5b..556e62ac4cd3 100644 --- a/contrib/libfido2/fuzz/fuzz_hid.c +++ b/contrib/libfido2/fuzz/fuzz_hid.c @@ -1,215 +1,229 @@ /* - * Copyright (c) 2020 Yubico AB. All rights reserved. + * Copyright (c) 2020-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "mutator_aux.h" +#include "dummy.h" extern int fido_hid_get_usage(const uint8_t *, size_t, uint32_t *); extern int fido_hid_get_report_len(const uint8_t *, size_t, size_t *, size_t *); extern void set_udev_parameters(const char *, const struct blob *); struct param { int seed; char uevent[MAXSTR]; struct blob report_descriptor; + struct blob netlink_wiredata; }; /* * Sample HID report descriptor from the FIDO HID interface of a YubiKey 5. */ static const uint8_t dummy_report_descriptor[] = { 0x06, 0xd0, 0xf1, 0x09, 0x01, 0xa1, 0x01, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x40, 0x81, 0x02, 0x09, 0x21, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x40, 0x91, 0x02, 0xc0 }; /* * Sample uevent file from a Yubico Security Key. */ static const char dummy_uevent[] = "DRIVER=hid-generic\n" "HID_ID=0003:00001050:00000120\n" "HID_NAME=Yubico Security Key by Yubico\n" "HID_PHYS=usb-0000:00:14.0-3/input0\n" "HID_UNIQ=\n" "MODALIAS=hid:b0003g0001v00001050p00000120\n"; struct param * unpack(const uint8_t *ptr, size_t len) { cbor_item_t *item = NULL, **v; struct cbor_load_result cbor; struct param *p; int ok = -1; if ((p = calloc(1, sizeof(*p))) == NULL || (item = cbor_load(ptr, len, &cbor)) == NULL || cbor.read != len || cbor_isa_array(item) == false || cbor_array_is_definite(item) == false || - cbor_array_size(item) != 3 || + cbor_array_size(item) != 4 || (v = cbor_array_handle(item)) == NULL) goto fail; if (unpack_int(v[0], &p->seed) < 0 || unpack_string(v[1], p->uevent) < 0 || - unpack_blob(v[2], &p->report_descriptor) < 0) + unpack_blob(v[2], &p->report_descriptor) < 0 || + unpack_blob(v[3], &p->netlink_wiredata) < 0) goto fail; ok = 0; fail: if (ok < 0) { free(p); p = NULL; } if (item) cbor_decref(&item); return p; } size_t pack(uint8_t *ptr, size_t len, const struct param *p) { - cbor_item_t *argv[3], *array = NULL; + cbor_item_t *argv[4], *array = NULL; size_t cbor_alloc_len, cbor_len = 0; unsigned char *cbor = NULL; memset(argv, 0, sizeof(argv)); - if ((array = cbor_new_definite_array(3)) == NULL || + if ((array = cbor_new_definite_array(4)) == NULL || (argv[0] = pack_int(p->seed)) == NULL || (argv[1] = pack_string(p->uevent)) == NULL || - (argv[2] = pack_blob(&p->report_descriptor)) == NULL) + (argv[2] = pack_blob(&p->report_descriptor)) == NULL || + (argv[3] = pack_blob(&p->netlink_wiredata)) == NULL) goto fail; - for (size_t i = 0; i < 3; i++) + for (size_t i = 0; i < 4; i++) if (cbor_array_push(array, argv[i]) == false) goto fail; if ((cbor_len = cbor_serialize_alloc(array, &cbor, &cbor_alloc_len)) > len) { cbor_len = 0; goto fail; } memcpy(ptr, cbor, cbor_len); fail: - for (size_t i = 0; i < 3; i++) + for (size_t i = 0; i < 4; i++) if (argv[i]) cbor_decref(&argv[i]); if (array) cbor_decref(&array); free(cbor); return cbor_len; } size_t pack_dummy(uint8_t *ptr, size_t len) { struct param dummy; uint8_t blob[4096]; size_t blob_len; memset(&dummy, 0, sizeof(dummy)); dummy.report_descriptor.len = sizeof(dummy_report_descriptor); strlcpy(dummy.uevent, dummy_uevent, sizeof(dummy.uevent)); memcpy(&dummy.report_descriptor.body, &dummy_report_descriptor, dummy.report_descriptor.len); + dummy.netlink_wiredata.len = sizeof(dummy_netlink_wiredata); + memcpy(&dummy.netlink_wiredata.body, &dummy_netlink_wiredata, + dummy.netlink_wiredata.len); assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); if (blob_len > len) blob_len = len; memcpy(ptr, blob, blob_len); return blob_len; } static void get_usage(const struct param *p) { uint32_t usage_page = 0; fido_hid_get_usage(p->report_descriptor.body, p->report_descriptor.len, &usage_page); consume(&usage_page, sizeof(usage_page)); } static void get_report_len(const struct param *p) { size_t report_in_len = 0; size_t report_out_len = 0; fido_hid_get_report_len(p->report_descriptor.body, p->report_descriptor.len, &report_in_len, &report_out_len); consume(&report_in_len, sizeof(report_in_len)); consume(&report_out_len, sizeof(report_out_len)); } static void manifest(const struct param *p) { size_t ndevs, nfound; fido_dev_info_t *devlist; int16_t vendor_id, product_id; + set_netlink_io_functions(fd_read, fd_write); + set_wire_data(p->netlink_wiredata.body, p->netlink_wiredata.len); set_udev_parameters(p->uevent, &p->report_descriptor); + ndevs = uniform_random(64); if ((devlist = fido_dev_info_new(ndevs)) == NULL || fido_dev_info_manifest(devlist, ndevs, &nfound) != FIDO_OK) goto out; for (size_t i = 0; i < nfound; i++) { const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i); consume_str(fido_dev_info_path(di)); consume_str(fido_dev_info_manufacturer_string(di)); consume_str(fido_dev_info_product_string(di)); vendor_id = fido_dev_info_vendor(di); product_id = fido_dev_info_product(di); consume(&vendor_id, sizeof(vendor_id)); consume(&product_id, sizeof(product_id)); } out: fido_dev_info_free(&devlist, ndevs); } void test(const struct param *p) { prng_init((unsigned int)p->seed); + fuzz_clock_reset(); fido_init(FIDO_DEBUG); fido_set_log_handler(consume_str); get_usage(p); get_report_len(p); manifest(p); } void mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN { if (flags & MUTATE_SEED) p->seed = (int)seed; if (flags & MUTATE_PARAM) { mutate_blob(&p->report_descriptor); mutate_string(p->uevent); } + + if (flags & MUTATE_WIREDATA) + mutate_blob(&p->netlink_wiredata); } diff --git a/contrib/libfido2/fuzz/fuzz_largeblob.c b/contrib/libfido2/fuzz/fuzz_largeblob.c index 6886261bf529..3289ed46e2a7 100644 --- a/contrib/libfido2/fuzz/fuzz_largeblob.c +++ b/contrib/libfido2/fuzz/fuzz_largeblob.c @@ -1,270 +1,271 @@ /* * Copyright (c) 2020 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "mutator_aux.h" #include "wiredata_fido2.h" #include "dummy.h" #include "../openbsd-compat/openbsd-compat.h" /* Parameter set defining a FIDO2 "large blob" operation. */ struct param { char pin[MAXSTR]; int seed; struct blob key; struct blob get_wiredata; struct blob set_wiredata; }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'authenticatorLargeBlobs' 'get' command. */ static const uint8_t dummy_get_wiredata[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY }; /* * Collection of HID reports from an authenticator issued with a FIDO2 * 'authenticatorLargeBlobs' 'set' command. */ static const uint8_t dummy_set_wiredata[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY, WIREDATA_CTAP_CBOR_AUTHKEY, WIREDATA_CTAP_CBOR_PINTOKEN, WIREDATA_CTAP_CBOR_STATUS }; /* * XXX this needs to match the encrypted blob embedded in * WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY. */ static const uint8_t dummy_key[] = { 0xa9, 0x1b, 0xc4, 0xdd, 0xfc, 0x9a, 0x93, 0x79, 0x75, 0xba, 0xf7, 0x7f, 0x4d, 0x57, 0xfc, 0xa6, 0xe1, 0xf8, 0x06, 0x43, 0x23, 0x99, 0x51, 0x32, 0xce, 0x6e, 0x19, 0x84, 0x50, 0x13, 0x2d, 0x7b }; struct param * unpack(const uint8_t *ptr, size_t len) { cbor_item_t *item = NULL, **v; struct cbor_load_result cbor; struct param *p; int ok = -1; if ((p = calloc(1, sizeof(*p))) == NULL || (item = cbor_load(ptr, len, &cbor)) == NULL || cbor.read != len || cbor_isa_array(item) == false || cbor_array_is_definite(item) == false || cbor_array_size(item) != 5 || (v = cbor_array_handle(item)) == NULL) goto fail; if (unpack_int(v[0], &p->seed) < 0 || unpack_string(v[1], p->pin) < 0 || unpack_blob(v[2], &p->key) < 0 || unpack_blob(v[3], &p->get_wiredata) < 0 || unpack_blob(v[4], &p->set_wiredata) < 0) goto fail; ok = 0; fail: if (ok < 0) { free(p); p = NULL; } if (item) cbor_decref(&item); return p; } size_t pack(uint8_t *ptr, size_t len, const struct param *p) { cbor_item_t *argv[5], *array = NULL; size_t cbor_alloc_len, cbor_len = 0; unsigned char *cbor = NULL; memset(argv, 0, sizeof(argv)); if ((array = cbor_new_definite_array(5)) == NULL || (argv[0] = pack_int(p->seed)) == NULL || (argv[1] = pack_string(p->pin)) == NULL || (argv[2] = pack_blob(&p->key)) == NULL || (argv[3] = pack_blob(&p->get_wiredata)) == NULL || (argv[4] = pack_blob(&p->set_wiredata)) == NULL) goto fail; for (size_t i = 0; i < 5; i++) if (cbor_array_push(array, argv[i]) == false) goto fail; if ((cbor_len = cbor_serialize_alloc(array, &cbor, &cbor_alloc_len)) > len) { cbor_len = 0; goto fail; } memcpy(ptr, cbor, cbor_len); fail: for (size_t i = 0; i < 5; i++) if (argv[i]) cbor_decref(&argv[i]); if (array) cbor_decref(&array); free(cbor); return cbor_len; } size_t pack_dummy(uint8_t *ptr, size_t len) { struct param dummy; uint8_t blob[4096]; size_t blob_len; memset(&dummy, 0, sizeof(dummy)); strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); dummy.get_wiredata.len = sizeof(dummy_get_wiredata); dummy.set_wiredata.len = sizeof(dummy_set_wiredata); dummy.key.len = sizeof(dummy_key); memcpy(&dummy.get_wiredata.body, &dummy_get_wiredata, dummy.get_wiredata.len); memcpy(&dummy.set_wiredata.body, &dummy_set_wiredata, dummy.set_wiredata.len); memcpy(&dummy.key.body, &dummy_key, dummy.key.len); assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); if (blob_len > len) { memcpy(ptr, blob, len); return len; } memcpy(ptr, blob, blob_len); return blob_len; } static fido_dev_t * prepare_dev(void) { fido_dev_t *dev; if ((dev = open_dev(0)) == NULL) return NULL; return dev; } static void get_blob(const struct param *p, int array) { fido_dev_t *dev; u_char *ptr = NULL; size_t len = 0; set_wire_data(p->get_wiredata.body, p->get_wiredata.len); if ((dev = prepare_dev()) == NULL) return; if (array) fido_dev_largeblob_get_array(dev, &ptr, &len); else fido_dev_largeblob_get(dev, p->key.body, p->key.len, &ptr, &len); consume(ptr, len); free(ptr); fido_dev_close(dev); fido_dev_free(&dev); } static void set_blob(const struct param *p, int op) { fido_dev_t *dev; const char *pin; set_wire_data(p->set_wiredata.body, p->set_wiredata.len); if ((dev = prepare_dev()) == NULL) return; pin = p->pin; if (strlen(pin) == 0) pin = NULL; switch (op) { case 0: fido_dev_largeblob_remove(dev, p->key.body, p->key.len, pin); break; case 1: /* XXX reuse p->get_wiredata as the blob to be set */ fido_dev_largeblob_set(dev, p->key.body, p->key.len, p->get_wiredata.body, p->get_wiredata.len, pin); break; case 2: /* XXX reuse p->get_wiredata as the body of the cbor array */ fido_dev_largeblob_set_array(dev, p->get_wiredata.body, p->get_wiredata.len, pin); } fido_dev_close(dev); fido_dev_free(&dev); } void test(const struct param *p) { prng_init((unsigned int)p->seed); + fuzz_clock_reset(); fido_init(FIDO_DEBUG); fido_set_log_handler(consume_str); get_blob(p, 0); get_blob(p, 1); set_blob(p, 0); set_blob(p, 1); set_blob(p, 2); } void mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN { if (flags & MUTATE_SEED) p->seed = (int)seed; if (flags & MUTATE_PARAM) { mutate_blob(&p->key); mutate_string(p->pin); } if (flags & MUTATE_WIREDATA) { mutate_blob(&p->get_wiredata); mutate_blob(&p->set_wiredata); } } diff --git a/contrib/libfido2/fuzz/fuzz_mgmt.c b/contrib/libfido2/fuzz/fuzz_mgmt.c index 28afbc6aae5f..7c28979fb624 100644 --- a/contrib/libfido2/fuzz/fuzz_mgmt.c +++ b/contrib/libfido2/fuzz/fuzz_mgmt.c @@ -1,480 +1,508 @@ /* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "mutator_aux.h" #include "wiredata_fido2.h" #include "dummy.h" #include "../openbsd-compat/openbsd-compat.h" +#define MAXRPID 64 + struct param { char pin1[MAXSTR]; char pin2[MAXSTR]; struct blob reset_wire_data; struct blob info_wire_data; struct blob set_pin_wire_data; struct blob change_pin_wire_data; struct blob retry_wire_data; struct blob config_wire_data; int seed; }; static const uint8_t dummy_reset_wire_data[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_KEEPALIVE, WIREDATA_CTAP_KEEPALIVE, WIREDATA_CTAP_KEEPALIVE, WIREDATA_CTAP_CBOR_STATUS, }; static const uint8_t dummy_info_wire_data[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_INFO, }; static const uint8_t dummy_set_pin_wire_data[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_AUTHKEY, WIREDATA_CTAP_CBOR_STATUS, }; static const uint8_t dummy_change_pin_wire_data[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_AUTHKEY, WIREDATA_CTAP_CBOR_STATUS, }; static const uint8_t dummy_retry_wire_data[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_RETRIES, }; static const uint8_t dummy_config_wire_data[] = { WIREDATA_CTAP_INIT, WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_STATUS, }; struct param * unpack(const uint8_t *ptr, size_t len) { cbor_item_t *item = NULL, **v; struct cbor_load_result cbor; struct param *p; int ok = -1; if ((p = calloc(1, sizeof(*p))) == NULL || (item = cbor_load(ptr, len, &cbor)) == NULL || cbor.read != len || cbor_isa_array(item) == false || cbor_array_is_definite(item) == false || cbor_array_size(item) != 9 || (v = cbor_array_handle(item)) == NULL) goto fail; if (unpack_int(v[0], &p->seed) < 0 || unpack_string(v[1], p->pin1) < 0 || unpack_string(v[2], p->pin2) < 0 || unpack_blob(v[3], &p->reset_wire_data) < 0 || unpack_blob(v[4], &p->info_wire_data) < 0 || unpack_blob(v[5], &p->set_pin_wire_data) < 0 || unpack_blob(v[6], &p->change_pin_wire_data) < 0 || unpack_blob(v[7], &p->retry_wire_data) < 0 || unpack_blob(v[8], &p->config_wire_data) < 0) goto fail; ok = 0; fail: if (ok < 0) { free(p); p = NULL; } if (item) cbor_decref(&item); return p; } size_t pack(uint8_t *ptr, size_t len, const struct param *p) { cbor_item_t *argv[9], *array = NULL; size_t cbor_alloc_len, cbor_len = 0; unsigned char *cbor = NULL; memset(argv, 0, sizeof(argv)); if ((array = cbor_new_definite_array(9)) == NULL || (argv[0] = pack_int(p->seed)) == NULL || (argv[1] = pack_string(p->pin1)) == NULL || (argv[2] = pack_string(p->pin2)) == NULL || (argv[3] = pack_blob(&p->reset_wire_data)) == NULL || (argv[4] = pack_blob(&p->info_wire_data)) == NULL || (argv[5] = pack_blob(&p->set_pin_wire_data)) == NULL || (argv[6] = pack_blob(&p->change_pin_wire_data)) == NULL || (argv[7] = pack_blob(&p->retry_wire_data)) == NULL || (argv[8] = pack_blob(&p->config_wire_data)) == NULL) goto fail; for (size_t i = 0; i < 9; i++) if (cbor_array_push(array, argv[i]) == false) goto fail; if ((cbor_len = cbor_serialize_alloc(array, &cbor, &cbor_alloc_len)) > len) { cbor_len = 0; goto fail; } memcpy(ptr, cbor, cbor_len); fail: for (size_t i = 0; i < 9; i++) if (argv[i]) cbor_decref(&argv[i]); if (array) cbor_decref(&array); free(cbor); return cbor_len; } size_t pack_dummy(uint8_t *ptr, size_t len) { struct param dummy; uint8_t blob[4096]; size_t blob_len; memset(&dummy, 0, sizeof(dummy)); strlcpy(dummy.pin1, dummy_pin1, sizeof(dummy.pin1)); strlcpy(dummy.pin2, dummy_pin2, sizeof(dummy.pin2)); dummy.reset_wire_data.len = sizeof(dummy_reset_wire_data); dummy.info_wire_data.len = sizeof(dummy_info_wire_data); dummy.set_pin_wire_data.len = sizeof(dummy_set_pin_wire_data); dummy.change_pin_wire_data.len = sizeof(dummy_change_pin_wire_data); dummy.retry_wire_data.len = sizeof(dummy_retry_wire_data); dummy.config_wire_data.len = sizeof(dummy_config_wire_data); memcpy(&dummy.reset_wire_data.body, &dummy_reset_wire_data, dummy.reset_wire_data.len); memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data, dummy.info_wire_data.len); memcpy(&dummy.set_pin_wire_data.body, &dummy_set_pin_wire_data, dummy.set_pin_wire_data.len); memcpy(&dummy.change_pin_wire_data.body, &dummy_change_pin_wire_data, dummy.change_pin_wire_data.len); memcpy(&dummy.retry_wire_data.body, &dummy_retry_wire_data, dummy.retry_wire_data.len); memcpy(&dummy.config_wire_data.body, &dummy_config_wire_data, dummy.config_wire_data.len); assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); if (blob_len > len) { memcpy(ptr, blob, len); return len; } memcpy(ptr, blob, blob_len); return blob_len; } static void dev_reset(const struct param *p) { fido_dev_t *dev; set_wire_data(p->reset_wire_data.body, p->reset_wire_data.len); if ((dev = open_dev(0)) == NULL) return; fido_dev_reset(dev); fido_dev_close(dev); fido_dev_free(&dev); } static void dev_get_cbor_info(const struct param *p) { fido_dev_t *dev; fido_cbor_info_t *ci; uint64_t n; uint8_t proto, major, minor, build, flags; set_wire_data(p->info_wire_data.body, p->info_wire_data.len); if ((dev = open_dev(0)) == NULL) return; proto = fido_dev_protocol(dev); major = fido_dev_major(dev); minor = fido_dev_minor(dev); build = fido_dev_build(dev); flags = fido_dev_flags(dev); consume(&proto, sizeof(proto)); consume(&major, sizeof(major)); consume(&minor, sizeof(minor)); consume(&build, sizeof(build)); consume(&flags, sizeof(flags)); if ((ci = fido_cbor_info_new()) == NULL) goto out; fido_dev_get_cbor_info(dev, ci); for (size_t i = 0; i < fido_cbor_info_versions_len(ci); i++) { char * const *sa = fido_cbor_info_versions_ptr(ci); consume(sa[i], strlen(sa[i])); } for (size_t i = 0; i < fido_cbor_info_extensions_len(ci); i++) { char * const *sa = fido_cbor_info_extensions_ptr(ci); consume(sa[i], strlen(sa[i])); } for (size_t i = 0; i < fido_cbor_info_transports_len(ci); i++) { char * const *sa = fido_cbor_info_transports_ptr(ci); consume(sa[i], strlen(sa[i])); } for (size_t i = 0; i < fido_cbor_info_options_len(ci); i++) { char * const *sa = fido_cbor_info_options_name_ptr(ci); const bool *va = fido_cbor_info_options_value_ptr(ci); consume(sa[i], strlen(sa[i])); consume(&va[i], sizeof(va[i])); } /* +1 on purpose */ for (size_t i = 0; i <= fido_cbor_info_algorithm_count(ci); i++) { const char *type = fido_cbor_info_algorithm_type(ci, i); int cose = fido_cbor_info_algorithm_cose(ci, i); consume_str(type); consume(&cose, sizeof(cose)); } n = fido_cbor_info_maxmsgsiz(ci); consume(&n, sizeof(n)); n = fido_cbor_info_maxcredbloblen(ci); consume(&n, sizeof(n)); n = fido_cbor_info_maxcredcntlst(ci); consume(&n, sizeof(n)); n = fido_cbor_info_maxcredidlen(ci); consume(&n, sizeof(n)); n = fido_cbor_info_fwversion(ci); consume(&n, sizeof(n)); consume(fido_cbor_info_aaguid_ptr(ci), fido_cbor_info_aaguid_len(ci)); consume(fido_cbor_info_protocols_ptr(ci), fido_cbor_info_protocols_len(ci)); out: fido_dev_close(dev); fido_dev_free(&dev); fido_cbor_info_free(&ci); } static void dev_set_pin(const struct param *p) { fido_dev_t *dev; set_wire_data(p->set_pin_wire_data.body, p->set_pin_wire_data.len); if ((dev = open_dev(0)) == NULL) return; fido_dev_set_pin(dev, p->pin1, NULL); fido_dev_close(dev); fido_dev_free(&dev); } static void dev_change_pin(const struct param *p) { fido_dev_t *dev; set_wire_data(p->change_pin_wire_data.body, p->change_pin_wire_data.len); if ((dev = open_dev(0)) == NULL) return; fido_dev_set_pin(dev, p->pin2, p->pin1); fido_dev_close(dev); fido_dev_free(&dev); } static void dev_get_retry_count(const struct param *p) { fido_dev_t *dev; int n = 0; set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len); if ((dev = open_dev(0)) == NULL) return; fido_dev_get_retry_count(dev, &n); consume(&n, sizeof(n)); fido_dev_close(dev); fido_dev_free(&dev); } static void dev_get_uv_retry_count(const struct param *p) { fido_dev_t *dev; int n = 0; set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len); if ((dev = open_dev(0)) == NULL) return; fido_dev_get_uv_retry_count(dev, &n); consume(&n, sizeof(n)); fido_dev_close(dev); fido_dev_free(&dev); } static void dev_enable_entattest(const struct param *p) { fido_dev_t *dev; const char *pin; int r; set_wire_data(p->config_wire_data.body, p->config_wire_data.len); if ((dev = open_dev(0)) == NULL) return; pin = p->pin1; if (strlen(pin) == 0) pin = NULL; r = fido_dev_enable_entattest(dev, pin); consume_str(fido_strerr(r)); fido_dev_close(dev); fido_dev_free(&dev); } static void dev_toggle_always_uv(const struct param *p) { fido_dev_t *dev; const char *pin; int r; set_wire_data(p->config_wire_data.body, p->config_wire_data.len); if ((dev = open_dev(0)) == NULL) return; pin = p->pin1; if (strlen(pin) == 0) pin = NULL; r = fido_dev_toggle_always_uv(dev, pin); consume_str(fido_strerr(r)); fido_dev_close(dev); fido_dev_free(&dev); } static void dev_force_pin_change(const struct param *p) { fido_dev_t *dev; const char *pin; int r; set_wire_data(p->config_wire_data.body, p->config_wire_data.len); if ((dev = open_dev(0)) == NULL) return; pin = p->pin1; if (strlen(pin) == 0) pin = NULL; r = fido_dev_force_pin_change(dev, pin); consume_str(fido_strerr(r)); fido_dev_close(dev); fido_dev_free(&dev); } static void dev_set_pin_minlen(const struct param *p) { fido_dev_t *dev; const char *pin; int r; set_wire_data(p->config_wire_data.body, p->config_wire_data.len); if ((dev = open_dev(0)) == NULL) return; pin = p->pin1; if (strlen(pin) == 0) pin = NULL; r = fido_dev_set_pin_minlen(dev, strlen(p->pin2), pin); consume_str(fido_strerr(r)); fido_dev_close(dev); fido_dev_free(&dev); } +static void +dev_set_pin_minlen_rpid(const struct param *p) +{ + fido_dev_t *dev; + const char *rpid[MAXRPID]; + const char *pin; + size_t n; + int r; + + set_wire_data(p->config_wire_data.body, p->config_wire_data.len); + if ((dev = open_dev(0)) == NULL) + return; + n = uniform_random(MAXRPID); + for (size_t i = 0; i < n; i++) + rpid[i] = dummy_rp_id; + pin = p->pin1; + if (strlen(pin) == 0) + pin = NULL; + r = fido_dev_set_pin_minlen_rpid(dev, rpid, n, pin); + consume_str(fido_strerr(r)); + fido_dev_close(dev); + fido_dev_free(&dev); +} + void test(const struct param *p) { prng_init((unsigned int)p->seed); + fuzz_clock_reset(); fido_init(FIDO_DEBUG); fido_set_log_handler(consume_str); dev_reset(p); dev_get_cbor_info(p); dev_set_pin(p); dev_change_pin(p); dev_get_retry_count(p); dev_get_uv_retry_count(p); dev_enable_entattest(p); dev_toggle_always_uv(p); dev_force_pin_change(p); dev_set_pin_minlen(p); + dev_set_pin_minlen_rpid(p); } void mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN { if (flags & MUTATE_SEED) p->seed = (int)seed; if (flags & MUTATE_PARAM) { mutate_string(p->pin1); mutate_string(p->pin2); } if (flags & MUTATE_WIREDATA) { mutate_blob(&p->reset_wire_data); mutate_blob(&p->info_wire_data); mutate_blob(&p->set_pin_wire_data); mutate_blob(&p->change_pin_wire_data); mutate_blob(&p->retry_wire_data); } } diff --git a/contrib/libfido2/fuzz/fuzz_netlink.c b/contrib/libfido2/fuzz/fuzz_netlink.c index 9b7f930cde38..2447215a2471 100644 --- a/contrib/libfido2/fuzz/fuzz_netlink.c +++ b/contrib/libfido2/fuzz/fuzz_netlink.c @@ -1,249 +1,163 @@ /* * Copyright (c) 2020 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "mutator_aux.h" +#include "dummy.h" struct param { int seed; int dev; struct blob wiredata; }; -/* - * Sample netlink messages. These are unlikely to get the harness very far in - * terms of coverage, but serve to give libFuzzer a sense of the underlying - * structure. - */ -static const uint8_t sample_netlink_wiredata[] = { - 0xd8, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x9d, 0x2e, 0x00, 0x00, - 0x01, 0x02, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, - 0x6e, 0x66, 0x63, 0x00, 0x06, 0x00, 0x01, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x05, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0x00, - 0x14, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, - 0x08, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x03, 0x00, 0x08, 0x00, 0x01, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x04, 0x00, - 0x08, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x05, 0x00, 0x08, 0x00, 0x01, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x06, 0x00, - 0x08, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x07, 0x00, 0x08, 0x00, 0x01, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x08, 0x00, - 0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x09, 0x00, 0x08, 0x00, 0x01, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0a, 0x00, - 0x08, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x01, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0c, 0x00, - 0x08, 0x00, 0x01, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x01, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0e, 0x00, - 0x08, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x01, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x10, 0x00, - 0x08, 0x00, 0x01, 0x00, 0x1b, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x11, 0x00, 0x08, 0x00, 0x01, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00, - 0x08, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x13, 0x00, 0x08, 0x00, 0x01, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x07, 0x00, - 0x18, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00, - 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x9d, 0x2e, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x9d, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x05, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x09, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x9d, 0x2e, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, - 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x05, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x06, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x93, 0xb9, 0x25, 0x00 -}; - struct param * unpack(const uint8_t *ptr, size_t len) { cbor_item_t *item = NULL, **v; struct cbor_load_result cbor; struct param *p; int ok = -1; if ((p = calloc(1, sizeof(*p))) == NULL || (item = cbor_load(ptr, len, &cbor)) == NULL || cbor.read != len || cbor_isa_array(item) == false || cbor_array_is_definite(item) == false || cbor_array_size(item) != 3 || (v = cbor_array_handle(item)) == NULL) goto fail; if (unpack_int(v[0], &p->seed) < 0 || unpack_int(v[1], &p->dev) < 0 || unpack_blob(v[2], &p->wiredata) < 0) goto fail; ok = 0; fail: if (ok < 0) { free(p); p = NULL; } if (item) cbor_decref(&item); return p; } size_t pack(uint8_t *ptr, size_t len, const struct param *p) { cbor_item_t *argv[3], *array = NULL; size_t cbor_alloc_len, cbor_len = 0; unsigned char *cbor = NULL; memset(argv, 0, sizeof(argv)); if ((array = cbor_new_definite_array(3)) == NULL || (argv[0] = pack_int(p->seed)) == NULL || (argv[1] = pack_int(p->dev)) == NULL || (argv[2] = pack_blob(&p->wiredata)) == NULL) goto fail; for (size_t i = 0; i < 3; i++) if (cbor_array_push(array, argv[i]) == false) goto fail; if ((cbor_len = cbor_serialize_alloc(array, &cbor, &cbor_alloc_len)) > len) { cbor_len = 0; goto fail; } memcpy(ptr, cbor, cbor_len); fail: for (size_t i = 0; i < 3; i++) if (argv[i]) cbor_decref(&argv[i]); if (array) cbor_decref(&array); free(cbor); return cbor_len; } size_t pack_dummy(uint8_t *ptr, size_t len) { struct param dummy; uint8_t blob[4096]; size_t blob_len; memset(&dummy, 0, sizeof(dummy)); - dummy.wiredata.len = sizeof(sample_netlink_wiredata); - memcpy(&dummy.wiredata.body, &sample_netlink_wiredata, + dummy.wiredata.len = sizeof(dummy_netlink_wiredata); + memcpy(&dummy.wiredata.body, &dummy_netlink_wiredata, dummy.wiredata.len); assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0); if (blob_len > len) { memcpy(ptr, blob, len); return len; } memcpy(ptr, blob, blob_len); return blob_len; } void test(const struct param *p) { fido_nl_t *nl; uint32_t target; prng_init((unsigned int)p->seed); + fuzz_clock_reset(); fido_init(FIDO_DEBUG); fido_set_log_handler(consume_str); set_netlink_io_functions(fd_read, fd_write); set_wire_data(p->wiredata.body, p->wiredata.len); if ((nl = fido_nl_new()) == NULL) return; consume(&nl->fd, sizeof(nl->fd)); consume(&nl->nfc_type, sizeof(nl->nfc_type)); consume(&nl->nfc_mcastgrp, sizeof(nl->nfc_mcastgrp)); consume(&nl->saddr, sizeof(nl->saddr)); fido_nl_power_nfc(nl, (uint32_t)p->dev); if (fido_nl_get_nfc_target(nl, (uint32_t)p->dev, &target) == 0) consume(&target, sizeof(target)); fido_nl_free(&nl); } void mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN { if (flags & MUTATE_SEED) p->seed = (int)seed; if (flags & MUTATE_PARAM) mutate_int(&p->dev); if (flags & MUTATE_WIREDATA) mutate_blob(&p->wiredata); } diff --git a/contrib/libfido2/fuzz/mutator_aux.c b/contrib/libfido2/fuzz/mutator_aux.c index 0dc3ae1bf054..92a67be78106 100644 --- a/contrib/libfido2/fuzz/mutator_aux.c +++ b/contrib/libfido2/fuzz/mutator_aux.c @@ -1,326 +1,329 @@ /* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include #include #include "mutator_aux.h" #define HID_DEV_HANDLE 0x68696421 #define NFC_DEV_HANDLE 0x6e666321 int fido_nfc_rx(fido_dev_t *, uint8_t, unsigned char *, size_t, int); int fido_nfc_tx(fido_dev_t *, uint8_t, const unsigned char *, size_t); size_t LLVMFuzzerMutate(uint8_t *, size_t, size_t); static const uint8_t *wire_data_ptr = NULL; static size_t wire_data_len = 0; void consume(const void *body, size_t len) { const volatile uint8_t *ptr = body; volatile uint8_t x = 0; #ifdef WITH_MSAN __msan_check_mem_is_initialized(body, len); #endif while (len--) x ^= *ptr++; + + (void)x; } void consume_str(const char *str) { if (str != NULL) consume(str, strlen(str) + 1); } int unpack_int(cbor_item_t *item, int *v) { if (cbor_is_int(item) == false || cbor_int_get_width(item) != CBOR_INT_64) return -1; if (cbor_isa_uint(item)) *v = (int)cbor_get_uint64(item); else *v = (int)(-cbor_get_uint64(item) - 1); return 0; } int unpack_string(cbor_item_t *item, char *v) { size_t len; if (cbor_isa_bytestring(item) == false || (len = cbor_bytestring_length(item)) >= MAXSTR) return -1; memcpy(v, cbor_bytestring_handle(item), len); v[len] = '\0'; return 0; } int unpack_byte(cbor_item_t *item, uint8_t *v) { if (cbor_isa_uint(item) == false || cbor_int_get_width(item) != CBOR_INT_8) return -1; *v = cbor_get_uint8(item); return 0; } int unpack_blob(cbor_item_t *item, struct blob *v) { if (cbor_isa_bytestring(item) == false || (v->len = cbor_bytestring_length(item)) > sizeof(v->body)) return -1; memcpy(v->body, cbor_bytestring_handle(item), v->len); return 0; } cbor_item_t * pack_int(int v) NO_MSAN { if (v < 0) return cbor_build_negint64((uint64_t)(-(int64_t)v - 1)); else return cbor_build_uint64((uint64_t)v); } cbor_item_t * pack_string(const char *v) NO_MSAN { if (strlen(v) >= MAXSTR) return NULL; return cbor_build_bytestring((const unsigned char *)v, strlen(v)); } cbor_item_t * pack_byte(uint8_t v) NO_MSAN { return cbor_build_uint8(v); } cbor_item_t * pack_blob(const struct blob *v) NO_MSAN { return cbor_build_bytestring(v->body, v->len); } void mutate_byte(uint8_t *b) { LLVMFuzzerMutate(b, sizeof(*b), sizeof(*b)); } void mutate_int(int *i) { LLVMFuzzerMutate((uint8_t *)i, sizeof(*i), sizeof(*i)); } void mutate_blob(struct blob *blob) { blob->len = LLVMFuzzerMutate((uint8_t *)blob->body, blob->len, sizeof(blob->body)); } void mutate_string(char *s) { size_t n; n = LLVMFuzzerMutate((uint8_t *)s, strlen(s), MAXSTR - 1); s[n] = '\0'; } /* XXX should fail, but doesn't */ static int buf_read(unsigned char *ptr, size_t len, int ms) { size_t n; (void)ms; if (wire_data_len < len) n = wire_data_len; else n = len; memcpy(ptr, wire_data_ptr, n); wire_data_ptr += n; wire_data_len -= n; return (int)n; } static int buf_write(const unsigned char *ptr, size_t len) { consume(ptr, len); if (uniform_random(400) < 1) { errno = EIO; return -1; } return (int)len; } static void * hid_open(const char *path) { (void)path; return (void *)HID_DEV_HANDLE; } static void hid_close(void *handle) { assert(handle == (void *)HID_DEV_HANDLE); } static int hid_read(void *handle, unsigned char *ptr, size_t len, int ms) { assert(handle == (void *)HID_DEV_HANDLE); assert(len >= CTAP_MIN_REPORT_LEN && len <= CTAP_MAX_REPORT_LEN); return buf_read(ptr, len, ms); } static int hid_write(void *handle, const unsigned char *ptr, size_t len) { assert(handle == (void *)HID_DEV_HANDLE); assert(len >= CTAP_MIN_REPORT_LEN + 1 && len <= CTAP_MAX_REPORT_LEN + 1); return buf_write(ptr, len); } static void * nfc_open(const char *path) { (void)path; return (void *)NFC_DEV_HANDLE; } static void nfc_close(void *handle) { assert(handle == (void *)NFC_DEV_HANDLE); } static int nfc_read(void *handle, unsigned char *ptr, size_t len, int ms) { assert(handle == (void *)NFC_DEV_HANDLE); assert(len > 0 && len <= 256 + 2); return buf_read(ptr, len, ms); } static int nfc_write(void *handle, const unsigned char *ptr, size_t len) { assert(handle == (void *)NFC_DEV_HANDLE); assert(len > 0 && len <= 256 + 2); return buf_write(ptr, len); } ssize_t fd_read(int fd, void *ptr, size_t len) { assert(fd != -1); return buf_read(ptr, len, -1); } ssize_t fd_write(int fd, const void *ptr, size_t len) { assert(fd != -1); return buf_write(ptr, len); } fido_dev_t * open_dev(int nfc) { fido_dev_t *dev; fido_dev_io_t io; fido_dev_transport_t t; memset(&io, 0, sizeof(io)); memset(&t, 0, sizeof(t)); if ((dev = fido_dev_new()) == NULL) return NULL; if (nfc) { io.open = nfc_open; io.close = nfc_close; io.read = nfc_read; io.write = nfc_write; } else { io.open = hid_open; io.close = hid_close; io.read = hid_read; io.write = hid_write; } if (fido_dev_set_io_functions(dev, &io) != FIDO_OK) goto fail; if (nfc) { t.rx = fido_nfc_rx; t.tx = fido_nfc_tx; if (fido_dev_set_transport_functions(dev, &t) != FIDO_OK) goto fail; } - if (fido_dev_open(dev, "nodev") != FIDO_OK) + if (fido_dev_set_timeout(dev, 300) != FIDO_OK || + fido_dev_open(dev, "nodev") != FIDO_OK) goto fail; return dev; fail: fido_dev_free(&dev); return NULL; } void set_wire_data(const uint8_t *ptr, size_t len) { wire_data_ptr = ptr; wire_data_len = len; } diff --git a/contrib/libfido2/fuzz/mutator_aux.h b/contrib/libfido2/fuzz/mutator_aux.h index 6b1a98215b07..a9bebe232bae 100644 --- a/contrib/libfido2/fuzz/mutator_aux.h +++ b/contrib/libfido2/fuzz/mutator_aux.h @@ -1,96 +1,97 @@ /* - * Copyright (c) 2019 Yubico AB. All rights reserved. + * Copyright (c) 2019-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _MUTATOR_AUX_H #define _MUTATOR_AUX_H #include #include #include #include "../src/fido.h" #include "../src/fido/bio.h" #include "../src/fido/config.h" #include "../src/fido/credman.h" #include "../src/fido/eddsa.h" #include "../src/fido/es256.h" #include "../src/fido/es256.h" #include "../src/fido/rs256.h" #include "../src/netlink.h" /* * As of LLVM 10.0.0, MSAN support in libFuzzer was still experimental. * We therefore have to be careful when using our custom mutator, or * MSAN will flag uninitialised reads on memory populated by libFuzzer. * Since there is no way to suppress MSAN without regenerating object * code (in which case you might as well rebuild libFuzzer with MSAN), * we adjust our mutator to make it less accurate while allowing * fuzzing to proceed. */ #if defined(__has_feature) # if __has_feature(memory_sanitizer) # include # define NO_MSAN __attribute__((no_sanitize("memory"))) # define WITH_MSAN 1 # endif #endif #if !defined(WITH_MSAN) # define NO_MSAN #endif #define MUTATE_SEED 0x01 #define MUTATE_PARAM 0x02 #define MUTATE_WIREDATA 0x04 #define MUTATE_ALL (MUTATE_SEED | MUTATE_PARAM | MUTATE_WIREDATA) #define MAXSTR 1024 -#define MAXBLOB 3072 +#define MAXBLOB 3600 struct blob { uint8_t body[MAXBLOB]; size_t len; }; struct param; struct param *unpack(const uint8_t *, size_t); size_t pack(uint8_t *, size_t, const struct param *); size_t pack_dummy(uint8_t *, size_t); void mutate(struct param *, unsigned int, unsigned int); void test(const struct param *); void consume(const void *, size_t); void consume_str(const char *); int unpack_blob(cbor_item_t *, struct blob *); int unpack_byte(cbor_item_t *, uint8_t *); int unpack_int(cbor_item_t *, int *); int unpack_string(cbor_item_t *, char *); cbor_item_t *pack_blob(const struct blob *); cbor_item_t *pack_byte(uint8_t); cbor_item_t *pack_int(int); cbor_item_t *pack_string(const char *); void mutate_byte(uint8_t *); void mutate_int(int *); void mutate_blob(struct blob *); void mutate_string(char *); ssize_t fd_read(int, void *, size_t); ssize_t fd_write(int, const void *, size_t); fido_dev_t *open_dev(int); void set_wire_data(const uint8_t *, size_t); +void fuzz_clock_reset(void); void prng_init(unsigned long); unsigned long prng_uint32(void); uint32_t uniform_random(uint32_t); #endif /* !_MUTATOR_AUX_H */ diff --git a/contrib/libfido2/fuzz/report.tgz b/contrib/libfido2/fuzz/report.tgz index c8d4d3f38028..cf74f315cb80 100644 Binary files a/contrib/libfido2/fuzz/report.tgz and b/contrib/libfido2/fuzz/report.tgz differ diff --git a/contrib/libfido2/fuzz/summary.txt b/contrib/libfido2/fuzz/summary.txt index 8516bf3723aa..298c8377379f 100644 --- a/contrib/libfido2/fuzz/summary.txt +++ b/contrib/libfido2/fuzz/summary.txt @@ -1,51 +1,57 @@ Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -fuzz/prng.c 31 0 100.00% 2 0 100.00% 49 0 100.00% -fuzz/udev.c 103 5 95.15% 17 1 94.12% 141 7 95.04% -fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 23 1 95.65% +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +fuzz/clock.c 24 1 95.83% 4 0 100.00% 35 0 100.00% +fuzz/prng.c 31 0 100.00% 2 0 100.00% 35 0 100.00% +fuzz/udev.c 103 1 99.03% 17 0 100.00% 126 3 97.62% +fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 12 1 91.67% fuzz/wrap.c 6 0 100.00% 1 0 100.00% 7 0 100.00% -openbsd-compat/explicit_bzero.c 4 0 100.00% 1 0 100.00% 13 0 100.00% +openbsd-compat/explicit_bzero.c 4 0 100.00% 1 0 100.00% 7 0 100.00% openbsd-compat/freezero.c 4 0 100.00% 1 0 100.00% 6 0 100.00% -openbsd-compat/recallocarray.c 41 7 82.93% 1 0 100.00% 49 7 85.71% -openbsd-compat/strlcat.c 12 1 91.67% 1 0 100.00% 25 1 96.00% -openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 8 0 100.00% -src/aes256.c 115 4 96.52% 8 0 100.00% 175 14 92.00% -src/assert.c 616 46 92.53% 59 3 94.92% 924 64 93.07% -src/authkey.c 44 0 100.00% 5 0 100.00% 75 0 100.00% -src/bio.c 419 20 95.23% 49 2 95.92% 660 22 96.67% -src/blob.c 53 3 94.34% 10 0 100.00% 96 7 92.71% -src/buf.c 8 1 87.50% 2 0 100.00% 20 1 95.00% -src/cbor.c 986 17 98.28% 53 0 100.00% 1426 37 97.41% -src/compress.c 34 4 88.24% 3 0 100.00% 30 3 90.00% -src/config.c 94 1 98.94% 10 0 100.00% 146 3 97.95% -src/cred.c 581 38 93.46% 63 2 96.83% 872 48 94.50% -src/credman.c 382 10 97.38% 40 0 100.00% 614 15 97.56% -src/dev.c 414 74 82.13% 43 6 86.05% 556 106 80.94% -src/ecdh.c 117 2 98.29% 4 0 100.00% 161 5 96.89% -src/eddsa.c 54 0 100.00% 8 0 100.00% 77 0 100.00% +openbsd-compat/recallocarray.c 41 7 82.93% 1 0 100.00% 36 7 80.56% +openbsd-compat/strlcat.c 12 1 91.67% 1 0 100.00% 21 1 95.24% +openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 7 0 100.00% +src/aes256.c 115 4 96.52% 8 0 100.00% 157 14 91.08% +src/assert.c 563 40 92.90% 56 3 94.64% 694 40 94.24% +src/authkey.c 44 0 100.00% 5 0 100.00% 59 0 100.00% +src/bio.c 419 20 95.23% 49 2 95.92% 559 21 96.24% +src/blob.c 53 2 96.23% 10 0 100.00% 83 4 95.18% +src/buf.c 8 1 87.50% 2 0 100.00% 16 1 93.75% +src/cbor.c 1047 28 97.33% 54 0 100.00% 1237 54 95.63% +src/compress.c 34 4 88.24% 3 0 100.00% 28 3 89.29% +src/config.c 108 0 100.00% 11 0 100.00% 151 0 100.00% +src/cred.c 632 34 94.62% 69 2 97.10% 830 36 95.66% +src/credman.c 382 10 97.38% 40 0 100.00% 518 15 97.10% +src/dev.c 420 78 81.43% 44 6 86.36% 488 102 79.10% +src/ecdh.c 117 2 98.29% 4 0 100.00% 146 5 96.58% +src/eddsa.c 80 3 96.25% 10 0 100.00% 106 8 92.45% src/err.c 122 10 91.80% 1 0 100.00% 126 10 92.06% -src/es256.c 280 0 100.00% 16 0 100.00% 394 0 100.00% -src/hid.c 60 0 100.00% 12 0 100.00% 134 0 100.00% -src/hid_linux.c 173 68 60.69% 14 7 50.00% 303 123 59.41% -src/hid_unix.c 30 20 33.33% 2 0 100.00% 52 28 46.15% -src/info.c 198 0 100.00% 44 0 100.00% 405 0 100.00% -src/io.c 158 7 95.57% 10 0 100.00% 228 11 95.18% -src/iso7816.c 18 1 94.44% 5 0 100.00% 42 0 100.00% -src/largeblob.c 513 19 96.30% 30 0 100.00% 759 43 94.33% -src/log.c 39 5 87.18% 7 1 85.71% 73 4 94.52% -src/netlink.c 327 15 95.41% 40 0 100.00% 565 35 93.81% -src/nfc_linux.c 304 123 59.54% 23 10 56.52% 520 199 61.73% -src/pin.c 403 3 99.26% 26 0 100.00% 583 3 99.49% -src/random.c 6 1 83.33% 1 0 100.00% 8 1 87.50% -src/reset.c 24 0 100.00% 3 0 100.00% 27 0 100.00% -src/rs256.c 102 4 96.08% 8 0 100.00% 138 6 95.65% -src/u2f.c 473 6 98.73% 15 0 100.00% 742 9 98.79% +src/es256.c 306 5 98.37% 19 0 100.00% 358 7 98.04% +src/hid.c 60 0 100.00% 12 0 100.00% 114 0 100.00% +src/hid_linux.c 173 68 60.69% 14 7 50.00% 250 104 58.40% +src/hid_unix.c 28 20 28.57% 2 0 100.00% 43 24 44.19% +src/info.c 184 0 100.00% 39 0 100.00% 316 0 100.00% +src/io.c 182 7 96.15% 13 0 100.00% 221 11 95.02% +src/iso7816.c 18 1 94.44% 5 0 100.00% 38 0 100.00% +src/largeblob.c 513 21 95.91% 30 0 100.00% 684 47 93.13% +src/log.c 39 5 87.18% 7 1 85.71% 63 4 93.65% +src/netlink.c 328 14 95.73% 40 0 100.00% 498 32 93.57% +src/nfc_linux.c 327 73 77.68% 23 5 78.26% 458 124 72.93% +src/pin.c 403 3 99.26% 26 0 100.00% 495 3 99.39% +src/random.c 6 1 83.33% 1 0 100.00% 6 1 83.33% +src/reset.c 24 0 100.00% 3 0 100.00% 23 0 100.00% +src/rs1.c 25 1 96.00% 3 0 100.00% 39 3 92.31% +src/rs256.c 141 8 94.33% 13 0 100.00% 172 10 94.19% +src/time.c 43 3 93.02% 3 0 100.00% 43 1 97.67% +src/tpm.c 76 0 100.00% 7 0 100.00% 138 0 100.00% +src/types.c 25 0 100.00% 6 0 100.00% 46 0 100.00% +src/u2f.c 528 4 99.24% 17 0 100.00% 685 12 98.25% Files which contain no functions: openbsd-compat/openbsd-compat.h 0 0 - 0 0 - 0 0 - +openbsd-compat/time.h 0 0 - 0 0 - 0 0 - src/extern.h 0 0 - 0 0 - 0 0 - src/fido.h 0 0 - 0 0 - 0 0 - src/fido/err.h 0 0 - 0 0 - 0 0 - src/fido/param.h 0 0 - 0 0 - 0 0 - --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -TOTAL 7359 516 92.99% 640 32 95.00% 11252 813 92.77% +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +TOTAL 7809 481 93.84% 679 26 96.17% 10180 708 93.05% diff --git a/contrib/libfido2/fuzz/wrap.c b/contrib/libfido2/fuzz/wrap.c index 5b91a64dbf4b..8d7be6bb6247 100644 --- a/contrib/libfido2/fuzz/wrap.c +++ b/contrib/libfido2/fuzz/wrap.c @@ -1,582 +1,637 @@ /* * Copyright (c) 2019-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ +#include +#include + #include #include #include #include #include #include #include #include #include "mutator_aux.h" extern int prng_up; /* * Build wrappers around functions of interest, and have them fail * in a pseudo-random manner. */ #define WRAP(type, name, args, retval, param, prob) \ extern type __wrap_##name args; \ extern type __real_##name args; \ type __wrap_##name args { \ if (prng_up && uniform_random(400) < (prob)) { \ return (retval); \ } \ \ return (__real_##name param); \ } WRAP(void *, malloc, (size_t size), NULL, (size), 1 ) WRAP(void *, calloc, (size_t nmemb, size_t size), NULL, (nmemb, size), 1 ) +WRAP(void *, + realloc, + (void *ptr, size_t size), + NULL, + (ptr, size), + 1 +) + WRAP(char *, strdup, (const char *s), NULL, (s), 1 ) WRAP(int, EVP_Cipher, (EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, unsigned int inl), -1, (ctx, out, in, inl), 1 ) WRAP(int, EVP_CIPHER_CTX_ctrl, (EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr), 0, (ctx, type, arg, ptr), 1 ) WRAP(EVP_CIPHER_CTX *, EVP_CIPHER_CTX_new, (void), NULL, (), 1 ) -WRAP(int, - EVP_EncryptInit_ex, - (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl, - const unsigned char *key, const unsigned char *iv), - 0, - (ctx, type, impl, key, iv), - 1 -) - -WRAP(int, - EVP_CIPHER_CTX_set_padding, - (EVP_CIPHER_CTX *x, int padding), - 0, - (x, padding), - 1 -) - -WRAP(int, - EVP_EncryptUpdate, - (EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, - const unsigned char *in, int inl), - 0, - (ctx, out, outl, in, inl), - 1 -) - WRAP(int, EVP_CipherInit, (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, const unsigned char *key, const unsigned char *iv, int enc), 0, (ctx, cipher, key, iv, enc), 1 ) -WRAP(int, - EVP_DecryptInit_ex, - (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl, - const unsigned char *key, const unsigned char *iv), - 0, - (ctx, type, impl, key, iv), - 1 -) - -WRAP(int, - EVP_DecryptUpdate, - (EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, - const unsigned char *in, int inl), - 0, - (ctx, out, outl, in, inl), - 1 -) - -WRAP(int, - SHA256_Init, - (SHA256_CTX *c), - 0, - (c), - 1 -) - -WRAP(int, - SHA256_Update, - (SHA256_CTX *c, const void *data, size_t len), - 0, - (c, data, len), - 1 -) - -WRAP(int, - SHA256_Final, - (unsigned char *md, SHA256_CTX *c), - 0, - (md, c), - 1 -) - WRAP(RSA *, EVP_PKEY_get0_RSA, (EVP_PKEY *pkey), NULL, (pkey), 1 ) WRAP(EC_KEY *, EVP_PKEY_get0_EC_KEY, (EVP_PKEY *pkey), NULL, (pkey), 1 ) WRAP(int, EVP_PKEY_get_raw_public_key, (const EVP_PKEY *pkey, unsigned char *pub, size_t *len), 0, (pkey, pub, len), 1 ) WRAP(EVP_MD_CTX *, EVP_MD_CTX_new, (void), NULL, (), 1 ) WRAP(int, EVP_DigestVerifyInit, (EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey), 0, (ctx, pctx, type, e, pkey), 1 ) +WRAP(int, + EVP_DigestInit_ex, + (EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl), + 0, + (ctx, type, impl), + 1 +) + +WRAP(int, + EVP_DigestUpdate, + (EVP_MD_CTX *ctx, const void *data, size_t count), + 0, + (ctx, data, count), + 1 +) + +WRAP(int, + EVP_DigestFinal_ex, + (EVP_MD_CTX *ctx, unsigned char *md, unsigned int *isize), + 0, + (ctx, md, isize), + 1 +) + WRAP(BIGNUM *, BN_bin2bn, (const unsigned char *s, int len, BIGNUM *ret), NULL, (s, len, ret), 1 ) WRAP(int, BN_bn2bin, (const BIGNUM *a, unsigned char *to), -1, (a, to), 1 ) WRAP(BIGNUM *, BN_CTX_get, (BN_CTX *ctx), NULL, (ctx), 1 ) WRAP(BN_CTX *, BN_CTX_new, (void), NULL, (), 1 ) WRAP(BIGNUM *, BN_new, (void), NULL, (), 1 ) +WRAP(RSA *, + RSA_new, + (void), + NULL, + (), + 1 +) + WRAP(int, RSA_set0_key, (RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d), 0, (r, n, e, d), 1 ) +WRAP(int, + RSA_pkey_ctx_ctrl, + (EVP_PKEY_CTX *ctx, int optype, int cmd, int p1, void *p2), + -1, + (ctx, optype, cmd, p1, p2), + 1 +) + WRAP(EC_KEY *, EC_KEY_new_by_curve_name, (int nid), NULL, (nid), 1 ) WRAP(const EC_GROUP *, EC_KEY_get0_group, (const EC_KEY *key), NULL, (key), 1 ) WRAP(const BIGNUM *, EC_KEY_get0_private_key, (const EC_KEY *key), NULL, (key), 1 ) WRAP(EC_POINT *, EC_POINT_new, (const EC_GROUP *group), NULL, (group), 1 ) WRAP(int, EC_POINT_get_affine_coordinates_GFp, (const EC_GROUP *group, const EC_POINT *p, BIGNUM *x, BIGNUM *y, BN_CTX *ctx), 0, (group, p, x, y, ctx), 1 ) WRAP(EVP_PKEY *, EVP_PKEY_new, (void), NULL, (), 1 ) WRAP(int, EVP_PKEY_assign, (EVP_PKEY *pkey, int type, void *key), 0, (pkey, type, key), 1 ) WRAP(int, EVP_PKEY_keygen_init, (EVP_PKEY_CTX *ctx), 0, (ctx), 1 ) WRAP(int, EVP_PKEY_keygen, (EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey), 0, (ctx, ppkey), 1 ) WRAP(int, EVP_PKEY_paramgen_init, (EVP_PKEY_CTX *ctx), 0, (ctx), 1 ) WRAP(int, EVP_PKEY_paramgen, (EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey), 0, (ctx, ppkey), 1 ) WRAP(EVP_PKEY *, EVP_PKEY_new_raw_public_key, (int type, ENGINE *e, const unsigned char *key, size_t keylen), NULL, (type, e, key, keylen), 1 ) WRAP(EVP_PKEY_CTX *, EVP_PKEY_CTX_new, (EVP_PKEY *pkey, ENGINE *e), NULL, (pkey, e), 1 ) WRAP(EVP_PKEY_CTX *, EVP_PKEY_CTX_new_id, (int id, ENGINE *e), NULL, (id, e), 1 ) WRAP(int, EVP_PKEY_derive, (EVP_PKEY_CTX *ctx, unsigned char *key, size_t *pkeylen), 0, (ctx, key, pkeylen), 1 ) WRAP(int, EVP_PKEY_derive_init, (EVP_PKEY_CTX *ctx), 0, (ctx), 1 ) WRAP(int, EVP_PKEY_derive_set_peer, (EVP_PKEY_CTX *ctx, EVP_PKEY *peer), 0, (ctx, peer), 1 ) +WRAP(int, + EVP_PKEY_verify_init, + (EVP_PKEY_CTX *ctx), + 0, + (ctx), + 1 +) + +WRAP(int, + EVP_PKEY_CTX_ctrl, + (EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd, int p1, void *p2), + -1, + (ctx, keytype, optype, cmd, p1, p2), + 1 +) + +WRAP(const EVP_MD *, + EVP_sha1, + (void), + NULL, + (), + 1 +) + WRAP(const EVP_MD *, EVP_sha256, (void), NULL, (), 1 ) +WRAP(const EVP_CIPHER *, + EVP_aes_256_cbc, + (void), + NULL, + (), + 1 +) + +WRAP(const EVP_CIPHER *, + EVP_aes_256_gcm, + (void), + NULL, + (), + 1 +) + WRAP(unsigned char *, HMAC, (const EVP_MD *evp_md, const void *key, int key_len, const unsigned char *d, int n, unsigned char *md, unsigned int *md_len), NULL, (evp_md, key, key_len, d, n, md, md_len), 1 ) WRAP(HMAC_CTX *, HMAC_CTX_new, (void), NULL, (), 1 ) WRAP(int, HMAC_Init_ex, (HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md, ENGINE *impl), 0, (ctx, key, key_len, md, impl), 1 ) WRAP(int, HMAC_Update, (HMAC_CTX *ctx, const unsigned char *data, int len), 0, (ctx, data, len), 1 ) WRAP(int, HMAC_Final, (HMAC_CTX *ctx, unsigned char *md, unsigned int *len), 0, (ctx, md, len), 1 ) +WRAP(unsigned char *, + SHA1, + (const unsigned char *d, size_t n, unsigned char *md), + NULL, + (d, n, md), + 1 +) + WRAP(unsigned char *, SHA256, (const unsigned char *d, size_t n, unsigned char *md), NULL, (d, n, md), 1 ) WRAP(cbor_item_t *, cbor_build_string, (const char *val), NULL, (val), 1 ) WRAP(cbor_item_t *, cbor_build_bytestring, (cbor_data handle, size_t length), NULL, (handle, length), 1 ) WRAP(cbor_item_t *, cbor_build_bool, (bool value), NULL, (value), 1 ) WRAP(cbor_item_t *, cbor_build_negint8, (uint8_t value), NULL, (value), 1 ) WRAP(cbor_item_t *, cbor_build_negint16, (uint16_t value), NULL, (value), 1 ) WRAP(cbor_item_t *, cbor_load, (cbor_data source, size_t source_size, struct cbor_load_result *result), NULL, (source, source_size, result), 1 ) WRAP(cbor_item_t *, cbor_build_uint8, (uint8_t value), NULL, (value), 1 ) +WRAP(cbor_item_t *, + cbor_build_uint16, + (uint16_t value), + NULL, + (value), + 1 +) + WRAP(cbor_item_t *, cbor_build_uint32, (uint32_t value), NULL, (value), 1 ) +WRAP(cbor_item_t *, + cbor_build_uint64, + (uint64_t value), + NULL, + (value), + 1 +) + WRAP(struct cbor_pair *, cbor_map_handle, (const cbor_item_t *item), NULL, (item), 1 ) WRAP(cbor_item_t **, cbor_array_handle, (const cbor_item_t *item), NULL, (item), 1 ) WRAP(bool, cbor_array_push, (cbor_item_t *array, cbor_item_t *pushee), false, (array, pushee), 1 ) WRAP(bool, cbor_map_add, (cbor_item_t *item, struct cbor_pair pair), false, (item, pair), 1 ) WRAP(cbor_item_t *, cbor_new_definite_map, (size_t size), NULL, (size), 1 ) WRAP(cbor_item_t *, cbor_new_definite_array, (size_t size), NULL, (size), 1 ) +WRAP(cbor_item_t *, + cbor_new_definite_bytestring, + (void), + NULL, + (), + 1 +) + WRAP(size_t, cbor_serialize_alloc, (const cbor_item_t *item, cbor_mutable_data *buffer, size_t *buffer_size), 0, (item, buffer, buffer_size), 1 ) WRAP(int, fido_tx, - (fido_dev_t *d, uint8_t cmd, const void *buf, size_t count), + (fido_dev_t *d, uint8_t cmd, const void *buf, size_t count, int *ms), -1, - (d, cmd, buf, count), + (d, cmd, buf, count, ms), 1 ) WRAP(int, - usleep, - (unsigned int usec), + bind, + (int sockfd, const struct sockaddr *addr, socklen_t addrlen), -1, - (usec), + (sockfd, addr, addrlen), 1 ) diff --git a/contrib/libfido2/fuzz/wrapped.sym b/contrib/libfido2/fuzz/wrapped.sym index de4f24ae0355..0e9d34627f86 100644 --- a/contrib/libfido2/fuzz/wrapped.sym +++ b/contrib/libfido2/fuzz/wrapped.sym @@ -1,83 +1,92 @@ +bind BN_bin2bn BN_bn2bin BN_CTX_get BN_CTX_new BN_new calloc cbor_array_handle cbor_array_push cbor_build_bool cbor_build_bytestring cbor_build_negint16 cbor_build_negint8 cbor_build_string +cbor_build_uint16 cbor_build_uint32 +cbor_build_uint64 cbor_build_uint8 cbor_load cbor_map_add cbor_map_handle cbor_new_definite_array +cbor_new_definite_bytestring cbor_new_definite_map cbor_serialize_alloc +clock_gettime EC_KEY_get0_group EC_KEY_get0_private_key EC_KEY_new_by_curve_name EC_POINT_get_affine_coordinates_GFp EC_POINT_new +EVP_aes_256_cbc +EVP_aes_256_gcm EVP_Cipher EVP_CIPHER_CTX_ctrl EVP_CIPHER_CTX_new -EVP_CIPHER_CTX_set_padding EVP_CipherInit -EVP_DecryptInit_ex -EVP_DecryptUpdate +EVP_DigestFinal_ex +EVP_DigestInit_ex +EVP_DigestUpdate EVP_DigestVerifyInit -EVP_EncryptInit_ex -EVP_EncryptUpdate EVP_MD_CTX_new EVP_PKEY_assign +EVP_PKEY_CTX_ctrl EVP_PKEY_CTX_new EVP_PKEY_CTX_new_id EVP_PKEY_derive EVP_PKEY_derive_init EVP_PKEY_derive_set_peer EVP_PKEY_get0_EC_KEY EVP_PKEY_get0_RSA EVP_PKEY_get_raw_public_key EVP_PKEY_keygen EVP_PKEY_keygen_init EVP_PKEY_new EVP_PKEY_new_raw_public_key EVP_PKEY_paramgen EVP_PKEY_paramgen_init +EVP_PKEY_verify_init +EVP_sha1 EVP_sha256 fido_tx HMAC HMAC_CTX_new HMAC_Final HMAC_Init_ex HMAC_Update ioctl malloc +realloc +RSA_new +RSA_pkey_ctx_ctrl RSA_set0_key +SHA1 SHA256 -SHA256_Final -SHA256_Init -SHA256_Update strdup udev_device_get_devnode udev_device_get_parent_with_subsystem_devtype udev_device_get_sysattr_value udev_device_get_sysnum udev_device_new_from_syspath udev_device_unref udev_enumerate_add_match_subsystem udev_enumerate_get_list_entry udev_enumerate_new udev_enumerate_scan_devices udev_enumerate_unref udev_list_entry_get_name udev_list_entry_get_next udev_new udev_unref usleep diff --git a/contrib/libfido2/man/CMakeLists.txt b/contrib/libfido2/man/CMakeLists.txt index ad9f339e6f9b..3e50c50d37a0 100644 --- a/contrib/libfido2/man/CMakeLists.txt +++ b/contrib/libfido2/man/CMakeLists.txt @@ -1,371 +1,380 @@ # Copyright (c) 2018 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. find_program(MANDOC_PATH mandoc) find_program(GZIP_PATH gzip) message(STATUS "MANDOC_PATH: ${MANDOC_PATH}") message(STATUS "GZIP_PATH: ${GZIP_PATH}") list(APPEND MAN_SOURCES eddsa_pk_new.3 es256_pk_new.3 fido2-assert.1 fido2-cred.1 fido2-token.1 fido_init.3 fido_assert_new.3 fido_assert_allow_cred.3 fido_assert_set_authdata.3 fido_assert_verify.3 fido_bio_dev_get_info.3 fido_bio_enroll_new.3 fido_bio_info_new.3 fido_bio_template.3 fido_cbor_info_new.3 fido_cred_new.3 fido_cred_exclude.3 fido_credman_metadata_new.3 fido_cred_set_authdata.3 fido_cred_verify.3 fido_dev_enable_entattest.3 fido_dev_get_assert.3 fido_dev_get_touch_begin.3 fido_dev_info_manifest.3 fido_dev_largeblob_get.3 fido_dev_make_cred.3 fido_dev_open.3 fido_dev_set_io_functions.3 fido_dev_set_pin.3 fido_strerr.3 rs256_pk_new.3 ) list(APPEND MAN_ALIAS eddsa_pk_new eddsa_pk_free eddsa_pk_new eddsa_pk_from_ptr eddsa_pk_new eddsa_pk_to_EVP_PKEY es256_pk_new es256_pk_free es256_pk_new es256_pk_from_EC_KEY + es256_pk_new es256_pk_from_EVP_PKEY es256_pk_new es256_pk_from_ptr es256_pk_new es256_pk_to_EVP_PKEY fido_assert_new fido_assert_authdata_len fido_assert_new fido_assert_authdata_ptr fido_assert_new fido_assert_blob_len fido_assert_new fido_assert_blob_ptr fido_assert_new fido_assert_clientdata_hash_len fido_assert_new fido_assert_clientdata_hash_ptr fido_assert_new fido_assert_count fido_assert_new fido_assert_flags fido_assert_new fido_assert_free fido_assert_new fido_assert_hmac_secret_len fido_assert_new fido_assert_hmac_secret_ptr fido_assert_new fido_assert_id_len fido_assert_new fido_assert_id_ptr fido_assert_new fido_assert_largeblob_key_len fido_assert_new fido_assert_largeblob_key_ptr fido_assert_new fido_assert_rp_id fido_assert_new fido_assert_sigcount fido_assert_new fido_assert_sig_len fido_assert_new fido_assert_sig_ptr fido_assert_new fido_assert_user_display_name fido_assert_new fido_assert_user_icon fido_assert_new fido_assert_user_id_len fido_assert_new fido_assert_user_id_ptr fido_assert_new fido_assert_user_name fido_assert_set_authdata fido_assert_set_clientdata fido_assert_set_authdata fido_assert_set_clientdata_hash fido_assert_set_authdata fido_assert_set_count fido_assert_set_authdata fido_assert_set_extensions fido_assert_set_authdata fido_assert_set_hmac_salt fido_assert_set_authdata fido_assert_set_hmac_secret fido_assert_set_authdata fido_assert_set_rp fido_assert_set_authdata fido_assert_set_sig fido_assert_set_authdata fido_assert_set_up fido_assert_set_authdata fido_assert_set_uv fido_bio_dev_get_info fido_bio_dev_enroll_begin fido_bio_dev_get_info fido_bio_dev_enroll_cancel fido_bio_dev_get_info fido_bio_dev_enroll_continue fido_bio_dev_get_info fido_bio_dev_enroll_remove fido_bio_dev_get_info fido_bio_dev_get_template_array fido_bio_dev_get_info fido_bio_dev_set_template_name fido_bio_enroll_new fido_bio_enroll_free fido_bio_enroll_new fido_bio_enroll_last_status fido_bio_enroll_new fido_bio_enroll_remaining_samples fido_bio_info_new fido_bio_info_free fido_bio_info_new fido_bio_info_max_samples fido_bio_info_new fido_bio_info_type fido_bio_template fido_bio_template_array_count fido_bio_template fido_bio_template_array_free fido_bio_template fido_bio_template_array_new fido_bio_template fido_bio_template_free fido_bio_template fido_bio_template_id_len fido_bio_template fido_bio_template_id_ptr fido_bio_template fido_bio_template_name fido_bio_template fido_bio_template_new fido_bio_template fido_bio_template_set_id fido_bio_template fido_bio_template_set_name fido_cbor_info_new fido_cbor_info_aaguid_len fido_cbor_info_new fido_cbor_info_aaguid_ptr fido_cbor_info_new fido_cbor_info_algorithm_cose fido_cbor_info_new fido_cbor_info_algorithm_count fido_cbor_info_new fido_cbor_info_algorithm_type fido_cbor_info_new fido_cbor_info_extensions_len fido_cbor_info_new fido_cbor_info_extensions_ptr fido_cbor_info_new fido_cbor_info_free fido_cbor_info_new fido_cbor_info_maxmsgsiz fido_cbor_info_new fido_cbor_info_maxcredbloblen fido_cbor_info_new fido_cbor_info_maxcredcntlst; fido_cbor_info_new fido_cbor_info_maxcredidlen; fido_cbor_info_new fido_cbor_info_fwversion fido_cbor_info_new fido_cbor_info_options_len fido_cbor_info_new fido_cbor_info_options_name_ptr fido_cbor_info_new fido_cbor_info_options_value_ptr fido_cbor_info_new fido_cbor_info_protocols_len fido_cbor_info_new fido_cbor_info_protocols_ptr fido_cbor_info_new fido_cbor_info_transports_len fido_cbor_info_new fido_cbor_info_transports_ptr fido_cbor_info_new fido_cbor_info_versions_len fido_cbor_info_new fido_cbor_info_versions_ptr fido_cbor_info_new fido_dev_get_cbor_info + fido_cred_new fido_cred_aaguid_len + fido_cred_new fido_cred_aaguid_ptr + fido_cred_new fido_cred_attstmt_len + fido_cred_new fido_cred_attstmt_ptr fido_cred_new fido_cred_authdata_len fido_cred_new fido_cred_authdata_ptr fido_cred_new fido_cred_authdata_raw_len fido_cred_new fido_cred_authdata_raw_ptr fido_cred_new fido_cred_clientdata_hash_len fido_cred_new fido_cred_clientdata_hash_ptr fido_cred_new fido_cred_display_name fido_cred_new fido_cred_flags - fido_cred_new fido_cred_sigcount fido_cred_new fido_cred_fmt fido_cred_new fido_cred_free fido_cred_new fido_cred_id_len fido_cred_new fido_cred_id_ptr - fido_cred_new fido_cred_aaguid_len - fido_cred_new fido_cred_aaguid_ptr fido_cred_new fido_cred_largeblob_key_len fido_cred_new fido_cred_largeblob_key_ptr + fido_cred_new fido_cred_pin_minlen fido_cred_new fido_cred_prot fido_cred_new fido_cred_pubkey_len fido_cred_new fido_cred_pubkey_ptr fido_cred_new fido_cred_rp_id fido_cred_new fido_cred_rp_name + fido_cred_new fido_cred_sigcount fido_cred_new fido_cred_sig_len fido_cred_new fido_cred_sig_ptr fido_cred_new fido_cred_type - fido_cred_new fido_cred_user_name fido_cred_new fido_cred_user_id_len fido_cred_new fido_cred_user_id_ptr + fido_cred_new fido_cred_user_name fido_cred_new fido_cred_x5c_len fido_cred_new fido_cred_x5c_ptr fido_credman_metadata_new fido_credman_del_dev_rk fido_credman_metadata_new fido_credman_get_dev_metadata fido_credman_metadata_new fido_credman_get_dev_rk fido_credman_metadata_new fido_credman_get_dev_rp fido_credman_metadata_new fido_credman_metadata_free fido_credman_metadata_new fido_credman_rk fido_credman_metadata_new fido_credman_rk_count fido_credman_metadata_new fido_credman_rk_existing fido_credman_metadata_new fido_credman_rk_free fido_credman_metadata_new fido_credman_rk_new fido_credman_metadata_new fido_credman_rk_remaining fido_credman_metadata_new fido_credman_rp_count fido_credman_metadata_new fido_credman_rp_free fido_credman_metadata_new fido_credman_rp_id fido_credman_metadata_new fido_credman_rp_id_hash_len fido_credman_metadata_new fido_credman_rp_id_hash_ptr fido_credman_metadata_new fido_credman_rp_name fido_credman_metadata_new fido_credman_rp_new fido_credman_metadata_new fido_credman_set_dev_rk + fido_cred_set_authdata fido_cred_set_attstmt fido_cred_set_authdata fido_cred_set_authdata_raw fido_cred_set_authdata fido_cred_set_blob fido_cred_set_authdata fido_cred_set_clientdata fido_cred_set_authdata fido_cred_set_clientdata_hash fido_cred_set_authdata fido_cred_set_extensions fido_cred_set_authdata fido_cred_set_fmt fido_cred_set_authdata fido_cred_set_id + fido_cred_set_authdata fido_cred_set_pin_minlen fido_cred_set_authdata fido_cred_set_prot fido_cred_set_authdata fido_cred_set_rk fido_cred_set_authdata fido_cred_set_rp fido_cred_set_authdata fido_cred_set_sig fido_cred_set_authdata fido_cred_set_type fido_cred_set_authdata fido_cred_set_user fido_cred_set_authdata fido_cred_set_uv fido_cred_set_authdata fido_cred_set_x509 fido_dev_enable_entattest fido_dev_toggle_always_uv fido_dev_enable_entattest fido_dev_force_pin_change fido_dev_enable_entattest fido_dev_set_pin_minlen + fido_dev_enable_entattest fido_dev_set_pin_minlen_rpid fido_dev_get_touch_begin fido_dev_get_touch_status fido_dev_info_manifest fido_dev_info_free fido_dev_info_manifest fido_dev_info_manufacturer_string fido_dev_info_manifest fido_dev_info_new fido_dev_info_manifest fido_dev_info_path fido_dev_info_manifest fido_dev_info_product fido_dev_info_manifest fido_dev_info_product_string fido_dev_info_manifest fido_dev_info_ptr fido_dev_info_manifest fido_dev_info_vendor fido_dev_open fido_dev_build fido_dev_open fido_dev_cancel fido_dev_open fido_dev_close fido_dev_open fido_dev_flags fido_dev_open fido_dev_force_fido2 fido_dev_open fido_dev_force_u2f fido_dev_open fido_dev_free fido_dev_open fido_dev_is_fido2 fido_dev_open fido_dev_is_winhello fido_dev_open fido_dev_major fido_dev_open fido_dev_minor fido_dev_open fido_dev_new fido_dev_open fido_dev_protocol fido_dev_open fido_dev_supports_cred_prot fido_dev_open fido_dev_supports_credman fido_dev_open fido_dev_supports_pin fido_dev_open fido_dev_supports_uv fido_dev_open fido_dev_has_uv fido_dev_set_pin fido_dev_get_retry_count fido_dev_set_pin fido_dev_get_uv_retry_count fido_dev_set_pin fido_dev_reset fido_dev_set_io_functions fido_dev_set_sigmask + fido_dev_set_io_functions fido_dev_set_timeout fido_dev_largeblob_get fido_dev_largeblob_set fido_dev_largeblob_get fido_dev_largeblob_remove fido_dev_largeblob_get fido_dev_largeblob_get_array fido_dev_largeblob_get fido_dev_largeblob_set_array rs256_pk_new rs256_pk_free rs256_pk_new rs256_pk_from_ptr + rs256_pk_new rs256_pk_from_EVP_PKEY rs256_pk_new rs256_pk_from_RSA rs256_pk_new rs256_pk_to_EVP_PKEY ) list(LENGTH MAN_ALIAS MAN_ALIAS_LEN) math(EXPR MAN_ALIAS_MAX "${MAN_ALIAS_LEN} - 2") # man_copy foreach(f ${MAN_SOURCES}) add_custom_command(OUTPUT ${f} COMMAND cp -f ${CMAKE_SOURCE_DIR}/man/${f} . DEPENDS ${f}) list(APPEND COPY_FILES ${f}) endforeach() # man_lint foreach(f ${MAN_SOURCES}) add_custom_command(OUTPUT ${f}.lint COMMAND mandoc -T lint -W warning ${f} > ${f}.lint DEPENDS ${f}) list(APPEND LINT_FILES ${f}.lint) endforeach() # man_html foreach(f ${MAN_SOURCES}) string(REGEX REPLACE ".[13]" "" g ${f}) add_custom_command(OUTPUT ${g}.html COMMAND mandoc -T html -O man="%N.html",style=style.css -I os="Yubico AB" ${f} > ${g}.html DEPENDS ${f}) list(APPEND HTML_FILES ${g}.html) endforeach() # man_html_partial foreach(f ${MAN_SOURCES}) string(REGEX REPLACE ".[13]" "" g ${f}) add_custom_command(OUTPUT ${g}.partial COMMAND cat ${CMAKE_SOURCE_DIR}/man/dyc.css > ${g}.partial COMMAND mandoc -T html -O man="%N.html",fragment ${f} >> ${g}.partial DEPENDS ${f}) list(APPEND HTML_PARTIAL_FILES ${g}.partial) endforeach() # man_gzip foreach(f ${MAN_SOURCES}) add_custom_command(OUTPUT ${f}.gz COMMAND gzip -cn ${f} > ${f}.gz DEPENDS ${f}) list(APPEND GZ_FILES ${f}.gz) endforeach() macro(define_symlink_target NAME EXT) foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2) math(EXPR j "${i} + 1") list(GET MAN_ALIAS ${i} SRC) list(GET MAN_ALIAS ${j} DST) add_custom_command(OUTPUT ${DST}.${EXT} COMMAND ln -sf ${SRC}.${EXT} ${DST}.${EXT}) list(APPEND ${NAME}_LINK_FILES ${DST}.${EXT}) endforeach() add_custom_target(${NAME} DEPENDS ${${NAME}_LINK_FILES}) endmacro() add_custom_target(man_copy DEPENDS ${COPY_FILES}) add_custom_target(man_lint DEPENDS ${LINT_FILES}) add_custom_target(man_html DEPENDS ${HTML_FILES}) add_custom_target(man_html_partial DEPENDS ${HTML_PARTIAL_FILES}) add_custom_target(man_gzip DEPENDS ${GZ_FILES}) define_symlink_target(man_symlink 3) define_symlink_target(man_symlink_html html) define_symlink_target(man_symlink_html_partial partial) define_symlink_target(man_symlink_gzip 3.gz) add_dependencies(man_symlink man_copy) add_dependencies(man_lint man_symlink) add_dependencies(man_html man_lint) add_dependencies(man_symlink_html man_html) add_dependencies(man_html_partial man_lint) add_dependencies(man_symlink_html_partial man_html_partial) add_custom_target(man ALL) if(MANDOC_PATH) add_dependencies(man man_symlink_html) add_dependencies(man_gzip man_lint) install(FILES ${CMAKE_SOURCE_DIR}/man/style.css DESTINATION "${CMAKE_INSTALL_DOCDIR}/html") foreach(f ${MAN_SOURCES}) string(REGEX REPLACE ".[13]" "" f ${f}) install(FILES ${CMAKE_BINARY_DIR}/man/${f}.html DESTINATION "${CMAKE_INSTALL_DOCDIR}/html") endforeach() foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2) math(EXPR j "${i} + 1") list(GET MAN_ALIAS ${j} DST) install(FILES ${CMAKE_BINARY_DIR}/man/${DST}.html DESTINATION "${CMAKE_INSTALL_DOCDIR}/html") endforeach() endif() if(GZIP_PATH) add_dependencies(man_gzip man_copy) add_dependencies(man_symlink_gzip man_gzip) add_dependencies(man man_symlink_gzip) foreach(f ${MAN_SOURCES}) if (${f} MATCHES ".1$") install(FILES ${CMAKE_BINARY_DIR}/man/${f}.gz DESTINATION "${CMAKE_INSTALL_MANDIR}/man1") elseif(${f} MATCHES ".3$") install(FILES ${CMAKE_BINARY_DIR}/man/${f}.gz DESTINATION "${CMAKE_INSTALL_MANDIR}/man3") endif() endforeach() foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2) math(EXPR j "${i} + 1") list(GET MAN_ALIAS ${j} DST) install(FILES ${CMAKE_BINARY_DIR}/man/${DST}.3.gz DESTINATION "${CMAKE_INSTALL_MANDIR}/man3") endforeach() elseif(NOT MSVC) add_dependencies(man man_symlink) foreach(f ${MAN_SOURCES}) if (${f} MATCHES ".1$") install(FILES ${CMAKE_BINARY_DIR}/man/${f} DESTINATION "${CMAKE_INSTALL_MANDIR}/man1") elseif(${f} MATCHES ".3$") install(FILES ${CMAKE_BINARY_DIR}/man/${f} DESTINATION "${CMAKE_INSTALL_MANDIR}/man3") endif() endforeach() foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2) math(EXPR j "${i} + 1") list(GET MAN_ALIAS ${j} DST) install(FILES ${CMAKE_BINARY_DIR}/man/${DST}.3 DESTINATION "${CMAKE_INSTALL_MANDIR}/man3") endforeach() endif() diff --git a/contrib/libfido2/man/es256_pk_new.3 b/contrib/libfido2/man/es256_pk_new.3 index 54439cd300cf..6c1bac0f57f9 100644 --- a/contrib/libfido2/man/es256_pk_new.3 +++ b/contrib/libfido2/man/es256_pk_new.3 @@ -1,126 +1,140 @@ -.\" Copyright (c) 2018 Yubico AB. All rights reserved. +.\" Copyright (c) 2018-2021 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 24 2018 $ .Dt ES256_PK_NEW 3 .Os .Sh NAME .Nm es256_pk_new , .Nm es256_pk_free , .Nm es256_pk_from_EC_KEY , +.Nm es256_pk_from_EVP_KEY , .Nm es256_pk_from_ptr , .Nm es256_pk_to_EVP_PKEY .Nd FIDO 2 COSE ES256 API .Sh SYNOPSIS .In openssl/ec.h .In fido/es256.h .Ft es256_pk_t * .Fn es256_pk_new "void" .Ft void .Fn es256_pk_free "es256_pk_t **pkp" .Ft int .Fn es256_pk_from_EC_KEY "es256_pk_t *pk" "const EC_KEY *ec" .Ft int +.Fn es256_pk_from_EVP_PKEY "es256_pk_t *pk" "const EVP_PKEY *pkey" +.Ft int .Fn es256_pk_from_ptr "es256_pk_t *pk" "const void *ptr" "size_t len" .Ft EVP_PKEY * .Fn es256_pk_to_EVP_PKEY "const es256_pk_t *pk" .Sh DESCRIPTION ES256 is the name given in the CBOR Object Signing and Encryption (COSE) RFC to ECDSA over P-256 with SHA-256. The COSE ES256 API of .Em libfido2 is an auxiliary API with routines to convert between the different ECDSA public key types used in .Em libfido2 and .Em OpenSSL . .Pp In .Em libfido2 , ES256 public keys are abstracted by the .Vt es256_pk_t type. .Pp The .Fn es256_pk_new function returns a pointer to a newly allocated, empty .Vt es256_pk_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn es256_pk_free function releases the memory backing .Fa *pkp , where .Fa *pkp must have been previously allocated by .Fn es256_pk_new . On return, .Fa *pkp is set to NULL. Either .Fa pkp or .Fa *pkp may be NULL, in which case .Fn es256_pk_free is a NOP. .Pp The .Fn es256_pk_from_EC_KEY function fills .Fa pk with the contents of .Fa ec . No references to .Fa ec are kept. .Pp The +.Fn es256_pk_from_EVP_KEY +function fills +.Fa pk +with the contents of +.Fa pkey . +No references to +.Fa pkey +are kept. +.Pp +The .Fn es256_pk_from_ptr function fills .Fa pk with the contents of .Fa ptr , where .Fa ptr points to .Fa len bytes. The .Fa ptr pointer may point to an uncompressed point, or to the concatenation of the x and y coordinates. No references to .Fa ptr are kept. .Pp The .Fn es256_pk_to_EVP_PKEY function converts .Fa pk to a newly allocated .Fa EVP_PKEY type with a reference count of 1. No internal references to the returned pointer are kept. If an error occurs, .Fn es256_pk_to_EVP_PKEY returns NULL. .Sh RETURN VALUES The -.Fn es256_pk_from_EC_KEY +.Fn es256_pk_from_EC_KEY , +.Fn es256_pk_from_EVP_KEY , and .Fn es256_pk_from_ptr functions return .Dv FIDO_OK on success. On error, a different error code defined in .In fido/err.h is returned. .Sh SEE ALSO .Xr eddsa_pk_new 3 , .Xr fido_assert_verify 3 , .Xr fido_cred_pubkey_ptr 3 , .Xr rs256_pk_new 3 diff --git a/contrib/libfido2/man/fido2-token.1 b/contrib/libfido2/man/fido2-token.1 index 43f1c0ea48b7..fd82c23cffb7 100644 --- a/contrib/libfido2/man/fido2-token.1 +++ b/contrib/libfido2/man/fido2-token.1 @@ -1,388 +1,400 @@ .\" Copyright (c) 2018-2021 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: September 13 2019 $ .Dt FIDO2-TOKEN 1 .Os .Sh NAME .Nm fido2-token .Nd find and manage a FIDO 2 authenticator .Sh SYNOPSIS .Nm .Fl C .Op Fl d .Ar device .Nm .Fl D .Op Fl d .Fl i .Ar cred_id .Ar device .Nm .Fl D .Fl b .Op Fl d .Fl k Ar key_path .Ar device .Nm .Fl D .Fl b .Op Fl d .Fl n Ar rp_id .Op Fl i Ar cred_id .Ar device .Nm .Fl D .Fl e .Op Fl d .Fl i .Ar template_id .Ar device .Nm .Fl D .Fl u .Op Fl d .Ar device .Nm .Fl G .Fl b .Op Fl d .Fl k Ar key_path .Ar blob_path .Ar device .Nm .Fl G .Fl b .Op Fl d .Fl n Ar rp_id .Op Fl i Ar cred_id .Ar blob_path .Ar device .Nm .Fl I .Op Fl cd .Op Fl k Ar rp_id Fl i Ar cred_id .Ar device .Nm .Fl L .Op Fl bder .Op Fl k Ar rp_id .Op device .Nm .Fl R .Op Fl d .Ar device .Nm .Fl S .Op Fl adefu .Ar device .Nm .Fl S .Op Fl d .Fl i Ar template_id .Fl n Ar template_name +.Ar device .Nm .Fl S .Op Fl d .Fl l Ar pin_length .Ar device .Nm .Fl S .Fl b .Op Fl d .Fl k Ar key_path .Ar blob_path .Ar device .Nm .Fl S .Fl b .Op Fl d .Fl n Ar rp_id .Op Fl i Ar cred_id .Ar blob_path .Ar device .Nm .Fl S .Fl c .Op Fl d .Fl i Ar cred_id .Fl k Ar user_id .Fl n Ar name .Fl p Ar display_name .Ar device .Nm +.Fl S +.Fl m +.Ar rp_id +.Ar device +.Nm .Fl V .Sh DESCRIPTION .Nm manages a FIDO 2 authenticator. .Pp The options are as follows: .Bl -tag -width Ds .It Fl C Ar device Changes the PIN of .Ar device . The user will be prompted for the current and new PINs. .It Fl D Fl i Ar id Ar device Deletes the resident credential specified by .Ar id from .Ar device , where .Ar id is the credential's base64-encoded id. The user will be prompted for the PIN. .It Fl D Fl b Fl k Ar key_path Ar device Deletes a .Dq largeBlob encrypted with .Ar key_path from .Ar device , where .Ar key_path must hold the blob's base64-encoded encryption key. A PIN or equivalent user-verification gesture is required. .It Fl D Fl b Fl n Ar rp_id Oo Fl i Ar cred_id Oc Ar device Deletes a .Dq largeBlob corresponding to .Ar rp_id from .Ar device . If .Ar rp_id has multiple credentials enrolled on .Ar device , the credential ID must be specified using .Fl i Ar cred_id , where .Ar cred_id is a base64-encoded blob. A PIN or equivalent user-verification gesture is required. .It Fl D Fl e Fl i Ar id Ar device Deletes the biometric enrollment specified by .Ar id from .Ar device , where .Ar id is the enrollment's template base64-encoded id. The user will be prompted for the PIN. .It Fl D Fl u Ar device Disables the FIDO 2.1 .Dq user verification always feature on .Ar device . .It Fl G Fl b Fl k Ar key_path Ar blob_path Ar device Gets a FIDO 2.1 .Dq largeBlob encrypted with .Ar key_path from .Ar device , where .Ar key_path must hold the blob's base64-encoded encryption key. The blob is written to .Ar blob_path . A PIN or equivalent user-verification gesture is required. .It Fl G Fl b Fl n Ar rp_id Oo Fl i Ar cred_id Oc Ar blob_path Ar device Gets a FIDO 2.1 .Dq largeBlob associated with .Ar rp_id from .Ar device . If .Ar rp_id has multiple credentials enrolled on .Ar device , the credential ID must be specified using .Fl i Ar cred_id , where .Ar cred_id is a base64-encoded blob. The blob is written to .Ar blob_path . A PIN or equivalent user-verification gesture is required. .It Fl I Ar device Retrieves information on .Ar device . .It Fl I Fl c Ar device Retrieves resident credential metadata from .Ar device . The user will be prompted for the PIN. .It Fl I Fl k Ar rp_id Fl i Ar cred_id Ar device Prints the credential id (base64-encoded) and public key (PEM encoded) of the resident credential specified by .Ar rp_id and .Ar cred_id , where .Ar rp_id is a UTF-8 relying party id, and .Ar cred_id is a base64-encoded credential id. The user will be prompted for the PIN. .It Fl L Produces a list of authenticators found by the operating system. .It Fl L Fl b Ar device Produces a list of FIDO 2.1 .Dq largeBlobs on .Ar device . A PIN or equivalent user-verification gesture is required. .It Fl L Fl e Ar device Produces a list of biometric enrollments on .Ar device . The user will be prompted for the PIN. .It Fl L Fl r Ar device Produces a list of relying parties with resident credentials on .Ar device . The user will be prompted for the PIN. .It Fl L Fl k Ar rp_id Ar device Produces a list of resident credentials corresponding to relying party .Ar rp_id on .Ar device . The user will be prompted for the PIN. .It Fl R Performs a reset on .Ar device . .Nm will NOT prompt for confirmation. .It Fl S Sets the PIN of .Ar device . The user will be prompted for the PIN. .It Fl S Fl a Ar device Enables FIDO 2.1 Enterprise Attestation on .Ar device . .It Fl S Fl b Fl k Ar key_path Ar blob_path Ar device Sets .Ar blob_path as a FIDO 2.1 .Dq largeBlob encrypted with .Ar key_path on .Ar device , where .Ar blob_path holds the blob's plaintext, and .Ar key_path the blob's base64-encoded encryption. A PIN or equivalent user-verification gesture is required. .It Fl S Fl b Fl n Ar rp_id Oo Fl i Ar cred_id Oc Ar blob_path Ar device Sets .Ar blob_path as a FIDO 2.1 .Dq largeBlob associated with .Ar rp_id on .Ar device . If .Ar rp_id has multiple credentials enrolled on .Ar device , the credential ID must be specified using .Fl i Ar cred_id , where .Ar cred_id is a base64-encoded blob. A PIN or equivalent user-verification gesture is required. .It Fl S Fl c Fl i Ar cred_id Fl k Ar user_id Fl n Ar name Fl p Ar display_name Ar device Sets the .Ar name and .Ar display_name attributes of the resident credential identified by .Ar cred_id and .Ar user_id , where .Ar name and .Ar display_name are UTF-8 strings and .Ar cred_id and .Ar user_id are base64-encoded blobs. A PIN or equivalent user-verification gesture is required. .It Fl S Fl e Ar device Performs a new biometric enrollment on .Ar device . The user will be prompted for the PIN. .It Fl S Fl e Fl i Ar template_id Fl n Ar template_name Ar device Sets the friendly name of the biometric enrollment specified by .Ar template_id to .Ar template_name on .Ar device , where .Ar template_id is base64-encoded and .Ar template_name is a UTF-8 string. The user will be prompted for the PIN. .It Fl S Fl f Ar device Forces a PIN change on .Ar device . The user will be prompted for the PIN. .It Fl S Fl l Ar pin_length Ar device Sets the minimum PIN length of .Ar device to .Ar pin_length . The user will be prompted for the PIN. +.It Fl S Fl m Ar rp_id Ar device +Sets the list of relying party IDs that are allowed to retrieve +the minimum PIN length of +.Ar device . +Multiple IDs may be specified, separated by commas. +The user will be prompted for the PIN. .It Fl S Fl u Ar device Enables the FIDO 2.1 .Dq user verification always feature on .Ar device . .It Fl V Prints version information. .It Fl d Causes .Nm to emit debugging output on .Em stderr . .El .Pp If a .Em tty is available, .Nm will use it to prompt for PINs. Otherwise, .Em stdin is used. .Pp .Nm exits 0 on success and 1 on error. .Sh SEE ALSO .Xr fido2-assert 1 , .Xr fido2-cred 1 .Sh CAVEATS The actual user-flow to perform a reset is outside the scope of the FIDO2 specification, and may therefore vary depending on the authenticator. Yubico authenticators do not allow resets after 5 seconds from power-up, and expect a reset to be confirmed by the user through touch within 30 seconds. .Pp An authenticator's path may contain spaces. .Pp Resident credentials are called .Dq discoverable credentials in FIDO 2.1. .Pp Whether the FIDO 2.1 .Dq user verification always feature is activated or deactivated after an authenticator reset is vendor-specific. diff --git a/contrib/libfido2/man/fido_cred_new.3 b/contrib/libfido2/man/fido_cred_new.3 index 8cecf5f29850..d779cb2c659d 100644 --- a/contrib/libfido2/man/fido_cred_new.3 +++ b/contrib/libfido2/man/fido_cred_new.3 @@ -1,257 +1,293 @@ -.\" Copyright (c) 2018 Yubico AB. All rights reserved. +.\" Copyright (c) 2018-2021 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 23 2018 $ .Dt FIDO_CRED_NEW 3 .Os .Sh NAME .Nm fido_cred_new , .Nm fido_cred_free , +.Nm fido_cred_pin_minlen , .Nm fido_cred_prot , .Nm fido_cred_fmt , .Nm fido_cred_rp_id , .Nm fido_cred_rp_name , .Nm fido_cred_user_name , .Nm fido_cred_display_name , .Nm fido_cred_authdata_ptr , .Nm fido_cred_authdata_raw_ptr , .Nm fido_cred_clientdata_hash_ptr , .Nm fido_cred_id_ptr , .Nm fido_cred_aaguid_ptr , .Nm fido_cred_largeblob_key_ptr , .Nm fido_cred_pubkey_ptr , .Nm fido_cred_sig_ptr , .Nm fido_cred_user_id_ptr , .Nm fido_cred_x5c_ptr , +.Nm fido_cred_attstmt_ptr , .Nm fido_cred_authdata_len , .Nm fido_cred_authdata_raw_len , .Nm fido_cred_clientdata_hash_len , .Nm fido_cred_id_len , .Nm fido_cred_aaguid_len , .Nm fido_cred_largeblob_key_len , .Nm fido_cred_pubkey_len , .Nm fido_cred_sig_len , .Nm fido_cred_user_id_len , .Nm fido_cred_x5c_len , +.Nm fido_cred_attstmt_len , .Nm fido_cred_type , .Nm fido_cred_flags , .Nm fido_cred_sigcount .Nd FIDO 2 credential API .Sh SYNOPSIS .In fido.h .Ft fido_cred_t * .Fn fido_cred_new "void" .Ft void .Fn fido_cred_free "fido_cred_t **cred_p" +.Ft size_t +.Fn fido_cred_pin_minlen "const fido_cred_t *cred" .Ft int -.Fn fido_cred_prot "fido_cred_t *cred" +.Fn fido_cred_prot "const fido_cred_t *cred" .Ft const char * .Fn fido_cred_fmt "const fido_cred_t *cred" .Ft const char * .Fn fido_cred_rp_id "const fido_cred_t *cred" .Ft const char * .Fn fido_cred_rp_name "const fido_cred_t *cred" .Ft const char * .Fn fido_cred_user_name "const fido_cred_t *cred" .Ft const char * .Fn fido_cred_display_name "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_authdata_ptr "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_authdata_raw_ptr "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_clientdata_hash_ptr "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_id_ptr "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_aaguid_ptr "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_largeblob_key_ptr "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_pubkey_ptr "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_sig_ptr "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_user_id_ptr "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_x5c_ptr "const fido_cred_t *cred" +.Ft const unsigned char * +.Fn fido_cred_attstmt_ptr "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_authdata_len "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_authdata_raw_len "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_clientdata_hash_len "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_id_len "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_aaguid_len "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_largeblob_key_len "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_pubkey_len "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_sig_len "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_user_id_len "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_x5c_len "const fido_cred_t *cred" +.Ft size_t +.Fn fido_cred_attstmt_len "const fido_cred_t *cred" .Ft int .Fn fido_cred_type "const fido_cred_t *cred" .Ft uint8_t .Fn fido_cred_flags "const fido_cred_t *cred" .Ft uint32_t .Fn fido_cred_sigcount "const fido_cred_t *cred" .Sh DESCRIPTION FIDO 2 credentials are abstracted in .Em libfido2 by the .Vt fido_cred_t type. The functions described in this page allow a .Vt fido_cred_t type to be allocated, deallocated, and inspected. For other operations on .Vt fido_cred_t , please refer to .Xr fido_cred_set_authdata 3 , .Xr fido_cred_exclude 3 , .Xr fido_cred_verify 3 , and .Xr fido_dev_make_cred 3 . .Pp The .Fn fido_cred_new function returns a pointer to a newly allocated, empty .Vt fido_cred_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_cred_free function releases the memory backing .Fa *cred_p , where .Fa *cred_p must have been previously allocated by .Fn fido_cred_new . On return, .Fa *cred_p is set to NULL. Either .Fa cred_p or .Fa *cred_p may be NULL, in which case .Fn fido_cred_free is a NOP. .Pp -The +If the FIDO 2.1 +.Dv FIDO_EXT_MINPINLEN +extension is enabled on +.Fa cred , +then the +.Fn fido_cred_pin_minlen +function returns the minimum PIN length of +.Fa cred . +Otherwise, +.Fn fido_cred_pin_minlen +returns zero. +See +.Xr fido_cred_set_pin_minlen 3 +on how to enable this extension. +.Pp +If the FIDO 2.1 +.Dv FIDO_EXT_CRED_PROTECT +extension is enabled on +.Fa cred , +then the .Fn fido_cred_prot function returns the protection of .Fa cred . +Otherwise, +.Fn fido_cred_prot +returns zero. See .Xr fido_cred_set_prot 3 -for the values understood by +for the protection policies understood by .Em libfido2 . .Pp The .Fn fido_cred_fmt function returns a pointer to a NUL-terminated string containing the format of .Fa cred , or NULL if .Fa cred does not have a format set. .Pp The .Fn fido_cred_rp_id , .Fn fido_cred_rp_name , .Fn fido_cred_user_name , and .Fn fido_cred_display_name functions return pointers to NUL-terminated strings holding the relying party ID, relying party name, user name, and user display name attributes of .Fa cred , or NULL if the respective entry is not set. .Pp The .Fn fido_cred_authdata_ptr , .Fn fido_cred_authdata_raw_ptr , .Fn fido_cred_clientdata_hash_ptr , .Fn fido_cred_id_ptr , .Fn fido_cred_aaguid_ptr , .Fn fido_cred_largeblob_key_ptr , .Fn fido_cred_pubkey_ptr , .Fn fido_cred_sig_ptr , .Fn fido_cred_user_id_ptr , +.Fn fido_cred_x5c_ptr , and -.Fn fido_cred_x5c_ptr +.Fn fido_cred_attstmt_ptr functions return pointers to the CBOR-encoded and raw authenticator data, client data hash, ID, authenticator attestation GUID, .Dq largeBlobKey , -public key, signature, user ID, and x509 certificate parts of +public key, signature, user ID, x509 certificate, and attestation +statement parts of .Fa cred , or NULL if the respective entry is not set. .Pp The corresponding length can be obtained by .Fn fido_cred_authdata_len , .Fn fido_cred_authdata_raw_len , .Fn fido_cred_clientdata_hash_len , .Fn fido_cred_id_len , .Fn fido_cred_aaguid_len , .Fn fido_cred_largeblob_key_len , .Fn fido_cred_pubkey_len , .Fn fido_cred_sig_len , .Fn fido_cred_user_id_len , +.Fn fido_cred_x5c_len , and -.Fn fido_cred_x5c_len . +.Fn fido_cred_attstmt_len . .Pp The authenticator data, x509 certificate, and signature parts of a credential are typically passed to a FIDO 2 server for verification. .Pp The .Fn fido_cred_type function returns the COSE algorithm of .Fa cred . .Pp The .Fn fido_cred_flags function returns the authenticator data flags of .Fa cred . .Pp The .Fn fido_cred_sigcount function returns the authenticator data signature counter of .Fa cred . .Sh RETURN VALUES The authenticator data returned by .Fn fido_cred_authdata_ptr is a CBOR-encoded byte string, as obtained from the authenticator. To obtain the decoded byte string, use .Fn fido_cred_authdata_raw_ptr . .Pp If not NULL, pointers returned by .Fn fido_cred_fmt , .Fn fido_cred_authdata_ptr , .Fn fido_cred_clientdata_hash_ptr , .Fn fido_cred_id_ptr , .Fn fido_cred_aaguid_ptr , .Fn fido_cred_largeblob_key_ptr , .Fn fido_cred_pubkey_ptr , .Fn fido_cred_sig_ptr , and .Fn fido_cred_x5c_ptr are guaranteed to exist until any API function that takes .Fa cred without the .Em const qualifier is invoked. .Sh SEE ALSO .Xr fido_cred_exclude 3 , .Xr fido_cred_set_authdata 3 , +.Xr fido_cred_set_pin_minlen 3 , +.Xr fido_cred_set_prot 3 , .Xr fido_cred_verify 3 , .Xr fido_credman_metadata_new 3 , .Xr fido_dev_largeblob_get 3 , .Xr fido_dev_make_cred 3 diff --git a/contrib/libfido2/man/fido_cred_set_authdata.3 b/contrib/libfido2/man/fido_cred_set_authdata.3 index 91e1edbaf810..7bae51f43674 100644 --- a/contrib/libfido2/man/fido_cred_set_authdata.3 +++ b/contrib/libfido2/man/fido_cred_set_authdata.3 @@ -1,307 +1,354 @@ -.\" Copyright (c) 2018 Yubico AB. All rights reserved. +.\" Copyright (c) 2018-2021 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 23 2018 $ .Dt FIDO_CRED_SET_AUTHDATA 3 .Os .Sh NAME .Nm fido_cred_set_authdata , .Nm fido_cred_set_authdata_raw , +.Nm fido_cred_set_attstmt , .Nm fido_cred_set_x509 , .Nm fido_cred_set_sig , .Nm fido_cred_set_id , .Nm fido_cred_set_clientdata , .Nm fido_cred_set_clientdata_hash , .Nm fido_cred_set_rp , .Nm fido_cred_set_user , .Nm fido_cred_set_extensions , .Nm fido_cred_set_blob , +.Nm fido_cred_set_pin_minlen , .Nm fido_cred_set_prot , .Nm fido_cred_set_rk , .Nm fido_cred_set_uv , .Nm fido_cred_set_fmt , .Nm fido_cred_set_type .Nd set parameters of a FIDO 2 credential .Sh SYNOPSIS .In fido.h .Bd -literal typedef enum { FIDO_OPT_OMIT = 0, /* use authenticator's default */ FIDO_OPT_FALSE, /* explicitly set option to false */ FIDO_OPT_TRUE, /* explicitly set option to true */ } fido_opt_t; .Ed .Ft int .Fn fido_cred_set_authdata "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_cred_set_authdata_raw "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" .Ft int +.Fn fido_cred_set_attstmt "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" +.Ft int .Fn fido_cred_set_x509 "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_cred_set_sig "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_cred_set_id "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_cred_set_clientdata "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_cred_set_clientdata_hash "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_cred_set_rp "fido_cred_t *cred" "const char *id" "const char *name" .Ft int .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" .Ft int .Fn fido_cred_set_extensions "fido_cred_t *cred" "int flags" .Ft int .Fn fido_cred_set_blob "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" .Ft int +.Fn fido_cred_set_pin_minlen "fido_cred_t *cred" "size_t len" +.Ft int .Fn fido_cred_set_prot "fido_cred_t *cred" "int prot" .Ft int .Fn fido_cred_set_rk "fido_cred_t *cred" "fido_opt_t rk" .Ft int .Fn fido_cred_set_uv "fido_cred_t *cred" "fido_opt_t uv" .Ft int .Fn fido_cred_set_fmt "fido_cred_t *cred" "const char *ptr" .Ft int .Fn fido_cred_set_type "fido_cred_t *cred" "int cose_alg" .Sh DESCRIPTION The .Nm set of functions define the various parameters of a FIDO 2 credential, allowing a .Fa fido_cred_t type to be prepared for a subsequent call to .Xr fido_dev_make_cred 3 or .Xr fido_cred_verify 3 . For the complete specification of a FIDO 2 credential and the format of its constituent parts, please refer to the Web Authentication (webauthn) standard. .Pp The .Fn fido_cred_set_authdata , +.Fn fido_cred_set_attstmt , .Fn fido_cred_set_x509 , .Fn fido_cred_set_sig , .Fn fido_cred_set_id , and .Fn fido_cred_set_clientdata_hash -functions set the authenticator data, attestation certificate, -signature, id, and client data hash parts of +functions set the authenticator data, attestation statement, +attestation certificate, attestation signature, id, and client +data hash parts of .Fa cred to .Fa ptr , where .Fa ptr points to .Fa len bytes. A copy of .Fa ptr is made, and no references to the passed pointer are kept. +.Pp The authenticator data passed to .Fn fido_cred_set_authdata must be a CBOR-encoded byte string, as obtained from .Fn fido_cred_authdata_ptr . Alternatively, a raw binary blob may be passed to .Fn fido_cred_set_authdata_raw . -.Pp An application calling .Fn fido_cred_set_authdata does not need to call .Fn fido_cred_set_id . The latter is meant to be used in contexts where the credential's authenticator data is not available. .Pp +The attestation statement passed to +.Fn fido_cred_set_attstmt +must be a CBOR-encoded map, as obtained from +.Fn fido_cred_attstmt_ptr . +An application calling +.Fn fido_cred_set_attstmt +does not need to call +.Fn fido_cred_set_x509 +or +.Fn fido_cred_set_sig . +The latter two are meant to be used in contexts where the +credential's complete attestation statement is not available or +required. +.Pp The .Fn fido_cred_set_clientdata function allows an application to set the client data hash of .Fa cred by specifying the credential's unhashed client data. This is required by Windows Hello, which calculates the client data hash internally. For compatibility with Windows Hello, applications should use .Fn fido_cred_set_clientdata instead of .Fn fido_cred_set_clientdata_hash . .Pp The .Fn fido_cred_set_rp function sets the relying party .Fa id and .Fa name parameters of .Fa cred , where .Fa id and .Fa name are NUL-terminated UTF-8 strings. The contents of .Fa id and .Fa name are copied, and no references to the passed pointers are kept. .Pp The .Fn fido_cred_set_user function sets the user attributes of .Fa cred , where .Fa user_id points to .Fa user_id_len bytes and .Fa name , .Fa display_name , and .Fa icon are NUL-terminated UTF-8 strings. The contents of .Fa user_id , .Fa name , .Fa display_name , and .Fa icon are copied, and no references to the passed pointers are kept. Previously set user attributes are flushed. The .Fa user_id , .Fa name , .Fa display_name , and .Fa icon parameters may be NULL. .Pp The .Fn fido_cred_set_extensions function sets the extensions of .Fa cred to the bitmask .Fa flags . At the moment, only the .Dv FIDO_EXT_CRED_BLOB , .Dv FIDO_EXT_CRED_PROTECT , .Dv FIDO_EXT_HMAC_SECRET , +.Dv FIDO_EXT_MINPINLEN , and .Dv FIDO_EXT_LARGEBLOB_KEY extensions are supported. If .Fa flags is zero, the extensions of .Fa cred are cleared. .Pp The .Fn fido_cred_set_blob function sets the .Dq credBlob to be stored with .Fa cred to the data pointed to by .Fa ptr , which must be .Fa len bytes long. .Pp The +.Fn fido_cred_set_pin_minlen +function enables the FIDO 2.1 +.Dv FIDO_EXT_MINPINLEN +extension on +.Fa cred +and sets the expected minimum PIN length of +.Fa cred +to +.Fa len , +where +.Fa len +is greater than zero. +If +.Fa len +is zero, the +.Dv FIDO_EXT_MINPINLEN +extension is disabled on +.Fa cred . +.Pp +The .Fn fido_cred_set_prot -function sets the protection of +function enables the FIDO 2.1 +.Dv FIDO_EXT_CRED_PROTECT +extension on +.Fa cred +and sets the protection of .Fa cred to the scalar .Fa prot . At the moment, only the .Dv FIDO_CRED_PROT_UV_OPTIONAL , .Dv FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID , and .Dv FIDO_CRED_PROT_UV_REQUIRED protections are supported. If .Fa prot is zero, the protection of .Fa cred is cleared. .Pp The .Fn fido_cred_set_rk and .Fn fido_cred_set_uv functions set the .Em rk .Pq resident/discoverable key and .Em uv .Pq user verification attributes of .Fa cred . Both are .Dv FIDO_OPT_OMIT by default, allowing the authenticator to use its default settings. .Pp The .Fn fido_cred_set_fmt function sets the attestation format of .Fa cred to .Fa fmt , where .Fa fmt must be .Vt "packed" .Pq the format used in FIDO2 , .Vt "fido-u2f" .Pq the format used by U2F , or .Vt "none" . A copy of .Fa fmt is made, and no references to the passed pointer are kept. Note that not all authenticators support FIDO2 and therefore may not be able to generate .Vt "packed" . .Pp The .Fn fido_cred_set_type function sets the type of .Fa cred to .Fa cose_alg , where .Fa cose_alg is .Dv COSE_ES256 , .Dv COSE_RS256 , or .Dv COSE_EDDSA . The type of a credential may only be set once. Note that not all authenticators support COSE_RS256 or COSE_EDDSA. .Pp Use of the .Nm set of functions may happen in two distinct situations: when generating a new credential on a FIDO device, prior to .Xr fido_dev_make_cred 3 (i.e, in the context of a FIDO client), or when validating a generated credential using .Xr fido_cred_verify 3 (i.e, in the context of a FIDO server). .Pp For a complete description of the generation of a FIDO 2 credential and its verification, please refer to the FIDO 2 specification. A concrete utilisation example of the .Nm set of functions can be found in the .Pa cred.c example shipped with .Em libfido2 . .Sh RETURN VALUES The error codes returned by the .Nm set of functions are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. .Sh SEE ALSO .Xr fido_cred_exclude 3 , .Xr fido_cred_verify 3 , .Xr fido_dev_make_cred 3 diff --git a/contrib/libfido2/man/fido_cred_verify.3 b/contrib/libfido2/man/fido_cred_verify.3 index 6b720f2132ea..ec95e134572e 100644 --- a/contrib/libfido2/man/fido_cred_verify.3 +++ b/contrib/libfido2/man/fido_cred_verify.3 @@ -1,69 +1,69 @@ -.\" Copyright (c) 2018 Yubico AB. All rights reserved. +.\" Copyright (c) 2018-2021 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 23 2018 $ .Dt FIDO_CRED_VERIFY 3 .Os .Sh NAME .Nm fido_cred_verify .Nd verifies the attestation signature of a FIDO 2 credential .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_cred_verify "const fido_cred_t *cred" .Sh DESCRIPTION The .Fn fido_cred_verify function verifies whether the attestation signature contained in .Fa cred matches the attributes of the credential. Before using .Fn fido_cred_verify in a sensitive context, the reader is strongly encouraged to make herself familiar with the FIDO 2 credential attestation process as defined in the Web Authentication (webauthn) standard. .Pp A brief description follows: .Pp The .Fn fido_cred_verify function verifies whether the client data hash, relying party ID, -credential ID, type, and resident/discoverable key and user verification -attributes of +credential ID, type, protection policy, minimum PIN length, and +resident/discoverable key and user verification attributes of .Fa cred have been attested by the holder of the private counterpart of the public key contained in the credential's x509 certificate. .Pp Please note that the x509 certificate itself is not verified. .Pp The attestation statement formats supported by .Fn fido_cred_verify are -.Em packed +.Em packed , +.Em fido-u2f , and -.Em fido-u2f . +.Em tpm . The attestation type implemented by .Fn fido_cred_verify is .Em Basic Attestation . -The attestation key pair is assumed to be of the type ES256. Other attestation formats and types are not supported. .Sh RETURN VALUES The error codes returned by .Fn fido_cred_verify are defined in .In fido/err.h . If .Fa cred does not contain attestation data, then .Dv FIDO_ERR_INVALID_ARGUMENT is returned. If .Fa cred passes verification, then .Dv FIDO_OK is returned. .Sh SEE ALSO .Xr fido_cred_new 3 , .Xr fido_cred_set_authdata 3 diff --git a/contrib/libfido2/man/fido_dev_enable_entattest.3 b/contrib/libfido2/man/fido_dev_enable_entattest.3 index 7cb766d41d0c..17962d3d35d5 100644 --- a/contrib/libfido2/man/fido_dev_enable_entattest.3 +++ b/contrib/libfido2/man/fido_dev_enable_entattest.3 @@ -1,98 +1,121 @@ .\" Copyright (c) 2020 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: September 22 2020 $ .Dt FIDO_DEV_ENABLE_ENTATTEST 3 .Os .Sh NAME .Nm fido_dev_enable_entattest , .Nm fido_dev_toggle_always_uv , .Nm fido_dev_force_pin_change , -.Nm fido_dev_set_pin_minlen +.Nm fido_dev_set_pin_minlen , +.Nm fido_dev_set_pin_minlen_rpid .Nd FIDO 2.1 configuration authenticator API .Sh SYNOPSIS .In fido.h .In fido/config.h .Ft int .Fn fido_dev_enable_entattest "fido_dev_t *dev" "const char *pin" .Ft int .Fn fido_dev_toggle_always_uv "fido_dev_t *dev" "const char *pin" .Ft int .Fn fido_dev_force_pin_change "fido_dev_t *dev" "const char *pin" .Ft int .Fn fido_dev_set_pin_minlen "fido_dev_t *dev" "size_t len" "const char *pin" +.Ft int +.Fn fido_dev_set_pin_minlen_rpid "fido_dev_t *dev" "const char * const *rpid" "size_t n" "const char *pin" .Sh DESCRIPTION The functions described in this page allow configuration of a FIDO 2.1 authenticator. .Pp The .Fn fido_dev_enable_entattest function enables the .Em Enterprise Attestation feature on .Fa dev . .Em Enterprise Attestation instructs the authenticator to include uniquely identifying information in subsequent attestation statements. The .Fa pin parameter may be NULL if .Fa dev does not have a PIN set. .Pp The .Fn fido_dev_toggle_always_uv function toggles the .Dq user verification always feature on .Fa dev . When set, this toggle enforces user verification at the authenticator level for all known credentials. If .Fa dev supports U2F (CTAP1) and the user verification methods supported by the authenticator do not allow protection of U2F credentials, the U2F subsystem will be disabled by the authenticator. The .Fa pin parameter may be NULL if .Fa dev does not have a PIN set. .Pp The .Fn fido_dev_force_pin_change instructs .Fa dev to require a PIN change. Subsequent PIN authentication attempts against .Fa dev will fail until its PIN is changed. .Pp The .Fn fido_dev_set_pin_minlen function sets the minimum PIN length of .Fa dev to .Fa len . Minimum PIN lengths may only be increased. .Pp +The +.Fn fido_dev_set_pin_minlen_rpid +function sets the list of relying party identifiers +.Pq RP IDs +that are allowed to obtain the minimum PIN length of +.Fa dev +through the FIDO 2.1 +.Dv FIDO_EXT_MINPINLEN +extension. +The list of RP identifiers is denoted by +.Fa rpid , +a vector of +.Fa n +NUL-terminated UTF-8 strings. +A copy of +.Fa rpid +is made, and no reference to it or its contents is kept. +.Pp Configuration settings are reflected in the payload returned by the authenticator in response to a .Xr fido_dev_get_cbor_info 3 call. .Sh RETURN VALUES The error codes returned by .Fn fido_dev_enable_entattest , .Fn fido_dev_toggle_always_uv , .Fn fido_dev_force_pin_change , +.Fn fido_dev_set_pin_minlen , and -.Fn fido_dev_set_pin_minlen +.Fn fido_dev_set_pin_minlen_rpid are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. .Sh SEE ALSO +.Xr fido_cred_pin_minlen 3 , .Xr fido_dev_get_cbor_info 3 , .Xr fido_dev_reset 3 diff --git a/contrib/libfido2/man/fido_dev_info_manifest.3 b/contrib/libfido2/man/fido_dev_info_manifest.3 index 22519e29b9fa..76e399cec319 100644 --- a/contrib/libfido2/man/fido_dev_info_manifest.3 +++ b/contrib/libfido2/man/fido_dev_info_manifest.3 @@ -1,143 +1,153 @@ .\" Copyright (c) 2018 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 25 2018 $ .Dt FIDO_DEV_INFO_MANIFEST 3 .Os .Sh NAME .Nm fido_dev_info_manifest , .Nm fido_dev_info_new , .Nm fido_dev_info_free , .Nm fido_dev_info_ptr , .Nm fido_dev_info_path , .Nm fido_dev_info_product , .Nm fido_dev_info_vendor , .Nm fido_dev_info_manufacturer_string , .Nm fido_dev_info_product_string .Nd FIDO 2 device discovery functions .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_dev_info_manifest "fido_dev_info_t *devlist" "size_t ilen" "size_t *olen" .Ft fido_dev_info_t * .Fn fido_dev_info_new "size_t n" .Ft void .Fn fido_dev_info_free "fido_dev_info_t **devlist_p" "size_t n" .Ft const fido_dev_info_t * .Fn fido_dev_info_ptr "const fido_dev_info_t *devlist" "size_t i" .Ft const char * .Fn fido_dev_info_path "const fido_dev_info_t *di" .Ft int16_t .Fn fido_dev_info_product "const fido_dev_info_t *di" .Ft int16_t .Fn fido_dev_info_vendor "const fido_dev_info_t *di" .Ft const char * .Fn fido_dev_info_manufacturer_string "const fido_dev_info_t *di" .Ft const char * .Fn fido_dev_info_product_string "const fido_dev_info_t *di" .Sh DESCRIPTION The .Fn fido_dev_info_manifest function fills .Fa devlist with up to .Fa ilen FIDO devices found by the underlying operating system. Currently only USB HID devices are supported. The number of discovered devices is returned in .Fa olen , where .Fa olen is an addressable pointer. .Pp The .Fn fido_dev_info_new function returns a pointer to a newly allocated, empty device list with .Fa n available slots. If memory is not available, NULL is returned. .Pp The .Fn fido_dev_info_free function releases the memory backing .Fa *devlist_p , where .Fa *devlist_p must have been previously allocated by .Fn fido_dev_info_new . The number .Fa n of allocated slots must also be provided. On return, .Fa *devlist_p is set to NULL. Either .Fa devlist_p or .Fa *devlist_p may be NULL, in which case .Fn fido_dev_info_free is a NOP. .Pp The .Fn fido_dev_info_ptr function returns a pointer to slot number .Fa i of .Fa devlist . It is the caller's responsibility to ensure that .Fa i is bounded. Please note that the first slot has index 0. .Pp The .Fn fido_dev_info_path returns the filesystem path or subsystem-specific identification string of .Fa di . .Pp The .Fn fido_dev_info_product function returns the product ID of .Fa di . .Pp The .Fn fido_dev_info_vendor function returns the vendor ID of .Fa di . .Pp The .Fn fido_dev_info_manufacturer_string function returns the manufacturer string of .Fa di . +If +.Fa di +does not have an associated manufacturer string, +.Fn fido_dev_info_manufacturer_string +returns an empty string. .Pp The .Fn fido_dev_info_product_string function returns the product string of .Fa di . +If +.Fa di +does not have an associated product string, +.Fn fido_dev_info_product_string +returns an empty string. .Pp An example of how to use the functions described in this document can be found in the .Pa examples/manifest.c file shipped with .Em libfido2 . .Sh RETURN VALUES The .Fn fido_dev_info_manifest function always returns .Dv FIDO_OK . If a discovery error occurs, the .Fa olen pointer is set to 0. .Pp The pointers returned by .Fn fido_dev_info_ptr , .Fn fido_dev_info_path , .Fn fido_dev_info_manufacturer_string , and .Fn fido_dev_info_product_string are guaranteed to exist until .Fn fido_dev_info_free is called on the corresponding device list. diff --git a/contrib/libfido2/man/fido_dev_set_io_functions.3 b/contrib/libfido2/man/fido_dev_set_io_functions.3 index 231ae2411be8..52081f126e78 100644 --- a/contrib/libfido2/man/fido_dev_set_io_functions.3 +++ b/contrib/libfido2/man/fido_dev_set_io_functions.3 @@ -1,134 +1,161 @@ -.\" Copyright (c) 2018 Yubico AB. All rights reserved. +.\" Copyright (c) 2018-2021 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 25 2018 $ .Dt FIDO_DEV_SET_IO_FUNCTIONS 3 .Os .Sh NAME .Nm fido_dev_set_io_functions , -.Nm fido_dev_set_sigmask +.Nm fido_dev_set_sigmask , +.Nm fido_dev_set_timeout .Nd FIDO 2 device I/O interface .Sh SYNOPSIS .In fido.h .Bd -literal typedef void *fido_dev_io_open_t(const char *); typedef void fido_dev_io_close_t(void *); typedef int fido_dev_io_read_t(void *, unsigned char *, size_t, int); typedef int fido_dev_io_write_t(void *, const unsigned char *, size_t); typedef struct fido_dev_io { fido_dev_io_open_t *open; fido_dev_io_close_t *close; fido_dev_io_read_t *read; fido_dev_io_write_t *write; } fido_dev_io_t; #ifdef _WIN32 typedef int fido_sigset_t; #else typedef sigset_t fido_sigset_t; #endif .Ed .Ft int .Fn fido_dev_set_io_functions "fido_dev_t *dev" "const fido_dev_io_t *io" .Ft int .Fn fido_dev_set_sigmask "fido_dev_t *dev" "const fido_sigset_t *sigmask" +.Ft int +.Fn fido_dev_set_timeout "fido_dev_t *dev" "int ms" .Sh DESCRIPTION The .Fn fido_dev_set_io_functions function sets the I/O handlers used by .Em libfido2 to talk to .Fa dev . By default, these handlers are set to the operating system's native HID or NFC interfaces. They are defined as follows: .Bl -tag -width Ds .It Vt fido_dev_open_t Receives a .Vt const char * holding a path and opens the corresponding device, returning a non-NULL opaque pointer on success and NULL on error. .It Vt fido_dev_close_t Receives the opaque pointer returned by .Vt fido_dev_open_t and closes the device. .It Vt fido_dev_read_t Reads a single transmission unit (HID report, APDU) from a device. The first parameter is the opaque pointer returned by .Vt fido_dev_open_t . The second parameter is the read buffer, and the third parameter is the read buffer size. The fourth parameter is the number of milliseconds the caller is willing to sleep, should the call need to block. If this value holds -1, .Vt fido_dev_read_t may block indefinitely. On success, the number of bytes read is returned. On error, -1 is returned. .It Vt fido_dev_write_t Writes a single transmission unit (HID report, APDU) to .Fa dev . The first parameter is the opaque pointer returned by .Vt fido_dev_open_t . The second parameter is the write buffer, and the third parameter is the number of bytes to be written. A .Vt fido_dev_write_t may block. On success, the number of bytes written is returned. On error, -1 is returned. .El .Pp When calling .Fn fido_dev_set_io_functions , the .Fa open , .Fa close , .Fa read , and .Fa write fields of .Fa io may not be NULL. .Pp No references to .Fa io are held by .Fn fido_dev_set_io_functions . .Pp The .Fn fido_dev_set_sigmask function may be used to specify a non-NULL signal mask .Fa sigmask to be used while .Em libfido2's default I/O handlers wait on .Fa dev . On UNIX-like operating systems, .Vt fido_sigset_t is defined as .Vt sigset_t . On Windows, .Vt fido_sigset_t is defined as .Vt int and .Fn fido_dev_set_sigmask is a no-op. .Pp No references to .Fa sigmask are held by .Fn fido_dev_set_sigmask . +.Pp +The +.Fn fido_dev_set_timeout +function informs +.Em libfido2 +not to block for more than +.Fa ms +milliseconds while communicating with +.Fa dev . +If a timeout occurs, the corresponding +.Em fido_dev_* +function will fail with +.Dv FIDO_ERR_RX . +If +.Fa ms +is -1, +then +.Em libfido2 +may block indefinitely. +This is the default behaviour. +When using the Windows Hello backend, +.Fa ms +is used as a guidance and may be overwritten by the platform. .Sh RETURN VALUES On success, -.Fn fido_dev_set_io_functions +.Fn fido_dev_set_io_functions , +.Fn fido_dev_set_sigmask , and -.Fn fido_dev_set_sigmask +.Fn fido_dev_set_timeout return .Dv FIDO_OK . On error, a different error code defined in .In fido/err.h is returned. diff --git a/contrib/libfido2/man/rs256_pk_new.3 b/contrib/libfido2/man/rs256_pk_new.3 index 4ad0ebe936f3..ad33ee66ba7b 100644 --- a/contrib/libfido2/man/rs256_pk_new.3 +++ b/contrib/libfido2/man/rs256_pk_new.3 @@ -1,122 +1,136 @@ -.\" Copyright (c) 2018 Yubico AB. All rights reserved. +.\" Copyright (c) 2018-2021 Yubico AB. All rights reserved. .\" Use of this source code is governed by a BSD-style .\" license that can be found in the LICENSE file. .\" .Dd $Mdocdate: May 24 2018 $ .Dt RS256_PK_NEW 3 .Os .Sh NAME .Nm rs256_pk_new , .Nm rs256_pk_free , +.Nm rs256_pk_from_EVP_PKEY , .Nm rs256_pk_from_RSA , .Nm rs256_pk_from_ptr , .Nm rs256_pk_to_EVP_PKEY .Nd FIDO 2 COSE RS256 API .Sh SYNOPSIS .In openssl/rsa.h .In fido/rs256.h .Ft rs256_pk_t * .Fn rs256_pk_new "void" .Ft void .Fn rs256_pk_free "rs256_pk_t **pkp" .Ft int +.Fn rs256_pk_from_EVP_PKEY "rs256_pk_t *pk" "const EVP_PKEY *pkey" +.Ft int .Fn rs256_pk_from_RSA "rs256_pk_t *pk" "const RSA *rsa" .Ft int .Fn rs256_pk_from_ptr "rs256_pk_t *pk" "const void *ptr" "size_t len" .Ft EVP_PKEY * .Fn rs256_pk_to_EVP_PKEY "const rs256_pk_t *pk" .Sh DESCRIPTION RS256 is the name given in the CBOR Object Signing and Encryption (COSE) RFC to PKCS#1.5 2048-bit RSA with SHA-256. The COSE RS256 API of .Em libfido2 is an auxiliary API with routines to convert between the different RSA public key types used in .Em libfido2 and .Em OpenSSL . .Pp In .Em libfido2 , RS256 public keys are abstracted by the .Vt rs256_pk_t type. .Pp The .Fn rs256_pk_new function returns a pointer to a newly allocated, empty .Vt rs256_pk_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn rs256_pk_free function releases the memory backing .Fa *pkp , where .Fa *pkp must have been previously allocated by .Fn rs256_pk_new . On return, .Fa *pkp is set to NULL. Either .Fa pkp or .Fa *pkp may be NULL, in which case .Fn rs256_pk_free is a NOP. .Pp The +.Fn rs256_pk_from_EVP_PKEY +function fills +.Fa pk +with the contents of +.Fa pkey . +No references to +.Fa pkey +are kept. +.Pp +The .Fn rs256_pk_from_RSA function fills .Fa pk with the contents of .Fa rsa . No references to .Fa rsa are kept. .Pp The .Fn rs256_pk_from_ptr function fills .Fa pk with the contents of .Fa ptr , where .Fa ptr points to .Fa len bytes. No references to .Fa ptr are kept. .Pp The .Fn rs256_pk_to_EVP_PKEY function converts .Fa pk to a newly allocated .Fa EVP_PKEY type with a reference count of 1. No internal references to the returned pointer are kept. If an error occurs, .Fn rs256_pk_to_EVP_PKEY returns NULL. .Sh RETURN VALUES The -.Fn rs256_pk_from_RSA +.Fn rs256_pk_from_EVP_PKEY , +.Fn rs256_pk_from_RSA , and .Fn rs256_pk_from_ptr functions return .Dv FIDO_OK on success. On error, a different error code defined in .In fido/err.h is returned. .Sh SEE ALSO .Xr eddsa_pk_new 3 , .Xr es256_pk_new 3 , .Xr fido_assert_verify 3 , .Xr fido_cred_pubkey_ptr 3 diff --git a/contrib/libfido2/openbsd-compat/hkdf.c b/contrib/libfido2/openbsd-compat/hkdf.c deleted file mode 100644 index 745b420f3747..000000000000 --- a/contrib/libfido2/openbsd-compat/hkdf.c +++ /dev/null @@ -1,124 +0,0 @@ -/* $OpenBSD: hkdf.c,v 1.4 2019/11/21 20:02:20 tim Exp $ */ -/* Copyright (c) 2014, Google Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "openbsd-compat.h" -#include "fido.h" - -#if OPENSSL_VERSION_NUMBER < 0x10100000L - -#include -#include - -#include -#include - -#define CRYPTOerror(r) CRYPTOerr(ERR_LIB_CRYPTO, (r)) - -/* https://tools.ietf.org/html/rfc5869#section-2 */ -int -HKDF(uint8_t *out_key, size_t out_len, const EVP_MD *digest, - const uint8_t *secret, size_t secret_len, const uint8_t *salt, - size_t salt_len, const uint8_t *info, size_t info_len) -{ - uint8_t prk[EVP_MAX_MD_SIZE]; - size_t prk_len; - - if (!HKDF_extract(prk, &prk_len, digest, secret, secret_len, salt, - salt_len)) - return 0; - if (!HKDF_expand(out_key, out_len, digest, prk, prk_len, info, - info_len)) - return 0; - - return 1; -} - -/* https://tools.ietf.org/html/rfc5869#section-2.2 */ -int -HKDF_extract(uint8_t *out_key, size_t *out_len, - const EVP_MD *digest, const uint8_t *secret, size_t secret_len, - const uint8_t *salt, size_t salt_len) -{ - unsigned int len; - - /* - * If salt is not given, HashLength zeros are used. However, HMAC does - * that internally already so we can ignore it. - */ - if (salt_len > INT_MAX || HMAC(digest, salt, (int)salt_len, secret, - secret_len, out_key, &len) == NULL) { - CRYPTOerror(ERR_R_CRYPTO_LIB); - return 0; - } - *out_len = len; - return 1; -} - -/* https://tools.ietf.org/html/rfc5869#section-2.3 */ -int -HKDF_expand(uint8_t *out_key, size_t out_len, - const EVP_MD *digest, const uint8_t *prk, size_t prk_len, - const uint8_t *info, size_t info_len) -{ - const size_t digest_len = EVP_MD_size(digest); - uint8_t previous[EVP_MAX_MD_SIZE]; - size_t n, done = 0; - unsigned int i; - int ret = 0; - HMAC_CTX hmac; - - /* Expand key material to desired length. */ - n = (out_len + digest_len - 1) / digest_len; - if (out_len + digest_len < out_len || n > 255 || prk_len > INT_MAX) { - CRYPTOerror(EVP_R_TOO_LARGE); - return 0; - } - - HMAC_CTX_init(&hmac); - if (!HMAC_Init_ex(&hmac, prk, (int)prk_len, digest, NULL)) - goto out; - - for (i = 0; i < n; i++) { - uint8_t ctr = i + 1; - size_t todo; - - if (i != 0 && (!HMAC_Init_ex(&hmac, NULL, 0, NULL, NULL) || - !HMAC_Update(&hmac, previous, digest_len))) - goto out; - - if (!HMAC_Update(&hmac, info, info_len) || - !HMAC_Update(&hmac, &ctr, 1) || - !HMAC_Final(&hmac, previous, NULL)) - goto out; - - todo = digest_len; - if (done + todo > out_len) - todo = out_len - done; - - memcpy(out_key + done, previous, todo); - done += todo; - } - - ret = 1; - - out: - HMAC_CTX_cleanup(&hmac); - explicit_bzero(previous, sizeof(previous)); - if (ret != 1) - CRYPTOerror(ERR_R_CRYPTO_LIB); - return ret; -} -#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ diff --git a/contrib/libfido2/openbsd-compat/hkdf.h b/contrib/libfido2/openbsd-compat/hkdf.h deleted file mode 100644 index 34450f9dd7f0..000000000000 --- a/contrib/libfido2/openbsd-compat/hkdf.h +++ /dev/null @@ -1,65 +0,0 @@ -/* $OpenBSD: hkdf.h,v 1.2 2018/04/03 13:33:53 tb Exp $ */ -/* Copyright (c) 2014, Google Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - -#ifndef OPENSSL_HEADER_HKDF_H -#define OPENSSL_HEADER_HKDF_H - -#include - -#if defined(__cplusplus) -extern "C" { -#endif - -/* - * HKDF computes HKDF (as specified by RFC 5869) of initial keying - * material |secret| with |salt| and |info| using |digest|, and - * outputs |out_len| bytes to |out_key|. It returns one on success and - * zero on error. - * - * HKDF is an Extract-and-Expand algorithm. It does not do any key - * stretching, and as such, is not suited to be used alone to generate - * a key from a password. - */ - -int HKDF(uint8_t *out_key, size_t out_len, const struct env_md_st *digest, - const uint8_t *secret, size_t secret_len, const uint8_t *salt, - size_t salt_len, const uint8_t *info, size_t info_len); - -/* - * HKDF_extract computes a HKDF PRK (as specified by RFC 5869) from - * initial keying material |secret| and salt |salt| using |digest|, - * and outputs |out_len| bytes to |out_key|. The maximum output size - * is |EVP_MAX_MD_SIZE|. It returns one on success and zero on error. - */ -int HKDF_extract(uint8_t *out_key, size_t *out_len, - const struct env_md_st *digest, const uint8_t *secret, - size_t secret_len, const uint8_t *salt, size_t salt_len); - -/* - * HKDF_expand computes a HKDF OKM (as specified by RFC 5869) of - * length |out_len| from the PRK |prk| and info |info| using |digest|, - * and outputs the result to |out_key|. It returns one on success and - * zero on error. - */ -int HKDF_expand(uint8_t *out_key, size_t out_len, - const EVP_MD *digest, const uint8_t *prk, size_t prk_len, - const uint8_t *info, size_t info_len); - - -#if defined(__cplusplus) -} /* extern C */ -#endif - -#endif /* OPENSSL_HEADER_HKDF_H */ diff --git a/contrib/libfido2/openbsd-compat/openbsd-compat.h b/contrib/libfido2/openbsd-compat/openbsd-compat.h index 1be3aa295051..dc9acec4c0a8 100644 --- a/contrib/libfido2/openbsd-compat/openbsd-compat.h +++ b/contrib/libfido2/openbsd-compat/openbsd-compat.h @@ -1,119 +1,118 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _OPENBSD_COMPAT_H #define _OPENBSD_COMPAT_H #if defined(_MSC_VER) #include "types.h" #endif #if defined(HAVE_ENDIAN_H) #include #endif #if defined(__APPLE__) && !defined(HAVE_ENDIAN_H) #include #define be16toh(x) OSSwapBigToHostInt16((x)) #define htobe16(x) OSSwapHostToBigInt16((x)) #define be32toh(x) OSSwapBigToHostInt32((x)) +#define htobe32(x) OSSwapHostToBigInt32((x)) #define htole32(x) OSSwapHostToLittleInt32((x)) #define htole64(x) OSSwapHostToLittleInt64((x)) #endif /* __APPLE__ && !HAVE_ENDIAN_H */ #if defined(_WIN32) && !defined(HAVE_ENDIAN_H) #include #include #if !defined(_MSC_VER) #include #endif #define be16toh(x) ntohs((x)) #define htobe16(x) htons((x)) #define be32toh(x) ntohl((x)) +#define htobe32(x) htonl((x)) uint32_t htole32(uint32_t); uint64_t htole64(uint64_t); #endif /* _WIN32 && !HAVE_ENDIAN_H */ -#if defined(__FreeBSD__) && !defined(HAVE_ENDIAN_H) +#if (defined(__FreeBSD__) || defined(__MidnightBSD__)) && !defined(HAVE_ENDIAN_H) #include #endif #include #include #if !defined(HAVE_STRLCAT) size_t strlcat(char *, const char *, size_t); #endif #if !defined(HAVE_STRLCPY) size_t strlcpy(char *, const char *, size_t); #endif +#if !defined(HAVE_STRSEP) +char *strsep(char **, const char *); +#endif + #if !defined(HAVE_RECALLOCARRAY) void *recallocarray(void *, size_t, size_t, size_t); #endif #if !defined(HAVE_EXPLICIT_BZERO) void explicit_bzero(void *, size_t); #endif #if !defined(HAVE_FREEZERO) void freezero(void *, size_t); #endif #if !defined(HAVE_GETPAGESIZE) int getpagesize(void); #endif #if !defined(HAVE_TIMINGSAFE_BCMP) int timingsafe_bcmp(const void *, const void *, size_t); #endif #if !defined(HAVE_READPASSPHRASE) #include "readpassphrase.h" #else #include #endif #include -#if OPENSSL_VERSION_NUMBER < 0x10100000L -#include -#include "hkdf.h" -#define EVP_PKEY_get0_EC_KEY(x) ((x)->pkey.ec) -#define EVP_PKEY_get0_RSA(x) ((x)->pkey.rsa) -#endif - #if !defined(HAVE_ERR_H) #include "err.h" #else #include #endif #if !defined(HAVE_GETOPT) #include "getopt.h" #else #include #endif #if !defined(HAVE_GETLINE) #include ssize_t getline(char **, size_t *, FILE *); #endif #if defined(_MSC_VER) #define strerror_r(e, b, l) strerror_s((b), (l), (e)) #endif #include "time.h" #if !defined(HAVE_POSIX_IOCTL) #define IOCTL_REQ(x) (x) #else #define IOCTL_REQ(x) ((int)(x)) #endif #endif /* !_OPENBSD_COMPAT_H */ diff --git a/contrib/libfido2/openbsd-compat/strsep.c b/contrib/libfido2/openbsd-compat/strsep.c new file mode 100644 index 000000000000..578668c8ac7b --- /dev/null +++ b/contrib/libfido2/openbsd-compat/strsep.c @@ -0,0 +1,79 @@ +/* $OpenBSD: strsep.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* OPENBSD ORIGINAL: lib/libc/string/strsep.c */ + +#include "openbsd-compat.h" + +#if !defined(HAVE_STRSEP) + +#include +#include + +/* + * Get next token from string *stringp, where tokens are possibly-empty + * strings separated by characters from delim. + * + * Writes NULs into the string at *stringp to end tokens. + * delim need not remain constant from call to call. + * On return, *stringp points past the last NUL written (if there might + * be further tokens), or is NULL (if there are definitely no more tokens). + * + * If *stringp is NULL, strsep returns NULL. + */ +char * +strsep(char **stringp, const char *delim) +{ + char *s; + const char *spanp; + int c, sc; + char *tok; + + if ((s = *stringp) == NULL) + return (NULL); + for (tok = s;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = 0; + *stringp = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +} + +#endif /* !defined(HAVE_STRSEP) */ diff --git a/contrib/libfido2/regress/CMakeLists.txt b/contrib/libfido2/regress/CMakeLists.txt index 0314c38f7161..c550b3141822 100644 --- a/contrib/libfido2/regress/CMakeLists.txt +++ b/contrib/libfido2/regress/CMakeLists.txt @@ -1,16 +1,20 @@ -# Copyright (c) 2018 Yubico AB. All rights reserved. +# Copyright (c) 2018-2021 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. add_custom_target(regress ALL) macro(add_regress_test NAME SOURCES) add_executable(${NAME} ${SOURCES}) target_link_libraries(${NAME} fido2_shared) - add_custom_command(TARGET regress POST_BUILD COMMAND ${NAME} - DEPENDS ${NAME}) + add_test(${NAME} ${NAME}) + add_dependencies(regress ${NAME}) endmacro() +add_custom_command(TARGET regress POST_BUILD + COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + add_regress_test(regress_cred cred.c) add_regress_test(regress_assert assert.c) add_regress_test(regress_dev dev.c) diff --git a/contrib/libfido2/regress/assert.c b/contrib/libfido2/regress/assert.c index dfaf50662c76..23d666a61173 100644 --- a/contrib/libfido2/regress/assert.c +++ b/contrib/libfido2/regress/assert.c @@ -1,553 +1,633 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ +#define _FIDO_INTERNAL + #include #include #include #include #include #include #define FAKE_DEV_HANDLE ((void *)0xdeadbeef) static const unsigned char es256_pk[64] = { 0x34, 0xeb, 0x99, 0x77, 0x02, 0x9c, 0x36, 0x38, 0xbb, 0xc2, 0xae, 0xa0, 0xa0, 0x18, 0xc6, 0x64, 0xfc, 0xe8, 0x49, 0x92, 0xd7, 0x74, 0x9e, 0x0c, 0x46, 0x8c, 0x9d, 0xa6, 0xdf, 0x46, 0xf7, 0x84, 0x60, 0x1e, 0x0f, 0x8b, 0x23, 0x85, 0x4a, 0x9a, 0xec, 0xc1, 0x08, 0x9f, 0x30, 0xd0, 0x0d, 0xd7, 0x76, 0x7b, 0x55, 0x48, 0x91, 0x7c, 0x4f, 0x0f, 0x64, 0x1a, 0x1d, 0xf8, 0xbe, 0x14, 0x90, 0x8a, }; +static const unsigned char rs256_pk[259] = { + 0x9e, 0x54, 0x78, 0xb2, 0x51, 0xbe, 0x19, 0x7c, + 0xcb, 0x1a, 0x9a, 0xc3, 0x49, 0x2a, 0x2f, 0xfd, + 0x99, 0x64, 0x76, 0xc6, 0xdb, 0xca, 0x38, 0x3f, + 0xb0, 0x6a, 0xc9, 0xc0, 0x07, 0x9f, 0x5c, 0x4d, + 0xfc, 0xd1, 0x01, 0x7f, 0x69, 0x65, 0xab, 0x9c, + 0x2a, 0xc2, 0x95, 0xd9, 0x44, 0xf3, 0xea, 0x94, + 0x6b, 0x25, 0x66, 0x54, 0x81, 0xee, 0x24, 0x1d, + 0xe1, 0x7d, 0x7f, 0xbe, 0xea, 0x76, 0x90, 0x5c, + 0xbf, 0x59, 0x22, 0xd3, 0xa0, 0x68, 0x1a, 0x65, + 0x8b, 0x2f, 0xb6, 0xa8, 0x30, 0x2d, 0x26, 0x81, + 0xfa, 0x9e, 0x59, 0xec, 0x2f, 0xee, 0x59, 0x39, + 0xe2, 0x79, 0x19, 0x54, 0x54, 0xdf, 0x24, 0x83, + 0xee, 0x61, 0x5a, 0x66, 0x24, 0x2b, 0x7b, 0xfb, + 0x82, 0x66, 0xe4, 0x85, 0x18, 0x20, 0x76, 0xe5, + 0x4a, 0xb6, 0xcb, 0xec, 0x43, 0xbe, 0xfd, 0xb0, + 0x8f, 0xfd, 0x2f, 0x69, 0xda, 0x06, 0x9c, 0x09, + 0x68, 0x7a, 0x94, 0x6c, 0xb7, 0x51, 0x6d, 0x4c, + 0xf7, 0x13, 0xe8, 0xd5, 0x22, 0x6b, 0x1e, 0xba, + 0xb9, 0x85, 0xe8, 0x5f, 0xa1, 0x66, 0xe3, 0x20, + 0x75, 0x30, 0x11, 0xb5, 0xa3, 0xc3, 0xb0, 0x72, + 0x08, 0xff, 0xa3, 0xbb, 0xf1, 0x32, 0x0b, 0x06, + 0xc4, 0x12, 0xa3, 0x49, 0x30, 0x19, 0xb9, 0xfe, + 0x69, 0x0c, 0xd6, 0xe1, 0x58, 0x36, 0xe6, 0x41, + 0x22, 0x41, 0xbf, 0x96, 0x50, 0x35, 0x56, 0x0d, + 0x92, 0x8c, 0x34, 0xea, 0x28, 0x91, 0x88, 0x9e, + 0x8a, 0xaa, 0x36, 0xd0, 0x0f, 0xbe, 0x16, 0xde, + 0x9d, 0x5f, 0x7b, 0xda, 0x52, 0xf7, 0xf1, 0xb6, + 0x28, 0x10, 0x05, 0x8f, 0xb9, 0x19, 0x7a, 0xcf, + 0x18, 0x9b, 0x40, 0xcd, 0xff, 0x78, 0xea, 0x61, + 0x24, 0x3b, 0x80, 0x68, 0x04, 0x9b, 0x40, 0x07, + 0x98, 0xd4, 0x94, 0xd1, 0x18, 0x44, 0xa5, 0xed, + 0xee, 0x18, 0xc2, 0x25, 0x52, 0x66, 0x42, 0xdf, + 0x01, 0x00, 0x01, +}; + static const unsigned char cdh[32] = { 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7, 0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56, 0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52, 0x35, 0x2d, 0xa2, 0x62, 0x4a, 0xbe, 0x89, 0x76, }; static const unsigned char authdata[39] = { 0x58, 0x25, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d, 0x97, 0x63, 0x00, 0x00, 0x00, 0x00, 0x03, }; static const unsigned char sig[72] = { 0x30, 0x46, 0x02, 0x21, 0x00, 0xf6, 0xd1, 0xa3, 0xd5, 0x24, 0x2b, 0xde, 0xee, 0xa0, 0x90, 0x89, 0xcd, 0xf8, 0x9e, 0xbd, 0x6b, 0x4d, 0x55, 0x79, 0xe4, 0xc1, 0x42, 0x27, 0xb7, 0x9b, 0x9b, 0xa4, 0x0a, 0xe2, 0x47, 0x64, 0x0e, 0x02, 0x21, 0x00, 0xe5, 0xc9, 0xc2, 0x83, 0x47, 0x31, 0xc7, 0x26, 0xe5, 0x25, 0xb2, 0xb4, 0x39, 0xa7, 0xfc, 0x3d, 0x70, 0xbe, 0xe9, 0x81, 0x0d, 0x4a, 0x62, 0xa9, 0xab, 0x4a, 0x91, 0xc0, 0x7d, 0x2d, 0x23, 0x1e, }; static void * dummy_open(const char *path) { (void)path; return (FAKE_DEV_HANDLE); } static void dummy_close(void *handle) { assert(handle == FAKE_DEV_HANDLE); } static int dummy_read(void *handle, unsigned char *buf, size_t len, int ms) { (void)handle; (void)buf; (void)len; (void)ms; abort(); /* NOTREACHED */ } static int dummy_write(void *handle, const unsigned char *buf, size_t len) { (void)handle; (void)buf; (void)len; abort(); /* NOTREACHED */ } static fido_assert_t * alloc_assert(void) { fido_assert_t *a; a = fido_assert_new(); assert(a != NULL); return (a); } static void free_assert(fido_assert_t *a) { fido_assert_free(&a); assert(a == NULL); } static fido_dev_t * alloc_dev(void) { fido_dev_t *d; d = fido_dev_new(); assert(d != NULL); return (d); } static void free_dev(fido_dev_t *d) { fido_dev_free(&d); assert(d == NULL); } static es256_pk_t * alloc_es256_pk(void) { es256_pk_t *pk; pk = es256_pk_new(); assert(pk != NULL); return (pk); } static void free_es256_pk(es256_pk_t *pk) { es256_pk_free(&pk); assert(pk == NULL); } static rs256_pk_t * alloc_rs256_pk(void) { rs256_pk_t *pk; pk = rs256_pk_new(); assert(pk != NULL); return (pk); } static void free_rs256_pk(rs256_pk_t *pk) { rs256_pk_free(&pk); assert(pk == NULL); } static eddsa_pk_t * alloc_eddsa_pk(void) { eddsa_pk_t *pk; pk = eddsa_pk_new(); assert(pk != NULL); return (pk); } static void free_eddsa_pk(eddsa_pk_t *pk) { eddsa_pk_free(&pk); assert(pk == NULL); } static void empty_assert(fido_dev_t *d, fido_assert_t *a, size_t idx) { es256_pk_t *es256; rs256_pk_t *rs256; eddsa_pk_t *eddsa; assert(fido_assert_flags(a, idx) == 0); assert(fido_assert_authdata_len(a, idx) == 0); assert(fido_assert_authdata_ptr(a, idx) == NULL); assert(fido_assert_clientdata_hash_len(a) == 0); assert(fido_assert_clientdata_hash_ptr(a) == NULL); assert(fido_assert_id_len(a, idx) == 0); assert(fido_assert_id_ptr(a, idx) == NULL); assert(fido_assert_rp_id(a) == NULL); assert(fido_assert_sig_len(a, idx) == 0); assert(fido_assert_sig_ptr(a, idx) == NULL); assert(fido_assert_user_display_name(a, idx) == NULL); assert(fido_assert_user_icon(a, idx) == NULL); assert(fido_assert_user_id_len(a, idx) == 0); assert(fido_assert_user_id_ptr(a, idx) == NULL); assert(fido_assert_user_name(a, idx) == NULL); es256 = alloc_es256_pk(); rs256 = alloc_rs256_pk(); eddsa = alloc_eddsa_pk(); fido_dev_force_u2f(d); assert(fido_dev_get_assert(d, a, NULL) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_dev_get_assert(d, a, "") == FIDO_ERR_INVALID_ARGUMENT); assert(fido_assert_verify(a, idx, COSE_ES256, NULL) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_assert_verify(a, idx, COSE_ES256, es256) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_assert_verify(a, idx, -1, es256) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_assert_verify(a, idx, COSE_RS256, rs256) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_assert_verify(a, idx, COSE_EDDSA, eddsa) == FIDO_ERR_INVALID_ARGUMENT); fido_dev_force_fido2(d); assert(fido_dev_get_assert(d, a, NULL) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_dev_get_assert(d, a, "") == FIDO_ERR_INVALID_ARGUMENT); assert(fido_assert_verify(a, idx, COSE_ES256, NULL) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_assert_verify(a, idx, COSE_ES256, es256) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_assert_verify(a, idx, -1, es256) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_assert_verify(a, idx, COSE_RS256, rs256) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_assert_verify(a, idx, COSE_EDDSA, eddsa) == FIDO_ERR_INVALID_ARGUMENT); free_es256_pk(es256); free_rs256_pk(rs256); free_eddsa_pk(eddsa); } static void empty_assert_tests(void) { fido_assert_t *a; fido_dev_t *d; fido_dev_io_t io_f; size_t i; memset(&io_f, 0, sizeof(io_f)); a = alloc_assert(); d = alloc_dev(); io_f.open = dummy_open; io_f.close = dummy_close; io_f.read = dummy_read; io_f.write = dummy_write; assert(fido_dev_set_io_functions(d, &io_f) == FIDO_OK); empty_assert(d, a, 0); assert(fido_assert_count(a) == 0); assert(fido_assert_set_count(a, 4) == FIDO_OK); assert(fido_assert_count(a) == 4); for (i = 0; i < 4; i++) { empty_assert(d, a, i); } empty_assert(d, a, 10); free_assert(a); free_dev(d); } static void valid_assert(void) { fido_assert_t *a; es256_pk_t *es256; rs256_pk_t *rs256; eddsa_pk_t *eddsa; a = alloc_assert(); es256 = alloc_es256_pk(); rs256 = alloc_rs256_pk(); eddsa = alloc_eddsa_pk(); assert(es256_pk_from_ptr(es256, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, es256) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_RS256, rs256) == FIDO_ERR_INVALID_SIG); assert(fido_assert_verify(a, 0, COSE_EDDSA, eddsa) == FIDO_ERR_INVALID_SIG); free_assert(a); free_es256_pk(es256); free_rs256_pk(rs256); free_eddsa_pk(eddsa); } static void no_cdh(void) { fido_assert_t *a; es256_pk_t *pk; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_ARGUMENT); free_assert(a); free_es256_pk(pk); } static void no_rp(void) { fido_assert_t *a; es256_pk_t *pk; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_ARGUMENT); free_assert(a); free_es256_pk(pk); } static void no_authdata(void) { fido_assert_t *a; es256_pk_t *pk; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_ARGUMENT); free_assert(a); free_es256_pk(pk); } static void no_sig(void) { fido_assert_t *a; es256_pk_t *pk; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_ARGUMENT); free_assert(a); free_es256_pk(pk); } static void junk_cdh(void) { fido_assert_t *a; es256_pk_t *pk; unsigned char *junk; junk = malloc(sizeof(cdh)); assert(junk != NULL); memcpy(junk, cdh, sizeof(cdh)); - junk[0] = ~junk[0]; + junk[0] = (unsigned char)~junk[0]; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_clientdata_hash(a, junk, sizeof(cdh)) == FIDO_OK); assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_SIG); free_assert(a); free_es256_pk(pk); free(junk); } static void junk_rp(void) { fido_assert_t *a; es256_pk_t *pk; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_assert_set_rp(a, "potato") == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_PARAM); free_assert(a); free_es256_pk(pk); } static void junk_authdata(void) { fido_assert_t *a; unsigned char *junk; junk = malloc(sizeof(authdata)); assert(junk != NULL); memcpy(junk, authdata, sizeof(authdata)); - junk[0] = ~junk[0]; + junk[0] = (unsigned char)~junk[0]; a = alloc_assert(); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, junk, sizeof(authdata)) == FIDO_ERR_INVALID_ARGUMENT); free_assert(a); free(junk); } static void junk_sig(void) { fido_assert_t *a; es256_pk_t *pk; unsigned char *junk; junk = malloc(sizeof(sig)); assert(junk != NULL); memcpy(junk, sig, sizeof(sig)); - junk[0] = ~junk[0]; + junk[0] = (unsigned char)~junk[0]; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_sig(a, 0, junk, sizeof(sig)) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_SIG); free_assert(a); free_es256_pk(pk); free(junk); } static void wrong_options(void) { fido_assert_t *a; es256_pk_t *pk; a = alloc_assert(); pk = alloc_es256_pk(); assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK); assert(fido_assert_set_clientdata_hash(a, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_assert_set_rp(a, "localhost") == FIDO_OK); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_set_up(a, FIDO_OPT_TRUE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_sig(a, 0, sig, sizeof(sig)) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_PARAM); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_TRUE) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_ERR_INVALID_PARAM); assert(fido_assert_set_up(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_set_uv(a, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_assert_verify(a, 0, COSE_ES256, pk) == FIDO_OK); free_assert(a); free_es256_pk(pk); } /* cbor_serialize_alloc misuse */ static void bad_cbor_serialize(void) { fido_assert_t *a; a = alloc_assert(); assert(fido_assert_set_count(a, 1) == FIDO_OK); assert(fido_assert_set_authdata(a, 0, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_assert_authdata_len(a, 0) == sizeof(authdata)); free_assert(a); } +/* rs256 <-> EVP_PKEY transformations */ +static void +rs256_PKEY(void) +{ + rs256_pk_t *pk1, *pk2; + EVP_PKEY *pkey; + + pk1 = alloc_rs256_pk(); + pk2 = alloc_rs256_pk(); + + assert(rs256_pk_from_ptr(pk1, rs256_pk, sizeof(rs256_pk)) == FIDO_OK); + assert((pkey = rs256_pk_to_EVP_PKEY(pk1)) != NULL); + assert(rs256_pk_from_EVP_PKEY(pk2, pkey) == FIDO_OK); + assert(memcmp(pk1, pk2, sizeof(*pk1)) == 0); + + free_rs256_pk(pk1); + free_rs256_pk(pk2); + EVP_PKEY_free(pkey); +} + +/* es256 <-> EVP_PKEY transformations */ +static void +es256_PKEY(void) +{ + es256_pk_t *pk1, *pk2; + EVP_PKEY *pkey; + + pk1 = alloc_es256_pk(); + pk2 = alloc_es256_pk(); + + assert(es256_pk_from_ptr(pk1, es256_pk, sizeof(es256_pk)) == FIDO_OK); + assert((pkey = es256_pk_to_EVP_PKEY(pk1)) != NULL); + assert(es256_pk_from_EVP_PKEY(pk2, pkey) == FIDO_OK); + assert(memcmp(pk1, pk2, sizeof(*pk1)) == 0); + + free_es256_pk(pk1); + free_es256_pk(pk2); + EVP_PKEY_free(pkey); +} + int main(void) { fido_init(0); empty_assert_tests(); valid_assert(); no_cdh(); no_rp(); no_authdata(); no_sig(); junk_cdh(); junk_rp(); junk_authdata(); junk_sig(); wrong_options(); bad_cbor_serialize(); + rs256_PKEY(); + es256_PKEY(); exit(0); } diff --git a/contrib/libfido2/regress/cred.c b/contrib/libfido2/regress/cred.c index 01df1ef9320d..b0df1481636a 100644 --- a/contrib/libfido2/regress/cred.c +++ b/contrib/libfido2/regress/cred.c @@ -1,988 +1,1622 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #define FAKE_DEV_HANDLE ((void *)0xdeadbeef) static const unsigned char cdh[32] = { 0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb, 0xdd, 0xd7, 0xfb, 0x06, 0x37, 0x62, 0xea, 0x26, 0x20, 0x44, 0x8e, 0x69, 0x7c, 0x03, 0xf2, 0x31, 0x2f, 0x99, 0xdc, 0xaf, 0x3e, 0x8a, 0x91, 0x6b, }; static const unsigned char authdata[198] = { 0x58, 0xc4, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d, 0x97, 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, 0x40, 0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde, 0xc5, 0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d, 0x53, 0xa8, 0xbf, 0x9d, 0xd6, 0x09, 0x6b, 0x5e, 0x7f, 0xe0, 0x0d, 0x51, 0x30, 0x85, 0x6a, 0xda, 0x68, 0x70, 0x85, 0xb0, 0xdb, 0x08, 0x0b, 0x83, 0x2c, 0xef, 0x44, 0xe2, 0x36, 0x88, 0xee, 0x76, 0x90, 0x6e, 0x7b, 0x50, 0x3e, 0x9a, 0xa0, 0xd6, 0x3c, 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, 0x25, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x17, 0x5b, 0x27, 0xa6, 0x56, 0xb2, 0x26, 0x0c, 0x26, 0x0c, 0x55, 0x42, 0x78, 0x17, 0x5d, 0x4c, 0xf8, 0xa2, 0xfd, 0x1b, 0xb9, 0x54, 0xdf, 0xd5, 0xeb, 0xbf, 0x22, 0x64, 0xf5, 0x21, 0x9a, 0xc6, 0x22, 0x58, 0x20, 0x87, 0x5f, 0x90, 0xe6, 0xfd, 0x71, 0x27, 0x9f, 0xeb, 0xe3, 0x03, 0x44, 0xbc, 0x8d, 0x49, 0xc6, 0x1c, 0x31, 0x3b, 0x72, 0xae, 0xd4, 0x53, 0xb1, 0xfe, 0x5d, 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2, }; static const unsigned char authdata_dupkeys[200] = { 0x58, 0xc6, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d, 0x97, 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, 0x40, 0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde, 0xc5, 0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d, 0x53, 0xa8, 0xbf, 0x9d, 0xd6, 0x09, 0x6b, 0x5e, 0x7f, 0xe0, 0x0d, 0x51, 0x30, 0x85, 0x6a, 0xda, 0x68, 0x70, 0x85, 0xb0, 0xdb, 0x08, 0x0b, 0x83, 0x2c, 0xef, 0x44, 0xe2, 0x36, 0x88, 0xee, 0x76, 0x90, 0x6e, 0x7b, 0x50, 0x3e, 0x9a, 0xa0, 0xd6, 0x3c, 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, 0x25, 0xa6, 0x01, 0x02, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x17, 0x5b, 0x27, 0xa6, 0x56, 0xb2, 0x26, 0x0c, 0x26, 0x0c, 0x55, 0x42, 0x78, 0x17, 0x5d, 0x4c, 0xf8, 0xa2, 0xfd, 0x1b, 0xb9, 0x54, 0xdf, 0xd5, 0xeb, 0xbf, 0x22, 0x64, 0xf5, 0x21, 0x9a, 0xc6, 0x22, 0x58, 0x20, 0x87, 0x5f, 0x90, 0xe6, 0xfd, 0x71, 0x27, 0x9f, 0xeb, 0xe3, 0x03, 0x44, 0xbc, 0x8d, 0x49, 0xc6, 0x1c, 0x31, 0x3b, 0x72, 0xae, 0xd4, 0x53, 0xb1, 0xfe, 0x5d, 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2, }; static const unsigned char authdata_unsorted_keys[198] = { 0x58, 0xc4, 0x49, 0x96, 0x0d, 0xe5, 0x88, 0x0e, 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, 0x76, 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, 0x86, 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, 0x1d, 0x97, 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, 0x40, 0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde, 0xc5, 0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d, 0x53, 0xa8, 0xbf, 0x9d, 0xd6, 0x09, 0x6b, 0x5e, 0x7f, 0xe0, 0x0d, 0x51, 0x30, 0x85, 0x6a, 0xda, 0x68, 0x70, 0x85, 0xb0, 0xdb, 0x08, 0x0b, 0x83, 0x2c, 0xef, 0x44, 0xe2, 0x36, 0x88, 0xee, 0x76, 0x90, 0x6e, 0x7b, 0x50, 0x3e, 0x9a, 0xa0, 0xd6, 0x3c, 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, 0x25, 0xa5, 0x03, 0x26, 0x01, 0x02, 0x20, 0x01, 0x21, 0x58, 0x20, 0x17, 0x5b, 0x27, 0xa6, 0x56, 0xb2, 0x26, 0x0c, 0x26, 0x0c, 0x55, 0x42, 0x78, 0x17, 0x5d, 0x4c, 0xf8, 0xa2, 0xfd, 0x1b, 0xb9, 0x54, 0xdf, 0xd5, 0xeb, 0xbf, 0x22, 0x64, 0xf5, 0x21, 0x9a, 0xc6, 0x22, 0x58, 0x20, 0x87, 0x5f, 0x90, 0xe6, 0xfd, 0x71, 0x27, 0x9f, 0xeb, 0xe3, 0x03, 0x44, 0xbc, 0x8d, 0x49, 0xc6, 0x1c, 0x31, 0x3b, 0x72, 0xae, 0xd4, 0x53, 0xb1, 0xfe, 0x5d, 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2, }; +const unsigned char authdata_tpm[362] = { + 0x59, 0x01, 0x67, 0x49, 0x96, 0x0d, 0xe5, 0x88, + 0x0e, 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64, + 0x76, 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2, + 0x86, 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83, + 0x1d, 0x97, 0x63, 0x45, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x98, 0x70, 0x58, 0xca, 0xdc, 0x4b, 0x81, + 0xb6, 0xe1, 0x30, 0xde, 0x50, 0xdc, 0xbe, 0x96, + 0x00, 0x20, 0x89, 0x99, 0x6d, 0x5a, 0x00, 0x29, + 0xe5, 0x3e, 0x6a, 0x1c, 0x72, 0x6d, 0x71, 0x4a, + 0x4f, 0x03, 0x9b, 0x68, 0x17, 0xdb, 0x29, 0x1a, + 0x6b, 0x02, 0x6c, 0x26, 0xf9, 0xbd, 0xc3, 0x0e, + 0x38, 0x1a, 0xa4, 0x01, 0x03, 0x03, 0x39, 0x01, + 0x00, 0x20, 0x59, 0x01, 0x00, 0xc5, 0xb6, 0x9c, + 0x06, 0x1d, 0xcf, 0xb9, 0xf2, 0x5e, 0x99, 0x7d, + 0x6d, 0x73, 0xd8, 0x36, 0xc1, 0x4a, 0x90, 0x05, + 0x4d, 0x82, 0x57, 0xc1, 0xb6, 0x6a, 0xd1, 0x43, + 0x03, 0x85, 0xf8, 0x52, 0x4f, 0xd2, 0x27, 0x91, + 0x0b, 0xb5, 0x93, 0xa0, 0x68, 0xf8, 0x80, 0x1b, + 0xaa, 0x65, 0x97, 0x45, 0x11, 0x86, 0x34, 0xd6, + 0x67, 0xf8, 0xd5, 0x12, 0x79, 0x84, 0xee, 0x70, + 0x99, 0x00, 0x63, 0xa8, 0xb4, 0x43, 0x0b, 0x4c, + 0x57, 0x4a, 0xd6, 0x9b, 0x75, 0x63, 0x8a, 0x46, + 0x57, 0xdb, 0x14, 0xc8, 0x71, 0xd1, 0xb3, 0x07, + 0x68, 0x58, 0xbc, 0x55, 0x84, 0x80, 0x2a, 0xd2, + 0x36, 0x9f, 0xc1, 0x64, 0xa0, 0x11, 0x4b, 0xc9, + 0x32, 0x31, 0x3a, 0xd6, 0x87, 0x26, 0x1a, 0x3a, + 0x78, 0x3d, 0x89, 0xdb, 0x00, 0x28, 0x3b, 0xae, + 0x2b, 0x1b, 0x56, 0xe2, 0x8c, 0x4c, 0x63, 0xac, + 0x6e, 0x6c, 0xf7, 0xb5, 0x7d, 0x4d, 0x0b, 0x9f, + 0x06, 0xa0, 0x10, 0x35, 0x38, 0x20, 0x4d, 0xcc, + 0x07, 0xd7, 0x00, 0x4e, 0x86, 0xba, 0xfe, 0x8b, + 0xe4, 0x3f, 0x4a, 0xd6, 0xca, 0xbf, 0x67, 0x40, + 0x1a, 0xa4, 0xda, 0x82, 0x52, 0x15, 0xb8, 0x14, + 0x3a, 0x7c, 0xa9, 0x02, 0xc1, 0x01, 0x69, 0xc6, + 0x51, 0xd4, 0xbc, 0x1f, 0x95, 0xb2, 0xee, 0x1f, + 0xdd, 0xb5, 0x73, 0x16, 0x5e, 0x29, 0x3f, 0x47, + 0xac, 0x65, 0xfb, 0x63, 0x5c, 0xb9, 0xc8, 0x13, + 0x2d, 0xec, 0x85, 0xde, 0x71, 0x0d, 0x84, 0x93, + 0x74, 0x76, 0x91, 0xdd, 0x1d, 0x6d, 0x3d, 0xc7, + 0x36, 0x19, 0x19, 0x86, 0xde, 0x7c, 0xca, 0xd6, + 0xc6, 0x65, 0x7e, 0x4b, 0x24, 0x9c, 0xce, 0x92, + 0x6b, 0x1c, 0xe0, 0xa0, 0xa9, 0x6c, 0xc3, 0xed, + 0x4f, 0x2a, 0x54, 0x07, 0x00, 0x32, 0x5e, 0x1b, + 0x94, 0x37, 0xcd, 0xe2, 0x32, 0xa8, 0xd5, 0x2c, + 0xfb, 0x03, 0x9d, 0x79, 0xdf, 0x21, 0x43, 0x01, + 0x00, 0x01 +}; + static const unsigned char x509[742] = { 0x30, 0x82, 0x02, 0xe2, 0x30, 0x81, 0xcb, 0x02, 0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x35, 0x31, 0x35, 0x31, 0x32, 0x35, 0x38, 0x35, 0x34, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x36, 0x31, 0x34, 0x31, 0x32, 0x35, 0x38, 0x35, 0x34, 0x5a, 0x30, 0x1d, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x45, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xdb, 0x0a, 0xdb, 0xf5, 0x21, 0xc7, 0x5c, 0xce, 0x63, 0xdc, 0xa6, 0xe1, 0xe8, 0x25, 0x06, 0x0d, 0x94, 0xe6, 0x27, 0x54, 0x19, 0x4f, 0x9d, 0x24, 0xaf, 0x26, 0x1a, 0xbe, 0xad, 0x99, 0x44, 0x1f, 0x95, 0xa3, 0x71, 0x91, 0x0a, 0x3a, 0x20, 0xe7, 0x3e, 0x91, 0x5e, 0x13, 0xe8, 0xbe, 0x38, 0x05, 0x7a, 0xd5, 0x7a, 0xa3, 0x7e, 0x76, 0x90, 0x8f, 0xaf, 0xe2, 0x8a, 0x94, 0xb6, 0x30, 0xeb, 0x9d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x95, 0x40, 0x6b, 0x50, 0x61, 0x7d, 0xad, 0x84, 0xa3, 0xb4, 0xeb, 0x88, 0x0f, 0xe3, 0x30, 0x0f, 0x2d, 0xa2, 0x0a, 0x00, 0xd9, 0x25, 0x04, 0xee, 0x72, 0xfa, 0x67, 0xdf, 0x58, 0x51, 0x0f, 0x0b, 0x47, 0x02, 0x9c, 0x3e, 0x41, 0x29, 0x4a, 0x93, 0xac, 0x29, 0x85, 0x89, 0x2d, 0xa4, 0x7a, 0x81, 0x32, 0x28, 0x57, 0x71, 0x01, 0xef, 0xa8, 0x42, 0x88, 0x16, 0x96, 0x37, 0x91, 0xd5, 0xdf, 0xe0, 0x8f, 0xc9, 0x3c, 0x8d, 0xb0, 0xcd, 0x89, 0x70, 0x82, 0xec, 0x79, 0xd3, 0xc6, 0x78, 0x73, 0x29, 0x32, 0xe5, 0xab, 0x6c, 0xbd, 0x56, 0x9f, 0xd5, 0x45, 0x91, 0xce, 0xc1, 0xdd, 0x8d, 0x64, 0xdc, 0xe9, 0x9c, 0x1f, 0x5e, 0x3c, 0xd2, 0xaf, 0x51, 0xa5, 0x82, 0x18, 0xaf, 0xe0, 0x37, 0xe7, 0x32, 0x9e, 0x76, 0x05, 0x77, 0x02, 0x7b, 0xe6, 0x24, 0xa0, 0x31, 0x56, 0x1b, 0xfd, 0x19, 0xc5, 0x71, 0xd3, 0xf0, 0x9e, 0xc0, 0x73, 0x05, 0x4e, 0xbc, 0x85, 0xb8, 0x53, 0x9e, 0xef, 0xc5, 0xbc, 0x9c, 0x56, 0xa3, 0xba, 0xd9, 0x27, 0x6a, 0xbb, 0xa9, 0x7a, 0x40, 0xd7, 0x47, 0x8b, 0x55, 0x72, 0x6b, 0xe3, 0xfe, 0x28, 0x49, 0x71, 0x24, 0xf4, 0x8f, 0xf4, 0x20, 0x81, 0xea, 0x38, 0xff, 0x7c, 0x0a, 0x4f, 0xdf, 0x02, 0x82, 0x39, 0x81, 0x82, 0x3b, 0xca, 0x09, 0xdd, 0xca, 0xaa, 0x0f, 0x27, 0xf5, 0xa4, 0x83, 0x55, 0x6c, 0x9a, 0x39, 0x9b, 0x15, 0x3a, 0x16, 0x63, 0xdc, 0x5b, 0xf9, 0xac, 0x5b, 0xbc, 0xf7, 0x9f, 0xbe, 0x0f, 0x8a, 0xa2, 0x3c, 0x31, 0x13, 0xa3, 0x32, 0x48, 0xca, 0x58, 0x87, 0xf8, 0x7b, 0xa0, 0xa1, 0x0a, 0x6a, 0x60, 0x96, 0x93, 0x5f, 0x5d, 0x26, 0x9e, 0x63, 0x1d, 0x09, 0xae, 0x9a, 0x41, 0xe5, 0xbd, 0x08, 0x47, 0xfe, 0xe5, 0x09, 0x9b, 0x20, 0xfd, 0x12, 0xe2, 0xe6, 0x40, 0x7f, 0xba, 0x4a, 0x61, 0x33, 0x66, 0x0d, 0x0e, 0x73, 0xdb, 0xb0, 0xd5, 0xa2, 0x9a, 0x9a, 0x17, 0x0d, 0x34, 0x30, 0x85, 0x6a, 0x42, 0x46, 0x9e, 0xff, 0x34, 0x8f, 0x5f, 0x87, 0x6c, 0x35, 0xe7, 0xa8, 0x4d, 0x35, 0xeb, 0xc1, 0x41, 0xaa, 0x8a, 0xd2, 0xda, 0x19, 0xaa, 0x79, 0xa2, 0x5f, 0x35, 0x2c, 0xa0, 0xfd, 0x25, 0xd3, 0xf7, 0x9d, 0x25, 0x18, 0x2d, 0xfa, 0xb4, 0xbc, 0xbb, 0x07, 0x34, 0x3c, 0x8d, 0x81, 0xbd, 0xf4, 0xe9, 0x37, 0xdb, 0x39, 0xe9, 0xd1, 0x45, 0x5b, 0x20, 0x41, 0x2f, 0x2d, 0x27, 0x22, 0xdc, 0x92, 0x74, 0x8a, 0x92, 0xd5, 0x83, 0xfd, 0x09, 0xfb, 0x13, 0x9b, 0xe3, 0x39, 0x7a, 0x6b, 0x5c, 0xfa, 0xe6, 0x76, 0x9e, 0xe0, 0xe4, 0xe3, 0xef, 0xad, 0xbc, 0xfd, 0x42, 0x45, 0x9a, 0xd4, 0x94, 0xd1, 0x7e, 0x8d, 0xa7, 0xd8, 0x05, 0xd5, 0xd3, 0x62, 0xcf, 0x15, 0xcf, 0x94, 0x7d, 0x1f, 0x5b, 0x58, 0x20, 0x44, 0x20, 0x90, 0x71, 0xbe, 0x66, 0xe9, 0x9a, 0xab, 0x74, 0x32, 0x70, 0x53, 0x1d, 0x69, 0xed, 0x87, 0x66, 0xf4, 0x09, 0x4f, 0xca, 0x25, 0x30, 0xc2, 0x63, 0x79, 0x00, 0x3c, 0xb1, 0x9b, 0x39, 0x3f, 0x00, 0xe0, 0xa8, 0x88, 0xef, 0x7a, 0x51, 0x5b, 0xe7, 0xbd, 0x49, 0x64, 0xda, 0x41, 0x7b, 0x24, 0xc3, 0x71, 0x22, 0xfd, 0xd1, 0xd1, 0x20, 0xb3, 0x3f, 0x97, 0xd3, 0x97, 0xb2, 0xaa, 0x18, 0x1c, 0x9e, 0x03, 0x77, 0x7b, 0x5b, 0x7e, 0xf9, 0xa3, 0xa0, 0xd6, 0x20, 0x81, 0x2c, 0x38, 0x8f, 0x9d, 0x25, 0xde, 0xe9, 0xc8, 0xf5, 0xdd, 0x6a, 0x47, 0x9c, 0x65, 0x04, 0x5a, 0x56, 0xe6, 0xc2, 0xeb, 0xf2, 0x02, 0x97, 0xe1, 0xb9, 0xd8, 0xe1, 0x24, 0x76, 0x9f, 0x23, 0x62, 0x39, 0x03, 0x4b, 0xc8, 0xf7, 0x34, 0x07, 0x49, 0xd6, 0xe7, 0x4d, 0x9a, }; const unsigned char sig[70] = { 0x30, 0x44, 0x02, 0x20, 0x54, 0x92, 0x28, 0x3b, 0x83, 0x33, 0x47, 0x56, 0x68, 0x79, 0xb2, 0x0c, 0x84, 0x80, 0xcc, 0x67, 0x27, 0x8b, 0xfa, 0x48, 0x43, 0x0d, 0x3c, 0xb4, 0x02, 0x36, 0x87, 0x97, 0x3e, 0xdf, 0x2f, 0x65, 0x02, 0x20, 0x1b, 0x56, 0x17, 0x06, 0xe2, 0x26, 0x0f, 0x6a, 0xe9, 0xa9, 0x70, 0x99, 0x62, 0xeb, 0x3a, 0x04, 0x1a, 0xc4, 0xa7, 0x03, 0x28, 0x56, 0x7c, 0xed, 0x47, 0x08, 0x68, 0x73, 0x6a, 0xb6, 0x89, 0x0d, }; const unsigned char pubkey[64] = { 0x17, 0x5b, 0x27, 0xa6, 0x56, 0xb2, 0x26, 0x0c, 0x26, 0x0c, 0x55, 0x42, 0x78, 0x17, 0x5d, 0x4c, 0xf8, 0xa2, 0xfd, 0x1b, 0xb9, 0x54, 0xdf, 0xd5, 0xeb, 0xbf, 0x22, 0x64, 0xf5, 0x21, 0x9a, 0xc6, 0x87, 0x5f, 0x90, 0xe6, 0xfd, 0x71, 0x27, 0x9f, 0xeb, 0xe3, 0x03, 0x44, 0xbc, 0x8d, 0x49, 0xc6, 0x1c, 0x31, 0x3b, 0x72, 0xae, 0xd4, 0x53, 0xb1, 0xfe, 0x5d, 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2, }; +const unsigned char pubkey_tpm[259] = { + 0xc5, 0xb6, 0x9c, 0x06, 0x1d, 0xcf, 0xb9, 0xf2, + 0x5e, 0x99, 0x7d, 0x6d, 0x73, 0xd8, 0x36, 0xc1, + 0x4a, 0x90, 0x05, 0x4d, 0x82, 0x57, 0xc1, 0xb6, + 0x6a, 0xd1, 0x43, 0x03, 0x85, 0xf8, 0x52, 0x4f, + 0xd2, 0x27, 0x91, 0x0b, 0xb5, 0x93, 0xa0, 0x68, + 0xf8, 0x80, 0x1b, 0xaa, 0x65, 0x97, 0x45, 0x11, + 0x86, 0x34, 0xd6, 0x67, 0xf8, 0xd5, 0x12, 0x79, + 0x84, 0xee, 0x70, 0x99, 0x00, 0x63, 0xa8, 0xb4, + 0x43, 0x0b, 0x4c, 0x57, 0x4a, 0xd6, 0x9b, 0x75, + 0x63, 0x8a, 0x46, 0x57, 0xdb, 0x14, 0xc8, 0x71, + 0xd1, 0xb3, 0x07, 0x68, 0x58, 0xbc, 0x55, 0x84, + 0x80, 0x2a, 0xd2, 0x36, 0x9f, 0xc1, 0x64, 0xa0, + 0x11, 0x4b, 0xc9, 0x32, 0x31, 0x3a, 0xd6, 0x87, + 0x26, 0x1a, 0x3a, 0x78, 0x3d, 0x89, 0xdb, 0x00, + 0x28, 0x3b, 0xae, 0x2b, 0x1b, 0x56, 0xe2, 0x8c, + 0x4c, 0x63, 0xac, 0x6e, 0x6c, 0xf7, 0xb5, 0x7d, + 0x4d, 0x0b, 0x9f, 0x06, 0xa0, 0x10, 0x35, 0x38, + 0x20, 0x4d, 0xcc, 0x07, 0xd7, 0x00, 0x4e, 0x86, + 0xba, 0xfe, 0x8b, 0xe4, 0x3f, 0x4a, 0xd6, 0xca, + 0xbf, 0x67, 0x40, 0x1a, 0xa4, 0xda, 0x82, 0x52, + 0x15, 0xb8, 0x14, 0x3a, 0x7c, 0xa9, 0x02, 0xc1, + 0x01, 0x69, 0xc6, 0x51, 0xd4, 0xbc, 0x1f, 0x95, + 0xb2, 0xee, 0x1f, 0xdd, 0xb5, 0x73, 0x16, 0x5e, + 0x29, 0x3f, 0x47, 0xac, 0x65, 0xfb, 0x63, 0x5c, + 0xb9, 0xc8, 0x13, 0x2d, 0xec, 0x85, 0xde, 0x71, + 0x0d, 0x84, 0x93, 0x74, 0x76, 0x91, 0xdd, 0x1d, + 0x6d, 0x3d, 0xc7, 0x36, 0x19, 0x19, 0x86, 0xde, + 0x7c, 0xca, 0xd6, 0xc6, 0x65, 0x7e, 0x4b, 0x24, + 0x9c, 0xce, 0x92, 0x6b, 0x1c, 0xe0, 0xa0, 0xa9, + 0x6c, 0xc3, 0xed, 0x4f, 0x2a, 0x54, 0x07, 0x00, + 0x32, 0x5e, 0x1b, 0x94, 0x37, 0xcd, 0xe2, 0x32, + 0xa8, 0xd5, 0x2c, 0xfb, 0x03, 0x9d, 0x79, 0xdf, + 0x01, 0x00, 0x01, +}; + const unsigned char id[64] = { 0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde, 0xc5, 0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d, 0x53, 0xa8, 0xbf, 0x9d, 0xd6, 0x09, 0x6b, 0x5e, 0x7f, 0xe0, 0x0d, 0x51, 0x30, 0x85, 0x6a, 0xda, 0x68, 0x70, 0x85, 0xb0, 0xdb, 0x08, 0x0b, 0x83, 0x2c, 0xef, 0x44, 0xe2, 0x36, 0x88, 0xee, 0x76, 0x90, 0x6e, 0x7b, 0x50, 0x3e, 0x9a, 0xa0, 0xd6, 0x3c, 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, 0x25, }; +const unsigned char id_tpm[32] = { + 0x89, 0x99, 0x6d, 0x5a, 0x00, 0x29, 0xe5, 0x3e, + 0x6a, 0x1c, 0x72, 0x6d, 0x71, 0x4a, 0x4f, 0x03, + 0x9b, 0x68, 0x17, 0xdb, 0x29, 0x1a, 0x6b, 0x02, + 0x6c, 0x26, 0xf9, 0xbd, 0xc3, 0x0e, 0x38, 0x1a +}; + +const unsigned char attstmt_tpm[4034] = { + 0xa6, 0x63, 0x61, 0x6c, 0x67, 0x39, 0xff, 0xfe, + 0x63, 0x73, 0x69, 0x67, 0x59, 0x01, 0x00, 0x1c, + 0x09, 0x0d, 0x35, 0x97, 0x22, 0xfc, 0xfe, 0xc0, + 0x58, 0x49, 0x9e, 0xd4, 0x7e, 0x6a, 0x7d, 0xdb, + 0x6d, 0x20, 0x95, 0x5c, 0x0b, 0xd0, 0xd5, 0x72, + 0x4f, 0x15, 0x22, 0x38, 0x97, 0xb2, 0x4b, 0xd0, + 0xef, 0x31, 0x7c, 0xf2, 0x42, 0x19, 0x41, 0xa1, + 0xe2, 0xc5, 0xca, 0xc6, 0x74, 0x95, 0xcf, 0xf9, + 0x41, 0x75, 0x0b, 0x56, 0x39, 0x82, 0x78, 0xf6, + 0x59, 0xf1, 0x09, 0x96, 0x9e, 0x38, 0x7f, 0x14, + 0x9b, 0xf5, 0x36, 0xbb, 0x92, 0x32, 0xc4, 0x64, + 0xe8, 0xff, 0xb4, 0xc7, 0xcf, 0xcd, 0x17, 0x48, + 0x0f, 0x83, 0xd9, 0x44, 0x03, 0x35, 0x26, 0xad, + 0x01, 0xb7, 0x57, 0x06, 0xb3, 0x9c, 0xa0, 0x6e, + 0x2f, 0x58, 0xcb, 0x5c, 0xaa, 0x7c, 0xea, 0x7e, + 0x3f, 0xbc, 0x76, 0xc9, 0x0e, 0x52, 0x39, 0x81, + 0xa9, 0x9e, 0x37, 0x14, 0x1f, 0x50, 0x6a, 0x4f, + 0xd7, 0xfc, 0xd4, 0xfa, 0xf2, 0x18, 0x60, 0xd5, + 0xc3, 0x57, 0x7d, 0x6d, 0x05, 0x28, 0x25, 0xc3, + 0xde, 0x86, 0x85, 0x06, 0x71, 0xfb, 0x84, 0xa2, + 0x07, 0xb6, 0x77, 0xc9, 0x68, 0x41, 0x53, 0x32, + 0x4c, 0xa8, 0x4b, 0xf7, 0x08, 0x84, 0x62, 0x6c, + 0x8a, 0xb6, 0xcf, 0xc1, 0xde, 0x6b, 0x61, 0xc8, + 0xdd, 0xc0, 0x13, 0x70, 0x22, 0x28, 0xe1, 0x0f, + 0x46, 0x02, 0xc6, 0xb1, 0xfa, 0x30, 0xcb, 0xec, + 0xd1, 0x82, 0xfa, 0x51, 0xcb, 0x71, 0x5e, 0x1f, + 0x1b, 0x5f, 0xe0, 0xb0, 0x02, 0x8a, 0x7c, 0x78, + 0xd1, 0xb7, 0x4d, 0x56, 0xb0, 0x92, 0x3e, 0xda, + 0xc7, 0xb1, 0x74, 0xcf, 0x6a, 0x40, 0xeb, 0x98, + 0x1c, 0x2e, 0xf2, 0x86, 0x76, 0xf8, 0x2e, 0x6a, + 0x9f, 0x77, 0x51, 0x64, 0xce, 0xdc, 0x12, 0x85, + 0x84, 0x6b, 0x01, 0xc8, 0xeb, 0xbc, 0x57, 0x6c, + 0x32, 0x26, 0xcb, 0xb2, 0x84, 0x02, 0x2a, 0x33, + 0x15, 0xd9, 0xe3, 0x15, 0xfc, 0x3a, 0x24, 0x63, + 0x76, 0x65, 0x72, 0x63, 0x32, 0x2e, 0x30, 0x63, + 0x78, 0x35, 0x63, 0x82, 0x59, 0x05, 0xc4, 0x30, + 0x82, 0x05, 0xc0, 0x30, 0x82, 0x03, 0xa8, 0xa0, + 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x78, 0xd9, + 0xa8, 0xb2, 0x64, 0xf9, 0x4d, 0x28, 0x82, 0xc0, + 0xd3, 0x1b, 0x40, 0x3c, 0xc8, 0xd9, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x41, 0x31, + 0x3f, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x13, 0x36, 0x45, 0x55, 0x53, 0x2d, 0x53, 0x54, + 0x4d, 0x2d, 0x4b, 0x45, 0x59, 0x49, 0x44, 0x2d, + 0x31, 0x41, 0x44, 0x42, 0x39, 0x39, 0x34, 0x41, + 0x42, 0x35, 0x38, 0x42, 0x45, 0x35, 0x37, 0x41, + 0x30, 0x43, 0x43, 0x39, 0x42, 0x39, 0x30, 0x30, + 0x45, 0x37, 0x38, 0x35, 0x31, 0x45, 0x31, 0x41, + 0x34, 0x33, 0x43, 0x30, 0x38, 0x36, 0x36, 0x30, + 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x37, + 0x31, 0x35, 0x31, 0x31, 0x31, 0x32, 0x31, 0x33, + 0x5a, 0x17, 0x0d, 0x32, 0x35, 0x30, 0x33, 0x32, + 0x31, 0x32, 0x30, 0x32, 0x39, 0x31, 0x35, 0x5a, + 0x30, 0x00, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, + 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, + 0x01, 0x01, 0x00, 0xca, 0xbe, 0x77, 0x9f, 0x45, + 0x97, 0x17, 0x8d, 0x01, 0xe1, 0x18, 0xcc, 0xf0, + 0xb5, 0xed, 0x9a, 0xb7, 0x36, 0xac, 0x05, 0x26, + 0xbe, 0x35, 0xd9, 0x5c, 0x00, 0x5c, 0x5d, 0x8b, + 0x6f, 0x2a, 0xb8, 0xf6, 0x02, 0x4f, 0x33, 0xfe, + 0x84, 0x45, 0x4c, 0x4f, 0x7a, 0xdb, 0xa9, 0x6a, + 0x62, 0x0f, 0x19, 0x35, 0x5d, 0xd2, 0x34, 0x1a, + 0x9d, 0x73, 0x55, 0xe5, 0x3e, 0x04, 0xa2, 0xd6, + 0xbe, 0xe7, 0x5a, 0xb9, 0x16, 0x6c, 0x55, 0x18, + 0xa8, 0x4b, 0xb2, 0x37, 0xb9, 0xa3, 0x87, 0xfc, + 0x76, 0xa8, 0x55, 0xc9, 0xe7, 0x30, 0xe5, 0x0e, + 0x3c, 0x7b, 0x74, 0xd2, 0x1e, 0xa8, 0x05, 0xd5, + 0xe2, 0xe3, 0xcb, 0xaf, 0x63, 0x33, 0x12, 0xaa, + 0xfd, 0x31, 0x32, 0x71, 0x4f, 0x41, 0x96, 0x05, + 0xb5, 0x69, 0x73, 0x45, 0xbe, 0x6f, 0x90, 0xd9, + 0x10, 0x36, 0xaf, 0x7a, 0x1c, 0xf1, 0x6d, 0x14, + 0xb0, 0x1e, 0xbb, 0xae, 0x1c, 0x35, 0xec, 0x1c, + 0xb5, 0x0e, 0xf6, 0x33, 0x98, 0x13, 0x4e, 0x44, + 0x7b, 0x5c, 0x97, 0x47, 0xed, 0x4f, 0xfe, 0xbd, + 0x08, 0xd2, 0xa9, 0xc6, 0xbe, 0x8c, 0x04, 0x9e, + 0xdc, 0x3d, 0xbe, 0x98, 0xe9, 0x2a, 0xb1, 0xf4, + 0xfa, 0x45, 0xf9, 0xc8, 0x9a, 0x55, 0x85, 0x26, + 0xfc, 0x5f, 0xad, 0x00, 0x8b, 0xc8, 0x41, 0xf2, + 0x86, 0x4e, 0xba, 0x55, 0x1c, 0xb2, 0x89, 0xe8, + 0x85, 0x6e, 0x1e, 0x02, 0x9f, 0x55, 0x70, 0xbe, + 0xfd, 0xe7, 0x9f, 0xba, 0x59, 0xa0, 0x2e, 0x9a, + 0x74, 0x11, 0xe7, 0xad, 0xa9, 0xc7, 0x7b, 0x58, + 0xc4, 0x16, 0xd3, 0x35, 0xcb, 0x61, 0x00, 0xec, + 0x36, 0x4a, 0xa3, 0x51, 0xa3, 0xdd, 0x61, 0xb6, + 0xd6, 0x29, 0xcb, 0x76, 0xe1, 0xab, 0x51, 0x3a, + 0xe8, 0xbf, 0xdb, 0x09, 0x4a, 0x39, 0x96, 0xd9, + 0xac, 0x8f, 0x6c, 0x62, 0xe0, 0x03, 0x23, 0x24, + 0xbe, 0xd4, 0x83, 0x02, 0x03, 0x01, 0x00, 0x01, + 0xa3, 0x82, 0x01, 0xf3, 0x30, 0x82, 0x01, 0xef, + 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, + 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, + 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x6d, + 0x06, 0x03, 0x55, 0x1d, 0x20, 0x01, 0x01, 0xff, + 0x04, 0x63, 0x30, 0x61, 0x30, 0x5f, 0x06, 0x09, + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, + 0x1f, 0x30, 0x52, 0x30, 0x50, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30, + 0x44, 0x1e, 0x42, 0x00, 0x54, 0x00, 0x43, 0x00, + 0x50, 0x00, 0x41, 0x00, 0x20, 0x00, 0x20, 0x00, + 0x54, 0x00, 0x72, 0x00, 0x75, 0x00, 0x73, 0x00, + 0x74, 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00, + 0x20, 0x00, 0x50, 0x00, 0x6c, 0x00, 0x61, 0x00, + 0x74, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, + 0x6d, 0x00, 0x20, 0x00, 0x20, 0x00, 0x49, 0x00, + 0x64, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, + 0x69, 0x00, 0x74, 0x00, 0x79, 0x30, 0x10, 0x06, + 0x03, 0x55, 0x1d, 0x25, 0x04, 0x09, 0x30, 0x07, + 0x06, 0x05, 0x67, 0x81, 0x05, 0x08, 0x03, 0x30, + 0x59, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x01, 0x01, + 0xff, 0x04, 0x4f, 0x30, 0x4d, 0xa4, 0x4b, 0x30, + 0x49, 0x31, 0x16, 0x30, 0x14, 0x06, 0x05, 0x67, + 0x81, 0x05, 0x02, 0x01, 0x0c, 0x0b, 0x69, 0x64, + 0x3a, 0x35, 0x33, 0x35, 0x34, 0x34, 0x44, 0x32, + 0x30, 0x31, 0x17, 0x30, 0x15, 0x06, 0x05, 0x67, + 0x81, 0x05, 0x02, 0x02, 0x0c, 0x0c, 0x53, 0x54, + 0x33, 0x33, 0x48, 0x54, 0x50, 0x48, 0x41, 0x48, + 0x42, 0x34, 0x31, 0x16, 0x30, 0x14, 0x06, 0x05, + 0x67, 0x81, 0x05, 0x02, 0x03, 0x0c, 0x0b, 0x69, + 0x64, 0x3a, 0x30, 0x30, 0x34, 0x39, 0x30, 0x30, + 0x30, 0x34, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xb8, + 0x5f, 0xd5, 0x67, 0xca, 0x92, 0xc4, 0x0e, 0xcf, + 0x0c, 0xd8, 0x1f, 0x6d, 0x3f, 0x03, 0x55, 0x6f, + 0x38, 0xa6, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xd4, 0x04, + 0x64, 0xfc, 0x6e, 0x50, 0x0a, 0x56, 0x48, 0x0f, + 0x05, 0xa9, 0x00, 0xb7, 0x1d, 0x5e, 0x57, 0x08, + 0xd5, 0xdc, 0x30, 0x81, 0xb2, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, + 0x81, 0xa5, 0x30, 0x81, 0xa2, 0x30, 0x81, 0x9f, + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, + 0x30, 0x02, 0x86, 0x81, 0x92, 0x68, 0x74, 0x74, + 0x70, 0x3a, 0x2f, 0x2f, 0x61, 0x7a, 0x63, 0x73, + 0x70, 0x72, 0x6f, 0x64, 0x65, 0x75, 0x73, 0x61, + 0x69, 0x6b, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, + 0x68, 0x2e, 0x62, 0x6c, 0x6f, 0x62, 0x2e, 0x63, + 0x6f, 0x72, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, + 0x6f, 0x77, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x2f, + 0x65, 0x75, 0x73, 0x2d, 0x73, 0x74, 0x6d, 0x2d, + 0x6b, 0x65, 0x79, 0x69, 0x64, 0x2d, 0x31, 0x61, + 0x64, 0x62, 0x39, 0x39, 0x34, 0x61, 0x62, 0x35, + 0x38, 0x62, 0x65, 0x35, 0x37, 0x61, 0x30, 0x63, + 0x63, 0x39, 0x62, 0x39, 0x30, 0x30, 0x65, 0x37, + 0x38, 0x35, 0x31, 0x65, 0x31, 0x61, 0x34, 0x33, + 0x63, 0x30, 0x38, 0x36, 0x36, 0x30, 0x2f, 0x61, + 0x62, 0x64, 0x36, 0x31, 0x35, 0x66, 0x32, 0x2d, + 0x31, 0x35, 0x38, 0x61, 0x2d, 0x34, 0x35, 0x38, + 0x65, 0x2d, 0x61, 0x31, 0x35, 0x35, 0x2d, 0x37, + 0x63, 0x34, 0x63, 0x38, 0x63, 0x62, 0x31, 0x33, + 0x63, 0x36, 0x35, 0x2e, 0x63, 0x65, 0x72, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, + 0x02, 0x01, 0x00, 0xa2, 0x10, 0xc5, 0xbf, 0x41, + 0xa6, 0xba, 0x8c, 0x72, 0xca, 0x0f, 0x3e, 0x5e, + 0x7f, 0xe2, 0xcb, 0x60, 0xb8, 0x3f, 0xfb, 0xde, + 0x03, 0xe2, 0xfe, 0x20, 0x29, 0xdf, 0x11, 0xf5, + 0xb0, 0x50, 0x6d, 0x32, 0xe8, 0x1b, 0x05, 0xad, + 0x6b, 0x60, 0xb5, 0xed, 0xf3, 0xa4, 0x4a, 0xea, + 0x09, 0xe5, 0x65, 0x7e, 0xe0, 0xd5, 0x3a, 0x6a, + 0xdb, 0x64, 0xb7, 0x07, 0x8f, 0xa1, 0x63, 0xb3, + 0x89, 0x8a, 0xac, 0x49, 0x97, 0xa0, 0x9a, 0xa3, + 0xd3, 0x3a, 0xc2, 0x13, 0xb2, 0xbb, 0xab, 0x0d, + 0xf2, 0x35, 0xc5, 0x03, 0xde, 0x1c, 0xad, 0x6a, + 0x03, 0x0a, 0x4c, 0xe1, 0x37, 0x8f, 0xbc, 0x13, + 0xc0, 0x9a, 0x17, 0xd4, 0x2e, 0x36, 0x17, 0x51, + 0x12, 0xb0, 0x79, 0xbf, 0x9b, 0xb3, 0xb0, 0x74, + 0x25, 0x81, 0x7e, 0x21, 0x31, 0xb7, 0xc2, 0x5e, + 0xfb, 0x36, 0xab, 0xf3, 0x7a, 0x5f, 0xa4, 0x5e, + 0x8f, 0x0c, 0xbd, 0xcf, 0xf5, 0x50, 0xe7, 0x0c, + 0x51, 0x55, 0x48, 0xe6, 0x15, 0xb6, 0xd4, 0xaf, + 0x95, 0x72, 0x56, 0x94, 0xf7, 0x0e, 0xd6, 0x90, + 0xe3, 0xd3, 0x5d, 0xbd, 0x93, 0xa1, 0xbd, 0x6c, + 0xe4, 0xf2, 0x39, 0x4d, 0x54, 0x74, 0xcf, 0xf5, + 0xeb, 0x70, 0xdb, 0x4f, 0x52, 0xcd, 0x39, 0x8f, + 0x11, 0x54, 0x28, 0x06, 0x29, 0x8f, 0x23, 0xde, + 0x9e, 0x2f, 0x7b, 0xb6, 0x5f, 0xa3, 0x89, 0x04, + 0x99, 0x0a, 0xf1, 0x2d, 0xf9, 0x66, 0xd3, 0x13, + 0x45, 0xbd, 0x6c, 0x22, 0x57, 0xf5, 0xb1, 0xb9, + 0xdf, 0x5b, 0x7b, 0x1a, 0x3a, 0xdd, 0x6b, 0xc7, + 0x35, 0x88, 0xed, 0xc4, 0x09, 0x70, 0x4e, 0x5f, + 0xb5, 0x3e, 0xd1, 0x0b, 0xd0, 0xca, 0xef, 0x0b, + 0xe9, 0x8b, 0x6f, 0xc3, 0x16, 0xc3, 0x3d, 0x79, + 0x06, 0xef, 0x81, 0xf0, 0x60, 0x0b, 0x32, 0xe3, + 0x86, 0x6b, 0x92, 0x38, 0x90, 0x62, 0xed, 0x84, + 0x3a, 0xb7, 0x45, 0x43, 0x2e, 0xd0, 0x3a, 0x71, + 0x9e, 0x80, 0xcc, 0x9c, 0xac, 0x27, 0x10, 0x91, + 0xb7, 0xb2, 0xbd, 0x41, 0x40, 0xa7, 0xb7, 0xcf, + 0xe7, 0x38, 0xca, 0x68, 0xdd, 0x62, 0x09, 0xff, + 0x68, 0xce, 0xba, 0xe2, 0x07, 0x49, 0x09, 0xe7, + 0x1f, 0xdf, 0xe6, 0x26, 0xe5, 0x0f, 0xa9, 0xbf, + 0x2a, 0x5b, 0x67, 0x92, 0xa1, 0x10, 0x53, 0xb2, + 0x7a, 0x07, 0x29, 0x9d, 0xfd, 0x6d, 0xb6, 0x3b, + 0x45, 0xc1, 0x94, 0xcb, 0x1c, 0xc3, 0xce, 0xf6, + 0x8a, 0x1a, 0x81, 0x66, 0xb0, 0xa5, 0x14, 0xc7, + 0x9e, 0x1f, 0x6e, 0xb6, 0xff, 0x8b, 0x90, 0x87, + 0x3a, 0x3f, 0xa8, 0xc2, 0x2d, 0x8f, 0x6f, 0xdb, + 0xb4, 0xc4, 0x14, 0x3c, 0x1d, 0x12, 0x1d, 0x6d, + 0xcf, 0xa6, 0x04, 0x6a, 0xa8, 0x13, 0x5e, 0xf2, + 0x5e, 0x77, 0x80, 0x6b, 0x85, 0x83, 0xfe, 0xbb, + 0xeb, 0x70, 0xcb, 0x5f, 0xe4, 0x95, 0xaa, 0x0f, + 0x61, 0x36, 0x7c, 0xbb, 0x22, 0x1e, 0xba, 0x98, + 0x43, 0x52, 0x33, 0xae, 0xed, 0x5d, 0x10, 0x2c, + 0xb3, 0xa9, 0x31, 0x8e, 0x60, 0x54, 0xaf, 0x40, + 0x6d, 0x2e, 0x18, 0xc2, 0x6a, 0xf4, 0x7b, 0x9a, + 0x73, 0x0f, 0x58, 0x69, 0x23, 0xbb, 0xc4, 0x84, + 0x53, 0x30, 0xe2, 0xd6, 0x1e, 0x10, 0xc1, 0xec, + 0x82, 0x13, 0xab, 0x53, 0x86, 0xa2, 0xb9, 0xda, + 0xbb, 0x3a, 0xa2, 0xbe, 0xb0, 0x10, 0x99, 0x0e, + 0xe5, 0x9c, 0xc9, 0xf1, 0xce, 0x76, 0x46, 0xea, + 0x86, 0xaa, 0x36, 0x83, 0x99, 0x09, 0x9b, 0x30, + 0xd3, 0x26, 0xc7, 0xdf, 0x66, 0xc7, 0xf0, 0xdd, + 0x08, 0x09, 0x15, 0x15, 0x21, 0x49, 0x46, 0xd8, + 0x8a, 0x66, 0xca, 0x62, 0x9c, 0x79, 0x1d, 0x81, + 0xea, 0x5d, 0x82, 0xb0, 0xa6, 0x6b, 0x5c, 0xf5, + 0xb8, 0x8c, 0xf6, 0x16, 0x01, 0x2c, 0xf8, 0x27, + 0xf8, 0xcf, 0x88, 0xfe, 0xf3, 0xa4, 0xfc, 0x17, + 0x97, 0xe7, 0x07, 0x59, 0x06, 0xef, 0x30, 0x82, + 0x06, 0xeb, 0x30, 0x82, 0x04, 0xd3, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x13, 0x33, 0x00, 0x00, + 0x02, 0x39, 0xf9, 0xbb, 0x6a, 0x1d, 0x49, 0x64, + 0x47, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x02, 0x39, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, + 0x81, 0x8c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x13, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, + 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x52, + 0x65, 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e, + 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, + 0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, + 0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x36, + 0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, + 0x2d, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, + 0x66, 0x74, 0x20, 0x54, 0x50, 0x4d, 0x20, 0x52, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, + 0x79, 0x20, 0x32, 0x30, 0x31, 0x34, 0x30, 0x1e, + 0x17, 0x0d, 0x31, 0x39, 0x30, 0x33, 0x32, 0x31, + 0x32, 0x30, 0x32, 0x39, 0x31, 0x35, 0x5a, 0x17, + 0x0d, 0x32, 0x35, 0x30, 0x33, 0x32, 0x31, 0x32, + 0x30, 0x32, 0x39, 0x31, 0x35, 0x5a, 0x30, 0x41, + 0x31, 0x3f, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x36, 0x45, 0x55, 0x53, 0x2d, 0x53, + 0x54, 0x4d, 0x2d, 0x4b, 0x45, 0x59, 0x49, 0x44, + 0x2d, 0x31, 0x41, 0x44, 0x42, 0x39, 0x39, 0x34, + 0x41, 0x42, 0x35, 0x38, 0x42, 0x45, 0x35, 0x37, + 0x41, 0x30, 0x43, 0x43, 0x39, 0x42, 0x39, 0x30, + 0x30, 0x45, 0x37, 0x38, 0x35, 0x31, 0x45, 0x31, + 0x41, 0x34, 0x33, 0x43, 0x30, 0x38, 0x36, 0x36, + 0x30, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, + 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, + 0x01, 0x00, 0xdb, 0xe2, 0x23, 0xf9, 0x86, 0x8f, + 0xa9, 0x71, 0x9f, 0x8b, 0xf9, 0x7c, 0xe9, 0x45, + 0x2d, 0x59, 0x56, 0x5e, 0x96, 0xf4, 0xdd, 0x9a, + 0x12, 0xcd, 0x90, 0x1a, 0x0c, 0xb5, 0x03, 0xbf, + 0x09, 0xbe, 0xbf, 0xf7, 0x55, 0x52, 0xe8, 0x39, + 0x4c, 0xbe, 0x2a, 0x28, 0x88, 0x78, 0x39, 0xa7, + 0xcb, 0xf9, 0x4c, 0x55, 0xd2, 0x31, 0x96, 0x3b, + 0x48, 0xa2, 0xf3, 0xf6, 0xd3, 0x1a, 0x81, 0x7f, + 0x90, 0x62, 0xab, 0xec, 0x5a, 0xc7, 0xa0, 0x7f, + 0x81, 0x32, 0x27, 0x9b, 0x29, 0x75, 0x7d, 0x1e, + 0x96, 0xc5, 0xfa, 0x0e, 0x7c, 0xe0, 0x60, 0x96, + 0x7a, 0xca, 0x94, 0xba, 0xe6, 0xb2, 0x69, 0xdd, + 0xc4, 0x7d, 0xbb, 0xd3, 0xc4, 0xb4, 0x6e, 0x00, + 0x86, 0x1f, 0x9d, 0x25, 0xe8, 0xae, 0xc7, 0x10, + 0x84, 0xdc, 0xc0, 0x34, 0x24, 0x6e, 0xf7, 0xfc, + 0xdd, 0x3d, 0x32, 0x7a, 0x43, 0x96, 0xd6, 0xc8, + 0x7b, 0xf4, 0x9b, 0x3d, 0xa7, 0x1e, 0xba, 0x4d, + 0xd0, 0x3b, 0x3d, 0x84, 0x9a, 0xd1, 0x25, 0x22, + 0x5d, 0x00, 0x44, 0xb0, 0x59, 0xb7, 0x40, 0xc5, + 0xa3, 0x53, 0x53, 0xaf, 0x8f, 0x9e, 0xfd, 0x8f, + 0x1e, 0x02, 0xd3, 0x4f, 0xf7, 0x09, 0xce, 0xc5, + 0xc6, 0x71, 0x5c, 0xe9, 0xe8, 0x7a, 0xb5, 0x6b, + 0xa4, 0xbf, 0x0b, 0xd9, 0xb6, 0xfa, 0x24, 0xb0, + 0xcd, 0x52, 0x22, 0x1d, 0x7e, 0xe8, 0x15, 0x2f, + 0x1e, 0x5e, 0xa2, 0xec, 0xd3, 0xa8, 0x02, 0x77, + 0xb9, 0x55, 0x9a, 0xcf, 0xcc, 0xd7, 0x08, 0x20, + 0xa5, 0xda, 0x39, 0x9a, 0x30, 0x76, 0x90, 0x37, + 0xa7, 0x60, 0xdf, 0x18, 0x12, 0x65, 0x17, 0xaa, + 0xdd, 0x48, 0xd5, 0x12, 0x1d, 0x4c, 0x83, 0x5d, + 0x81, 0x07, 0x1d, 0x18, 0x81, 0x40, 0x55, 0x60, + 0x8f, 0xa3, 0x6b, 0x34, 0x1e, 0xd5, 0xe6, 0xcf, + 0x52, 0x73, 0x77, 0x4a, 0x50, 0x4f, 0x1b, 0x0f, + 0x39, 0xc3, 0x0d, 0x16, 0xf9, 0xbb, 0x4c, 0x77, + 0xf6, 0x4e, 0xac, 0x9c, 0xfe, 0xe8, 0xbb, 0x52, + 0xa5, 0x0a, 0x0e, 0x9b, 0xf0, 0x0d, 0xef, 0xfb, + 0x6f, 0x89, 0x34, 0x7d, 0x47, 0xec, 0x14, 0x6a, + 0xf4, 0x0a, 0xe1, 0x60, 0x44, 0x73, 0x7b, 0xa0, + 0xab, 0x5b, 0x8c, 0x43, 0xa6, 0x05, 0x42, 0x61, + 0x46, 0xaa, 0x1c, 0xf5, 0xec, 0x2c, 0x86, 0x85, + 0x21, 0x99, 0xdf, 0x45, 0x8e, 0xf4, 0xd1, 0x1e, + 0xfb, 0xcd, 0x9b, 0x94, 0x32, 0xe0, 0xa0, 0xcc, + 0x4f, 0xad, 0xae, 0x44, 0x8b, 0x86, 0x27, 0x91, + 0xfe, 0x60, 0x9f, 0xf2, 0x63, 0x30, 0x6c, 0x5d, + 0x8d, 0xbc, 0xab, 0xd4, 0xf5, 0xa2, 0xb2, 0x74, + 0xe8, 0xd4, 0x95, 0xf2, 0xd6, 0x03, 0x8b, 0xc9, + 0xa3, 0x52, 0xe7, 0x63, 0x05, 0x64, 0x50, 0xe5, + 0x0a, 0x6a, 0xa0, 0x6c, 0x50, 0xcd, 0x37, 0x98, + 0xa8, 0x87, 0x02, 0x38, 0x5b, 0x6c, 0x02, 0x69, + 0x3d, 0x1f, 0x95, 0x74, 0x4d, 0x46, 0x76, 0x2a, + 0x9d, 0x62, 0xd4, 0xc7, 0x1b, 0xf9, 0x31, 0xa6, + 0x51, 0xee, 0x7b, 0xc8, 0xe4, 0x6e, 0x3a, 0xcf, + 0x4f, 0x4f, 0x49, 0x8a, 0xf5, 0x4f, 0x25, 0x93, + 0x23, 0x02, 0xef, 0x79, 0xa6, 0x27, 0xbe, 0x5a, + 0xe7, 0x74, 0xb7, 0xd7, 0xa8, 0xc1, 0xae, 0x55, + 0x88, 0xa4, 0xc7, 0x4d, 0xb7, 0x62, 0xf0, 0xf9, + 0x5b, 0xbf, 0x47, 0x5b, 0xfe, 0xcc, 0x0b, 0x89, + 0x19, 0x65, 0x4b, 0x6f, 0xdf, 0x4f, 0x7d, 0x4d, + 0x96, 0x42, 0x0d, 0x2a, 0xa1, 0xbd, 0x3e, 0x70, + 0x92, 0xba, 0xc8, 0x59, 0xd5, 0x1d, 0x3a, 0x98, + 0x53, 0x75, 0xa6, 0x32, 0xc8, 0x72, 0x03, 0x46, + 0x5f, 0x5c, 0x13, 0xa4, 0xdb, 0xc7, 0x55, 0x35, + 0x22, 0x0d, 0xc6, 0x17, 0x85, 0xbd, 0x46, 0x4b, + 0xfa, 0x1e, 0x49, 0xc2, 0xfe, 0x1e, 0xf9, 0x62, + 0x89, 0x56, 0x84, 0xdf, 0xa0, 0xfb, 0xfd, 0x93, + 0xa4, 0x25, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, + 0x82, 0x01, 0x8e, 0x30, 0x82, 0x01, 0x8a, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x84, 0x30, + 0x1b, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x14, + 0x30, 0x12, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, + 0x01, 0x82, 0x37, 0x15, 0x24, 0x06, 0x05, 0x67, + 0x81, 0x05, 0x08, 0x03, 0x30, 0x16, 0x06, 0x03, + 0x55, 0x1d, 0x20, 0x04, 0x0f, 0x30, 0x0d, 0x30, + 0x0b, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, + 0x82, 0x37, 0x15, 0x1f, 0x30, 0x12, 0x06, 0x03, + 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, + 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, + 0x16, 0x04, 0x14, 0xb8, 0x5f, 0xd5, 0x67, 0xca, + 0x92, 0xc4, 0x0e, 0xcf, 0x0c, 0xd8, 0x1f, 0x6d, + 0x3f, 0x03, 0x55, 0x6f, 0x38, 0xa6, 0x51, 0x30, + 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, + 0x30, 0x16, 0x80, 0x14, 0x7a, 0x8c, 0x0a, 0xce, + 0x2f, 0x48, 0x62, 0x17, 0xe2, 0x94, 0xd1, 0xae, + 0x55, 0xc1, 0x52, 0xec, 0x71, 0x74, 0xa4, 0x56, + 0x30, 0x70, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, + 0x69, 0x30, 0x67, 0x30, 0x65, 0xa0, 0x63, 0xa0, + 0x61, 0x86, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6d, 0x69, + 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6b, 0x69, 0x6f, + 0x70, 0x73, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x4d, + 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, + 0x25, 0x32, 0x30, 0x54, 0x50, 0x4d, 0x25, 0x32, + 0x30, 0x52, 0x6f, 0x6f, 0x74, 0x25, 0x32, 0x30, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x25, 0x32, 0x30, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x25, + 0x32, 0x30, 0x32, 0x30, 0x31, 0x34, 0x2e, 0x63, + 0x72, 0x6c, 0x30, 0x7d, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x71, + 0x30, 0x6f, 0x30, 0x6d, 0x06, 0x08, 0x2b, 0x06, + 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x61, + 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, + 0x77, 0x77, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, + 0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x70, 0x6b, 0x69, 0x6f, 0x70, 0x73, 0x2f, + 0x63, 0x65, 0x72, 0x74, 0x73, 0x2f, 0x4d, 0x69, + 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x25, + 0x32, 0x30, 0x54, 0x50, 0x4d, 0x25, 0x32, 0x30, + 0x52, 0x6f, 0x6f, 0x74, 0x25, 0x32, 0x30, 0x43, + 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x25, 0x32, 0x30, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x25, 0x32, + 0x30, 0x32, 0x30, 0x31, 0x34, 0x2e, 0x63, 0x72, + 0x74, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, + 0x03, 0x82, 0x02, 0x01, 0x00, 0x41, 0xaa, 0xfe, + 0x28, 0x6c, 0xf7, 0x6b, 0x53, 0xde, 0x77, 0xc0, + 0x80, 0x50, 0x94, 0xd9, 0xdb, 0x46, 0x8e, 0x6a, + 0x93, 0xa9, 0x10, 0x37, 0x27, 0x1f, 0xf5, 0x70, + 0xf1, 0xa8, 0xcf, 0xa1, 0x45, 0x86, 0x2a, 0xdd, + 0x8f, 0xb8, 0xb5, 0xc1, 0xe6, 0xcf, 0x8a, 0xfa, + 0x32, 0xa1, 0x4b, 0xb7, 0xa4, 0xbf, 0x0a, 0x48, + 0xcb, 0x42, 0x63, 0x71, 0xc1, 0x96, 0xb9, 0x3a, + 0x37, 0x84, 0x0e, 0x24, 0x39, 0xeb, 0x58, 0xce, + 0x3d, 0xb7, 0xa9, 0x44, 0x92, 0x59, 0xb9, 0xff, + 0xdb, 0x18, 0xbe, 0x6a, 0x5e, 0xe7, 0xce, 0xef, + 0xb8, 0x40, 0x53, 0xaf, 0xc1, 0x9b, 0xfb, 0x42, + 0x99, 0x7e, 0x9d, 0x05, 0x2b, 0x71, 0x0a, 0x7a, + 0x7a, 0x44, 0xd1, 0x31, 0xca, 0xf0, 0x5f, 0x74, + 0x85, 0xa9, 0xe2, 0xbc, 0xc8, 0x0c, 0xad, 0x57, + 0xd1, 0xe9, 0x48, 0x90, 0x88, 0x57, 0x86, 0xd7, + 0xc5, 0xc9, 0xe6, 0xb2, 0x5e, 0x5f, 0x13, 0xdc, + 0x10, 0x7f, 0xdf, 0x63, 0x8a, 0xd5, 0x9e, 0x90, + 0xc2, 0x75, 0x53, 0x1e, 0x68, 0x17, 0x2b, 0x03, + 0x29, 0x15, 0x03, 0xc5, 0x8c, 0x66, 0x3e, 0xae, + 0xbd, 0x4a, 0x32, 0x7e, 0x59, 0x89, 0x0b, 0x84, + 0xc2, 0xd9, 0x90, 0xfa, 0x02, 0x22, 0x90, 0x8d, + 0x9c, 0xb6, 0x0c, 0x4d, 0xe1, 0x28, 0x76, 0xd7, + 0x82, 0xc3, 0x36, 0xc2, 0xa3, 0x2a, 0x52, 0xe5, + 0xfe, 0x3c, 0x8f, 0xe3, 0x4b, 0xda, 0x6a, 0xdb, + 0xc0, 0x7a, 0x3c, 0x57, 0xfa, 0x85, 0x8f, 0xfb, + 0x62, 0xc3, 0xa1, 0x38, 0xce, 0x84, 0xf2, 0xba, + 0x12, 0xf4, 0x30, 0x2a, 0x4a, 0x94, 0xa9, 0x35, + 0x2c, 0x7d, 0x11, 0xc7, 0x68, 0x1f, 0x47, 0xaa, + 0x57, 0x43, 0x06, 0x70, 0x79, 0x8c, 0xb6, 0x3b, + 0x5d, 0x57, 0xf3, 0xf3, 0xc0, 0x2c, 0xc5, 0xde, + 0x41, 0x99, 0xf6, 0xdd, 0x55, 0x8a, 0xe4, 0x13, + 0xca, 0xc9, 0xec, 0x69, 0x93, 0x13, 0x48, 0xf0, + 0x5f, 0xda, 0x2e, 0xfd, 0xfb, 0xa9, 0x1b, 0x92, + 0xde, 0x49, 0x71, 0x37, 0x8c, 0x3f, 0xc2, 0x08, + 0x0a, 0x83, 0x25, 0xf1, 0x6e, 0x0a, 0xe3, 0x55, + 0x85, 0x96, 0x9a, 0x2d, 0xa2, 0xc0, 0xa1, 0xee, + 0xfe, 0x23, 0x3b, 0x69, 0x22, 0x03, 0xfd, 0xcc, + 0x8a, 0xdd, 0xb4, 0x53, 0x8d, 0x84, 0xa6, 0xac, + 0xe0, 0x1e, 0x07, 0xe5, 0xd7, 0xf9, 0xcb, 0xb9, + 0xe3, 0x9a, 0xb7, 0x84, 0x70, 0xa1, 0x93, 0xd6, + 0x02, 0x1e, 0xfe, 0xdb, 0x28, 0x7c, 0xf7, 0xd4, + 0x62, 0x6f, 0x80, 0x75, 0xc8, 0xd8, 0x35, 0x26, + 0x0c, 0xcb, 0x84, 0xed, 0xbb, 0x95, 0xdf, 0x7f, + 0xd5, 0xbb, 0x00, 0x96, 0x97, 0x32, 0xe7, 0xba, + 0xe8, 0x29, 0xb5, 0x1a, 0x51, 0x81, 0xbb, 0x04, + 0xd1, 0x21, 0x76, 0x34, 0x6d, 0x1e, 0x93, 0x96, + 0x1f, 0x96, 0x53, 0x5f, 0x5c, 0x9e, 0xf3, 0x9d, + 0x82, 0x1c, 0x39, 0x36, 0x59, 0xae, 0xc9, 0x3c, + 0x53, 0x4a, 0x67, 0x65, 0x6e, 0xbf, 0xa6, 0xac, + 0x3e, 0xda, 0xb2, 0xa7, 0x63, 0x07, 0x17, 0xe1, + 0x5b, 0xda, 0x6a, 0x31, 0x9f, 0xfb, 0xb4, 0xea, + 0xa1, 0x97, 0x08, 0x6e, 0xb2, 0x68, 0xf3, 0x72, + 0x76, 0x99, 0xe8, 0x00, 0x46, 0x88, 0x26, 0xe1, + 0x3c, 0x07, 0x2b, 0x78, 0x49, 0xda, 0x79, 0x3a, + 0xbd, 0x6f, 0xca, 0x5c, 0xa0, 0xa8, 0xed, 0x34, + 0xcc, 0xdb, 0x13, 0xe2, 0x51, 0x9b, 0x3d, 0x03, + 0xac, 0xc7, 0xf6, 0x32, 0xe1, 0x11, 0x5d, 0xe1, + 0xc5, 0xfd, 0x9e, 0x7a, 0xcd, 0x06, 0xb9, 0xe6, + 0xfc, 0xe0, 0x03, 0x31, 0xf4, 0x4a, 0xa9, 0x3b, + 0x79, 0x01, 0xb0, 0x64, 0x68, 0x9f, 0x6e, 0x76, + 0xa1, 0xcc, 0xec, 0x17, 0x41, 0x9d, 0xd4, 0x5b, + 0x4e, 0x9d, 0xe5, 0x46, 0xd4, 0x6b, 0x60, 0x2a, + 0x23, 0xb5, 0x7a, 0x89, 0x7c, 0x27, 0x96, 0x65, + 0x97, 0x56, 0xec, 0x98, 0xe3, 0x67, 0x70, 0x75, + 0x62, 0x41, 0x72, 0x65, 0x61, 0x59, 0x01, 0x36, + 0x00, 0x01, 0x00, 0x0b, 0x00, 0x06, 0x04, 0x72, + 0x00, 0x20, 0x9d, 0xff, 0xcb, 0xf3, 0x6c, 0x38, + 0x3a, 0xe6, 0x99, 0xfb, 0x98, 0x68, 0xdc, 0x6d, + 0xcb, 0x89, 0xd7, 0x15, 0x38, 0x84, 0xbe, 0x28, + 0x03, 0x92, 0x2c, 0x12, 0x41, 0x58, 0xbf, 0xad, + 0x22, 0xae, 0x00, 0x10, 0x00, 0x10, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc5, 0xb6, + 0x9c, 0x06, 0x1d, 0xcf, 0xb9, 0xf2, 0x5e, 0x99, + 0x7d, 0x6d, 0x73, 0xd8, 0x36, 0xc1, 0x4a, 0x90, + 0x05, 0x4d, 0x82, 0x57, 0xc1, 0xb6, 0x6a, 0xd1, + 0x43, 0x03, 0x85, 0xf8, 0x52, 0x4f, 0xd2, 0x27, + 0x91, 0x0b, 0xb5, 0x93, 0xa0, 0x68, 0xf8, 0x80, + 0x1b, 0xaa, 0x65, 0x97, 0x45, 0x11, 0x86, 0x34, + 0xd6, 0x67, 0xf8, 0xd5, 0x12, 0x79, 0x84, 0xee, + 0x70, 0x99, 0x00, 0x63, 0xa8, 0xb4, 0x43, 0x0b, + 0x4c, 0x57, 0x4a, 0xd6, 0x9b, 0x75, 0x63, 0x8a, + 0x46, 0x57, 0xdb, 0x14, 0xc8, 0x71, 0xd1, 0xb3, + 0x07, 0x68, 0x58, 0xbc, 0x55, 0x84, 0x80, 0x2a, + 0xd2, 0x36, 0x9f, 0xc1, 0x64, 0xa0, 0x11, 0x4b, + 0xc9, 0x32, 0x31, 0x3a, 0xd6, 0x87, 0x26, 0x1a, + 0x3a, 0x78, 0x3d, 0x89, 0xdb, 0x00, 0x28, 0x3b, + 0xae, 0x2b, 0x1b, 0x56, 0xe2, 0x8c, 0x4c, 0x63, + 0xac, 0x6e, 0x6c, 0xf7, 0xb5, 0x7d, 0x4d, 0x0b, + 0x9f, 0x06, 0xa0, 0x10, 0x35, 0x38, 0x20, 0x4d, + 0xcc, 0x07, 0xd7, 0x00, 0x4e, 0x86, 0xba, 0xfe, + 0x8b, 0xe4, 0x3f, 0x4a, 0xd6, 0xca, 0xbf, 0x67, + 0x40, 0x1a, 0xa4, 0xda, 0x82, 0x52, 0x15, 0xb8, + 0x14, 0x3a, 0x7c, 0xa9, 0x02, 0xc1, 0x01, 0x69, + 0xc6, 0x51, 0xd4, 0xbc, 0x1f, 0x95, 0xb2, 0xee, + 0x1f, 0xdd, 0xb5, 0x73, 0x16, 0x5e, 0x29, 0x3f, + 0x47, 0xac, 0x65, 0xfb, 0x63, 0x5c, 0xb9, 0xc8, + 0x13, 0x2d, 0xec, 0x85, 0xde, 0x71, 0x0d, 0x84, + 0x93, 0x74, 0x76, 0x91, 0xdd, 0x1d, 0x6d, 0x3d, + 0xc7, 0x36, 0x19, 0x19, 0x86, 0xde, 0x7c, 0xca, + 0xd6, 0xc6, 0x65, 0x7e, 0x4b, 0x24, 0x9c, 0xce, + 0x92, 0x6b, 0x1c, 0xe0, 0xa0, 0xa9, 0x6c, 0xc3, + 0xed, 0x4f, 0x2a, 0x54, 0x07, 0x00, 0x32, 0x5e, + 0x1b, 0x94, 0x37, 0xcd, 0xe2, 0x32, 0xa8, 0xd5, + 0x2c, 0xfb, 0x03, 0x9d, 0x79, 0xdf, 0x68, 0x63, + 0x65, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x58, + 0xa1, 0xff, 0x54, 0x43, 0x47, 0x80, 0x17, 0x00, + 0x22, 0x00, 0x0b, 0xdb, 0x1f, 0x74, 0x21, 0x4f, + 0xa9, 0x0d, 0x90, 0x64, 0xa2, 0x33, 0xbe, 0x3f, + 0xf1, 0x95, 0xb0, 0x4e, 0x3f, 0x02, 0xdc, 0xad, + 0xb0, 0x05, 0x13, 0xe6, 0x32, 0x5f, 0xed, 0x90, + 0x2c, 0xad, 0xc0, 0x00, 0x14, 0x58, 0x52, 0x07, + 0x5d, 0x64, 0x6c, 0x1f, 0xd1, 0x13, 0x7f, 0xc3, + 0x74, 0xf6, 0x4b, 0xe3, 0xa0, 0x2e, 0xb7, 0x71, + 0xda, 0x00, 0x00, 0x00, 0x00, 0x29, 0x3c, 0x64, + 0xdf, 0x95, 0x38, 0xba, 0x73, 0xe3, 0x57, 0x61, + 0xa0, 0x01, 0x24, 0x01, 0x08, 0xc9, 0xd6, 0xea, + 0x60, 0xe4, 0x00, 0x22, 0x00, 0x0b, 0xe1, 0x86, + 0xbb, 0x79, 0x27, 0xe5, 0x01, 0x19, 0x90, 0xb3, + 0xe9, 0x08, 0xb0, 0xee, 0xfa, 0x3a, 0x67, 0xa9, + 0xf3, 0xc8, 0x9e, 0x03, 0x41, 0x07, 0x75, 0x60, + 0xbc, 0x94, 0x0c, 0x2a, 0xb7, 0xad, 0x00, 0x22, + 0x00, 0x0b, 0x35, 0xb1, 0x72, 0xd6, 0x3c, 0xe9, + 0x85, 0xe8, 0x66, 0xed, 0x10, 0x7a, 0x5c, 0xa3, + 0xe6, 0xd9, 0x4d, 0xf0, 0x52, 0x69, 0x26, 0x14, + 0xb4, 0x36, 0x7e, 0xad, 0x76, 0x9e, 0x58, 0x68, + 0x3e, 0x91 +}; + /* * Security Key By Yubico * 5.1.X * f8a011f3-8c0a-4d15-8006-17111f9edc7d -*/ + */ const unsigned char aaguid[16] = { 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, }; +/* + * Windows Hello by Microsoft + */ +const unsigned char aaguid_tpm[16] = { + 0x08, 0x98, 0x70, 0x58, 0xca, 0xdc, 0x4b, 0x81, + 0xb6, 0xe1, 0x30, 0xde, 0x50, 0xdc, 0xbe, 0x96, +}; + const char rp_id[] = "localhost"; const char rp_name[] = "sweet home localhost"; static void * dummy_open(const char *path) { (void)path; return (FAKE_DEV_HANDLE); } static void dummy_close(void *handle) { assert(handle == FAKE_DEV_HANDLE); } static int dummy_read(void *handle, unsigned char *buf, size_t len, int ms) { (void)handle; (void)buf; (void)len; (void)ms; abort(); /* NOTREACHED */ } static int dummy_write(void *handle, const unsigned char *buf, size_t len) { (void)handle; (void)buf; (void)len; abort(); /* NOTREACHED */ } static fido_cred_t * alloc_cred(void) { fido_cred_t *c; c = fido_cred_new(); assert(c != NULL); return (c); } static void free_cred(fido_cred_t *c) { fido_cred_free(&c); assert(c == NULL); } static fido_dev_t * alloc_dev(void) { fido_dev_t *d; d = fido_dev_new(); assert(d != NULL); return (d); } static void free_dev(fido_dev_t *d) { fido_dev_free(&d); assert(d == NULL); } static void empty_cred(void) { fido_cred_t *c; fido_dev_t *d; fido_dev_io_t io_f; c = alloc_cred(); assert(fido_cred_authdata_len(c) == 0); assert(fido_cred_authdata_ptr(c) == NULL); assert(fido_cred_authdata_raw_len(c) == 0); assert(fido_cred_authdata_raw_ptr(c) == NULL); assert(fido_cred_clientdata_hash_len(c) == 0); assert(fido_cred_clientdata_hash_ptr(c) == NULL); assert(fido_cred_flags(c) == 0); assert(fido_cred_fmt(c) == NULL); assert(fido_cred_id_len(c) == 0); assert(fido_cred_id_ptr(c) == NULL); assert(fido_cred_prot(c) == 0); assert(fido_cred_pubkey_len(c) == 0); assert(fido_cred_pubkey_ptr(c) == NULL); assert(fido_cred_rp_id(c) == NULL); assert(fido_cred_rp_name(c) == NULL); assert(fido_cred_sig_len(c) == 0); assert(fido_cred_sig_ptr(c) == NULL); assert(fido_cred_x5c_len(c) == 0); assert(fido_cred_x5c_ptr(c) == NULL); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); memset(&io_f, 0, sizeof(io_f)); io_f.open = dummy_open; io_f.close = dummy_close; io_f.read = dummy_read; io_f.write = dummy_write; d = alloc_dev(); fido_dev_force_u2f(d); assert(fido_dev_set_io_functions(d, &io_f) == FIDO_OK); assert(fido_dev_make_cred(d, c, NULL) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_dev_make_cred(d, c, "") == FIDO_ERR_UNSUPPORTED_OPTION); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); fido_dev_force_fido2(d); assert(fido_dev_set_io_functions(d, &io_f) == FIDO_OK); assert(fido_dev_make_cred(d, c, NULL) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_dev_make_cred(d, c, "") == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); free_cred(c); free_dev(d); } static void valid_cred(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_OK); assert(fido_cred_prot(c) == 0); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } static void no_cdh(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } static void no_rp_id(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } static void no_rp_name(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, NULL) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_OK); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } static void no_authdata(void) { fido_cred_t *c; unsigned char *unset; unset = calloc(1, sizeof(aaguid)); assert(unset != NULL); c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_pubkey_len(c) == 0); assert(fido_cred_pubkey_ptr(c) == NULL); assert(fido_cred_id_len(c) == 0); assert(fido_cred_id_ptr(c) == NULL); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), unset, sizeof(aaguid)) == 0); free_cred(c); free(unset); } static void no_x509(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } static void no_sig(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } static void no_fmt(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } static void wrong_options(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_TRUE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_PARAM); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } static void junk_cdh(void) { fido_cred_t *c; unsigned char *junk; junk = malloc(sizeof(cdh)); assert(junk != NULL); memcpy(junk, cdh, sizeof(cdh)); - junk[0] = ~junk[0]; + junk[0] = (unsigned char)~junk[0]; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, junk, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_SIG); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); free(junk); } static void junk_fmt(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "junk") == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); free_cred(c); } static void junk_rp_id(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, "potato", rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_PARAM); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } static void junk_rp_name(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, "potato") == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_OK); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } static void junk_authdata(void) { fido_cred_t *c; unsigned char *junk; unsigned char *unset; junk = malloc(sizeof(authdata)); assert(junk != NULL); memcpy(junk, authdata, sizeof(authdata)); - junk[0] = ~junk[0]; + junk[0] = (unsigned char)~junk[0]; unset = calloc(1, sizeof(aaguid)); assert(unset != NULL); c = alloc_cred(); assert(fido_cred_set_authdata(c, junk, sizeof(authdata)) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_authdata_len(c) == 0); assert(fido_cred_authdata_ptr(c) == NULL); assert(fido_cred_authdata_raw_len(c) == 0); assert(fido_cred_authdata_raw_ptr(c) == NULL); assert(fido_cred_flags(c) == 0); assert(fido_cred_fmt(c) == NULL); assert(fido_cred_id_len(c) == 0); assert(fido_cred_id_ptr(c) == NULL); assert(fido_cred_pubkey_len(c) == 0); assert(fido_cred_pubkey_ptr(c) == NULL); assert(fido_cred_rp_id(c) == NULL); assert(fido_cred_rp_name(c) == NULL); assert(fido_cred_sig_len(c) == 0); assert(fido_cred_sig_ptr(c) == NULL); assert(fido_cred_x5c_len(c) == 0); assert(fido_cred_x5c_ptr(c) == NULL); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), unset, sizeof(aaguid)) == 0); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); free_cred(c); free(junk); free(unset); } static void junk_sig(void) { fido_cred_t *c; unsigned char *junk; junk = malloc(sizeof(sig)); assert(junk != NULL); memcpy(junk, sig, sizeof(sig)); - junk[0] = ~junk[0]; + junk[0] = (unsigned char)~junk[0]; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, junk, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_SIG); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); free(junk); } static void junk_x509(void) { fido_cred_t *c; unsigned char *junk; junk = malloc(sizeof(x509)); assert(junk != NULL); memcpy(junk, x509, sizeof(x509)); - junk[0] = ~junk[0]; + junk[0] = (unsigned char)~junk[0]; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, junk, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_SIG); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); free(junk); } /* github issue #6 */ static void invalid_type(void) { fido_cred_t *c; unsigned char *unset; unset = calloc(1, sizeof(aaguid)); assert(unset != NULL); c = alloc_cred(); assert(fido_cred_set_type(c, COSE_RS256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_pubkey_len(c) == 0); assert(fido_cred_pubkey_ptr(c) == NULL); assert(fido_cred_id_len(c) == 0); assert(fido_cred_id_ptr(c) == NULL); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), unset, sizeof(aaguid)) == 0); free_cred(c); free(unset); } /* cbor_serialize_alloc misuse */ static void bad_cbor_serialize(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_authdata_len(c) == sizeof(authdata)); free_cred(c); } static void duplicate_keys(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata_dupkeys, sizeof(authdata_dupkeys)) == FIDO_ERR_INVALID_ARGUMENT); free_cred(c); } static void unsorted_keys(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata_unsorted_keys, sizeof(authdata_unsorted_keys)) == FIDO_ERR_INVALID_ARGUMENT); free_cred(c); } static void wrong_credprot(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_set_prot(c, FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_PARAM); free_cred(c); } static void raw_authdata(void) { fido_cred_t *c; cbor_item_t *item; struct cbor_load_result cbor_result; const unsigned char *ptr; unsigned char *cbor; size_t len; size_t cbor_len; size_t alloclen; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert((ptr = fido_cred_authdata_ptr(c)) != NULL); assert((len = fido_cred_authdata_len(c)) != 0); assert((item = cbor_load(ptr, len, &cbor_result)) != NULL); assert(cbor_result.read == len); assert(cbor_isa_bytestring(item)); assert((ptr = fido_cred_authdata_raw_ptr(c)) != NULL); assert((len = fido_cred_authdata_raw_len(c)) != 0); assert(cbor_bytestring_length(item) == len); assert(memcmp(ptr, cbor_bytestring_handle(item), len) == 0); assert((len = fido_cred_authdata_len(c)) != 0); assert((cbor_len = cbor_serialize_alloc(item, &cbor, &alloclen)) == len); assert((ptr = cbor_bytestring_handle(item)) != NULL); assert((len = cbor_bytestring_length(item)) != 0); assert(fido_cred_set_authdata_raw(c, ptr, len) == FIDO_OK); assert((ptr = fido_cred_authdata_ptr(c)) != NULL); assert((len = fido_cred_authdata_len(c)) != 0); assert(len == cbor_len); assert(memcmp(cbor, ptr, len) == 0); assert(cbor_len == sizeof(authdata)); assert(memcmp(cbor, authdata, cbor_len) == 0); cbor_decref(&item); free(cbor); free_cred(c); } static void fmt_none(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_uv(c, FIDO_OPT_FALSE) == FIDO_OK); assert(fido_cred_set_fmt(c, "none") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_cred_prot(c) == 0); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } +static void +valid_tpm_cred(void) +{ + fido_cred_t *c; + + c = alloc_cred(); + assert(fido_cred_set_type(c, COSE_RS256) == FIDO_OK); + assert(fido_cred_set_clientdata(c, cdh, sizeof(cdh)) == FIDO_OK); + assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); + assert(fido_cred_set_authdata(c, authdata_tpm, sizeof(authdata_tpm)) == FIDO_OK); + assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK); + assert(fido_cred_set_uv(c, FIDO_OPT_TRUE) == FIDO_OK); + assert(fido_cred_set_fmt(c, "tpm") == FIDO_OK); + assert(fido_cred_set_attstmt(c, attstmt_tpm, sizeof(attstmt_tpm)) == FIDO_OK); + assert(fido_cred_verify(c) == FIDO_OK); + assert(fido_cred_prot(c) == 0); + assert(fido_cred_pubkey_len(c) == sizeof(pubkey_tpm)); + assert(memcmp(fido_cred_pubkey_ptr(c), pubkey_tpm, sizeof(pubkey_tpm)) == 0); + assert(fido_cred_id_len(c) == sizeof(id_tpm)); + assert(memcmp(fido_cred_id_ptr(c), id_tpm, sizeof(id_tpm)) == 0); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid_tpm)); + assert(memcmp(fido_cred_aaguid_ptr(c), aaguid_tpm, sizeof(aaguid_tpm)) == 0); + free_cred(c); +} + int main(void) { fido_init(0); empty_cred(); valid_cred(); no_cdh(); no_rp_id(); no_rp_name(); no_authdata(); no_x509(); no_sig(); no_fmt(); junk_cdh(); junk_fmt(); junk_rp_id(); junk_rp_name(); junk_authdata(); junk_x509(); junk_sig(); wrong_options(); invalid_type(); bad_cbor_serialize(); duplicate_keys(); unsorted_keys(); wrong_credprot(); raw_authdata(); fmt_none(); + valid_tpm_cred(); exit(0); } diff --git a/contrib/libfido2/regress/dev.c b/contrib/libfido2/regress/dev.c index 35061aabbb64..a5dc8d6e4529 100644 --- a/contrib/libfido2/regress/dev.c +++ b/contrib/libfido2/regress/dev.c @@ -1,266 +1,412 @@ /* - * Copyright (c) 2019 Yubico AB. All rights reserved. + * Copyright (c) 2019-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include +#include #include #include +#include #include "../fuzz/wiredata_fido2.h" #define FAKE_DEV_HANDLE ((void *)0xdeadbeef) #define REPORT_LEN (64 + 1) static uint8_t ctap_nonce[8]; static uint8_t *wiredata_ptr; static size_t wiredata_len; static int initialised; +static long interval_ms; static void * dummy_open(const char *path) { (void)path; return (FAKE_DEV_HANDLE); } static void dummy_close(void *handle) { assert(handle == FAKE_DEV_HANDLE); } static int dummy_read(void *handle, unsigned char *ptr, size_t len, int ms) { - size_t n; - - (void)ms; + struct timespec tv; + size_t n; + long d; assert(handle == FAKE_DEV_HANDLE); assert(ptr != NULL); assert(len == REPORT_LEN - 1); if (wiredata_ptr == NULL) return (-1); if (!initialised) { assert(wiredata_len >= REPORT_LEN - 1); memcpy(&wiredata_ptr[7], &ctap_nonce, sizeof(ctap_nonce)); initialised = 1; } + if (ms >= 0 && ms < interval_ms) + d = ms; + else + d = interval_ms; + + if (d) { + tv.tv_sec = d / 1000; + tv.tv_nsec = (d % 1000) * 1000000; + if (nanosleep(&tv, NULL) == -1) + err(1, "nanosleep"); + } + + if (d != interval_ms) + return (-1); /* timeout */ + if (wiredata_len < len) n = wiredata_len; else n = len; memcpy(ptr, wiredata_ptr, n); wiredata_ptr += n; wiredata_len -= n; return ((int)n); } static int dummy_write(void *handle, const unsigned char *ptr, size_t len) { + struct timespec tv; + assert(handle == FAKE_DEV_HANDLE); assert(ptr != NULL); assert(len == REPORT_LEN); if (!initialised) memcpy(&ctap_nonce, &ptr[8], sizeof(ctap_nonce)); + if (interval_ms) { + tv.tv_sec = interval_ms / 1000; + tv.tv_nsec = (interval_ms % 1000) * 1000000; + if (nanosleep(&tv, NULL) == -1) + err(1, "nanosleep"); + } + return ((int)len); } static uint8_t * wiredata_setup(const uint8_t *data, size_t len) { const uint8_t ctap_init_data[] = { WIREDATA_CTAP_INIT }; assert(wiredata_ptr == NULL); assert(SIZE_MAX - len > sizeof(ctap_init_data)); assert((wiredata_ptr = malloc(sizeof(ctap_init_data) + len)) != NULL); memcpy(wiredata_ptr, ctap_init_data, sizeof(ctap_init_data)); if (len) memcpy(wiredata_ptr + sizeof(ctap_init_data), data, len); wiredata_len = sizeof(ctap_init_data) + len; return (wiredata_ptr); } static void wiredata_clear(uint8_t **wiredata) { free(*wiredata); *wiredata = NULL; wiredata_ptr = NULL; wiredata_len = 0; initialised = 0; } /* gh#56 */ static void open_iff_ok(void) { fido_dev_t *dev = NULL; fido_dev_io_t io; memset(&io, 0, sizeof(io)); io.open = dummy_open; io.close = dummy_close; io.read = dummy_read; io.write = dummy_write; assert((dev = fido_dev_new()) != NULL); assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); assert(fido_dev_open(dev, "dummy") == FIDO_ERR_RX); assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT); fido_dev_free(&dev); } static void reopen(void) { const uint8_t cbor_info_data[] = { WIREDATA_CTAP_CBOR_INFO }; uint8_t *wiredata; fido_dev_t *dev = NULL; fido_dev_io_t io; memset(&io, 0, sizeof(io)); io.open = dummy_open; io.close = dummy_close; io.read = dummy_read; io.write = dummy_write; wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data)); assert((dev = fido_dev_new()) != NULL); assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); assert(fido_dev_open(dev, "dummy") == FIDO_OK); assert(fido_dev_close(dev) == FIDO_OK); wiredata_clear(&wiredata); wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data)); assert(fido_dev_open(dev, "dummy") == FIDO_OK); assert(fido_dev_close(dev) == FIDO_OK); + fido_dev_free(&dev); wiredata_clear(&wiredata); } static void double_open(void) { const uint8_t cbor_info_data[] = { WIREDATA_CTAP_CBOR_INFO }; uint8_t *wiredata; fido_dev_t *dev = NULL; fido_dev_io_t io; memset(&io, 0, sizeof(io)); io.open = dummy_open; io.close = dummy_close; io.read = dummy_read; io.write = dummy_write; wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data)); assert((dev = fido_dev_new()) != NULL); assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); assert(fido_dev_open(dev, "dummy") == FIDO_OK); assert(fido_dev_open(dev, "dummy") == FIDO_ERR_INVALID_ARGUMENT); assert(fido_dev_close(dev) == FIDO_OK); + fido_dev_free(&dev); + wiredata_clear(&wiredata); +} + +static void +double_close(void) +{ + const uint8_t cbor_info_data[] = { WIREDATA_CTAP_CBOR_INFO }; + uint8_t *wiredata; + fido_dev_t *dev = NULL; + fido_dev_io_t io; + + memset(&io, 0, sizeof(io)); + + io.open = dummy_open; + io.close = dummy_close; + io.read = dummy_read; + io.write = dummy_write; + + wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data)); + assert((dev = fido_dev_new()) != NULL); + assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT); + assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); + assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT); + assert(fido_dev_open(dev, "dummy") == FIDO_OK); + assert(fido_dev_close(dev) == FIDO_OK); + assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT); + fido_dev_free(&dev); wiredata_clear(&wiredata); } static void is_fido2(void) { const uint8_t cbor_info_data[] = { WIREDATA_CTAP_CBOR_INFO }; uint8_t *wiredata; fido_dev_t *dev = NULL; fido_dev_io_t io; memset(&io, 0, sizeof(io)); io.open = dummy_open; io.close = dummy_close; io.read = dummy_read; io.write = dummy_write; wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data)); assert((dev = fido_dev_new()) != NULL); assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); assert(fido_dev_open(dev, "dummy") == FIDO_OK); assert(fido_dev_is_fido2(dev) == true); assert(fido_dev_supports_pin(dev) == true); fido_dev_force_u2f(dev); assert(fido_dev_is_fido2(dev) == false); assert(fido_dev_supports_pin(dev) == false); assert(fido_dev_close(dev) == FIDO_OK); wiredata_clear(&wiredata); wiredata = wiredata_setup(NULL, 0); assert(fido_dev_open(dev, "dummy") == FIDO_OK); assert(fido_dev_is_fido2(dev) == false); assert(fido_dev_supports_pin(dev) == false); fido_dev_force_fido2(dev); assert(fido_dev_is_fido2(dev) == true); assert(fido_dev_supports_pin(dev) == false); assert(fido_dev_close(dev) == FIDO_OK); + fido_dev_free(&dev); wiredata_clear(&wiredata); } static void has_pin(void) { const uint8_t set_pin_data[] = { WIREDATA_CTAP_CBOR_INFO, WIREDATA_CTAP_CBOR_AUTHKEY, WIREDATA_CTAP_CBOR_STATUS, WIREDATA_CTAP_CBOR_STATUS }; uint8_t *wiredata; fido_dev_t *dev = NULL; fido_dev_io_t io; memset(&io, 0, sizeof(io)); io.open = dummy_open; io.close = dummy_close; io.read = dummy_read; io.write = dummy_write; wiredata = wiredata_setup(set_pin_data, sizeof(set_pin_data)); assert((dev = fido_dev_new()) != NULL); assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); assert(fido_dev_open(dev, "dummy") == FIDO_OK); assert(fido_dev_has_pin(dev) == false); assert(fido_dev_set_pin(dev, "top secret", NULL) == FIDO_OK); assert(fido_dev_has_pin(dev) == true); assert(fido_dev_reset(dev) == FIDO_OK); assert(fido_dev_has_pin(dev) == false); assert(fido_dev_close(dev) == FIDO_OK); + fido_dev_free(&dev); wiredata_clear(&wiredata); } +static void +timeout_rx(void) +{ + const uint8_t timeout_rx_data[] = { + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_KEEPALIVE, + WIREDATA_CTAP_KEEPALIVE, + WIREDATA_CTAP_KEEPALIVE, + WIREDATA_CTAP_KEEPALIVE, + WIREDATA_CTAP_KEEPALIVE, + WIREDATA_CTAP_CBOR_STATUS + }; + uint8_t *wiredata; + fido_dev_t *dev = NULL; + fido_dev_io_t io; + + memset(&io, 0, sizeof(io)); + + io.open = dummy_open; + io.close = dummy_close; + io.read = dummy_read; + io.write = dummy_write; + + wiredata = wiredata_setup(timeout_rx_data, sizeof(timeout_rx_data)); + assert((dev = fido_dev_new()) != NULL); + assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); + assert(fido_dev_open(dev, "dummy") == FIDO_OK); + assert(fido_dev_set_timeout(dev, 3 * 1000) == FIDO_OK); + interval_ms = 1000; + assert(fido_dev_reset(dev) == FIDO_ERR_RX); + assert(fido_dev_close(dev) == FIDO_OK); + fido_dev_free(&dev); + wiredata_clear(&wiredata); + interval_ms = 0; +} + +static void +timeout_ok(void) +{ + const uint8_t timeout_ok_data[] = { + WIREDATA_CTAP_CBOR_INFO, + WIREDATA_CTAP_KEEPALIVE, + WIREDATA_CTAP_KEEPALIVE, + WIREDATA_CTAP_KEEPALIVE, + WIREDATA_CTAP_KEEPALIVE, + WIREDATA_CTAP_KEEPALIVE, + WIREDATA_CTAP_CBOR_STATUS + }; + uint8_t *wiredata; + fido_dev_t *dev = NULL; + fido_dev_io_t io; + + memset(&io, 0, sizeof(io)); + + io.open = dummy_open; + io.close = dummy_close; + io.read = dummy_read; + io.write = dummy_write; + + wiredata = wiredata_setup(timeout_ok_data, sizeof(timeout_ok_data)); + assert((dev = fido_dev_new()) != NULL); + assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK); + assert(fido_dev_open(dev, "dummy") == FIDO_OK); + assert(fido_dev_set_timeout(dev, 30 * 1000) == FIDO_OK); + interval_ms = 1000; + assert(fido_dev_reset(dev) == FIDO_OK); + assert(fido_dev_close(dev) == FIDO_OK); + fido_dev_free(&dev); + wiredata_clear(&wiredata); + interval_ms = 0; +} + +static void +timeout_misc(void) +{ + fido_dev_t *dev; + + assert((dev = fido_dev_new()) != NULL); + assert(fido_dev_set_timeout(dev, -2) == FIDO_ERR_INVALID_ARGUMENT); + assert(fido_dev_set_timeout(dev, 3 * 1000) == FIDO_OK); + assert(fido_dev_set_timeout(dev, -1) == FIDO_OK); + fido_dev_free(&dev); +} + int main(void) { fido_init(0); open_iff_ok(); reopen(); double_open(); + double_close(); is_fido2(); has_pin(); + timeout_rx(); + timeout_ok(); + timeout_misc(); exit(0); } diff --git a/contrib/libfido2/src/CMakeLists.txt b/contrib/libfido2/src/CMakeLists.txt index f9efd3f234ed..bd14a62f0c99 100644 --- a/contrib/libfido2/src/CMakeLists.txt +++ b/contrib/libfido2/src/CMakeLists.txt @@ -1,136 +1,139 @@ -# Copyright (c) 2018 Yubico AB. All rights reserved. +# Copyright (c) 2018-2021 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. add_definitions(-D_FIDO_INTERNAL) list(APPEND FIDO_SOURCES aes256.c assert.c authkey.c bio.c blob.c buf.c cbor.c compress.c config.c cred.c credman.c dev.c ecdh.c eddsa.c err.c es256.c hid.c info.c io.c iso7816.c largeblob.c log.c pin.c random.c reset.c + rs1.c rs256.c + time.c + tpm.c + types.c u2f.c ) if(FUZZ) + list(APPEND FIDO_SOURCES ../fuzz/clock.c) list(APPEND FIDO_SOURCES ../fuzz/prng.c) list(APPEND FIDO_SOURCES ../fuzz/uniform_random.c) list(APPEND FIDO_SOURCES ../fuzz/udev.c) list(APPEND FIDO_SOURCES ../fuzz/wrap.c) endif() if(NFC_LINUX) list(APPEND FIDO_SOURCES netlink.c nfc_linux.c) endif() if(USE_HIDAPI) list(APPEND FIDO_SOURCES hid_hidapi.c) if(NOT WIN32 AND NOT APPLE) list(APPEND FIDO_SOURCES hid_unix.c) endif() elseif(WIN32) list(APPEND FIDO_SOURCES hid_win.c) if(USE_WINHELLO) list(APPEND FIDO_SOURCES winhello.c) endif() elseif(APPLE) list(APPEND FIDO_SOURCES hid_osx.c) elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") list(APPEND FIDO_SOURCES hid_linux.c hid_unix.c) elseif(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") list(APPEND FIDO_SOURCES hid_netbsd.c hid_unix.c) elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") list(APPEND FIDO_SOURCES hid_openbsd.c hid_unix.c) -elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") +elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR + CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD") list(APPEND FIDO_SOURCES hid_freebsd.c hid_unix.c) else() message(FATAL_ERROR "please define a hid backend for your platform") endif() if(NOT MSVC) set_source_files_properties(${FIDO_SOURCES} PROPERTIES COMPILE_FLAGS "-Wconversion -Wsign-conversion") endif() list(APPEND COMPAT_SOURCES ../openbsd-compat/bsd-getpagesize.c + ../openbsd-compat/clock_gettime.c ../openbsd-compat/endian_win32.c ../openbsd-compat/explicit_bzero.c ../openbsd-compat/explicit_bzero_win32.c ../openbsd-compat/freezero.c - ../openbsd-compat/hkdf.c ../openbsd-compat/recallocarray.c ../openbsd-compat/strlcat.c ../openbsd-compat/timingsafe_bcmp.c ) if(WIN32) list(APPEND BASE_LIBRARIES wsock32 ws2_32 bcrypt setupapi hid) - if(USE_WINHELLO) - list(APPEND BASE_LIBRARIES webauthn) - endif() elseif(APPLE) list(APPEND BASE_LIBRARIES "-framework CoreFoundation" "-framework IOKit") endif() list(APPEND TARGET_LIBRARIES ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES} ${UDEV_LIBRARIES} ${BASE_LIBRARIES} ${HIDAPI_LIBRARIES} ${ZLIB_LIBRARIES} ) # static library if(BUILD_STATIC_LIBS) add_library(fido2 STATIC ${FIDO_SOURCES} ${COMPAT_SOURCES}) if(WIN32 AND NOT MINGW) set_target_properties(fido2 PROPERTIES OUTPUT_NAME fido2_static) endif() target_link_libraries(fido2 ${TARGET_LIBRARIES}) install(TARGETS fido2 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) endif() # dynamic library if(BUILD_SHARED_LIBS) add_library(fido2_shared SHARED ${FIDO_SOURCES} ${COMPAT_SOURCES}) set_target_properties(fido2_shared PROPERTIES OUTPUT_NAME fido2 VERSION ${FIDO_VERSION} SOVERSION ${FIDO_MAJOR}) target_link_libraries(fido2_shared ${TARGET_LIBRARIES}) install(TARGETS fido2_shared ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() install(FILES fido.h DESTINATION include) install(DIRECTORY fido DESTINATION include) if(NOT WIN32) configure_file(libfido2.pc.in libfido2.pc @ONLY) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libfido2.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") endif() diff --git a/contrib/libfido2/src/assert.c b/contrib/libfido2/src/assert.c index b36f8e324660..949af919d25e 100644 --- a/contrib/libfido2/src/assert.c +++ b/contrib/libfido2/src/assert.c @@ -1,1134 +1,1024 @@ /* * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ -#include #include #include "fido.h" #include "fido/es256.h" #include "fido/rs256.h" #include "fido/eddsa.h" static int adjust_assert_count(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_assert_t *assert = arg; uint64_t n; /* numberOfCredentials; see section 6.2 */ if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != 5) { fido_log_debug("%s: cbor_type", __func__); return (0); /* ignore */ } if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) { fido_log_debug("%s: cbor_decode_uint64", __func__); return (-1); } if (assert->stmt_len != 0 || assert->stmt_cnt != 1 || (size_t)n < assert->stmt_cnt) { fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu, n=%zu", __func__, assert->stmt_len, assert->stmt_cnt, (size_t)n); return (-1); } if (fido_assert_set_count(assert, (size_t)n) != FIDO_OK) { fido_log_debug("%s: fido_assert_set_count", __func__); return (-1); } assert->stmt_len = 0; /* XXX */ return (0); } static int parse_assert_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_assert_stmt *stmt = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 1: /* credential id */ return (cbor_decode_cred_id(val, &stmt->id)); case 2: /* authdata */ return (cbor_decode_assert_authdata(val, &stmt->authdata_cbor, &stmt->authdata, &stmt->authdata_ext)); case 3: /* signature */ return (fido_blob_decode(val, &stmt->sig)); case 4: /* user attributes */ return (cbor_decode_user(val, &stmt->user)); case 7: /* large blob key */ return (fido_blob_decode(val, &stmt->largeblob_key)); default: /* ignore */ fido_log_debug("%s: cbor type", __func__); return (0); } } static int fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert, - const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin) + const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int *ms) { fido_blob_t f; fido_opt_t uv = assert->uv; cbor_item_t *argv[7]; const uint8_t cmd = CTAP_CBOR_ASSERT; int r; memset(argv, 0, sizeof(argv)); memset(&f, 0, sizeof(f)); /* do we have everything we need? */ if (assert->rp_id == NULL || assert->cdh.ptr == NULL) { fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__, (void *)assert->rp_id, (void *)assert->cdh.ptr); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if ((argv[0] = cbor_build_string(assert->rp_id)) == NULL || (argv[1] = fido_blob_encode(&assert->cdh)) == NULL) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } /* allowed credentials */ if (assert->allow_list.len) { const fido_blob_array_t *cl = &assert->allow_list; if ((argv[2] = cbor_encode_pubkey_list(cl)) == NULL) { fido_log_debug("%s: cbor_encode_pubkey_list", __func__); r = FIDO_ERR_INTERNAL; goto fail; } } if (assert->ext.mask) if ((argv[3] = cbor_encode_assert_ext(dev, &assert->ext, ecdh, pk)) == NULL) { fido_log_debug("%s: cbor_encode_assert_ext", __func__); r = FIDO_ERR_INTERNAL; goto fail; } /* user verification */ if (pin != NULL || (uv == FIDO_OPT_TRUE && fido_dev_supports_permissions(dev))) { if ((r = cbor_add_uv_params(dev, cmd, &assert->cdh, pk, ecdh, - pin, assert->rp_id, &argv[5], &argv[6])) != FIDO_OK) { + pin, assert->rp_id, &argv[5], &argv[6], ms)) != FIDO_OK) { fido_log_debug("%s: cbor_add_uv_params", __func__); goto fail; } uv = FIDO_OPT_OMIT; } /* options */ if (assert->up != FIDO_OPT_OMIT || uv != FIDO_OPT_OMIT) if ((argv[4] = cbor_encode_assert_opt(assert->up, uv)) == NULL) { fido_log_debug("%s: cbor_encode_assert_opt", __func__); r = FIDO_ERR_INTERNAL; goto fail; } /* frame and transmit */ if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 || - fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { + fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); free(f.ptr); return (r); } static int -fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) +fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; int r; fido_assert_reset_rx(assert); if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } /* start with room for a single assertion */ if ((assert->stmt = calloc(1, sizeof(fido_assert_stmt))) == NULL) return (FIDO_ERR_INTERNAL); assert->stmt_len = 0; assert->stmt_cnt = 1; /* adjust as needed */ if ((r = cbor_parse_reply(reply, (size_t)reply_len, assert, adjust_assert_count)) != FIDO_OK) { fido_log_debug("%s: adjust_assert_count", __func__); return (r); } /* parse the first assertion */ if ((r = cbor_parse_reply(reply, (size_t)reply_len, &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) { fido_log_debug("%s: parse_assert_reply", __func__); return (r); } assert->stmt_len++; return (FIDO_OK); } static int -fido_get_next_assert_tx(fido_dev_t *dev) +fido_get_next_assert_tx(fido_dev_t *dev, int *ms) { const unsigned char cbor[] = { CTAP_CBOR_NEXT_ASSERT }; - if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor)) < 0) { + if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor), ms) < 0) { fido_log_debug("%s: fido_tx", __func__); return (FIDO_ERR_TX); } return (FIDO_OK); } static int -fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms) +fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; int r; if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } /* sanity check */ if (assert->stmt_len >= assert->stmt_cnt) { fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu", __func__, assert->stmt_len, assert->stmt_cnt); return (FIDO_ERR_INTERNAL); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) { fido_log_debug("%s: parse_assert_reply", __func__); return (r); } return (FIDO_OK); } static int fido_dev_get_assert_wait(fido_dev_t *dev, fido_assert_t *assert, - const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int ms) + const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int *ms) { int r; - if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin)) != FIDO_OK || + if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin, + ms)) != FIDO_OK || (r = fido_dev_get_assert_rx(dev, assert, ms)) != FIDO_OK) return (r); while (assert->stmt_len < assert->stmt_cnt) { - if ((r = fido_get_next_assert_tx(dev)) != FIDO_OK || + if ((r = fido_get_next_assert_tx(dev, ms)) != FIDO_OK || (r = fido_get_next_assert_rx(dev, assert, ms)) != FIDO_OK) return (r); assert->stmt_len++; } return (FIDO_OK); } static int decrypt_hmac_secrets(const fido_dev_t *dev, fido_assert_t *assert, const fido_blob_t *key) { for (size_t i = 0; i < assert->stmt_cnt; i++) { fido_assert_stmt *stmt = &assert->stmt[i]; if (stmt->authdata_ext.hmac_secret_enc.ptr != NULL) { if (aes256_cbc_dec(dev, key, &stmt->authdata_ext.hmac_secret_enc, &stmt->hmac_secret) < 0) { fido_log_debug("%s: aes256_cbc_dec %zu", __func__, i); return (-1); } } } return (0); } int fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin) { fido_blob_t *ecdh = NULL; es256_pk_t *pk = NULL; + int ms = dev->timeout_ms; int r; #ifdef USE_WINHELLO if (dev->flags & FIDO_DEV_WINHELLO) - return (fido_winhello_get_assert(dev, assert, pin)); + return (fido_winhello_get_assert(dev, assert, pin, ms)); #endif if (assert->rp_id == NULL || assert->cdh.ptr == NULL) { fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__, (void *)assert->rp_id, (void *)assert->cdh.ptr); return (FIDO_ERR_INVALID_ARGUMENT); } if (fido_dev_is_fido2(dev) == false) { if (pin != NULL || assert->ext.mask != 0) return (FIDO_ERR_UNSUPPORTED_OPTION); - return (u2f_authenticate(dev, assert, -1)); + return (u2f_authenticate(dev, assert, &ms)); } if (pin != NULL || (assert->uv == FIDO_OPT_TRUE && fido_dev_supports_permissions(dev)) || (assert->ext.mask & FIDO_EXT_HMAC_SECRET)) { - if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { + if ((r = fido_do_ecdh(dev, &pk, &ecdh, &ms)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } } - r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, -1); + r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, &ms); if (r == FIDO_OK && (assert->ext.mask & FIDO_EXT_HMAC_SECRET)) if (decrypt_hmac_secrets(dev, assert, ecdh) < 0) { fido_log_debug("%s: decrypt_hmac_secrets", __func__); r = FIDO_ERR_INTERNAL; goto fail; } fail: es256_pk_free(&pk); fido_blob_free(&ecdh); return (r); } int fido_check_flags(uint8_t flags, fido_opt_t up, fido_opt_t uv) { fido_log_debug("%s: flags=%02x", __func__, flags); fido_log_debug("%s: up=%d, uv=%d", __func__, up, uv); if (up == FIDO_OPT_TRUE && (flags & CTAP_AUTHDATA_USER_PRESENT) == 0) { fido_log_debug("%s: CTAP_AUTHDATA_USER_PRESENT", __func__); return (-1); /* user not present */ } if (uv == FIDO_OPT_TRUE && (flags & CTAP_AUTHDATA_USER_VERIFIED) == 0) { fido_log_debug("%s: CTAP_AUTHDATA_USER_VERIFIED", __func__); return (-1); /* user not verified */ } return (0); } static int check_extensions(int authdata_ext, int ext) { /* XXX: largeBlobKey is not part of extensions map */ ext &= ~FIDO_EXT_LARGEBLOB_KEY; if (authdata_ext != ext) { fido_log_debug("%s: authdata_ext=0x%x != ext=0x%x", __func__, authdata_ext, ext); return (-1); } return (0); } int fido_get_signed_hash(int cose_alg, fido_blob_t *dgst, const fido_blob_t *clientdata, const fido_blob_t *authdata_cbor) { cbor_item_t *item = NULL; unsigned char *authdata_ptr = NULL; size_t authdata_len; struct cbor_load_result cbor; - SHA256_CTX ctx; + const EVP_MD *md = NULL; + EVP_MD_CTX *ctx = NULL; int ok = -1; if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len, &cbor)) == NULL || cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false) { fido_log_debug("%s: authdata", __func__); goto fail; } authdata_ptr = cbor_bytestring_handle(item); authdata_len = cbor_bytestring_length(item); if (cose_alg != COSE_EDDSA) { - if (dgst->len < SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 || - SHA256_Update(&ctx, authdata_ptr, authdata_len) == 0 || - SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 || - SHA256_Final(dgst->ptr, &ctx) == 0) { + if (dgst->len < SHA256_DIGEST_LENGTH || + (md = EVP_sha256()) == NULL || + (ctx = EVP_MD_CTX_new()) == NULL || + EVP_DigestInit_ex(ctx, md, NULL) != 1 || + EVP_DigestUpdate(ctx, authdata_ptr, authdata_len) != 1 || + EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 || + EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) { fido_log_debug("%s: sha256", __func__); goto fail; } dgst->len = SHA256_DIGEST_LENGTH; } else { if (SIZE_MAX - authdata_len < clientdata->len || dgst->len < authdata_len + clientdata->len) { fido_log_debug("%s: memcpy", __func__); goto fail; } memcpy(dgst->ptr, authdata_ptr, authdata_len); memcpy(dgst->ptr + authdata_len, clientdata->ptr, clientdata->len); dgst->len = authdata_len + clientdata->len; } ok = 0; fail: if (item != NULL) cbor_decref(&item); - return (ok); -} - -int -fido_verify_sig_es256(const fido_blob_t *dgst, const es256_pk_t *pk, - const fido_blob_t *sig) -{ - EVP_PKEY *pkey = NULL; - EC_KEY *ec = NULL; - int ok = -1; - - /* ECDSA_verify needs ints */ - if (dgst->len > INT_MAX || sig->len > INT_MAX) { - fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, - dgst->len, sig->len); - return (-1); - } - - if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL || - (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) { - fido_log_debug("%s: pk -> ec", __func__); - goto fail; - } - - if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr, - (int)sig->len, ec) != 1) { - fido_log_debug("%s: ECDSA_verify", __func__); - goto fail; - } - - ok = 0; -fail: - if (pkey != NULL) - EVP_PKEY_free(pkey); - - return (ok); -} - -int -fido_verify_sig_rs256(const fido_blob_t *dgst, const rs256_pk_t *pk, - const fido_blob_t *sig) -{ - EVP_PKEY *pkey = NULL; - RSA *rsa = NULL; - int ok = -1; - - /* RSA_verify needs unsigned ints */ - if (dgst->len > UINT_MAX || sig->len > UINT_MAX) { - fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, - dgst->len, sig->len); - return (-1); - } - - if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL || - (rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) { - fido_log_debug("%s: pk -> ec", __func__); - goto fail; - } - - if (RSA_verify(NID_sha256, dgst->ptr, (unsigned int)dgst->len, sig->ptr, - (unsigned int)sig->len, rsa) != 1) { - fido_log_debug("%s: RSA_verify", __func__); - goto fail; - } - - ok = 0; -fail: - if (pkey != NULL) - EVP_PKEY_free(pkey); - - return (ok); -} - -int -fido_verify_sig_eddsa(const fido_blob_t *dgst, const eddsa_pk_t *pk, - const fido_blob_t *sig) -{ - EVP_PKEY *pkey = NULL; - EVP_MD_CTX *mdctx = NULL; - int ok = -1; - - /* EVP_DigestVerify needs ints */ - if (dgst->len > INT_MAX || sig->len > INT_MAX) { - fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, - dgst->len, sig->len); - return (-1); - } - - if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { - fido_log_debug("%s: pk -> pkey", __func__); - goto fail; - } - - if ((mdctx = EVP_MD_CTX_new()) == NULL) { - fido_log_debug("%s: EVP_MD_CTX_new", __func__); - goto fail; - } - - if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) { - fido_log_debug("%s: EVP_DigestVerifyInit", __func__); - goto fail; - } - - if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr, - dgst->len) != 1) { - fido_log_debug("%s: EVP_DigestVerify", __func__); - goto fail; - } - - ok = 0; -fail: - if (mdctx != NULL) - EVP_MD_CTX_free(mdctx); - - if (pkey != NULL) - EVP_PKEY_free(pkey); + EVP_MD_CTX_free(ctx); return (ok); } int fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg, const void *pk) { unsigned char buf[1024]; /* XXX */ fido_blob_t dgst; const fido_assert_stmt *stmt = NULL; int ok = -1; int r; dgst.ptr = buf; dgst.len = sizeof(buf); if (idx >= assert->stmt_len || pk == NULL) { r = FIDO_ERR_INVALID_ARGUMENT; goto out; } stmt = &assert->stmt[idx]; /* do we have everything we need? */ if (assert->cdh.ptr == NULL || assert->rp_id == NULL || stmt->authdata_cbor.ptr == NULL || stmt->sig.ptr == NULL) { fido_log_debug("%s: cdh=%p, rp_id=%s, authdata=%p, sig=%p", __func__, (void *)assert->cdh.ptr, assert->rp_id, (void *)stmt->authdata_cbor.ptr, (void *)stmt->sig.ptr); r = FIDO_ERR_INVALID_ARGUMENT; goto out; } if (fido_check_flags(stmt->authdata.flags, assert->up, assert->uv) < 0) { fido_log_debug("%s: fido_check_flags", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (check_extensions(stmt->authdata_ext.mask, assert->ext.mask) < 0) { fido_log_debug("%s: check_extensions", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (fido_check_rp_id(assert->rp_id, stmt->authdata.rp_id_hash) != 0) { fido_log_debug("%s: fido_check_rp_id", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (fido_get_signed_hash(cose_alg, &dgst, &assert->cdh, &stmt->authdata_cbor) < 0) { fido_log_debug("%s: fido_get_signed_hash", __func__); r = FIDO_ERR_INTERNAL; goto out; } switch (cose_alg) { case COSE_ES256: - ok = fido_verify_sig_es256(&dgst, pk, &stmt->sig); + ok = es256_pk_verify_sig(&dgst, pk, &stmt->sig); break; case COSE_RS256: - ok = fido_verify_sig_rs256(&dgst, pk, &stmt->sig); + ok = rs256_pk_verify_sig(&dgst, pk, &stmt->sig); break; case COSE_EDDSA: - ok = fido_verify_sig_eddsa(&dgst, pk, &stmt->sig); + ok = eddsa_pk_verify_sig(&dgst, pk, &stmt->sig); break; default: fido_log_debug("%s: unsupported cose_alg %d", __func__, cose_alg); r = FIDO_ERR_UNSUPPORTED_OPTION; goto out; } if (ok < 0) r = FIDO_ERR_INVALID_SIG; else r = FIDO_OK; out: explicit_bzero(buf, sizeof(buf)); return (r); } int fido_assert_set_clientdata(fido_assert_t *assert, const unsigned char *data, size_t data_len) { if (!fido_blob_is_empty(&assert->cdh) || fido_blob_set(&assert->cd, data, data_len) < 0) { return (FIDO_ERR_INVALID_ARGUMENT); } if (fido_sha256(&assert->cdh, data, data_len) < 0) { fido_blob_reset(&assert->cd); return (FIDO_ERR_INTERNAL); } return (FIDO_OK); } int fido_assert_set_clientdata_hash(fido_assert_t *assert, const unsigned char *hash, size_t hash_len) { if (!fido_blob_is_empty(&assert->cd) || fido_blob_set(&assert->cdh, hash, hash_len) < 0) return (FIDO_ERR_INVALID_ARGUMENT); return (FIDO_OK); } int fido_assert_set_hmac_salt(fido_assert_t *assert, const unsigned char *salt, size_t salt_len) { if ((salt_len != 32 && salt_len != 64) || fido_blob_set(&assert->ext.hmac_salt, salt, salt_len) < 0) return (FIDO_ERR_INVALID_ARGUMENT); return (FIDO_OK); } int fido_assert_set_hmac_secret(fido_assert_t *assert, size_t idx, const unsigned char *secret, size_t secret_len) { if (idx >= assert->stmt_len || (secret_len != 32 && secret_len != 64) || fido_blob_set(&assert->stmt[idx].hmac_secret, secret, secret_len) < 0) return (FIDO_ERR_INVALID_ARGUMENT); return (FIDO_OK); } int fido_assert_set_rp(fido_assert_t *assert, const char *id) { if (assert->rp_id != NULL) { free(assert->rp_id); assert->rp_id = NULL; } if (id == NULL) return (FIDO_ERR_INVALID_ARGUMENT); if ((assert->rp_id = strdup(id)) == NULL) return (FIDO_ERR_INTERNAL); return (FIDO_OK); } int fido_assert_allow_cred(fido_assert_t *assert, const unsigned char *ptr, size_t len) { fido_blob_t id; fido_blob_t *list_ptr; int r; memset(&id, 0, sizeof(id)); if (assert->allow_list.len == SIZE_MAX) { r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if (fido_blob_set(&id, ptr, len) < 0 || (list_ptr = recallocarray(assert->allow_list.ptr, assert->allow_list.len, assert->allow_list.len + 1, sizeof(fido_blob_t))) == NULL) { r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } list_ptr[assert->allow_list.len++] = id; assert->allow_list.ptr = list_ptr; return (FIDO_OK); fail: free(id.ptr); return (r); } int fido_assert_set_extensions(fido_assert_t *assert, int ext) { if (ext == 0) assert->ext.mask = 0; else { if ((ext & FIDO_EXT_ASSERT_MASK) != ext) return (FIDO_ERR_INVALID_ARGUMENT); assert->ext.mask |= ext; } return (FIDO_OK); } int fido_assert_set_options(fido_assert_t *assert, bool up, bool uv) { assert->up = up ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; assert->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; return (FIDO_OK); } int fido_assert_set_up(fido_assert_t *assert, fido_opt_t up) { assert->up = up; return (FIDO_OK); } int fido_assert_set_uv(fido_assert_t *assert, fido_opt_t uv) { assert->uv = uv; return (FIDO_OK); } const unsigned char * fido_assert_clientdata_hash_ptr(const fido_assert_t *assert) { return (assert->cdh.ptr); } size_t fido_assert_clientdata_hash_len(const fido_assert_t *assert) { return (assert->cdh.len); } fido_assert_t * fido_assert_new(void) { return (calloc(1, sizeof(fido_assert_t))); } void fido_assert_reset_tx(fido_assert_t *assert) { free(assert->rp_id); fido_blob_reset(&assert->cd); fido_blob_reset(&assert->cdh); fido_blob_reset(&assert->ext.hmac_salt); fido_free_blob_array(&assert->allow_list); memset(&assert->ext, 0, sizeof(assert->ext)); memset(&assert->allow_list, 0, sizeof(assert->allow_list)); assert->rp_id = NULL; assert->up = FIDO_OPT_OMIT; assert->uv = FIDO_OPT_OMIT; } static void fido_assert_reset_extattr(fido_assert_extattr_t *ext) { fido_blob_reset(&ext->hmac_secret_enc); fido_blob_reset(&ext->blob); memset(ext, 0, sizeof(*ext)); } void fido_assert_reset_rx(fido_assert_t *assert) { for (size_t i = 0; i < assert->stmt_cnt; i++) { free(assert->stmt[i].user.icon); free(assert->stmt[i].user.name); free(assert->stmt[i].user.display_name); fido_blob_reset(&assert->stmt[i].user.id); fido_blob_reset(&assert->stmt[i].id); fido_blob_reset(&assert->stmt[i].hmac_secret); fido_blob_reset(&assert->stmt[i].authdata_cbor); fido_blob_reset(&assert->stmt[i].largeblob_key); fido_blob_reset(&assert->stmt[i].sig); fido_assert_reset_extattr(&assert->stmt[i].authdata_ext); memset(&assert->stmt[i], 0, sizeof(assert->stmt[i])); } free(assert->stmt); assert->stmt = NULL; assert->stmt_len = 0; assert->stmt_cnt = 0; } void fido_assert_free(fido_assert_t **assert_p) { fido_assert_t *assert; if (assert_p == NULL || (assert = *assert_p) == NULL) return; fido_assert_reset_tx(assert); fido_assert_reset_rx(assert); free(assert); *assert_p = NULL; } size_t fido_assert_count(const fido_assert_t *assert) { return (assert->stmt_len); } const char * fido_assert_rp_id(const fido_assert_t *assert) { return (assert->rp_id); } uint8_t fido_assert_flags(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (0); return (assert->stmt[idx].authdata.flags); } uint32_t fido_assert_sigcount(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (0); return (assert->stmt[idx].authdata.sigcount); } const unsigned char * fido_assert_authdata_ptr(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].authdata_cbor.ptr); } size_t fido_assert_authdata_len(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (0); return (assert->stmt[idx].authdata_cbor.len); } const unsigned char * fido_assert_sig_ptr(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].sig.ptr); } size_t fido_assert_sig_len(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (0); return (assert->stmt[idx].sig.len); } const unsigned char * fido_assert_id_ptr(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].id.ptr); } size_t fido_assert_id_len(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (0); return (assert->stmt[idx].id.len); } const unsigned char * fido_assert_user_id_ptr(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].user.id.ptr); } size_t fido_assert_user_id_len(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (0); return (assert->stmt[idx].user.id.len); } const char * fido_assert_user_icon(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].user.icon); } const char * fido_assert_user_name(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].user.name); } const char * fido_assert_user_display_name(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].user.display_name); } const unsigned char * fido_assert_hmac_secret_ptr(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].hmac_secret.ptr); } size_t fido_assert_hmac_secret_len(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (0); return (assert->stmt[idx].hmac_secret.len); } const unsigned char * fido_assert_largeblob_key_ptr(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].largeblob_key.ptr); } size_t fido_assert_largeblob_key_len(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (0); return (assert->stmt[idx].largeblob_key.len); } const unsigned char * fido_assert_blob_ptr(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (NULL); return (assert->stmt[idx].authdata_ext.blob.ptr); } size_t fido_assert_blob_len(const fido_assert_t *assert, size_t idx) { if (idx >= assert->stmt_len) return (0); return (assert->stmt[idx].authdata_ext.blob.len); } static void fido_assert_clean_authdata(fido_assert_stmt *stmt) { fido_blob_reset(&stmt->authdata_cbor); fido_assert_reset_extattr(&stmt->authdata_ext); memset(&stmt->authdata, 0, sizeof(stmt->authdata)); } int fido_assert_set_authdata(fido_assert_t *assert, size_t idx, const unsigned char *ptr, size_t len) { cbor_item_t *item = NULL; fido_assert_stmt *stmt = NULL; struct cbor_load_result cbor; int r; if (idx >= assert->stmt_len || ptr == NULL || len == 0) return (FIDO_ERR_INVALID_ARGUMENT); stmt = &assert->stmt[idx]; fido_assert_clean_authdata(stmt); if ((item = cbor_load(ptr, len, &cbor)) == NULL) { fido_log_debug("%s: cbor_load", __func__); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor, &stmt->authdata, &stmt->authdata_ext) < 0) { fido_log_debug("%s: cbor_decode_assert_authdata", __func__); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } r = FIDO_OK; fail: if (item != NULL) cbor_decref(&item); if (r != FIDO_OK) fido_assert_clean_authdata(stmt); return (r); } int fido_assert_set_authdata_raw(fido_assert_t *assert, size_t idx, const unsigned char *ptr, size_t len) { cbor_item_t *item = NULL; fido_assert_stmt *stmt = NULL; int r; if (idx >= assert->stmt_len || ptr == NULL || len == 0) return (FIDO_ERR_INVALID_ARGUMENT); stmt = &assert->stmt[idx]; fido_assert_clean_authdata(stmt); if ((item = cbor_build_bytestring(ptr, len)) == NULL) { fido_log_debug("%s: cbor_build_bytestring", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor, &stmt->authdata, &stmt->authdata_ext) < 0) { fido_log_debug("%s: cbor_decode_assert_authdata", __func__); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } r = FIDO_OK; fail: if (item != NULL) cbor_decref(&item); if (r != FIDO_OK) fido_assert_clean_authdata(stmt); return (r); } int fido_assert_set_sig(fido_assert_t *a, size_t idx, const unsigned char *ptr, size_t len) { if (idx >= a->stmt_len || ptr == NULL || len == 0) return (FIDO_ERR_INVALID_ARGUMENT); if (fido_blob_set(&a->stmt[idx].sig, ptr, len) < 0) return (FIDO_ERR_INTERNAL); return (FIDO_OK); } /* XXX shrinking leaks memory; fortunately that shouldn't happen */ int fido_assert_set_count(fido_assert_t *assert, size_t n) { void *new_stmt; #ifdef FIDO_FUZZ if (n > UINT8_MAX) { fido_log_debug("%s: n > UINT8_MAX", __func__); return (FIDO_ERR_INTERNAL); } #endif new_stmt = recallocarray(assert->stmt, assert->stmt_cnt, n, sizeof(fido_assert_stmt)); if (new_stmt == NULL) return (FIDO_ERR_INTERNAL); assert->stmt = new_stmt; assert->stmt_cnt = n; assert->stmt_len = n; return (FIDO_OK); } diff --git a/contrib/libfido2/src/authkey.c b/contrib/libfido2/src/authkey.c index c3474ccafc01..33e0a8d44bd2 100644 --- a/contrib/libfido2/src/authkey.c +++ b/contrib/libfido2/src/authkey.c @@ -1,97 +1,97 @@ /* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include "fido.h" static int parse_authkey(const cbor_item_t *key, const cbor_item_t *val, void *arg) { es256_pk_t *authkey = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != 1) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } return (es256_pk_decode(val, authkey)); } static int -fido_dev_authkey_tx(fido_dev_t *dev) +fido_dev_authkey_tx(fido_dev_t *dev, int *ms) { fido_blob_t f; cbor_item_t *argv[2]; int r; fido_log_debug("%s: dev=%p", __func__, (void *)dev); memset(&f, 0, sizeof(f)); memset(argv, 0, sizeof(argv)); /* add command parameters */ if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL || (argv[1] = cbor_build_uint8(2)) == NULL) { fido_log_debug("%s: cbor_build", __func__); r = FIDO_ERR_INTERNAL; goto fail; } /* frame and transmit */ if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), - &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { + &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); free(f.ptr); return (r); } static int -fido_dev_authkey_rx(fido_dev_t *dev, es256_pk_t *authkey, int ms) +fido_dev_authkey_rx(fido_dev_t *dev, es256_pk_t *authkey, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; fido_log_debug("%s: dev=%p, authkey=%p, ms=%d", __func__, (void *)dev, - (void *)authkey, ms); + (void *)authkey, *ms); memset(authkey, 0, sizeof(*authkey)); if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } return (cbor_parse_reply(reply, (size_t)reply_len, authkey, parse_authkey)); } static int -fido_dev_authkey_wait(fido_dev_t *dev, es256_pk_t *authkey, int ms) +fido_dev_authkey_wait(fido_dev_t *dev, es256_pk_t *authkey, int *ms) { int r; - if ((r = fido_dev_authkey_tx(dev)) != FIDO_OK || + if ((r = fido_dev_authkey_tx(dev, ms)) != FIDO_OK || (r = fido_dev_authkey_rx(dev, authkey, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int -fido_dev_authkey(fido_dev_t *dev, es256_pk_t *authkey) +fido_dev_authkey(fido_dev_t *dev, es256_pk_t *authkey, int *ms) { - return (fido_dev_authkey_wait(dev, authkey, -1)); + return (fido_dev_authkey_wait(dev, authkey, ms)); } diff --git a/contrib/libfido2/src/bio.c b/contrib/libfido2/src/bio.c index 06bc32eea7ed..4ddc93749cc3 100644 --- a/contrib/libfido2/src/bio.c +++ b/contrib/libfido2/src/bio.c @@ -1,841 +1,856 @@ /* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include "fido.h" #include "fido/bio.h" #include "fido/es256.h" #define CMD_ENROLL_BEGIN 0x01 #define CMD_ENROLL_NEXT 0x02 #define CMD_ENROLL_CANCEL 0x03 #define CMD_ENUM 0x04 #define CMD_SET_NAME 0x05 #define CMD_ENROLL_REMOVE 0x06 #define CMD_GET_INFO 0x07 static int bio_prepare_hmac(uint8_t cmd, cbor_item_t **argv, size_t argc, cbor_item_t **param, fido_blob_t *hmac_data) { const uint8_t prefix[2] = { 0x01 /* modality */, cmd }; int ok = -1; size_t cbor_alloc_len; size_t cbor_len; unsigned char *cbor = NULL; if (argv == NULL || param == NULL) return (fido_blob_set(hmac_data, prefix, sizeof(prefix))); if ((*param = cbor_flatten_vector(argv, argc)) == NULL) { fido_log_debug("%s: cbor_flatten_vector", __func__); goto fail; } if ((cbor_len = cbor_serialize_alloc(*param, &cbor, &cbor_alloc_len)) == 0 || cbor_len > SIZE_MAX - sizeof(prefix)) { fido_log_debug("%s: cbor_serialize_alloc", __func__); goto fail; } if ((hmac_data->ptr = malloc(cbor_len + sizeof(prefix))) == NULL) { fido_log_debug("%s: malloc", __func__); goto fail; } memcpy(hmac_data->ptr, prefix, sizeof(prefix)); memcpy(hmac_data->ptr + sizeof(prefix), cbor, cbor_len); hmac_data->len = cbor_len + sizeof(prefix); ok = 0; fail: free(cbor); return (ok); } static int bio_tx(fido_dev_t *dev, uint8_t subcmd, cbor_item_t **sub_argv, size_t sub_argc, - const char *pin, const fido_blob_t *token) + const char *pin, const fido_blob_t *token, int *ms) { cbor_item_t *argv[5]; es256_pk_t *pk = NULL; fido_blob_t *ecdh = NULL; fido_blob_t f; fido_blob_t hmac; const uint8_t cmd = CTAP_CBOR_BIO_ENROLL_PRE; int r = FIDO_ERR_INTERNAL; memset(&f, 0, sizeof(f)); memset(&hmac, 0, sizeof(hmac)); memset(&argv, 0, sizeof(argv)); /* modality, subCommand */ if ((argv[0] = cbor_build_uint8(1)) == NULL || (argv[1] = cbor_build_uint8(subcmd)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } /* subParams */ if (pin || token) { if (bio_prepare_hmac(subcmd, sub_argv, sub_argc, &argv[2], &hmac) < 0) { fido_log_debug("%s: bio_prepare_hmac", __func__); goto fail; } } /* pinProtocol, pinAuth */ if (pin) { - if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { + if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin, - NULL, &argv[4], &argv[3])) != FIDO_OK) { + NULL, &argv[4], &argv[3], ms)) != FIDO_OK) { fido_log_debug("%s: cbor_add_uv_params", __func__); goto fail; } } else if (token) { if ((argv[3] = cbor_encode_pin_opt(dev)) == NULL || (argv[4] = cbor_encode_pin_auth(dev, token, &hmac)) == NULL) { fido_log_debug("%s: encode pin", __func__); goto fail; } } /* framing and transmission */ if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 || - fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { + fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); es256_pk_free(&pk); fido_blob_free(&ecdh); free(f.ptr); free(hmac.ptr); return (r); } static void bio_reset_template(fido_bio_template_t *t) { free(t->name); t->name = NULL; fido_blob_reset(&t->id); } static void bio_reset_template_array(fido_bio_template_array_t *ta) { for (size_t i = 0; i < ta->n_alloc; i++) bio_reset_template(&ta->ptr[i]); free(ta->ptr); ta->ptr = NULL; memset(ta, 0, sizeof(*ta)); } static int decode_template(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_bio_template_t *t = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 1: /* id */ return (fido_blob_decode(val, &t->id)); case 2: /* name */ return (cbor_string_copy(val, &t->name)); } return (0); /* ignore */ } static int decode_template_array(const cbor_item_t *item, void *arg) { fido_bio_template_array_t *ta = arg; if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } if (ta->n_rx >= ta->n_alloc) { fido_log_debug("%s: n_rx >= n_alloc", __func__); return (-1); } if (cbor_map_iter(item, &ta->ptr[ta->n_rx], decode_template) < 0) { fido_log_debug("%s: decode_template", __func__); return (-1); } ta->n_rx++; return (0); } static int bio_parse_template_array(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_bio_template_array_t *ta = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != 7) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } if (cbor_isa_array(val) == false || cbor_array_is_definite(val) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } if (ta->ptr != NULL || ta->n_alloc != 0 || ta->n_rx != 0) { fido_log_debug("%s: ptr != NULL || n_alloc != 0 || n_rx != 0", __func__); return (-1); } if ((ta->ptr = calloc(cbor_array_size(val), sizeof(*ta->ptr))) == NULL) return (-1); ta->n_alloc = cbor_array_size(val); if (cbor_array_iter(val, ta, decode_template_array) < 0) { fido_log_debug("%s: decode_template_array", __func__); return (-1); } return (0); } static int -bio_rx_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, int ms) +bio_rx_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; int r; bio_reset_template_array(ta); if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, ta, bio_parse_template_array)) != FIDO_OK) { fido_log_debug("%s: bio_parse_template_array" , __func__); return (r); } return (FIDO_OK); } static int bio_get_template_array_wait(fido_dev_t *dev, fido_bio_template_array_t *ta, - const char *pin, int ms) + const char *pin, int *ms) { int r; - if ((r = bio_tx(dev, CMD_ENUM, NULL, 0, pin, NULL)) != FIDO_OK || + if ((r = bio_tx(dev, CMD_ENUM, NULL, 0, pin, NULL, ms)) != FIDO_OK || (r = bio_rx_template_array(dev, ta, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_bio_dev_get_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, const char *pin) { + int ms = dev->timeout_ms; + if (pin == NULL) return (FIDO_ERR_INVALID_ARGUMENT); - return (bio_get_template_array_wait(dev, ta, pin, -1)); + return (bio_get_template_array_wait(dev, ta, pin, &ms)); } static int bio_set_template_name_wait(fido_dev_t *dev, const fido_bio_template_t *t, - const char *pin, int ms) + const char *pin, int *ms) { cbor_item_t *argv[2]; int r = FIDO_ERR_INTERNAL; memset(&argv, 0, sizeof(argv)); if ((argv[0] = fido_blob_encode(&t->id)) == NULL || (argv[1] = cbor_build_string(t->name)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } - if ((r = bio_tx(dev, CMD_SET_NAME, argv, 2, pin, NULL)) != FIDO_OK || + if ((r = bio_tx(dev, CMD_SET_NAME, argv, 2, pin, NULL, + ms)) != FIDO_OK || (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { fido_log_debug("%s: tx/rx", __func__); goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); return (r); } int fido_bio_dev_set_template_name(fido_dev_t *dev, const fido_bio_template_t *t, const char *pin) { + int ms = dev->timeout_ms; + if (pin == NULL || t->name == NULL) return (FIDO_ERR_INVALID_ARGUMENT); - return (bio_set_template_name_wait(dev, t, pin, -1)); + return (bio_set_template_name_wait(dev, t, pin, &ms)); } static void bio_reset_enroll(fido_bio_enroll_t *e) { e->remaining_samples = 0; e->last_status = 0; if (e->token) fido_blob_free(&e->token); } static int bio_parse_enroll_status(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_bio_enroll_t *e = arg; uint64_t x; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 5: if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) { fido_log_debug("%s: cbor_decode_uint64", __func__); return (-1); } e->last_status = (uint8_t)x; break; case 6: if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) { fido_log_debug("%s: cbor_decode_uint64", __func__); return (-1); } e->remaining_samples = (uint8_t)x; break; default: return (0); /* ignore */ } return (0); } static int bio_parse_template_id(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_blob_t *id = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != 4) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } return (fido_blob_decode(val, id)); } static int bio_rx_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t, - fido_bio_enroll_t *e, int ms) + fido_bio_enroll_t *e, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; int r; bio_reset_template(t); e->remaining_samples = 0; e->last_status = 0; if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, e, bio_parse_enroll_status)) != FIDO_OK) { fido_log_debug("%s: bio_parse_enroll_status", __func__); return (r); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, &t->id, bio_parse_template_id)) != FIDO_OK) { fido_log_debug("%s: bio_parse_template_id", __func__); return (r); } return (FIDO_OK); } static int bio_enroll_begin_wait(fido_dev_t *dev, fido_bio_template_t *t, - fido_bio_enroll_t *e, uint32_t timo_ms, int ms) + fido_bio_enroll_t *e, uint32_t timo_ms, int *ms) { cbor_item_t *argv[3]; const uint8_t cmd = CMD_ENROLL_BEGIN; int r = FIDO_ERR_INTERNAL; memset(&argv, 0, sizeof(argv)); if ((argv[2] = cbor_build_uint32(timo_ms)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } - if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token)) != FIDO_OK || + if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token, ms)) != FIDO_OK || (r = bio_rx_enroll_begin(dev, t, e, ms)) != FIDO_OK) { fido_log_debug("%s: tx/rx", __func__); goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); return (r); } int fido_bio_dev_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t, fido_bio_enroll_t *e, uint32_t timo_ms, const char *pin) { es256_pk_t *pk = NULL; fido_blob_t *ecdh = NULL; fido_blob_t *token = NULL; + int ms = dev->timeout_ms; int r; if (pin == NULL || e->token != NULL) return (FIDO_ERR_INVALID_ARGUMENT); if ((token = fido_blob_new()) == NULL) { r = FIDO_ERR_INTERNAL; goto fail; } - if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { + if ((r = fido_do_ecdh(dev, &pk, &ecdh, &ms)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } if ((r = fido_dev_get_uv_token(dev, CTAP_CBOR_BIO_ENROLL_PRE, pin, ecdh, - pk, NULL, token)) != FIDO_OK) { + pk, NULL, token, &ms)) != FIDO_OK) { fido_log_debug("%s: fido_dev_get_uv_token", __func__); goto fail; } e->token = token; token = NULL; fail: es256_pk_free(&pk); fido_blob_free(&ecdh); fido_blob_free(&token); if (r != FIDO_OK) return (r); - return (bio_enroll_begin_wait(dev, t, e, timo_ms, -1)); + return (bio_enroll_begin_wait(dev, t, e, timo_ms, &ms)); } static int -bio_rx_enroll_continue(fido_dev_t *dev, fido_bio_enroll_t *e, int ms) +bio_rx_enroll_continue(fido_dev_t *dev, fido_bio_enroll_t *e, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; int r; e->remaining_samples = 0; e->last_status = 0; if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, e, bio_parse_enroll_status)) != FIDO_OK) { fido_log_debug("%s: bio_parse_enroll_status", __func__); return (r); } return (FIDO_OK); } static int bio_enroll_continue_wait(fido_dev_t *dev, const fido_bio_template_t *t, - fido_bio_enroll_t *e, uint32_t timo_ms, int ms) + fido_bio_enroll_t *e, uint32_t timo_ms, int *ms) { cbor_item_t *argv[3]; const uint8_t cmd = CMD_ENROLL_NEXT; int r = FIDO_ERR_INTERNAL; memset(&argv, 0, sizeof(argv)); if ((argv[0] = fido_blob_encode(&t->id)) == NULL || (argv[2] = cbor_build_uint32(timo_ms)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } - if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token)) != FIDO_OK || + if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token, ms)) != FIDO_OK || (r = bio_rx_enroll_continue(dev, e, ms)) != FIDO_OK) { fido_log_debug("%s: tx/rx", __func__); goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); return (r); } int fido_bio_dev_enroll_continue(fido_dev_t *dev, const fido_bio_template_t *t, fido_bio_enroll_t *e, uint32_t timo_ms) { + int ms = dev->timeout_ms; + if (e->token == NULL) return (FIDO_ERR_INVALID_ARGUMENT); - return (bio_enroll_continue_wait(dev, t, e, timo_ms, -1)); + return (bio_enroll_continue_wait(dev, t, e, timo_ms, &ms)); } static int -bio_enroll_cancel_wait(fido_dev_t *dev, int ms) +bio_enroll_cancel_wait(fido_dev_t *dev, int *ms) { const uint8_t cmd = CMD_ENROLL_CANCEL; int r; - if ((r = bio_tx(dev, cmd, NULL, 0, NULL, NULL)) != FIDO_OK || + if ((r = bio_tx(dev, cmd, NULL, 0, NULL, NULL, ms)) != FIDO_OK || (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { fido_log_debug("%s: tx/rx", __func__); return (r); } return (FIDO_OK); } int fido_bio_dev_enroll_cancel(fido_dev_t *dev) { - return (bio_enroll_cancel_wait(dev, -1)); + int ms = dev->timeout_ms; + + return (bio_enroll_cancel_wait(dev, &ms)); } static int bio_enroll_remove_wait(fido_dev_t *dev, const fido_bio_template_t *t, - const char *pin, int ms) + const char *pin, int *ms) { cbor_item_t *argv[1]; const uint8_t cmd = CMD_ENROLL_REMOVE; int r = FIDO_ERR_INTERNAL; memset(&argv, 0, sizeof(argv)); if ((argv[0] = fido_blob_encode(&t->id)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } - if ((r = bio_tx(dev, cmd, argv, 1, pin, NULL)) != FIDO_OK || + if ((r = bio_tx(dev, cmd, argv, 1, pin, NULL, ms)) != FIDO_OK || (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { fido_log_debug("%s: tx/rx", __func__); goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); return (r); } int fido_bio_dev_enroll_remove(fido_dev_t *dev, const fido_bio_template_t *t, const char *pin) { - return (bio_enroll_remove_wait(dev, t, pin, -1)); + int ms = dev->timeout_ms; + + return (bio_enroll_remove_wait(dev, t, pin, &ms)); } static void bio_reset_info(fido_bio_info_t *i) { i->type = 0; i->max_samples = 0; } static int bio_parse_info(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_bio_info_t *i = arg; uint64_t x; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 2: if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) { fido_log_debug("%s: cbor_decode_uint64", __func__); return (-1); } i->type = (uint8_t)x; break; case 3: if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) { fido_log_debug("%s: cbor_decode_uint64", __func__); return (-1); } i->max_samples = (uint8_t)x; break; default: return (0); /* ignore */ } return (0); } static int -bio_rx_info(fido_dev_t *dev, fido_bio_info_t *i, int ms) +bio_rx_info(fido_dev_t *dev, fido_bio_info_t *i, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; int r; bio_reset_info(i); if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, i, bio_parse_info)) != FIDO_OK) { fido_log_debug("%s: bio_parse_info" , __func__); return (r); } return (FIDO_OK); } static int -bio_get_info_wait(fido_dev_t *dev, fido_bio_info_t *i, int ms) +bio_get_info_wait(fido_dev_t *dev, fido_bio_info_t *i, int *ms) { int r; - if ((r = bio_tx(dev, CMD_GET_INFO, NULL, 0, NULL, NULL)) != FIDO_OK || + if ((r = bio_tx(dev, CMD_GET_INFO, NULL, 0, NULL, NULL, + ms)) != FIDO_OK || (r = bio_rx_info(dev, i, ms)) != FIDO_OK) { fido_log_debug("%s: tx/rx", __func__); return (r); } return (FIDO_OK); } int fido_bio_dev_get_info(fido_dev_t *dev, fido_bio_info_t *i) { - return (bio_get_info_wait(dev, i, -1)); + int ms = dev->timeout_ms; + + return (bio_get_info_wait(dev, i, &ms)); } const char * fido_bio_template_name(const fido_bio_template_t *t) { return (t->name); } const unsigned char * fido_bio_template_id_ptr(const fido_bio_template_t *t) { return (t->id.ptr); } size_t fido_bio_template_id_len(const fido_bio_template_t *t) { return (t->id.len); } size_t fido_bio_template_array_count(const fido_bio_template_array_t *ta) { return (ta->n_rx); } fido_bio_template_array_t * fido_bio_template_array_new(void) { return (calloc(1, sizeof(fido_bio_template_array_t))); } fido_bio_template_t * fido_bio_template_new(void) { return (calloc(1, sizeof(fido_bio_template_t))); } void fido_bio_template_array_free(fido_bio_template_array_t **tap) { fido_bio_template_array_t *ta; if (tap == NULL || (ta = *tap) == NULL) return; bio_reset_template_array(ta); free(ta); *tap = NULL; } void fido_bio_template_free(fido_bio_template_t **tp) { fido_bio_template_t *t; if (tp == NULL || (t = *tp) == NULL) return; bio_reset_template(t); free(t); *tp = NULL; } int fido_bio_template_set_name(fido_bio_template_t *t, const char *name) { free(t->name); t->name = NULL; if (name && (t->name = strdup(name)) == NULL) return (FIDO_ERR_INTERNAL); return (FIDO_OK); } int fido_bio_template_set_id(fido_bio_template_t *t, const unsigned char *ptr, size_t len) { fido_blob_reset(&t->id); if (ptr && fido_blob_set(&t->id, ptr, len) < 0) return (FIDO_ERR_INTERNAL); return (FIDO_OK); } const fido_bio_template_t * fido_bio_template(const fido_bio_template_array_t *ta, size_t idx) { if (idx >= ta->n_alloc) return (NULL); return (&ta->ptr[idx]); } fido_bio_enroll_t * fido_bio_enroll_new(void) { return (calloc(1, sizeof(fido_bio_enroll_t))); } fido_bio_info_t * fido_bio_info_new(void) { return (calloc(1, sizeof(fido_bio_info_t))); } uint8_t fido_bio_info_type(const fido_bio_info_t *i) { return (i->type); } uint8_t fido_bio_info_max_samples(const fido_bio_info_t *i) { return (i->max_samples); } void fido_bio_enroll_free(fido_bio_enroll_t **ep) { fido_bio_enroll_t *e; if (ep == NULL || (e = *ep) == NULL) return; bio_reset_enroll(e); free(e); *ep = NULL; } void fido_bio_info_free(fido_bio_info_t **ip) { fido_bio_info_t *i; if (ip == NULL || (i = *ip) == NULL) return; free(i); *ip = NULL; } uint8_t fido_bio_enroll_remaining_samples(const fido_bio_enroll_t *e) { return (e->remaining_samples); } uint8_t fido_bio_enroll_last_status(const fido_bio_enroll_t *e) { return (e->last_status); } diff --git a/contrib/libfido2/src/cbor.c b/contrib/libfido2/src/cbor.c index 5c1b11583e7b..7935e5017dcf 100644 --- a/contrib/libfido2/src/cbor.c +++ b/contrib/libfido2/src/cbor.c @@ -1,1635 +1,1682 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include "fido.h" static int check_key_type(cbor_item_t *item) { if (item->type == CBOR_TYPE_UINT || item->type == CBOR_TYPE_NEGINT || item->type == CBOR_TYPE_STRING) return (0); fido_log_debug("%s: invalid type: %d", __func__, item->type); return (-1); } /* * Validate CTAP2 canonical CBOR encoding rules for maps. */ static int ctap_check_cbor(cbor_item_t *prev, cbor_item_t *curr) { size_t curr_len; size_t prev_len; if (check_key_type(prev) < 0 || check_key_type(curr) < 0) return (-1); if (prev->type != curr->type) { if (prev->type < curr->type) return (0); fido_log_debug("%s: unsorted types", __func__); return (-1); } if (curr->type == CBOR_TYPE_UINT || curr->type == CBOR_TYPE_NEGINT) { if (cbor_int_get_width(curr) >= cbor_int_get_width(prev) && cbor_get_int(curr) > cbor_get_int(prev)) return (0); } else { curr_len = cbor_string_length(curr); prev_len = cbor_string_length(prev); if (curr_len > prev_len || (curr_len == prev_len && memcmp(cbor_string_handle(prev), cbor_string_handle(curr), curr_len) < 0)) return (0); } fido_log_debug("%s: invalid cbor", __func__); return (-1); } int cbor_map_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *, const cbor_item_t *, void *)) { struct cbor_pair *v; size_t n; if ((v = cbor_map_handle(item)) == NULL) { fido_log_debug("%s: cbor_map_handle", __func__); return (-1); } n = cbor_map_size(item); for (size_t i = 0; i < n; i++) { if (v[i].key == NULL || v[i].value == NULL) { fido_log_debug("%s: key=%p, value=%p for i=%zu", __func__, (void *)v[i].key, (void *)v[i].value, i); return (-1); } if (i && ctap_check_cbor(v[i - 1].key, v[i].key) < 0) { fido_log_debug("%s: ctap_check_cbor", __func__); return (-1); } if (f(v[i].key, v[i].value, arg) < 0) { fido_log_debug("%s: iterator < 0 on i=%zu", __func__, i); return (-1); } } return (0); } int cbor_array_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *, void *)) { cbor_item_t **v; size_t n; if ((v = cbor_array_handle(item)) == NULL) { fido_log_debug("%s: cbor_array_handle", __func__); return (-1); } n = cbor_array_size(item); for (size_t i = 0; i < n; i++) if (v[i] == NULL || f(v[i], arg) < 0) { fido_log_debug("%s: iterator < 0 on i=%zu,%p", __func__, i, (void *)v[i]); return (-1); } return (0); } int cbor_parse_reply(const unsigned char *blob, size_t blob_len, void *arg, int(*parser)(const cbor_item_t *, const cbor_item_t *, void *)) { cbor_item_t *item = NULL; struct cbor_load_result cbor; int r; if (blob_len < 1) { fido_log_debug("%s: blob_len=%zu", __func__, blob_len); r = FIDO_ERR_RX; goto fail; } if (blob[0] != FIDO_OK) { fido_log_debug("%s: blob[0]=0x%02x", __func__, blob[0]); r = blob[0]; goto fail; } if ((item = cbor_load(blob + 1, blob_len - 1, &cbor)) == NULL) { fido_log_debug("%s: cbor_load", __func__); r = FIDO_ERR_RX_NOT_CBOR; goto fail; } if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); r = FIDO_ERR_RX_INVALID_CBOR; goto fail; } if (cbor_map_iter(item, arg, parser) < 0) { fido_log_debug("%s: cbor_map_iter", __func__); r = FIDO_ERR_RX_INVALID_CBOR; goto fail; } r = FIDO_OK; fail: if (item != NULL) cbor_decref(&item); return (r); } void cbor_vector_free(cbor_item_t **item, size_t len) { for (size_t i = 0; i < len; i++) if (item[i] != NULL) cbor_decref(&item[i]); } int cbor_bytestring_copy(const cbor_item_t *item, unsigned char **buf, size_t *len) { if (*buf != NULL || *len != 0) { fido_log_debug("%s: dup", __func__); return (-1); } if (cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } *len = cbor_bytestring_length(item); if ((*buf = malloc(*len)) == NULL) { *len = 0; return (-1); } memcpy(*buf, cbor_bytestring_handle(item), *len); return (0); } int cbor_string_copy(const cbor_item_t *item, char **str) { size_t len; if (*str != NULL) { fido_log_debug("%s: dup", __func__); return (-1); } if (cbor_isa_string(item) == false || cbor_string_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } if ((len = cbor_string_length(item)) == SIZE_MAX || (*str = malloc(len + 1)) == NULL) return (-1); memcpy(*str, cbor_string_handle(item), len); (*str)[len] = '\0'; return (0); } int cbor_add_bytestring(cbor_item_t *item, const char *key, const unsigned char *value, size_t value_len) { struct cbor_pair pair; int ok = -1; memset(&pair, 0, sizeof(pair)); if ((pair.key = cbor_build_string(key)) == NULL || (pair.value = cbor_build_bytestring(value, value_len)) == NULL) { fido_log_debug("%s: cbor_build", __func__); goto fail; } if (!cbor_map_add(item, pair)) { fido_log_debug("%s: cbor_map_add", __func__); goto fail; } ok = 0; fail: if (pair.key) cbor_decref(&pair.key); if (pair.value) cbor_decref(&pair.value); return (ok); } int cbor_add_string(cbor_item_t *item, const char *key, const char *value) { struct cbor_pair pair; int ok = -1; memset(&pair, 0, sizeof(pair)); if ((pair.key = cbor_build_string(key)) == NULL || (pair.value = cbor_build_string(value)) == NULL) { fido_log_debug("%s: cbor_build", __func__); goto fail; } if (!cbor_map_add(item, pair)) { fido_log_debug("%s: cbor_map_add", __func__); goto fail; } ok = 0; fail: if (pair.key) cbor_decref(&pair.key); if (pair.value) cbor_decref(&pair.value); return (ok); } int cbor_add_bool(cbor_item_t *item, const char *key, fido_opt_t value) { struct cbor_pair pair; int ok = -1; memset(&pair, 0, sizeof(pair)); if ((pair.key = cbor_build_string(key)) == NULL || (pair.value = cbor_build_bool(value == FIDO_OPT_TRUE)) == NULL) { fido_log_debug("%s: cbor_build", __func__); goto fail; } if (!cbor_map_add(item, pair)) { fido_log_debug("%s: cbor_map_add", __func__); goto fail; } ok = 0; fail: if (pair.key) cbor_decref(&pair.key); if (pair.value) cbor_decref(&pair.value); return (ok); } static int cbor_add_uint8(cbor_item_t *item, const char *key, uint8_t value) { struct cbor_pair pair; int ok = -1; memset(&pair, 0, sizeof(pair)); if ((pair.key = cbor_build_string(key)) == NULL || (pair.value = cbor_build_uint8(value)) == NULL) { fido_log_debug("%s: cbor_build", __func__); goto fail; } if (!cbor_map_add(item, pair)) { fido_log_debug("%s: cbor_map_add", __func__); goto fail; } ok = 0; fail: if (pair.key) cbor_decref(&pair.key); if (pair.value) cbor_decref(&pair.value); return (ok); } static int cbor_add_arg(cbor_item_t *item, uint8_t n, cbor_item_t *arg) { struct cbor_pair pair; int ok = -1; memset(&pair, 0, sizeof(pair)); if (arg == NULL) return (0); /* empty argument */ if ((pair.key = cbor_build_uint8(n)) == NULL) { fido_log_debug("%s: cbor_build", __func__); goto fail; } pair.value = arg; if (!cbor_map_add(item, pair)) { fido_log_debug("%s: cbor_map_add", __func__); goto fail; } ok = 0; fail: if (pair.key) cbor_decref(&pair.key); return (ok); } cbor_item_t * cbor_flatten_vector(cbor_item_t *argv[], size_t argc) { cbor_item_t *map; uint8_t i; if (argc > UINT8_MAX - 1) return (NULL); if ((map = cbor_new_definite_map(argc)) == NULL) return (NULL); for (i = 0; i < argc; i++) if (cbor_add_arg(map, (uint8_t)(i + 1), argv[i]) < 0) break; if (i != argc) { cbor_decref(&map); map = NULL; } return (map); } int cbor_build_frame(uint8_t cmd, cbor_item_t *argv[], size_t argc, fido_blob_t *f) { cbor_item_t *flat = NULL; unsigned char *cbor = NULL; size_t cbor_len; size_t cbor_alloc_len; int ok = -1; if ((flat = cbor_flatten_vector(argv, argc)) == NULL) goto fail; cbor_len = cbor_serialize_alloc(flat, &cbor, &cbor_alloc_len); if (cbor_len == 0 || cbor_len == SIZE_MAX) { fido_log_debug("%s: cbor_len=%zu", __func__, cbor_len); goto fail; } if ((f->ptr = malloc(cbor_len + 1)) == NULL) goto fail; f->len = cbor_len + 1; f->ptr[0] = cmd; memcpy(f->ptr + 1, cbor, f->len - 1); ok = 0; fail: if (flat != NULL) cbor_decref(&flat); free(cbor); return (ok); } cbor_item_t * cbor_encode_rp_entity(const fido_rp_t *rp) { cbor_item_t *item = NULL; if ((item = cbor_new_definite_map(2)) == NULL) return (NULL); if ((rp->id && cbor_add_string(item, "id", rp->id) < 0) || (rp->name && cbor_add_string(item, "name", rp->name) < 0)) { cbor_decref(&item); return (NULL); } return (item); } cbor_item_t * cbor_encode_user_entity(const fido_user_t *user) { cbor_item_t *item = NULL; const fido_blob_t *id = &user->id; const char *display = user->display_name; if ((item = cbor_new_definite_map(4)) == NULL) return (NULL); if ((id->ptr && cbor_add_bytestring(item, "id", id->ptr, id->len) < 0) || (user->icon && cbor_add_string(item, "icon", user->icon) < 0) || (user->name && cbor_add_string(item, "name", user->name) < 0) || (display && cbor_add_string(item, "displayName", display) < 0)) { cbor_decref(&item); return (NULL); } return (item); } cbor_item_t * cbor_encode_pubkey_param(int cose_alg) { cbor_item_t *item = NULL; cbor_item_t *body = NULL; struct cbor_pair alg; int ok = -1; memset(&alg, 0, sizeof(alg)); if ((item = cbor_new_definite_array(1)) == NULL || (body = cbor_new_definite_map(2)) == NULL || cose_alg > -1 || cose_alg < INT16_MIN) goto fail; alg.key = cbor_build_string("alg"); if (-cose_alg - 1 > UINT8_MAX) alg.value = cbor_build_negint16((uint16_t)(-cose_alg - 1)); else alg.value = cbor_build_negint8((uint8_t)(-cose_alg - 1)); if (alg.key == NULL || alg.value == NULL) { fido_log_debug("%s: cbor_build", __func__); goto fail; } if (cbor_map_add(body, alg) == false || cbor_add_string(body, "type", "public-key") < 0 || cbor_array_push(item, body) == false) goto fail; ok = 0; fail: if (ok < 0) { if (item != NULL) { cbor_decref(&item); item = NULL; } } if (body != NULL) cbor_decref(&body); if (alg.key != NULL) cbor_decref(&alg.key); if (alg.value != NULL) cbor_decref(&alg.value); return (item); } cbor_item_t * cbor_encode_pubkey(const fido_blob_t *pubkey) { cbor_item_t *cbor_key = NULL; if ((cbor_key = cbor_new_definite_map(2)) == NULL || cbor_add_bytestring(cbor_key, "id", pubkey->ptr, pubkey->len) < 0 || cbor_add_string(cbor_key, "type", "public-key") < 0) { if (cbor_key) cbor_decref(&cbor_key); return (NULL); } return (cbor_key); } cbor_item_t * cbor_encode_pubkey_list(const fido_blob_array_t *list) { cbor_item_t *array = NULL; cbor_item_t *key = NULL; if ((array = cbor_new_definite_array(list->len)) == NULL) goto fail; for (size_t i = 0; i < list->len; i++) { if ((key = cbor_encode_pubkey(&list->ptr[i])) == NULL || cbor_array_push(array, key) == false) goto fail; cbor_decref(&key); } return (array); fail: if (key != NULL) cbor_decref(&key); if (array != NULL) cbor_decref(&array); return (NULL); } +cbor_item_t * +cbor_encode_str_array(const fido_str_array_t *a) +{ + cbor_item_t *array = NULL; + cbor_item_t *entry = NULL; + + if ((array = cbor_new_definite_array(a->len)) == NULL) + goto fail; + + for (size_t i = 0; i < a->len; i++) { + if ((entry = cbor_build_string(a->ptr[i])) == NULL || + cbor_array_push(array, entry) == false) + goto fail; + cbor_decref(&entry); + } + + return (array); +fail: + if (entry != NULL) + cbor_decref(&entry); + if (array != NULL) + cbor_decref(&array); + + return (NULL); +} + static int cbor_encode_largeblob_key_ext(cbor_item_t *map) { if (map == NULL || cbor_add_bool(map, "largeBlobKey", FIDO_OPT_TRUE) < 0) return (-1); return (0); } cbor_item_t * cbor_encode_cred_ext(const fido_cred_ext_t *ext, const fido_blob_t *blob) { cbor_item_t *item = NULL; size_t size = 0; if (ext->mask & FIDO_EXT_CRED_BLOB) size++; if (ext->mask & FIDO_EXT_HMAC_SECRET) size++; if (ext->mask & FIDO_EXT_CRED_PROTECT) size++; if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) size++; + if (ext->mask & FIDO_EXT_MINPINLEN) + size++; if (size == 0 || (item = cbor_new_definite_map(size)) == NULL) return (NULL); if (ext->mask & FIDO_EXT_CRED_BLOB) { if (cbor_add_bytestring(item, "credBlob", blob->ptr, blob->len) < 0) { cbor_decref(&item); return (NULL); } } if (ext->mask & FIDO_EXT_CRED_PROTECT) { if (ext->prot < 0 || ext->prot > UINT8_MAX || cbor_add_uint8(item, "credProtect", (uint8_t)ext->prot) < 0) { cbor_decref(&item); return (NULL); } } if (ext->mask & FIDO_EXT_HMAC_SECRET) { if (cbor_add_bool(item, "hmac-secret", FIDO_OPT_TRUE) < 0) { cbor_decref(&item); return (NULL); } } if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) { if (cbor_encode_largeblob_key_ext(item) < 0) { cbor_decref(&item); return (NULL); } } + if (ext->mask & FIDO_EXT_MINPINLEN) { + if (cbor_add_bool(item, "minPinLength", FIDO_OPT_TRUE) < 0) { + cbor_decref(&item); + return (NULL); + } + } return (item); } cbor_item_t * cbor_encode_cred_opt(fido_opt_t rk, fido_opt_t uv) { cbor_item_t *item = NULL; if ((item = cbor_new_definite_map(2)) == NULL) return (NULL); if ((rk != FIDO_OPT_OMIT && cbor_add_bool(item, "rk", rk) < 0) || (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) { cbor_decref(&item); return (NULL); } return (item); } cbor_item_t * cbor_encode_assert_opt(fido_opt_t up, fido_opt_t uv) { cbor_item_t *item = NULL; if ((item = cbor_new_definite_map(2)) == NULL) return (NULL); if ((up != FIDO_OPT_OMIT && cbor_add_bool(item, "up", up) < 0) || (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) { cbor_decref(&item); return (NULL); } return (item); } cbor_item_t * cbor_encode_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret, const fido_blob_t *data) { const EVP_MD *md = NULL; unsigned char dgst[SHA256_DIGEST_LENGTH]; unsigned int dgst_len; size_t outlen; uint8_t prot; fido_blob_t key; key.ptr = secret->ptr; key.len = secret->len; if ((prot = fido_dev_get_pin_protocol(dev)) == 0) { fido_log_debug("%s: fido_dev_get_pin_protocol", __func__); return (NULL); } /* select hmac portion of the shared secret */ if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32) key.len = 32; if ((md = EVP_sha256()) == NULL || HMAC(md, key.ptr, (int)key.len, data->ptr, data->len, dgst, &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH) return (NULL); outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len; return (cbor_build_bytestring(dgst, outlen)); } cbor_item_t * cbor_encode_pin_opt(const fido_dev_t *dev) { uint8_t prot; if ((prot = fido_dev_get_pin_protocol(dev)) == 0) { fido_log_debug("%s: fido_dev_get_pin_protocol", __func__); return (NULL); } return (cbor_build_uint8(prot)); } cbor_item_t * cbor_encode_change_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret, const fido_blob_t *new_pin_enc, const fido_blob_t *pin_hash_enc) { unsigned char dgst[SHA256_DIGEST_LENGTH]; unsigned int dgst_len; cbor_item_t *item = NULL; const EVP_MD *md = NULL; -#if OPENSSL_VERSION_NUMBER < 0x10100000L - HMAC_CTX ctx; -#else HMAC_CTX *ctx = NULL; -#endif fido_blob_t key; uint8_t prot; size_t outlen; key.ptr = secret->ptr; key.len = secret->len; if ((prot = fido_dev_get_pin_protocol(dev)) == 0) { fido_log_debug("%s: fido_dev_get_pin_protocol", __func__); goto fail; } if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32) key.len = 32; -#if OPENSSL_VERSION_NUMBER < 0x10100000L - HMAC_CTX_init(&ctx); - - if ((md = EVP_sha256()) == NULL || - HMAC_Init_ex(&ctx, key.ptr, (int)key.len, md, NULL) == 0 || - HMAC_Update(&ctx, new_pin_enc->ptr, new_pin_enc->len) == 0 || - HMAC_Update(&ctx, pin_hash_enc->ptr, pin_hash_enc->len) == 0 || - HMAC_Final(&ctx, dgst, &dgst_len) == 0 || - dgst_len != SHA256_DIGEST_LENGTH) { - fido_log_debug("%s: HMAC", __func__); - goto fail; - } -#else if ((ctx = HMAC_CTX_new()) == NULL || (md = EVP_sha256()) == NULL || HMAC_Init_ex(ctx, key.ptr, (int)key.len, md, NULL) == 0 || HMAC_Update(ctx, new_pin_enc->ptr, new_pin_enc->len) == 0 || HMAC_Update(ctx, pin_hash_enc->ptr, pin_hash_enc->len) == 0 || HMAC_Final(ctx, dgst, &dgst_len) == 0 || dgst_len != SHA256_DIGEST_LENGTH) { fido_log_debug("%s: HMAC", __func__); goto fail; } -#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len; if ((item = cbor_build_bytestring(dgst, outlen)) == NULL) { fido_log_debug("%s: cbor_build_bytestring", __func__); goto fail; } fail: -#if OPENSSL_VERSION_NUMBER >= 0x10100000L - if (ctx != NULL) - HMAC_CTX_free(ctx); -#endif + HMAC_CTX_free(ctx); return (item); } static int cbor_encode_hmac_secret_param(const fido_dev_t *dev, cbor_item_t *item, const fido_blob_t *ecdh, const es256_pk_t *pk, const fido_blob_t *salt) { cbor_item_t *param = NULL; cbor_item_t *argv[4]; struct cbor_pair pair; fido_blob_t *enc = NULL; + uint8_t prot; int r; memset(argv, 0, sizeof(argv)); memset(&pair, 0, sizeof(pair)); if (item == NULL || ecdh == NULL || pk == NULL || salt->ptr == NULL) { fido_log_debug("%s: ecdh=%p, pk=%p, salt->ptr=%p", __func__, (const void *)ecdh, (const void *)pk, (const void *)salt->ptr); r = FIDO_ERR_INTERNAL; goto fail; } if (salt->len != 32 && salt->len != 64) { fido_log_debug("%s: salt->len=%zu", __func__, salt->len); r = FIDO_ERR_INTERNAL; goto fail; } if ((enc = fido_blob_new()) == NULL || aes256_cbc_enc(dev, ecdh, salt, enc) < 0) { fido_log_debug("%s: aes256_cbc_enc", __func__); r = FIDO_ERR_INTERNAL; goto fail; } + if ((prot = fido_dev_get_pin_protocol(dev)) == 0) { + fido_log_debug("%s: fido_dev_get_pin_protocol", __func__); + r = FIDO_ERR_INTERNAL; + goto fail; + } + /* XXX not pin, but salt */ if ((argv[0] = es256_pk_encode(pk, 1)) == NULL || (argv[1] = fido_blob_encode(enc)) == NULL || (argv[2] = cbor_encode_pin_auth(dev, ecdh, enc)) == NULL || - (argv[3] = cbor_encode_pin_opt(dev)) == NULL) { + (prot != 1 && (argv[3] = cbor_build_uint8(prot)) == NULL)) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if ((param = cbor_flatten_vector(argv, nitems(argv))) == NULL) { fido_log_debug("%s: cbor_flatten_vector", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if ((pair.key = cbor_build_string("hmac-secret")) == NULL) { fido_log_debug("%s: cbor_build", __func__); r = FIDO_ERR_INTERNAL; goto fail; } pair.value = param; if (!cbor_map_add(item, pair)) { fido_log_debug("%s: cbor_map_add", __func__); r = FIDO_ERR_INTERNAL; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); if (param != NULL) cbor_decref(¶m); if (pair.key != NULL) cbor_decref(&pair.key); fido_blob_free(&enc); return (r); } cbor_item_t * cbor_encode_assert_ext(fido_dev_t *dev, const fido_assert_ext_t *ext, const fido_blob_t *ecdh, const es256_pk_t *pk) { cbor_item_t *item = NULL; size_t size = 0; if (ext->mask & FIDO_EXT_CRED_BLOB) size++; if (ext->mask & FIDO_EXT_HMAC_SECRET) size++; if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) size++; if (size == 0 || (item = cbor_new_definite_map(size)) == NULL) return (NULL); if (ext->mask & FIDO_EXT_CRED_BLOB) { if (cbor_add_bool(item, "credBlob", FIDO_OPT_TRUE) < 0) { cbor_decref(&item); return (NULL); } } if (ext->mask & FIDO_EXT_HMAC_SECRET) { if (cbor_encode_hmac_secret_param(dev, item, ecdh, pk, &ext->hmac_salt) < 0) { cbor_decref(&item); return (NULL); } } if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) { if (cbor_encode_largeblob_key_ext(item) < 0) { cbor_decref(&item); return (NULL); } } return (item); } int cbor_decode_fmt(const cbor_item_t *item, char **fmt) { char *type = NULL; if (cbor_string_copy(item, &type) < 0) { fido_log_debug("%s: cbor_string_copy", __func__); return (-1); } if (strcmp(type, "packed") && strcmp(type, "fido-u2f") && - strcmp(type, "none")) { + strcmp(type, "none") && strcmp(type, "tpm")) { fido_log_debug("%s: type=%s", __func__, type); free(type); return (-1); } *fmt = type; return (0); } struct cose_key { int kty; int alg; int crv; }; static int find_cose_alg(const cbor_item_t *key, const cbor_item_t *val, void *arg) { struct cose_key *cose_key = arg; if (cbor_isa_uint(key) == true && cbor_int_get_width(key) == CBOR_INT_8) { switch (cbor_get_uint8(key)) { case 1: if (cbor_isa_uint(val) == false || cbor_get_int(val) > INT_MAX || cose_key->kty != 0) { fido_log_debug("%s: kty", __func__); return (-1); } cose_key->kty = (int)cbor_get_int(val); break; case 3: if (cbor_isa_negint(val) == false || cbor_get_int(val) > INT_MAX || cose_key->alg != 0) { fido_log_debug("%s: alg", __func__); return (-1); } cose_key->alg = -(int)cbor_get_int(val) - 1; break; } } else if (cbor_isa_negint(key) == true && cbor_int_get_width(key) == CBOR_INT_8) { if (cbor_get_uint8(key) == 0) { /* get crv if not rsa, otherwise ignore */ if (cbor_isa_uint(val) == true && cbor_get_int(val) <= INT_MAX && cose_key->crv == 0) cose_key->crv = (int)cbor_get_int(val); } } return (0); } static int get_cose_alg(const cbor_item_t *item, int *cose_alg) { struct cose_key cose_key; memset(&cose_key, 0, sizeof(cose_key)); *cose_alg = 0; if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, &cose_key, find_cose_alg) < 0) { fido_log_debug("%s: cbor type", __func__); return (-1); } switch (cose_key.alg) { case COSE_ES256: if (cose_key.kty != COSE_KTY_EC2 || cose_key.crv != COSE_P256) { fido_log_debug("%s: invalid kty/crv", __func__); return (-1); } break; case COSE_EDDSA: if (cose_key.kty != COSE_KTY_OKP || cose_key.crv != COSE_ED25519) { fido_log_debug("%s: invalid kty/crv", __func__); return (-1); } break; case COSE_RS256: if (cose_key.kty != COSE_KTY_RSA) { fido_log_debug("%s: invalid kty/crv", __func__); return (-1); } break; default: fido_log_debug("%s: unknown alg %d", __func__, cose_key.alg); return (-1); } *cose_alg = cose_key.alg; return (0); } int cbor_decode_pubkey(const cbor_item_t *item, int *type, void *key) { if (get_cose_alg(item, type) < 0) { fido_log_debug("%s: get_cose_alg", __func__); return (-1); } switch (*type) { case COSE_ES256: if (es256_pk_decode(item, key) < 0) { fido_log_debug("%s: es256_pk_decode", __func__); return (-1); } break; case COSE_RS256: if (rs256_pk_decode(item, key) < 0) { fido_log_debug("%s: rs256_pk_decode", __func__); return (-1); } break; case COSE_EDDSA: if (eddsa_pk_decode(item, key) < 0) { fido_log_debug("%s: eddsa_pk_decode", __func__); return (-1); } break; default: fido_log_debug("%s: invalid cose_alg %d", __func__, *type); return (-1); } return (0); } static int decode_attcred(const unsigned char **buf, size_t *len, int cose_alg, fido_attcred_t *attcred) { cbor_item_t *item = NULL; struct cbor_load_result cbor; uint16_t id_len; int ok = -1; fido_log_xxd(*buf, *len, "%s", __func__); if (fido_buf_read(buf, len, &attcred->aaguid, sizeof(attcred->aaguid)) < 0) { fido_log_debug("%s: fido_buf_read aaguid", __func__); return (-1); } if (fido_buf_read(buf, len, &id_len, sizeof(id_len)) < 0) { fido_log_debug("%s: fido_buf_read id_len", __func__); return (-1); } attcred->id.len = (size_t)be16toh(id_len); if ((attcred->id.ptr = malloc(attcred->id.len)) == NULL) return (-1); fido_log_debug("%s: attcred->id.len=%zu", __func__, attcred->id.len); if (fido_buf_read(buf, len, attcred->id.ptr, attcred->id.len) < 0) { fido_log_debug("%s: fido_buf_read id", __func__); return (-1); } if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { fido_log_debug("%s: cbor_load", __func__); goto fail; } if (cbor_decode_pubkey(item, &attcred->type, &attcred->pubkey) < 0) { fido_log_debug("%s: cbor_decode_pubkey", __func__); goto fail; } if (attcred->type != cose_alg) { fido_log_debug("%s: cose_alg mismatch (%d != %d)", __func__, attcred->type, cose_alg); goto fail; } *buf += cbor.read; *len -= cbor.read; ok = 0; fail: if (item != NULL) cbor_decref(&item); return (ok); } static int decode_cred_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_cred_ext_t *authdata_ext = arg; char *type = NULL; int ok = -1; if (cbor_string_copy(key, &type) < 0) { fido_log_debug("%s: cbor type", __func__); ok = 0; /* ignore */ goto out; } if (strcmp(type, "hmac-secret") == 0) { if (cbor_isa_float_ctrl(val) == false || cbor_float_get_width(val) != CBOR_FLOAT_0 || cbor_is_bool(val) == false) { fido_log_debug("%s: cbor type", __func__); goto out; } if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE) authdata_ext->mask |= FIDO_EXT_HMAC_SECRET; } else if (strcmp(type, "credProtect") == 0) { if (cbor_isa_uint(val) == false || cbor_int_get_width(val) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); goto out; } authdata_ext->mask |= FIDO_EXT_CRED_PROTECT; authdata_ext->prot = cbor_get_uint8(val); } else if (strcmp(type, "credBlob") == 0) { if (cbor_isa_float_ctrl(val) == false || cbor_float_get_width(val) != CBOR_FLOAT_0 || cbor_is_bool(val) == false) { fido_log_debug("%s: cbor type", __func__); goto out; } if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE) authdata_ext->mask |= FIDO_EXT_CRED_BLOB; + } else if (strcmp(type, "minPinLength") == 0) { + if (cbor_isa_uint(val) == false || + cbor_int_get_width(val) != CBOR_INT_8) { + fido_log_debug("%s: cbor type", __func__); + goto out; + } + authdata_ext->mask |= FIDO_EXT_MINPINLEN; + authdata_ext->minpinlen = cbor_get_uint8(val); } ok = 0; out: free(type); return (ok); } static int decode_cred_extensions(const unsigned char **buf, size_t *len, fido_cred_ext_t *authdata_ext) { cbor_item_t *item = NULL; struct cbor_load_result cbor; int ok = -1; memset(authdata_ext, 0, sizeof(*authdata_ext)); fido_log_xxd(*buf, *len, "%s", __func__); if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { fido_log_debug("%s: cbor_load", __func__); goto fail; } if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, authdata_ext, decode_cred_extension) < 0) { fido_log_debug("%s: cbor type", __func__); goto fail; } *buf += cbor.read; *len -= cbor.read; ok = 0; fail: if (item != NULL) cbor_decref(&item); return (ok); } static int decode_assert_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_assert_extattr_t *authdata_ext = arg; char *type = NULL; int ok = -1; if (cbor_string_copy(key, &type) < 0) { fido_log_debug("%s: cbor type", __func__); ok = 0; /* ignore */ goto out; } if (strcmp(type, "hmac-secret") == 0) { if (fido_blob_decode(val, &authdata_ext->hmac_secret_enc) < 0) { fido_log_debug("%s: fido_blob_decode", __func__); goto out; } authdata_ext->mask |= FIDO_EXT_HMAC_SECRET; } else if (strcmp(type, "credBlob") == 0) { if (fido_blob_decode(val, &authdata_ext->blob) < 0) { fido_log_debug("%s: fido_blob_decode", __func__); goto out; } authdata_ext->mask |= FIDO_EXT_CRED_BLOB; } ok = 0; out: free(type); return (ok); } static int decode_assert_extensions(const unsigned char **buf, size_t *len, fido_assert_extattr_t *authdata_ext) { cbor_item_t *item = NULL; struct cbor_load_result cbor; int ok = -1; fido_log_xxd(*buf, *len, "%s", __func__); if ((item = cbor_load(*buf, *len, &cbor)) == NULL) { fido_log_debug("%s: cbor_load", __func__); goto fail; } if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, authdata_ext, decode_assert_extension) < 0) { fido_log_debug("%s: cbor type", __func__); goto fail; } *buf += cbor.read; *len -= cbor.read; ok = 0; fail: if (item != NULL) cbor_decref(&item); return (ok); } int cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg, fido_blob_t *authdata_cbor, fido_authdata_t *authdata, fido_attcred_t *attcred, fido_cred_ext_t *authdata_ext) { const unsigned char *buf = NULL; size_t len; size_t alloc_len; if (cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } if (authdata_cbor->ptr != NULL || (authdata_cbor->len = cbor_serialize_alloc(item, &authdata_cbor->ptr, &alloc_len)) == 0) { fido_log_debug("%s: cbor_serialize_alloc", __func__); return (-1); } buf = cbor_bytestring_handle(item); len = cbor_bytestring_length(item); fido_log_xxd(buf, len, "%s", __func__); if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) { fido_log_debug("%s: fido_buf_read", __func__); return (-1); } authdata->sigcount = be32toh(authdata->sigcount); if (attcred != NULL) { if ((authdata->flags & CTAP_AUTHDATA_ATT_CRED) == 0 || decode_attcred(&buf, &len, cose_alg, attcred) < 0) return (-1); } if (authdata_ext != NULL) { if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 && decode_cred_extensions(&buf, &len, authdata_ext) < 0) return (-1); } /* XXX we should probably ensure that len == 0 at this point */ return (FIDO_OK); } int cbor_decode_assert_authdata(const cbor_item_t *item, fido_blob_t *authdata_cbor, fido_authdata_t *authdata, fido_assert_extattr_t *authdata_ext) { const unsigned char *buf = NULL; size_t len; size_t alloc_len; if (cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } if (authdata_cbor->ptr != NULL || (authdata_cbor->len = cbor_serialize_alloc(item, &authdata_cbor->ptr, &alloc_len)) == 0) { fido_log_debug("%s: cbor_serialize_alloc", __func__); return (-1); } buf = cbor_bytestring_handle(item); len = cbor_bytestring_length(item); fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len); if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) { fido_log_debug("%s: fido_buf_read", __func__); return (-1); } authdata->sigcount = be32toh(authdata->sigcount); if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0) { if (decode_assert_extensions(&buf, &len, authdata_ext) < 0) { fido_log_debug("%s: decode_assert_extensions", __func__); return (-1); } } /* XXX we should probably ensure that len == 0 at this point */ return (FIDO_OK); } static int decode_x5c(const cbor_item_t *item, void *arg) { fido_blob_t *x5c = arg; if (x5c->len) return (0); /* ignore */ return (fido_blob_decode(item, x5c)); } static int decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_attstmt_t *attstmt = arg; char *name = NULL; - int cose_alg = 0; int ok = -1; if (cbor_string_copy(key, &name) < 0) { fido_log_debug("%s: cbor type", __func__); ok = 0; /* ignore */ goto out; } if (!strcmp(name, "alg")) { if (cbor_isa_negint(val) == false || cbor_get_int(val) > UINT16_MAX) { fido_log_debug("%s: alg", __func__); goto out; } - if ((cose_alg = -(int)cbor_get_int(val) - 1) != COSE_ES256 && - cose_alg != COSE_RS256 && cose_alg != COSE_EDDSA) { - fido_log_debug("%s: unsupported cose_alg=%d", __func__, - cose_alg); + attstmt->alg = -(int)cbor_get_int(val) - 1; + if (attstmt->alg != COSE_ES256 && attstmt->alg != COSE_RS256 && + attstmt->alg != COSE_EDDSA && attstmt->alg != COSE_RS1) { + fido_log_debug("%s: unsupported attstmt->alg=%d", + __func__, attstmt->alg); goto out; } } else if (!strcmp(name, "sig")) { if (fido_blob_decode(val, &attstmt->sig) < 0) { fido_log_debug("%s: sig", __func__); goto out; } } else if (!strcmp(name, "x5c")) { if (cbor_isa_array(val) == false || cbor_array_is_definite(val) == false || cbor_array_iter(val, &attstmt->x5c, decode_x5c) < 0) { fido_log_debug("%s: x5c", __func__); goto out; } + } else if (!strcmp(name, "certInfo")) { + if (fido_blob_decode(val, &attstmt->certinfo) < 0) { + fido_log_debug("%s: certinfo", __func__); + goto out; + } + } else if (!strcmp(name, "pubArea")) { + if (fido_blob_decode(val, &attstmt->pubarea) < 0) { + fido_log_debug("%s: pubarea", __func__); + goto out; + } } ok = 0; out: free(name); return (ok); } int cbor_decode_attstmt(const cbor_item_t *item, fido_attstmt_t *attstmt) { + size_t alloc_len; + if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, attstmt, decode_attstmt_entry) < 0) { fido_log_debug("%s: cbor type", __func__); return (-1); } + if (attstmt->cbor.ptr != NULL || + (attstmt->cbor.len = cbor_serialize_alloc(item, + &attstmt->cbor.ptr, &alloc_len)) == 0) { + fido_log_debug("%s: cbor_serialize_alloc", __func__); + return (-1); + } + return (0); } int cbor_decode_uint64(const cbor_item_t *item, uint64_t *n) { if (cbor_isa_uint(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } *n = cbor_get_int(item); return (0); } static int decode_cred_id_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_blob_t *id = arg; char *name = NULL; int ok = -1; if (cbor_string_copy(key, &name) < 0) { fido_log_debug("%s: cbor type", __func__); ok = 0; /* ignore */ goto out; } if (!strcmp(name, "id")) if (fido_blob_decode(val, id) < 0) { fido_log_debug("%s: cbor_bytestring_copy", __func__); goto out; } ok = 0; out: free(name); return (ok); } int cbor_decode_cred_id(const cbor_item_t *item, fido_blob_t *id) { if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, id, decode_cred_id_entry) < 0) { fido_log_debug("%s: cbor type", __func__); return (-1); } return (0); } static int decode_user_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_user_t *user = arg; char *name = NULL; int ok = -1; if (cbor_string_copy(key, &name) < 0) { fido_log_debug("%s: cbor type", __func__); ok = 0; /* ignore */ goto out; } if (!strcmp(name, "icon")) { if (cbor_string_copy(val, &user->icon) < 0) { fido_log_debug("%s: icon", __func__); goto out; } } else if (!strcmp(name, "name")) { if (cbor_string_copy(val, &user->name) < 0) { fido_log_debug("%s: name", __func__); goto out; } } else if (!strcmp(name, "displayName")) { if (cbor_string_copy(val, &user->display_name) < 0) { fido_log_debug("%s: display_name", __func__); goto out; } } else if (!strcmp(name, "id")) { if (fido_blob_decode(val, &user->id) < 0) { fido_log_debug("%s: id", __func__); goto out; } } ok = 0; out: free(name); return (ok); } int cbor_decode_user(const cbor_item_t *item, fido_user_t *user) { if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, user, decode_user_entry) < 0) { fido_log_debug("%s: cbor type", __func__); return (-1); } return (0); } static int decode_rp_entity_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_rp_t *rp = arg; char *name = NULL; int ok = -1; if (cbor_string_copy(key, &name) < 0) { fido_log_debug("%s: cbor type", __func__); ok = 0; /* ignore */ goto out; } if (!strcmp(name, "id")) { if (cbor_string_copy(val, &rp->id) < 0) { fido_log_debug("%s: id", __func__); goto out; } } else if (!strcmp(name, "name")) { if (cbor_string_copy(val, &rp->name) < 0) { fido_log_debug("%s: name", __func__); goto out; } } ok = 0; out: free(name); return (ok); } int cbor_decode_rp_entity(const cbor_item_t *item, fido_rp_t *rp) { if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, rp, decode_rp_entity_entry) < 0) { fido_log_debug("%s: cbor type", __func__); return (-1); } return (0); } cbor_item_t * cbor_build_uint(const uint64_t value) { if (value <= UINT8_MAX) return cbor_build_uint8((uint8_t)value); else if (value <= UINT16_MAX) return cbor_build_uint16((uint16_t)value); else if (value <= UINT32_MAX) return cbor_build_uint32((uint32_t)value); return cbor_build_uint64(value); } int cbor_array_append(cbor_item_t **array, cbor_item_t *item) { cbor_item_t **v, *ret; size_t n; if ((v = cbor_array_handle(*array)) == NULL || (n = cbor_array_size(*array)) == SIZE_MAX || (ret = cbor_new_definite_array(n + 1)) == NULL) return -1; for (size_t i = 0; i < n; i++) { if (cbor_array_push(ret, v[i]) == 0) { cbor_decref(&ret); return -1; } } if (cbor_array_push(ret, item) == 0) { cbor_decref(&ret); return -1; } cbor_decref(array); *array = ret; return 0; } int cbor_array_drop(cbor_item_t **array, size_t idx) { cbor_item_t **v, *ret; size_t n; if ((v = cbor_array_handle(*array)) == NULL || (n = cbor_array_size(*array)) == 0 || idx >= n || (ret = cbor_new_definite_array(n - 1)) == NULL) return -1; for (size_t i = 0; i < n; i++) { if (i != idx && cbor_array_push(ret, v[i]) == 0) { cbor_decref(&ret); return -1; } } cbor_decref(array); *array = ret; return 0; } diff --git a/contrib/libfido2/src/config.c b/contrib/libfido2/src/config.c index 0dda16163bc8..2baaab0fd62c 100644 --- a/contrib/libfido2/src/config.c +++ b/contrib/libfido2/src/config.c @@ -1,191 +1,229 @@ /* * Copyright (c) 2020 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include "fido.h" #include "fido/config.h" #include "fido/es256.h" #define CMD_ENABLE_ENTATTEST 0x01 #define CMD_TOGGLE_ALWAYS_UV 0x02 #define CMD_SET_PIN_MINLEN 0x03 static int config_prepare_hmac(uint8_t subcmd, const cbor_item_t *item, fido_blob_t *hmac) { uint8_t prefix[32 + 2 * sizeof(uint8_t)], cbor[128]; size_t cbor_len; memset(prefix, 0xff, sizeof(prefix)); prefix[sizeof(prefix) - 2] = CTAP_CBOR_CONFIG; prefix[sizeof(prefix) - 1] = subcmd; if ((cbor_len = cbor_serialize(item, cbor, sizeof(cbor))) == 0) { fido_log_debug("%s: cbor_serialize", __func__); return -1; } if ((hmac->ptr = malloc(cbor_len + sizeof(prefix))) == NULL) { fido_log_debug("%s: malloc", __func__); return -1; } memcpy(hmac->ptr, prefix, sizeof(prefix)); memcpy(hmac->ptr + sizeof(prefix), cbor, cbor_len); hmac->len = cbor_len + sizeof(prefix); return 0; } static int config_tx(fido_dev_t *dev, uint8_t subcmd, cbor_item_t **paramv, size_t paramc, - const char *pin) + const char *pin, int *ms) { cbor_item_t *argv[4]; es256_pk_t *pk = NULL; fido_blob_t *ecdh = NULL, f, hmac; const uint8_t cmd = CTAP_CBOR_CONFIG; int r = FIDO_ERR_INTERNAL; memset(&f, 0, sizeof(f)); memset(&hmac, 0, sizeof(hmac)); memset(&argv, 0, sizeof(argv)); /* subCommand */ if ((argv[0] = cbor_build_uint8(subcmd)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } /* pinProtocol, pinAuth */ if (pin != NULL || (fido_dev_supports_permissions(dev) && fido_dev_has_uv(dev))) { if ((argv[1] = cbor_flatten_vector(paramv, paramc)) == NULL) { fido_log_debug("%s: cbor_flatten_vector", __func__); goto fail; } if (config_prepare_hmac(subcmd, argv[1], &hmac) < 0) { fido_log_debug("%s: config_prepare_hmac", __func__); goto fail; } - if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { + if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin, - NULL, &argv[3], &argv[2])) != FIDO_OK) { + NULL, &argv[3], &argv[2], ms)) != FIDO_OK) { fido_log_debug("%s: cbor_add_uv_params", __func__); goto fail; } } /* framing and transmission */ if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 || - fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { + fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); es256_pk_free(&pk); fido_blob_free(&ecdh); free(f.ptr); free(hmac.ptr); return r; } static int -config_enable_entattest_wait(fido_dev_t *dev, const char *pin, int ms) +config_enable_entattest_wait(fido_dev_t *dev, const char *pin, int *ms) { int r; - if ((r = config_tx(dev, CMD_ENABLE_ENTATTEST, NULL, 0, pin)) != FIDO_OK) + if ((r = config_tx(dev, CMD_ENABLE_ENTATTEST, NULL, 0, pin, + ms)) != FIDO_OK) return r; return fido_rx_cbor_status(dev, ms); } int fido_dev_enable_entattest(fido_dev_t *dev, const char *pin) { - return (config_enable_entattest_wait(dev, pin, -1)); + int ms = dev->timeout_ms; + + return (config_enable_entattest_wait(dev, pin, &ms)); } static int -config_toggle_always_uv_wait(fido_dev_t *dev, const char *pin, int ms) +config_toggle_always_uv_wait(fido_dev_t *dev, const char *pin, int *ms) { int r; - if ((r = config_tx(dev, CMD_TOGGLE_ALWAYS_UV, NULL, 0, pin)) != FIDO_OK) + if ((r = config_tx(dev, CMD_TOGGLE_ALWAYS_UV, NULL, 0, pin, + ms)) != FIDO_OK) return r; return (fido_rx_cbor_status(dev, ms)); } int fido_dev_toggle_always_uv(fido_dev_t *dev, const char *pin) { - return config_toggle_always_uv_wait(dev, pin, -1); + int ms = dev->timeout_ms; + + return config_toggle_always_uv_wait(dev, pin, &ms); } static int -config_pin_minlen_tx(fido_dev_t *dev, size_t len, bool force, const char *pin) +config_pin_minlen_tx(fido_dev_t *dev, size_t len, bool force, + const fido_str_array_t *rpid, const char *pin, int *ms) { cbor_item_t *argv[3]; int r; memset(argv, 0, sizeof(argv)); - if ((!len && !force) || len > UINT8_MAX) { + if ((rpid == NULL && len == 0 && !force) || len > UINT8_MAX) { r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if (len && (argv[0] = cbor_build_uint8((uint8_t)len)) == NULL) { fido_log_debug("%s: cbor_encode_uint8", __func__); r = FIDO_ERR_INTERNAL; goto fail; } + if (rpid != NULL && (argv[1] = cbor_encode_str_array(rpid)) == NULL) { + fido_log_debug("%s: cbor_encode_str_array", __func__); + r = FIDO_ERR_INTERNAL; + goto fail; + } if (force && (argv[2] = cbor_build_bool(true)) == NULL) { fido_log_debug("%s: cbor_build_bool", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if ((r = config_tx(dev, CMD_SET_PIN_MINLEN, argv, nitems(argv), - pin)) != FIDO_OK) { + pin, ms)) != FIDO_OK) { fido_log_debug("%s: config_tx", __func__); goto fail; } fail: cbor_vector_free(argv, nitems(argv)); return r; } static int -config_pin_minlen(fido_dev_t *dev, size_t len, bool force, const char *pin, - int ms) +config_pin_minlen(fido_dev_t *dev, size_t len, bool force, + const fido_str_array_t *rpid, const char *pin, int *ms) { int r; - if ((r = config_pin_minlen_tx(dev, len, force, pin)) != FIDO_OK) + if ((r = config_pin_minlen_tx(dev, len, force, rpid, pin, + ms)) != FIDO_OK) return r; return fido_rx_cbor_status(dev, ms); } int fido_dev_set_pin_minlen(fido_dev_t *dev, size_t len, const char *pin) { - return config_pin_minlen(dev, len, false, pin, -1); + int ms = dev->timeout_ms; + + return config_pin_minlen(dev, len, false, NULL, pin, &ms); } int fido_dev_force_pin_change(fido_dev_t *dev, const char *pin) { - return config_pin_minlen(dev, 0, true, pin, -1); + int ms = dev->timeout_ms; + + return config_pin_minlen(dev, 0, true, NULL, pin, &ms); +} + +int +fido_dev_set_pin_minlen_rpid(fido_dev_t *dev, const char * const *rpid, + size_t n, const char *pin) +{ + fido_str_array_t sa; + int ms = dev->timeout_ms; + int r; + + memset(&sa, 0, sizeof(sa)); + if (fido_str_array_pack(&sa, rpid, n) < 0) { + fido_log_debug("%s: fido_str_array_pack", __func__); + r = FIDO_ERR_INTERNAL; + goto fail; + } + r = config_pin_minlen(dev, 0, false, &sa, pin, &ms); +fail: + fido_str_array_free(&sa); + + return r; } diff --git a/contrib/libfido2/src/cred.c b/contrib/libfido2/src/cred.c index 5e65b08293b1..6da502c8d90a 100644 --- a/contrib/libfido2/src/cred.c +++ b/contrib/libfido2/src/cred.c @@ -1,1086 +1,1201 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include "fido.h" #include "fido/es256.h" +#ifndef FIDO_MAXMSG_CRED +#define FIDO_MAXMSG_CRED 4096 +#endif + static int parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_cred_t *cred = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 1: /* fmt */ return (cbor_decode_fmt(val, &cred->fmt)); case 2: /* authdata */ if (fido_blob_decode(val, &cred->authdata_raw) < 0) { fido_log_debug("%s: fido_blob_decode", __func__); return (-1); } return (cbor_decode_cred_authdata(val, cred->type, &cred->authdata_cbor, &cred->authdata, &cred->attcred, &cred->authdata_ext)); case 3: /* attestation statement */ return (cbor_decode_attstmt(val, &cred->attstmt)); case 5: /* large blob key */ return (fido_blob_decode(val, &cred->largeblob_key)); default: /* ignore */ fido_log_debug("%s: cbor type", __func__); return (0); } } static int -fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin) +fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin, + int *ms) { fido_blob_t f; fido_blob_t *ecdh = NULL; fido_opt_t uv = cred->uv; es256_pk_t *pk = NULL; cbor_item_t *argv[9]; const uint8_t cmd = CTAP_CBOR_MAKECRED; int r; memset(&f, 0, sizeof(f)); memset(argv, 0, sizeof(argv)); if (cred->cdh.ptr == NULL || cred->type == 0) { fido_log_debug("%s: cdh=%p, type=%d", __func__, (void *)cred->cdh.ptr, cred->type); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if ((argv[0] = fido_blob_encode(&cred->cdh)) == NULL || (argv[1] = cbor_encode_rp_entity(&cred->rp)) == NULL || (argv[2] = cbor_encode_user_entity(&cred->user)) == NULL || (argv[3] = cbor_encode_pubkey_param(cred->type)) == NULL) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } /* excluded credentials */ if (cred->excl.len) if ((argv[4] = cbor_encode_pubkey_list(&cred->excl)) == NULL) { fido_log_debug("%s: cbor_encode_pubkey_list", __func__); r = FIDO_ERR_INTERNAL; goto fail; } /* extensions */ if (cred->ext.mask) if ((argv[5] = cbor_encode_cred_ext(&cred->ext, &cred->blob)) == NULL) { fido_log_debug("%s: cbor_encode_cred_ext", __func__); r = FIDO_ERR_INTERNAL; goto fail; } /* user verification */ if (pin != NULL || (uv == FIDO_OPT_TRUE && fido_dev_supports_permissions(dev))) { - if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { + if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } if ((r = cbor_add_uv_params(dev, cmd, &cred->cdh, pk, ecdh, - pin, cred->rp.id, &argv[7], &argv[8])) != FIDO_OK) { + pin, cred->rp.id, &argv[7], &argv[8], ms)) != FIDO_OK) { fido_log_debug("%s: cbor_add_uv_params", __func__); goto fail; } uv = FIDO_OPT_OMIT; } /* options */ if (cred->rk != FIDO_OPT_OMIT || uv != FIDO_OPT_OMIT) if ((argv[6] = cbor_encode_cred_opt(cred->rk, uv)) == NULL) { fido_log_debug("%s: cbor_encode_cred_opt", __func__); r = FIDO_ERR_INTERNAL; goto fail; } /* framing and transmission */ if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 || - fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { + fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: es256_pk_free(&pk); fido_blob_free(&ecdh); cbor_vector_free(argv, nitems(argv)); free(f.ptr); return (r); } static int -fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int ms) +fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int *ms) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; - int r; + unsigned char *reply; + int reply_len; + int r; fido_cred_reset_rx(cred); - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), + if ((reply = malloc(FIDO_MAXMSG_CRED)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto fail; + } + + if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, reply, FIDO_MAXMSG_CRED, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto fail; } if ((r = cbor_parse_reply(reply, (size_t)reply_len, cred, parse_makecred_reply)) != FIDO_OK) { fido_log_debug("%s: parse_makecred_reply", __func__); - return (r); + goto fail; } if (cred->fmt == NULL || fido_blob_is_empty(&cred->authdata_cbor) || fido_blob_is_empty(&cred->attcred.id)) { - fido_cred_reset_rx(cred); - return (FIDO_ERR_INVALID_CBOR); + r = FIDO_ERR_INVALID_CBOR; + goto fail; } - return (FIDO_OK); + r = FIDO_OK; +fail: + free(reply); + + if (r != FIDO_OK) + fido_cred_reset_rx(cred); + + return (r); } static int fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin, - int ms) + int *ms) { int r; - if ((r = fido_dev_make_cred_tx(dev, cred, pin)) != FIDO_OK || + if ((r = fido_dev_make_cred_tx(dev, cred, pin, ms)) != FIDO_OK || (r = fido_dev_make_cred_rx(dev, cred, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin) { + int ms = dev->timeout_ms; + #ifdef USE_WINHELLO if (dev->flags & FIDO_DEV_WINHELLO) - return (fido_winhello_make_cred(dev, cred, pin)); + return (fido_winhello_make_cred(dev, cred, pin, ms)); #endif if (fido_dev_is_fido2(dev) == false) { if (pin != NULL || cred->rk == FIDO_OPT_TRUE || cred->ext.mask != 0) return (FIDO_ERR_UNSUPPORTED_OPTION); - return (u2f_register(dev, cred, -1)); + return (u2f_register(dev, cred, &ms)); } - return (fido_dev_make_cred_wait(dev, cred, pin, -1)); + return (fido_dev_make_cred_wait(dev, cred, pin, &ms)); } static int check_extensions(const fido_cred_ext_t *authdata_ext, const fido_cred_ext_t *ext) { fido_cred_ext_t tmp; /* XXX: largeBlobKey is not part of the extensions map */ memcpy(&tmp, ext, sizeof(tmp)); tmp.mask &= ~FIDO_EXT_LARGEBLOB_KEY; return (timingsafe_bcmp(authdata_ext, &tmp, sizeof(*authdata_ext))); } int fido_check_rp_id(const char *id, const unsigned char *obtained_hash) { unsigned char expected_hash[SHA256_DIGEST_LENGTH]; explicit_bzero(expected_hash, sizeof(expected_hash)); if (SHA256((const unsigned char *)id, strlen(id), expected_hash) != expected_hash) { fido_log_debug("%s: sha256", __func__); return (-1); } return (timingsafe_bcmp(expected_hash, obtained_hash, SHA256_DIGEST_LENGTH)); } static int get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id, size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id, const es256_pk_t *pk) { - const uint8_t zero = 0; - const uint8_t four = 4; /* uncompressed point */ - SHA256_CTX ctx; - - if (dgst->len != SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 || - SHA256_Update(&ctx, &zero, sizeof(zero)) == 0 || - SHA256_Update(&ctx, rp_id, rp_id_len) == 0 || - SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 || - SHA256_Update(&ctx, id->ptr, id->len) == 0 || - SHA256_Update(&ctx, &four, sizeof(four)) == 0 || - SHA256_Update(&ctx, pk->x, sizeof(pk->x)) == 0 || - SHA256_Update(&ctx, pk->y, sizeof(pk->y)) == 0 || - SHA256_Final(dgst->ptr, &ctx) == 0) { + const uint8_t zero = 0; + const uint8_t four = 4; /* uncompressed point */ + const EVP_MD *md = NULL; + EVP_MD_CTX *ctx = NULL; + int ok = -1; + + if (dgst->len != SHA256_DIGEST_LENGTH || + (md = EVP_sha256()) == NULL || + (ctx = EVP_MD_CTX_new()) == NULL || + EVP_DigestInit_ex(ctx, md, NULL) != 1 || + EVP_DigestUpdate(ctx, &zero, sizeof(zero)) != 1 || + EVP_DigestUpdate(ctx, rp_id, rp_id_len) != 1 || + EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 || + EVP_DigestUpdate(ctx, id->ptr, id->len) != 1 || + EVP_DigestUpdate(ctx, &four, sizeof(four)) != 1 || + EVP_DigestUpdate(ctx, pk->x, sizeof(pk->x)) != 1 || + EVP_DigestUpdate(ctx, pk->y, sizeof(pk->y)) != 1 || + EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) { fido_log_debug("%s: sha256", __func__); - return (-1); + goto fail; } - return (0); + ok = 0; +fail: + EVP_MD_CTX_free(ctx); + + return (ok); } static int -verify_sig(const fido_blob_t *dgst, const fido_blob_t *x5c, - const fido_blob_t *sig) +verify_attstmt(const fido_blob_t *dgst, const fido_attstmt_t *attstmt) { BIO *rawcert = NULL; X509 *cert = NULL; EVP_PKEY *pkey = NULL; - EC_KEY *ec; int ok = -1; /* openssl needs ints */ - if (dgst->len > INT_MAX || x5c->len > INT_MAX || sig->len > INT_MAX) { - fido_log_debug("%s: dgst->len=%zu, x5c->len=%zu, sig->len=%zu", - __func__, dgst->len, x5c->len, sig->len); + if (attstmt->x5c.len > INT_MAX) { + fido_log_debug("%s: x5c.len=%zu", __func__, attstmt->x5c.len); return (-1); } /* fetch key from x509 */ - if ((rawcert = BIO_new_mem_buf(x5c->ptr, (int)x5c->len)) == NULL || + if ((rawcert = BIO_new_mem_buf(attstmt->x5c.ptr, + (int)attstmt->x5c.len)) == NULL || (cert = d2i_X509_bio(rawcert, NULL)) == NULL || - (pkey = X509_get_pubkey(cert)) == NULL || - (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) { + (pkey = X509_get_pubkey(cert)) == NULL) { fido_log_debug("%s: x509 key", __func__); goto fail; } - if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr, - (int)sig->len, ec) != 1) { - fido_log_debug("%s: ECDSA_verify", __func__); - goto fail; + switch (attstmt->alg) { + case COSE_UNSPEC: + case COSE_ES256: + ok = es256_verify_sig(dgst, pkey, &attstmt->sig); + break; + case COSE_RS256: + ok = rs256_verify_sig(dgst, pkey, &attstmt->sig); + break; + case COSE_RS1: + ok = rs1_verify_sig(dgst, pkey, &attstmt->sig); + break; + case COSE_EDDSA: + ok = eddsa_verify_sig(dgst, pkey, &attstmt->sig); + break; + default: + fido_log_debug("%s: unknown alg %d", __func__, attstmt->alg); + break; } - ok = 0; fail: - if (rawcert != NULL) - BIO_free(rawcert); - if (cert != NULL) - X509_free(cert); - if (pkey != NULL) - EVP_PKEY_free(pkey); + BIO_free(rawcert); + X509_free(cert); + EVP_PKEY_free(pkey); return (ok); } int fido_cred_verify(const fido_cred_t *cred) { unsigned char buf[SHA256_DIGEST_LENGTH]; fido_blob_t dgst; int r; dgst.ptr = buf; dgst.len = sizeof(buf); /* do we have everything we need? */ if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL || cred->attstmt.x5c.ptr == NULL || cred->attstmt.sig.ptr == NULL || cred->fmt == NULL || cred->attcred.id.ptr == NULL || cred->rp.id == NULL) { fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, " "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr, (void *)cred->authdata_cbor.ptr, (void *)cred->attstmt.x5c.ptr, (void *)cred->attstmt.sig.ptr, (void *)cred->fmt, (void *)cred->attcred.id.ptr, cred->rp.id); r = FIDO_ERR_INVALID_ARGUMENT; goto out; } if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) { fido_log_debug("%s: fido_check_rp_id", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE, cred->uv) < 0) { fido_log_debug("%s: fido_check_flags", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (check_extensions(&cred->authdata_ext, &cred->ext) != 0) { fido_log_debug("%s: check_extensions", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (!strcmp(cred->fmt, "packed")) { if (fido_get_signed_hash(COSE_ES256, &dgst, &cred->cdh, &cred->authdata_cbor) < 0) { fido_log_debug("%s: fido_get_signed_hash", __func__); r = FIDO_ERR_INTERNAL; goto out; } } else if (!strcmp(cred->fmt, "fido-u2f")) { if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash, sizeof(cred->authdata.rp_id_hash), &cred->cdh, &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) { fido_log_debug("%s: get_signed_hash_u2f", __func__); r = FIDO_ERR_INTERNAL; goto out; } + } else if (!strcmp(cred->fmt, "tpm")) { + if (fido_get_signed_hash_tpm(&dgst, &cred->cdh, + &cred->authdata_raw, &cred->attstmt, &cred->attcred) < 0) { + fido_log_debug("%s: fido_get_signed_hash_tpm", __func__); + r = FIDO_ERR_INTERNAL; + goto out; + } } else { fido_log_debug("%s: unknown fmt %s", __func__, cred->fmt); r = FIDO_ERR_INVALID_ARGUMENT; goto out; } - if (verify_sig(&dgst, &cred->attstmt.x5c, &cred->attstmt.sig) < 0) { - fido_log_debug("%s: verify_sig", __func__); + if (verify_attstmt(&dgst, &cred->attstmt) < 0) { + fido_log_debug("%s: verify_attstmt", __func__); r = FIDO_ERR_INVALID_SIG; goto out; } r = FIDO_OK; out: explicit_bzero(buf, sizeof(buf)); return (r); } int fido_cred_verify_self(const fido_cred_t *cred) { unsigned char buf[1024]; /* XXX */ fido_blob_t dgst; int ok = -1; int r; dgst.ptr = buf; dgst.len = sizeof(buf); /* do we have everything we need? */ if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL || cred->attstmt.x5c.ptr != NULL || cred->attstmt.sig.ptr == NULL || cred->fmt == NULL || cred->attcred.id.ptr == NULL || cred->rp.id == NULL) { fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, " "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr, (void *)cred->authdata_cbor.ptr, (void *)cred->attstmt.x5c.ptr, (void *)cred->attstmt.sig.ptr, (void *)cred->fmt, (void *)cred->attcred.id.ptr, cred->rp.id); r = FIDO_ERR_INVALID_ARGUMENT; goto out; } if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) { fido_log_debug("%s: fido_check_rp_id", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE, cred->uv) < 0) { fido_log_debug("%s: fido_check_flags", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (check_extensions(&cred->authdata_ext, &cred->ext) != 0) { fido_log_debug("%s: check_extensions", __func__); r = FIDO_ERR_INVALID_PARAM; goto out; } if (!strcmp(cred->fmt, "packed")) { if (fido_get_signed_hash(cred->attcred.type, &dgst, &cred->cdh, &cred->authdata_cbor) < 0) { fido_log_debug("%s: fido_get_signed_hash", __func__); r = FIDO_ERR_INTERNAL; goto out; } } else if (!strcmp(cred->fmt, "fido-u2f")) { if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash, sizeof(cred->authdata.rp_id_hash), &cred->cdh, &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) { fido_log_debug("%s: get_signed_hash_u2f", __func__); r = FIDO_ERR_INTERNAL; goto out; } } else { fido_log_debug("%s: unknown fmt %s", __func__, cred->fmt); r = FIDO_ERR_INVALID_ARGUMENT; goto out; } switch (cred->attcred.type) { case COSE_ES256: - ok = fido_verify_sig_es256(&dgst, &cred->attcred.pubkey.es256, + ok = es256_pk_verify_sig(&dgst, &cred->attcred.pubkey.es256, &cred->attstmt.sig); break; case COSE_RS256: - ok = fido_verify_sig_rs256(&dgst, &cred->attcred.pubkey.rs256, + ok = rs256_pk_verify_sig(&dgst, &cred->attcred.pubkey.rs256, &cred->attstmt.sig); break; case COSE_EDDSA: - ok = fido_verify_sig_eddsa(&dgst, &cred->attcred.pubkey.eddsa, + ok = eddsa_pk_verify_sig(&dgst, &cred->attcred.pubkey.eddsa, &cred->attstmt.sig); break; default: fido_log_debug("%s: unsupported cose_alg %d", __func__, cred->attcred.type); r = FIDO_ERR_UNSUPPORTED_OPTION; goto out; } if (ok < 0) r = FIDO_ERR_INVALID_SIG; else r = FIDO_OK; out: explicit_bzero(buf, sizeof(buf)); return (r); } fido_cred_t * fido_cred_new(void) { return (calloc(1, sizeof(fido_cred_t))); } static void fido_cred_clean_authdata(fido_cred_t *cred) { fido_blob_reset(&cred->authdata_cbor); fido_blob_reset(&cred->authdata_raw); fido_blob_reset(&cred->attcred.id); memset(&cred->authdata_ext, 0, sizeof(cred->authdata_ext)); memset(&cred->authdata, 0, sizeof(cred->authdata)); memset(&cred->attcred, 0, sizeof(cred->attcred)); } +static void +fido_cred_clean_attstmt(fido_attstmt_t *attstmt) +{ + fido_blob_reset(&attstmt->certinfo); + fido_blob_reset(&attstmt->pubarea); + fido_blob_reset(&attstmt->cbor); + fido_blob_reset(&attstmt->x5c); + fido_blob_reset(&attstmt->sig); + + memset(attstmt, 0, sizeof(*attstmt)); +} + void fido_cred_reset_tx(fido_cred_t *cred) { fido_blob_reset(&cred->cd); fido_blob_reset(&cred->cdh); fido_blob_reset(&cred->user.id); fido_blob_reset(&cred->blob); free(cred->rp.id); free(cred->rp.name); free(cred->user.icon); free(cred->user.name); free(cred->user.display_name); fido_free_blob_array(&cred->excl); memset(&cred->rp, 0, sizeof(cred->rp)); memset(&cred->user, 0, sizeof(cred->user)); memset(&cred->excl, 0, sizeof(cred->excl)); memset(&cred->ext, 0, sizeof(cred->ext)); cred->type = 0; cred->rk = FIDO_OPT_OMIT; cred->uv = FIDO_OPT_OMIT; } void fido_cred_reset_rx(fido_cred_t *cred) { free(cred->fmt); cred->fmt = NULL; fido_cred_clean_authdata(cred); - fido_blob_reset(&cred->attstmt.x5c); - fido_blob_reset(&cred->attstmt.sig); + fido_cred_clean_attstmt(&cred->attstmt); fido_blob_reset(&cred->largeblob_key); } void fido_cred_free(fido_cred_t **cred_p) { fido_cred_t *cred; if (cred_p == NULL || (cred = *cred_p) == NULL) return; fido_cred_reset_tx(cred); fido_cred_reset_rx(cred); free(cred); *cred_p = NULL; } int fido_cred_set_authdata(fido_cred_t *cred, const unsigned char *ptr, size_t len) { cbor_item_t *item = NULL; struct cbor_load_result cbor; int r = FIDO_ERR_INVALID_ARGUMENT; fido_cred_clean_authdata(cred); if (ptr == NULL || len == 0) goto fail; if ((item = cbor_load(ptr, len, &cbor)) == NULL) { fido_log_debug("%s: cbor_load", __func__); goto fail; } if (fido_blob_decode(item, &cred->authdata_raw) < 0) { fido_log_debug("%s: fido_blob_decode", __func__); goto fail; } if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor, &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) { fido_log_debug("%s: cbor_decode_cred_authdata", __func__); goto fail; } r = FIDO_OK; fail: if (item != NULL) cbor_decref(&item); if (r != FIDO_OK) fido_cred_clean_authdata(cred); return (r); - } int fido_cred_set_authdata_raw(fido_cred_t *cred, const unsigned char *ptr, size_t len) { cbor_item_t *item = NULL; int r = FIDO_ERR_INVALID_ARGUMENT; fido_cred_clean_authdata(cred); if (ptr == NULL || len == 0) goto fail; if (fido_blob_set(&cred->authdata_raw, ptr, len) < 0) { fido_log_debug("%s: fido_blob_set", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if ((item = cbor_build_bytestring(ptr, len)) == NULL) { fido_log_debug("%s: cbor_build_bytestring", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor, &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) { fido_log_debug("%s: cbor_decode_cred_authdata", __func__); goto fail; } r = FIDO_OK; fail: if (item != NULL) cbor_decref(&item); if (r != FIDO_OK) fido_cred_clean_authdata(cred); return (r); - } int fido_cred_set_id(fido_cred_t *cred, const unsigned char *ptr, size_t len) { if (fido_blob_set(&cred->attcred.id, ptr, len) < 0) return (FIDO_ERR_INVALID_ARGUMENT); return (FIDO_OK); } int fido_cred_set_x509(fido_cred_t *cred, const unsigned char *ptr, size_t len) { if (fido_blob_set(&cred->attstmt.x5c, ptr, len) < 0) return (FIDO_ERR_INVALID_ARGUMENT); return (FIDO_OK); } int fido_cred_set_sig(fido_cred_t *cred, const unsigned char *ptr, size_t len) { if (fido_blob_set(&cred->attstmt.sig, ptr, len) < 0) return (FIDO_ERR_INVALID_ARGUMENT); return (FIDO_OK); } +int +fido_cred_set_attstmt(fido_cred_t *cred, const unsigned char *ptr, size_t len) +{ + cbor_item_t *item = NULL; + struct cbor_load_result cbor; + int r = FIDO_ERR_INVALID_ARGUMENT; + + fido_cred_clean_attstmt(&cred->attstmt); + + if (ptr == NULL || len == 0) + goto fail; + + if ((item = cbor_load(ptr, len, &cbor)) == NULL) { + fido_log_debug("%s: cbor_load", __func__); + goto fail; + } + + if (cbor_decode_attstmt(item, &cred->attstmt) < 0) { + fido_log_debug("%s: cbor_decode_attstmt", __func__); + goto fail; + } + + r = FIDO_OK; +fail: + if (item != NULL) + cbor_decref(&item); + + if (r != FIDO_OK) + fido_cred_clean_attstmt(&cred->attstmt); + + return (r); +} + int fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len) { fido_blob_t id_blob; fido_blob_t *list_ptr; memset(&id_blob, 0, sizeof(id_blob)); if (fido_blob_set(&id_blob, id_ptr, id_len) < 0) return (FIDO_ERR_INVALID_ARGUMENT); if (cred->excl.len == SIZE_MAX) { free(id_blob.ptr); return (FIDO_ERR_INVALID_ARGUMENT); } if ((list_ptr = recallocarray(cred->excl.ptr, cred->excl.len, cred->excl.len + 1, sizeof(fido_blob_t))) == NULL) { free(id_blob.ptr); return (FIDO_ERR_INTERNAL); } list_ptr[cred->excl.len++] = id_blob; cred->excl.ptr = list_ptr; return (FIDO_OK); } int fido_cred_set_clientdata(fido_cred_t *cred, const unsigned char *data, size_t data_len) { if (!fido_blob_is_empty(&cred->cdh) || fido_blob_set(&cred->cd, data, data_len) < 0) { return (FIDO_ERR_INVALID_ARGUMENT); } if (fido_sha256(&cred->cdh, data, data_len) < 0) { fido_blob_reset(&cred->cd); return (FIDO_ERR_INTERNAL); } return (FIDO_OK); } int fido_cred_set_clientdata_hash(fido_cred_t *cred, const unsigned char *hash, size_t hash_len) { if (!fido_blob_is_empty(&cred->cd) || fido_blob_set(&cred->cdh, hash, hash_len) < 0) return (FIDO_ERR_INVALID_ARGUMENT); return (FIDO_OK); } int fido_cred_set_rp(fido_cred_t *cred, const char *id, const char *name) { fido_rp_t *rp = &cred->rp; if (rp->id != NULL) { free(rp->id); rp->id = NULL; } if (rp->name != NULL) { free(rp->name); rp->name = NULL; } if (id != NULL && (rp->id = strdup(id)) == NULL) goto fail; if (name != NULL && (rp->name = strdup(name)) == NULL) goto fail; return (FIDO_OK); fail: free(rp->id); free(rp->name); rp->id = NULL; rp->name = NULL; return (FIDO_ERR_INTERNAL); } int 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) { fido_user_t *up = &cred->user; if (up->id.ptr != NULL) { free(up->id.ptr); up->id.ptr = NULL; up->id.len = 0; } if (up->name != NULL) { free(up->name); up->name = NULL; } if (up->display_name != NULL) { free(up->display_name); up->display_name = NULL; } if (up->icon != NULL) { free(up->icon); up->icon = NULL; } if (user_id != NULL && fido_blob_set(&up->id, user_id, user_id_len) < 0) goto fail; if (name != NULL && (up->name = strdup(name)) == NULL) goto fail; if (display_name != NULL && (up->display_name = strdup(display_name)) == NULL) goto fail; if (icon != NULL && (up->icon = strdup(icon)) == NULL) goto fail; return (FIDO_OK); fail: free(up->id.ptr); free(up->name); free(up->display_name); free(up->icon); up->id.ptr = NULL; up->id.len = 0; up->name = NULL; up->display_name = NULL; up->icon = NULL; return (FIDO_ERR_INTERNAL); } int fido_cred_set_extensions(fido_cred_t *cred, int ext) { if (ext == 0) cred->ext.mask = 0; else { if ((ext & FIDO_EXT_CRED_MASK) != ext) return (FIDO_ERR_INVALID_ARGUMENT); cred->ext.mask |= ext; } return (FIDO_OK); } int fido_cred_set_options(fido_cred_t *cred, bool rk, bool uv) { cred->rk = rk ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; cred->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE; return (FIDO_OK); } int fido_cred_set_rk(fido_cred_t *cred, fido_opt_t rk) { cred->rk = rk; return (FIDO_OK); } int fido_cred_set_uv(fido_cred_t *cred, fido_opt_t uv) { cred->uv = uv; return (FIDO_OK); } int fido_cred_set_prot(fido_cred_t *cred, int prot) { if (prot == 0) { cred->ext.mask &= ~FIDO_EXT_CRED_PROTECT; cred->ext.prot = 0; } else { if (prot != FIDO_CRED_PROT_UV_OPTIONAL && prot != FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID && prot != FIDO_CRED_PROT_UV_REQUIRED) return (FIDO_ERR_INVALID_ARGUMENT); cred->ext.mask |= FIDO_EXT_CRED_PROTECT; cred->ext.prot = prot; } return (FIDO_OK); } +int +fido_cred_set_pin_minlen(fido_cred_t *cred, size_t len) +{ + if (len == 0) + cred->ext.mask &= ~FIDO_EXT_MINPINLEN; + else + cred->ext.mask |= FIDO_EXT_MINPINLEN; + + cred->ext.minpinlen = len; + + return (FIDO_OK); +} + int fido_cred_set_blob(fido_cred_t *cred, const unsigned char *ptr, size_t len) { if (ptr == NULL || len == 0) return (FIDO_ERR_INVALID_ARGUMENT); if (fido_blob_set(&cred->blob, ptr, len) < 0) return (FIDO_ERR_INTERNAL); cred->ext.mask |= FIDO_EXT_CRED_BLOB; return (FIDO_OK); } int fido_cred_set_fmt(fido_cred_t *cred, const char *fmt) { free(cred->fmt); cred->fmt = NULL; if (fmt == NULL) return (FIDO_ERR_INVALID_ARGUMENT); if (strcmp(fmt, "packed") && strcmp(fmt, "fido-u2f") && - strcmp(fmt, "none")) + strcmp(fmt, "none") && strcmp(fmt, "tpm")) return (FIDO_ERR_INVALID_ARGUMENT); if ((cred->fmt = strdup(fmt)) == NULL) return (FIDO_ERR_INTERNAL); return (FIDO_OK); } int fido_cred_set_type(fido_cred_t *cred, int cose_alg) { if ((cose_alg != COSE_ES256 && cose_alg != COSE_RS256 && cose_alg != COSE_EDDSA) || cred->type != 0) return (FIDO_ERR_INVALID_ARGUMENT); cred->type = cose_alg; return (FIDO_OK); } int fido_cred_type(const fido_cred_t *cred) { return (cred->type); } uint8_t fido_cred_flags(const fido_cred_t *cred) { return (cred->authdata.flags); } uint32_t fido_cred_sigcount(const fido_cred_t *cred) { return (cred->authdata.sigcount); } const unsigned char * fido_cred_clientdata_hash_ptr(const fido_cred_t *cred) { return (cred->cdh.ptr); } size_t fido_cred_clientdata_hash_len(const fido_cred_t *cred) { return (cred->cdh.len); } const unsigned char * fido_cred_x5c_ptr(const fido_cred_t *cred) { return (cred->attstmt.x5c.ptr); } size_t fido_cred_x5c_len(const fido_cred_t *cred) { return (cred->attstmt.x5c.len); } const unsigned char * fido_cred_sig_ptr(const fido_cred_t *cred) { return (cred->attstmt.sig.ptr); } size_t fido_cred_sig_len(const fido_cred_t *cred) { return (cred->attstmt.sig.len); } const unsigned char * fido_cred_authdata_ptr(const fido_cred_t *cred) { return (cred->authdata_cbor.ptr); } size_t fido_cred_authdata_len(const fido_cred_t *cred) { return (cred->authdata_cbor.len); } const unsigned char * fido_cred_authdata_raw_ptr(const fido_cred_t *cred) { return (cred->authdata_raw.ptr); } size_t fido_cred_authdata_raw_len(const fido_cred_t *cred) { return (cred->authdata_raw.len); } +const unsigned char * +fido_cred_attstmt_ptr(const fido_cred_t *cred) +{ + return (cred->attstmt.cbor.ptr); +} + +size_t +fido_cred_attstmt_len(const fido_cred_t *cred) +{ + return (cred->attstmt.cbor.len); +} + const unsigned char * fido_cred_pubkey_ptr(const fido_cred_t *cred) { const void *ptr; switch (cred->attcred.type) { case COSE_ES256: ptr = &cred->attcred.pubkey.es256; break; case COSE_RS256: ptr = &cred->attcred.pubkey.rs256; break; case COSE_EDDSA: ptr = &cred->attcred.pubkey.eddsa; break; default: ptr = NULL; break; } return (ptr); } size_t fido_cred_pubkey_len(const fido_cred_t *cred) { size_t len; switch (cred->attcred.type) { case COSE_ES256: len = sizeof(cred->attcred.pubkey.es256); break; case COSE_RS256: len = sizeof(cred->attcred.pubkey.rs256); break; case COSE_EDDSA: len = sizeof(cred->attcred.pubkey.eddsa); break; default: len = 0; break; } return (len); } const unsigned char * fido_cred_id_ptr(const fido_cred_t *cred) { return (cred->attcred.id.ptr); } size_t fido_cred_id_len(const fido_cred_t *cred) { return (cred->attcred.id.len); } const unsigned char * fido_cred_aaguid_ptr(const fido_cred_t *cred) { return (cred->attcred.aaguid); } size_t fido_cred_aaguid_len(const fido_cred_t *cred) { return (sizeof(cred->attcred.aaguid)); } int fido_cred_prot(const fido_cred_t *cred) { return (cred->ext.prot); } +size_t +fido_cred_pin_minlen(const fido_cred_t *cred) +{ + return (cred->ext.minpinlen); +} + const char * fido_cred_fmt(const fido_cred_t *cred) { return (cred->fmt); } const char * fido_cred_rp_id(const fido_cred_t *cred) { return (cred->rp.id); } const char * fido_cred_rp_name(const fido_cred_t *cred) { return (cred->rp.name); } const char * fido_cred_user_name(const fido_cred_t *cred) { return (cred->user.name); } const char * fido_cred_display_name(const fido_cred_t *cred) { return (cred->user.display_name); } const unsigned char * fido_cred_user_id_ptr(const fido_cred_t *cred) { return (cred->user.id.ptr); } size_t fido_cred_user_id_len(const fido_cred_t *cred) { return (cred->user.id.len); } const unsigned char * fido_cred_largeblob_key_ptr(const fido_cred_t *cred) { return (cred->largeblob_key.ptr); } size_t fido_cred_largeblob_key_len(const fido_cred_t *cred) { return (cred->largeblob_key.len); } diff --git a/contrib/libfido2/src/credman.c b/contrib/libfido2/src/credman.c index e48ca4543b10..8d2649a144f2 100644 --- a/contrib/libfido2/src/credman.c +++ b/contrib/libfido2/src/credman.c @@ -1,767 +1,777 @@ /* * Copyright (c) 2019-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include "fido.h" #include "fido/credman.h" #include "fido/es256.h" #define CMD_CRED_METADATA 0x01 #define CMD_RP_BEGIN 0x02 #define CMD_RP_NEXT 0x03 #define CMD_RK_BEGIN 0x04 #define CMD_RK_NEXT 0x05 #define CMD_DELETE_CRED 0x06 #define CMD_UPDATE_CRED 0x07 static int credman_grow_array(void **ptr, size_t *n_alloc, size_t *n_rx, size_t n, size_t size) { void *new_ptr; #ifdef FIDO_FUZZ if (n > UINT8_MAX) { fido_log_debug("%s: n > UINT8_MAX", __func__); return (-1); } #endif if (n < *n_alloc) return (0); /* sanity check */ if (*n_rx > 0 || *n_rx > *n_alloc || n < *n_alloc) { fido_log_debug("%s: n=%zu, n_rx=%zu, n_alloc=%zu", __func__, n, *n_rx, *n_alloc); return (-1); } if ((new_ptr = recallocarray(*ptr, *n_alloc, n, size)) == NULL) return (-1); *ptr = new_ptr; *n_alloc = n; return (0); } static int credman_prepare_hmac(uint8_t cmd, const void *body, cbor_item_t **param, fido_blob_t *hmac_data) { cbor_item_t *param_cbor[3]; const fido_cred_t *cred; size_t n; int ok = -1; memset(¶m_cbor, 0, sizeof(param_cbor)); if (body == NULL) return (fido_blob_set(hmac_data, &cmd, sizeof(cmd))); switch (cmd) { case CMD_RK_BEGIN: n = 1; if ((param_cbor[0] = fido_blob_encode(body)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } break; case CMD_DELETE_CRED: n = 2; if ((param_cbor[1] = cbor_encode_pubkey(body)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } break; case CMD_UPDATE_CRED: n = 3; cred = body; param_cbor[1] = cbor_encode_pubkey(&cred->attcred.id); param_cbor[2] = cbor_encode_user_entity(&cred->user); if (param_cbor[1] == NULL || param_cbor[2] == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } break; default: fido_log_debug("%s: unknown cmd=0x%02x", __func__, cmd); return (-1); } if ((*param = cbor_flatten_vector(param_cbor, n)) == NULL) { fido_log_debug("%s: cbor_flatten_vector", __func__); goto fail; } if (cbor_build_frame(cmd, param_cbor, n, hmac_data) < 0) { fido_log_debug("%s: cbor_build_frame", __func__); goto fail; } ok = 0; fail: cbor_vector_free(param_cbor, nitems(param_cbor)); return (ok); } static int credman_tx(fido_dev_t *dev, uint8_t subcmd, const void *param, const char *pin, - const char *rp_id, fido_opt_t uv) + const char *rp_id, fido_opt_t uv, int *ms) { fido_blob_t f; fido_blob_t *ecdh = NULL; fido_blob_t hmac; es256_pk_t *pk = NULL; cbor_item_t *argv[4]; const uint8_t cmd = CTAP_CBOR_CRED_MGMT_PRE; int r = FIDO_ERR_INTERNAL; memset(&f, 0, sizeof(f)); memset(&hmac, 0, sizeof(hmac)); memset(&argv, 0, sizeof(argv)); if (fido_dev_is_fido2(dev) == false) { fido_log_debug("%s: fido_dev_is_fido2", __func__); r = FIDO_ERR_INVALID_COMMAND; goto fail; } /* subCommand */ if ((argv[0] = cbor_build_uint8(subcmd)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } /* pinProtocol, pinAuth */ if (pin != NULL || uv == FIDO_OPT_TRUE) { if (credman_prepare_hmac(subcmd, param, &argv[1], &hmac) < 0) { fido_log_debug("%s: credman_prepare_hmac", __func__); goto fail; } - if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { + if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin, - rp_id, &argv[3], &argv[2])) != FIDO_OK) { + rp_id, &argv[3], &argv[2], ms)) != FIDO_OK) { fido_log_debug("%s: cbor_add_uv_params", __func__); goto fail; } } /* framing and transmission */ if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 || - fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { + fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: es256_pk_free(&pk); fido_blob_free(&ecdh); cbor_vector_free(argv, nitems(argv)); free(f.ptr); free(hmac.ptr); return (r); } static int credman_parse_metadata(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_credman_metadata_t *metadata = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 1: return (cbor_decode_uint64(val, &metadata->rk_existing)); case 2: return (cbor_decode_uint64(val, &metadata->rk_remaining)); default: fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } } static int -credman_rx_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, int ms) +credman_rx_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; int r; memset(metadata, 0, sizeof(*metadata)); if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, metadata, credman_parse_metadata)) != FIDO_OK) { fido_log_debug("%s: credman_parse_metadata", __func__); return (r); } return (FIDO_OK); } static int credman_get_metadata_wait(fido_dev_t *dev, fido_credman_metadata_t *metadata, - const char *pin, int ms) + const char *pin, int *ms) { int r; if ((r = credman_tx(dev, CMD_CRED_METADATA, NULL, pin, NULL, - FIDO_OPT_TRUE)) != FIDO_OK || + FIDO_OPT_TRUE, ms)) != FIDO_OK || (r = credman_rx_metadata(dev, metadata, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_credman_get_dev_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, const char *pin) { - return (credman_get_metadata_wait(dev, metadata, pin, -1)); + int ms = dev->timeout_ms; + + return (credman_get_metadata_wait(dev, metadata, pin, &ms)); } static int credman_parse_rk(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_cred_t *cred = arg; uint64_t prot; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 6: return (cbor_decode_user(val, &cred->user)); case 7: return (cbor_decode_cred_id(val, &cred->attcred.id)); case 8: if (cbor_decode_pubkey(val, &cred->attcred.type, &cred->attcred.pubkey) < 0) return (-1); cred->type = cred->attcred.type; /* XXX */ return (0); case 10: if (cbor_decode_uint64(val, &prot) < 0 || prot > INT_MAX || fido_cred_set_prot(cred, (int)prot) != FIDO_OK) return (-1); return (0); case 11: return (fido_blob_decode(val, &cred->largeblob_key)); default: fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } } static void credman_reset_rk(fido_credman_rk_t *rk) { for (size_t i = 0; i < rk->n_alloc; i++) { fido_cred_reset_tx(&rk->ptr[i]); fido_cred_reset_rx(&rk->ptr[i]); } free(rk->ptr); rk->ptr = NULL; memset(rk, 0, sizeof(*rk)); } static int credman_parse_rk_count(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_credman_rk_t *rk = arg; uint64_t n; /* totalCredentials */ if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != 9) { fido_log_debug("%s: cbor_type", __func__); return (0); /* ignore */ } if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) { fido_log_debug("%s: cbor_decode_uint64", __func__); return (-1); } if (credman_grow_array((void **)&rk->ptr, &rk->n_alloc, &rk->n_rx, (size_t)n, sizeof(*rk->ptr)) < 0) { fido_log_debug("%s: credman_grow_array", __func__); return (-1); } return (0); } static int -credman_rx_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms) +credman_rx_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; int r; credman_reset_rk(rk); if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } /* adjust as needed */ if ((r = cbor_parse_reply(reply, (size_t)reply_len, rk, credman_parse_rk_count)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rk_count", __func__); return (r); } if (rk->n_alloc == 0) { fido_log_debug("%s: n_alloc=0", __func__); return (FIDO_OK); } /* parse the first rk */ if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rk->ptr[0], credman_parse_rk)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rk", __func__); return (r); } rk->n_rx++; return (FIDO_OK); } static int -credman_rx_next_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms) +credman_rx_next_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; int r; if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } /* sanity check */ if (rk->n_rx >= rk->n_alloc) { fido_log_debug("%s: n_rx=%zu, n_alloc=%zu", __func__, rk->n_rx, rk->n_alloc); return (FIDO_ERR_INTERNAL); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rk->ptr[rk->n_rx], credman_parse_rk)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rk", __func__); return (r); } return (FIDO_OK); } static int credman_get_rk_wait(fido_dev_t *dev, const char *rp_id, fido_credman_rk_t *rk, - const char *pin, int ms) + const char *pin, int *ms) { fido_blob_t rp_dgst; uint8_t dgst[SHA256_DIGEST_LENGTH]; int r; if (SHA256((const unsigned char *)rp_id, strlen(rp_id), dgst) != dgst) { fido_log_debug("%s: sha256", __func__); return (FIDO_ERR_INTERNAL); } rp_dgst.ptr = dgst; rp_dgst.len = sizeof(dgst); if ((r = credman_tx(dev, CMD_RK_BEGIN, &rp_dgst, pin, rp_id, - FIDO_OPT_TRUE)) != FIDO_OK || + FIDO_OPT_TRUE, ms)) != FIDO_OK || (r = credman_rx_rk(dev, rk, ms)) != FIDO_OK) return (r); while (rk->n_rx < rk->n_alloc) { if ((r = credman_tx(dev, CMD_RK_NEXT, NULL, NULL, NULL, - FIDO_OPT_FALSE)) != FIDO_OK || + FIDO_OPT_FALSE, ms)) != FIDO_OK || (r = credman_rx_next_rk(dev, rk, ms)) != FIDO_OK) return (r); rk->n_rx++; } return (FIDO_OK); } int fido_credman_get_dev_rk(fido_dev_t *dev, const char *rp_id, fido_credman_rk_t *rk, const char *pin) { - return (credman_get_rk_wait(dev, rp_id, rk, pin, -1)); + int ms = dev->timeout_ms; + + return (credman_get_rk_wait(dev, rp_id, rk, pin, &ms)); } static int credman_del_rk_wait(fido_dev_t *dev, const unsigned char *cred_id, - size_t cred_id_len, const char *pin, int ms) + size_t cred_id_len, const char *pin, int *ms) { fido_blob_t cred; int r; memset(&cred, 0, sizeof(cred)); if (fido_blob_set(&cred, cred_id, cred_id_len) < 0) return (FIDO_ERR_INVALID_ARGUMENT); if ((r = credman_tx(dev, CMD_DELETE_CRED, &cred, pin, NULL, - FIDO_OPT_TRUE)) != FIDO_OK || + FIDO_OPT_TRUE, ms)) != FIDO_OK || (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) goto fail; r = FIDO_OK; fail: free(cred.ptr); return (r); } int fido_credman_del_dev_rk(fido_dev_t *dev, const unsigned char *cred_id, size_t cred_id_len, const char *pin) { - return (credman_del_rk_wait(dev, cred_id, cred_id_len, pin, -1)); + int ms = dev->timeout_ms; + + return (credman_del_rk_wait(dev, cred_id, cred_id_len, pin, &ms)); } static int credman_parse_rp(const cbor_item_t *key, const cbor_item_t *val, void *arg) { struct fido_credman_single_rp *rp = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 3: return (cbor_decode_rp_entity(val, &rp->rp_entity)); case 4: return (fido_blob_decode(val, &rp->rp_id_hash)); default: fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } } static void credman_reset_rp(fido_credman_rp_t *rp) { for (size_t i = 0; i < rp->n_alloc; i++) { free(rp->ptr[i].rp_entity.id); free(rp->ptr[i].rp_entity.name); rp->ptr[i].rp_entity.id = NULL; rp->ptr[i].rp_entity.name = NULL; fido_blob_reset(&rp->ptr[i].rp_id_hash); } free(rp->ptr); rp->ptr = NULL; memset(rp, 0, sizeof(*rp)); } static int credman_parse_rp_count(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_credman_rp_t *rp = arg; uint64_t n; /* totalRPs */ if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != 5) { fido_log_debug("%s: cbor_type", __func__); return (0); /* ignore */ } if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) { fido_log_debug("%s: cbor_decode_uint64", __func__); return (-1); } if (credman_grow_array((void **)&rp->ptr, &rp->n_alloc, &rp->n_rx, (size_t)n, sizeof(*rp->ptr)) < 0) { fido_log_debug("%s: credman_grow_array", __func__); return (-1); } return (0); } static int -credman_rx_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms) +credman_rx_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; int r; credman_reset_rp(rp); if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } /* adjust as needed */ if ((r = cbor_parse_reply(reply, (size_t)reply_len, rp, credman_parse_rp_count)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rp_count", __func__); return (r); } if (rp->n_alloc == 0) { fido_log_debug("%s: n_alloc=0", __func__); return (FIDO_OK); } /* parse the first rp */ if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rp->ptr[0], credman_parse_rp)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rp", __func__); return (r); } rp->n_rx++; return (FIDO_OK); } static int -credman_rx_next_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms) +credman_rx_next_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; int r; if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } /* sanity check */ if (rp->n_rx >= rp->n_alloc) { fido_log_debug("%s: n_rx=%zu, n_alloc=%zu", __func__, rp->n_rx, rp->n_alloc); return (FIDO_ERR_INTERNAL); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rp->ptr[rp->n_rx], credman_parse_rp)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rp", __func__); return (r); } return (FIDO_OK); } static int credman_get_rp_wait(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin, - int ms) + int *ms) { int r; if ((r = credman_tx(dev, CMD_RP_BEGIN, NULL, pin, NULL, - FIDO_OPT_TRUE)) != FIDO_OK || + FIDO_OPT_TRUE, ms)) != FIDO_OK || (r = credman_rx_rp(dev, rp, ms)) != FIDO_OK) return (r); while (rp->n_rx < rp->n_alloc) { if ((r = credman_tx(dev, CMD_RP_NEXT, NULL, NULL, NULL, - FIDO_OPT_FALSE)) != FIDO_OK || + FIDO_OPT_FALSE, ms)) != FIDO_OK || (r = credman_rx_next_rp(dev, rp, ms)) != FIDO_OK) return (r); rp->n_rx++; } return (FIDO_OK); } int fido_credman_get_dev_rp(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin) { - return (credman_get_rp_wait(dev, rp, pin, -1)); + int ms = dev->timeout_ms; + + return (credman_get_rp_wait(dev, rp, pin, &ms)); } static int credman_set_dev_rk_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin, - int ms) + int *ms) { int r; if ((r = credman_tx(dev, CMD_UPDATE_CRED, cred, pin, NULL, - FIDO_OPT_TRUE)) != FIDO_OK || + FIDO_OPT_TRUE, ms)) != FIDO_OK || (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_credman_set_dev_rk(fido_dev_t *dev, fido_cred_t *cred, const char *pin) { - return (credman_set_dev_rk_wait(dev, cred, pin, -1)); + int ms = dev->timeout_ms; + + return (credman_set_dev_rk_wait(dev, cred, pin, &ms)); } fido_credman_rk_t * fido_credman_rk_new(void) { return (calloc(1, sizeof(fido_credman_rk_t))); } void fido_credman_rk_free(fido_credman_rk_t **rk_p) { fido_credman_rk_t *rk; if (rk_p == NULL || (rk = *rk_p) == NULL) return; credman_reset_rk(rk); free(rk); *rk_p = NULL; } size_t fido_credman_rk_count(const fido_credman_rk_t *rk) { return (rk->n_rx); } const fido_cred_t * fido_credman_rk(const fido_credman_rk_t *rk, size_t idx) { if (idx >= rk->n_alloc) return (NULL); return (&rk->ptr[idx]); } fido_credman_metadata_t * fido_credman_metadata_new(void) { return (calloc(1, sizeof(fido_credman_metadata_t))); } void fido_credman_metadata_free(fido_credman_metadata_t **metadata_p) { fido_credman_metadata_t *metadata; if (metadata_p == NULL || (metadata = *metadata_p) == NULL) return; free(metadata); *metadata_p = NULL; } uint64_t fido_credman_rk_existing(const fido_credman_metadata_t *metadata) { return (metadata->rk_existing); } uint64_t fido_credman_rk_remaining(const fido_credman_metadata_t *metadata) { return (metadata->rk_remaining); } fido_credman_rp_t * fido_credman_rp_new(void) { return (calloc(1, sizeof(fido_credman_rp_t))); } void fido_credman_rp_free(fido_credman_rp_t **rp_p) { fido_credman_rp_t *rp; if (rp_p == NULL || (rp = *rp_p) == NULL) return; credman_reset_rp(rp); free(rp); *rp_p = NULL; } size_t fido_credman_rp_count(const fido_credman_rp_t *rp) { return (rp->n_rx); } const char * fido_credman_rp_id(const fido_credman_rp_t *rp, size_t idx) { if (idx >= rp->n_alloc) return (NULL); return (rp->ptr[idx].rp_entity.id); } const char * fido_credman_rp_name(const fido_credman_rp_t *rp, size_t idx) { if (idx >= rp->n_alloc) return (NULL); return (rp->ptr[idx].rp_entity.name); } size_t fido_credman_rp_id_hash_len(const fido_credman_rp_t *rp, size_t idx) { if (idx >= rp->n_alloc) return (0); return (rp->ptr[idx].rp_id_hash.len); } const unsigned char * fido_credman_rp_id_hash_ptr(const fido_credman_rp_t *rp, size_t idx) { if (idx >= rp->n_alloc) return (NULL); return (rp->ptr[idx].rp_id_hash.ptr); } diff --git a/contrib/libfido2/src/dev.c b/contrib/libfido2/src/dev.c index a003854f89d2..0c3cf64a462b 100644 --- a/contrib/libfido2/src/dev.c +++ b/contrib/libfido2/src/dev.c @@ -1,732 +1,749 @@ /* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include "fido.h" #ifndef TLS #define TLS #endif typedef struct dev_manifest_func_node { dev_manifest_func_t manifest_func; struct dev_manifest_func_node *next; } dev_manifest_func_node_t; static TLS dev_manifest_func_node_t *manifest_funcs = NULL; static TLS bool disable_u2f_fallback; static void find_manifest_func_node(dev_manifest_func_t f, dev_manifest_func_node_t **curr, dev_manifest_func_node_t **prev) { *prev = NULL; *curr = manifest_funcs; while (*curr != NULL && (*curr)->manifest_func != f) { *prev = *curr; *curr = (*curr)->next; } } #ifdef FIDO_FUZZ static void set_random_report_len(fido_dev_t *dev) { dev->rx_len = CTAP_MIN_REPORT_LEN + uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1); dev->tx_len = CTAP_MIN_REPORT_LEN + uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1); } #endif static void fido_dev_set_extension_flags(fido_dev_t *dev, const fido_cbor_info_t *info) { char * const *ptr = fido_cbor_info_extensions_ptr(info); size_t len = fido_cbor_info_extensions_len(info); for (size_t i = 0; i < len; i++) if (strcmp(ptr[i], "credProtect") == 0) dev->flags |= FIDO_DEV_CRED_PROT; } static void fido_dev_set_option_flags(fido_dev_t *dev, const fido_cbor_info_t *info) { char * const *ptr = fido_cbor_info_options_name_ptr(info); const bool *val = fido_cbor_info_options_value_ptr(info); size_t len = fido_cbor_info_options_len(info); for (size_t i = 0; i < len; i++) if (strcmp(ptr[i], "clientPin") == 0) { dev->flags |= val[i] ? FIDO_DEV_PIN_SET : FIDO_DEV_PIN_UNSET; } else if (strcmp(ptr[i], "credMgmt") == 0 || strcmp(ptr[i], "credentialMgmtPreview") == 0) { if (val[i]) dev->flags |= FIDO_DEV_CREDMAN; } else if (strcmp(ptr[i], "uv") == 0) { dev->flags |= val[i] ? FIDO_DEV_UV_SET : FIDO_DEV_UV_UNSET; } else if (strcmp(ptr[i], "pinUvAuthToken") == 0) { if (val[i]) dev->flags |= FIDO_DEV_TOKEN_PERMS; } } static void fido_dev_set_protocol_flags(fido_dev_t *dev, const fido_cbor_info_t *info) { const uint8_t *ptr = fido_cbor_info_protocols_ptr(info); size_t len = fido_cbor_info_protocols_len(info); for (size_t i = 0; i < len; i++) switch (ptr[i]) { case CTAP_PIN_PROTOCOL1: dev->flags |= FIDO_DEV_PIN_PROTOCOL1; break; case CTAP_PIN_PROTOCOL2: dev->flags |= FIDO_DEV_PIN_PROTOCOL2; break; default: fido_log_debug("%s: unknown protocol %u", __func__, ptr[i]); break; } } static void fido_dev_set_flags(fido_dev_t *dev, const fido_cbor_info_t *info) { fido_dev_set_extension_flags(dev, info); fido_dev_set_option_flags(dev, info); fido_dev_set_protocol_flags(dev, info); } static int -fido_dev_open_tx(fido_dev_t *dev, const char *path) +fido_dev_open_tx(fido_dev_t *dev, const char *path, int *ms) { int r; if (dev->io_handle != NULL) { fido_log_debug("%s: handle=%p", __func__, dev->io_handle); return (FIDO_ERR_INVALID_ARGUMENT); } if (dev->io.open == NULL || dev->io.close == NULL) { fido_log_debug("%s: NULL open/close", __func__); return (FIDO_ERR_INVALID_ARGUMENT); } if (dev->cid != CTAP_CID_BROADCAST) { fido_log_debug("%s: cid=0x%x", __func__, dev->cid); return (FIDO_ERR_INVALID_ARGUMENT); } if (fido_get_random(&dev->nonce, sizeof(dev->nonce)) < 0) { fido_log_debug("%s: fido_get_random", __func__); return (FIDO_ERR_INTERNAL); } if ((dev->io_handle = dev->io.open(path)) == NULL) { fido_log_debug("%s: dev->io.open", __func__); return (FIDO_ERR_INTERNAL); } if (dev->io_own) { dev->rx_len = CTAP_MAX_REPORT_LEN; dev->tx_len = CTAP_MAX_REPORT_LEN; } else { dev->rx_len = fido_hid_report_in_len(dev->io_handle); dev->tx_len = fido_hid_report_out_len(dev->io_handle); } #ifdef FIDO_FUZZ set_random_report_len(dev); #endif if (dev->rx_len < CTAP_MIN_REPORT_LEN || dev->rx_len > CTAP_MAX_REPORT_LEN) { fido_log_debug("%s: invalid rx_len %zu", __func__, dev->rx_len); r = FIDO_ERR_RX; goto fail; } if (dev->tx_len < CTAP_MIN_REPORT_LEN || dev->tx_len > CTAP_MAX_REPORT_LEN) { fido_log_debug("%s: invalid tx_len %zu", __func__, dev->tx_len); r = FIDO_ERR_TX; goto fail; } - if (fido_tx(dev, CTAP_CMD_INIT, &dev->nonce, sizeof(dev->nonce)) < 0) { + if (fido_tx(dev, CTAP_CMD_INIT, &dev->nonce, sizeof(dev->nonce), + ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } return (FIDO_OK); fail: dev->io.close(dev->io_handle); dev->io_handle = NULL; return (r); } static int -fido_dev_open_rx(fido_dev_t *dev, int ms) +fido_dev_open_rx(fido_dev_t *dev, int *ms) { fido_cbor_info_t *info = NULL; int reply_len; int r; if ((reply_len = fido_rx(dev, CTAP_CMD_INIT, &dev->attr, sizeof(dev->attr), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); r = FIDO_ERR_RX; goto fail; } #ifdef FIDO_FUZZ dev->attr.nonce = dev->nonce; #endif if ((size_t)reply_len != sizeof(dev->attr) || dev->attr.nonce != dev->nonce) { fido_log_debug("%s: invalid nonce", __func__); r = FIDO_ERR_RX; goto fail; } dev->flags = 0; dev->cid = dev->attr.cid; if (fido_dev_is_fido2(dev)) { if ((info = fido_cbor_info_new()) == NULL) { fido_log_debug("%s: fido_cbor_info_new", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if ((r = fido_dev_get_cbor_info_wait(dev, info, ms)) != FIDO_OK) { fido_log_debug("%s: fido_dev_cbor_info_wait: %d", __func__, r); if (disable_u2f_fallback) goto fail; fido_log_debug("%s: falling back to u2f", __func__); fido_dev_force_u2f(dev); } else { fido_dev_set_flags(dev, info); } } if (fido_dev_is_fido2(dev) && info != NULL) { dev->maxmsgsize = fido_cbor_info_maxmsgsiz(info); fido_log_debug("%s: FIDO_MAXMSG=%d, maxmsgsiz=%lu", __func__, FIDO_MAXMSG, (unsigned long)dev->maxmsgsize); } r = FIDO_OK; fail: fido_cbor_info_free(&info); if (r != FIDO_OK) { dev->io.close(dev->io_handle); dev->io_handle = NULL; } return (r); } static int -fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms) +fido_dev_open_wait(fido_dev_t *dev, const char *path, int *ms) { int r; #ifdef USE_WINHELLO if (strcmp(path, FIDO_WINHELLO_PATH) == 0) return (fido_winhello_open(dev)); #endif - if ((r = fido_dev_open_tx(dev, path)) != FIDO_OK || + if ((r = fido_dev_open_tx(dev, path, ms)) != FIDO_OK || (r = fido_dev_open_rx(dev, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_dev_register_manifest_func(const dev_manifest_func_t f) { dev_manifest_func_node_t *prev, *curr, *n; find_manifest_func_node(f, &curr, &prev); if (curr != NULL) return (FIDO_OK); if ((n = calloc(1, sizeof(*n))) == NULL) { fido_log_debug("%s: calloc", __func__); return (FIDO_ERR_INTERNAL); } n->manifest_func = f; n->next = manifest_funcs; manifest_funcs = n; return (FIDO_OK); } void fido_dev_unregister_manifest_func(const dev_manifest_func_t f) { dev_manifest_func_node_t *prev, *curr; find_manifest_func_node(f, &curr, &prev); if (curr == NULL) return; if (prev != NULL) prev->next = curr->next; else manifest_funcs = curr->next; free(curr); } int fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { dev_manifest_func_node_t *curr = NULL; dev_manifest_func_t m_func; size_t curr_olen; int r; *olen = 0; if (fido_dev_register_manifest_func(fido_hid_manifest) != FIDO_OK) return (FIDO_ERR_INTERNAL); #ifdef NFC_LINUX if (fido_dev_register_manifest_func(fido_nfc_manifest) != FIDO_OK) return (FIDO_ERR_INTERNAL); #endif #ifdef USE_WINHELLO if (fido_dev_register_manifest_func(fido_winhello_manifest) != FIDO_OK) return (FIDO_ERR_INTERNAL); #endif for (curr = manifest_funcs; curr != NULL; curr = curr->next) { curr_olen = 0; m_func = curr->manifest_func; r = m_func(devlist + *olen, ilen - *olen, &curr_olen); if (r != FIDO_OK) return (r); *olen += curr_olen; if (*olen == ilen) break; } return (FIDO_OK); } int fido_dev_open_with_info(fido_dev_t *dev) { + int ms = dev->timeout_ms; + if (dev->path == NULL) return (FIDO_ERR_INVALID_ARGUMENT); - return (fido_dev_open_wait(dev, dev->path, -1)); + return (fido_dev_open_wait(dev, dev->path, &ms)); } int fido_dev_open(fido_dev_t *dev, const char *path) { + int ms = dev->timeout_ms; + #ifdef NFC_LINUX - /* - * this is a hack to get existing applications up and running with nfc; - * it will *NOT* be part of a libfido2 release. to support nfc in your - * application, please change it to use fido_dev_open_with_info(). - */ - if (strncmp(path, "/sys", strlen("/sys")) == 0 && strlen(path) > 4 && - path[strlen(path) - 4] == 'n' && path[strlen(path) - 3] == 'f' && - path[strlen(path) - 2] == 'c') { + if (strncmp(path, FIDO_NFC_PREFIX, strlen(FIDO_NFC_PREFIX)) == 0) { dev->io_own = true; dev->io = (fido_dev_io_t) { fido_nfc_open, fido_nfc_close, fido_nfc_read, fido_nfc_write, }; dev->transport = (fido_dev_transport_t) { fido_nfc_rx, fido_nfc_tx, }; } #endif - return (fido_dev_open_wait(dev, path, -1)); + return (fido_dev_open_wait(dev, path, &ms)); } int fido_dev_close(fido_dev_t *dev) { #ifdef USE_WINHELLO if (dev->flags & FIDO_DEV_WINHELLO) return (fido_winhello_close(dev)); #endif if (dev->io_handle == NULL || dev->io.close == NULL) return (FIDO_ERR_INVALID_ARGUMENT); dev->io.close(dev->io_handle); dev->io_handle = NULL; dev->cid = CTAP_CID_BROADCAST; return (FIDO_OK); } int fido_dev_set_sigmask(fido_dev_t *dev, const fido_sigset_t *sigmask) { - if (dev->io_own || dev->io_handle == NULL || sigmask == NULL) + if (dev->io_handle == NULL || sigmask == NULL) return (FIDO_ERR_INVALID_ARGUMENT); #ifdef NFC_LINUX - if (dev->transport.rx == fido_nfc_rx) + if (dev->transport.rx == fido_nfc_rx && dev->io.read == fido_nfc_read) return (fido_nfc_set_sigmask(dev->io_handle, sigmask)); #endif - return (fido_hid_set_sigmask(dev->io_handle, sigmask)); + if (dev->transport.rx == NULL && dev->io.read == fido_hid_read) + return (fido_hid_set_sigmask(dev->io_handle, sigmask)); + + return (FIDO_ERR_INVALID_ARGUMENT); } int fido_dev_cancel(fido_dev_t *dev) { + int ms = dev->timeout_ms; + #ifdef USE_WINHELLO if (dev->flags & FIDO_DEV_WINHELLO) return (fido_winhello_cancel(dev)); #endif if (fido_dev_is_fido2(dev) == false) return (FIDO_ERR_INVALID_ARGUMENT); - if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0) < 0) + if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0, &ms) < 0) return (FIDO_ERR_TX); return (FIDO_OK); } int fido_dev_get_touch_begin(fido_dev_t *dev) { fido_blob_t f; cbor_item_t *argv[9]; const char *clientdata = FIDO_DUMMY_CLIENTDATA; const uint8_t user_id = FIDO_DUMMY_USER_ID; unsigned char cdh[SHA256_DIGEST_LENGTH]; fido_rp_t rp; fido_user_t user; + int ms = dev->timeout_ms; int r = FIDO_ERR_INTERNAL; memset(&f, 0, sizeof(f)); memset(argv, 0, sizeof(argv)); memset(cdh, 0, sizeof(cdh)); memset(&rp, 0, sizeof(rp)); memset(&user, 0, sizeof(user)); if (fido_dev_is_fido2(dev) == false) - return (u2f_get_touch_begin(dev)); + return (u2f_get_touch_begin(dev, &ms)); if (SHA256((const void *)clientdata, strlen(clientdata), cdh) != cdh) { fido_log_debug("%s: sha256", __func__); return (FIDO_ERR_INTERNAL); } if ((rp.id = strdup(FIDO_DUMMY_RP_ID)) == NULL || (user.name = strdup(FIDO_DUMMY_USER_NAME)) == NULL) { fido_log_debug("%s: strdup", __func__); goto fail; } if (fido_blob_set(&user.id, &user_id, sizeof(user_id)) < 0) { fido_log_debug("%s: fido_blob_set", __func__); goto fail; } if ((argv[0] = cbor_build_bytestring(cdh, sizeof(cdh))) == NULL || (argv[1] = cbor_encode_rp_entity(&rp)) == NULL || (argv[2] = cbor_encode_user_entity(&user)) == NULL || (argv[3] = cbor_encode_pubkey_param(COSE_ES256)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } if (fido_dev_supports_pin(dev)) { if ((argv[7] = cbor_new_definite_bytestring()) == NULL || (argv[8] = cbor_encode_pin_opt(dev)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } } if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, nitems(argv), &f) < 0 || - fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { + fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, &ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); free(f.ptr); free(rp.id); free(user.name); free(user.id.ptr); return (r); } int fido_dev_get_touch_status(fido_dev_t *dev, int *touched, int ms) { int r; *touched = 0; if (fido_dev_is_fido2(dev) == false) - return (u2f_get_touch_status(dev, touched, ms)); + return (u2f_get_touch_status(dev, touched, &ms)); - switch ((r = fido_rx_cbor_status(dev, ms))) { + switch ((r = fido_rx_cbor_status(dev, &ms))) { case FIDO_ERR_PIN_AUTH_INVALID: case FIDO_ERR_PIN_INVALID: case FIDO_ERR_PIN_NOT_SET: case FIDO_ERR_SUCCESS: *touched = 1; break; case FIDO_ERR_RX: /* ignore */ break; default: fido_log_debug("%s: fido_rx_cbor_status", __func__); return (r); } return (FIDO_OK); } int fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) { if (dev->io_handle != NULL) { fido_log_debug("%s: non-NULL handle", __func__); return (FIDO_ERR_INVALID_ARGUMENT); } if (io == NULL || io->open == NULL || io->close == NULL || io->read == NULL || io->write == NULL) { fido_log_debug("%s: NULL function", __func__); return (FIDO_ERR_INVALID_ARGUMENT); } dev->io = *io; dev->io_own = true; return (FIDO_OK); } int fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t) { if (dev->io_handle != NULL) { fido_log_debug("%s: non-NULL handle", __func__); return (FIDO_ERR_INVALID_ARGUMENT); } dev->transport = *t; dev->io_own = true; return (FIDO_OK); } void fido_init(int flags) { if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL) fido_log_init(); disable_u2f_fallback = (flags & FIDO_DISABLE_U2F_FALLBACK); } fido_dev_t * fido_dev_new(void) { fido_dev_t *dev; if ((dev = calloc(1, sizeof(*dev))) == NULL) return (NULL); dev->cid = CTAP_CID_BROADCAST; + dev->timeout_ms = -1; dev->io = (fido_dev_io_t) { &fido_hid_open, &fido_hid_close, &fido_hid_read, &fido_hid_write, }; return (dev); } fido_dev_t * fido_dev_new_with_info(const fido_dev_info_t *di) { fido_dev_t *dev; if ((dev = calloc(1, sizeof(*dev))) == NULL) return (NULL); #if 0 if (di->io.open == NULL || di->io.close == NULL || di->io.read == NULL || di->io.write == NULL) { fido_log_debug("%s: NULL function", __func__); fido_dev_free(&dev); return (NULL); } #endif dev->io = di->io; dev->io_own = di->transport.tx != NULL || di->transport.rx != NULL; dev->transport = di->transport; dev->cid = CTAP_CID_BROADCAST; + dev->timeout_ms = -1; if ((dev->path = strdup(di->path)) == NULL) { fido_log_debug("%s: strdup", __func__); fido_dev_free(&dev); return (NULL); } return (dev); } void fido_dev_free(fido_dev_t **dev_p) { fido_dev_t *dev; if (dev_p == NULL || (dev = *dev_p) == NULL) return; free(dev->path); free(dev); *dev_p = NULL; } uint8_t fido_dev_protocol(const fido_dev_t *dev) { return (dev->attr.protocol); } uint8_t fido_dev_major(const fido_dev_t *dev) { return (dev->attr.major); } uint8_t fido_dev_minor(const fido_dev_t *dev) { return (dev->attr.minor); } uint8_t fido_dev_build(const fido_dev_t *dev) { return (dev->attr.build); } uint8_t fido_dev_flags(const fido_dev_t *dev) { return (dev->attr.flags); } bool fido_dev_is_fido2(const fido_dev_t *dev) { return (dev->attr.flags & FIDO_CAP_CBOR); } bool fido_dev_is_winhello(const fido_dev_t *dev) { return (dev->flags & FIDO_DEV_WINHELLO); } bool fido_dev_supports_pin(const fido_dev_t *dev) { return (dev->flags & (FIDO_DEV_PIN_SET|FIDO_DEV_PIN_UNSET)); } bool fido_dev_has_pin(const fido_dev_t *dev) { return (dev->flags & FIDO_DEV_PIN_SET); } bool fido_dev_supports_cred_prot(const fido_dev_t *dev) { return (dev->flags & FIDO_DEV_CRED_PROT); } bool fido_dev_supports_credman(const fido_dev_t *dev) { return (dev->flags & FIDO_DEV_CREDMAN); } bool fido_dev_supports_uv(const fido_dev_t *dev) { return (dev->flags & (FIDO_DEV_UV_SET|FIDO_DEV_UV_UNSET)); } bool fido_dev_has_uv(const fido_dev_t *dev) { return (dev->flags & FIDO_DEV_UV_SET); } bool fido_dev_supports_permissions(const fido_dev_t *dev) { return (dev->flags & FIDO_DEV_TOKEN_PERMS); } void fido_dev_force_u2f(fido_dev_t *dev) { dev->attr.flags &= (uint8_t)~FIDO_CAP_CBOR; dev->flags = 0; } void fido_dev_force_fido2(fido_dev_t *dev) { dev->attr.flags |= FIDO_CAP_CBOR; } uint8_t fido_dev_get_pin_protocol(const fido_dev_t *dev) { if (dev->flags & FIDO_DEV_PIN_PROTOCOL2) return (CTAP_PIN_PROTOCOL2); else if (dev->flags & FIDO_DEV_PIN_PROTOCOL1) return (CTAP_PIN_PROTOCOL1); return (0); } uint64_t fido_dev_maxmsgsize(const fido_dev_t *dev) { return (dev->maxmsgsize); } + +int +fido_dev_set_timeout(fido_dev_t *dev, int ms) +{ + if (ms < -1) + return (FIDO_ERR_INVALID_ARGUMENT); + + dev->timeout_ms = ms; + + return (FIDO_OK); +} diff --git a/contrib/libfido2/src/ecdh.c b/contrib/libfido2/src/ecdh.c index 3ea47ae6457e..9c4f2b99e1a9 100644 --- a/contrib/libfido2/src/ecdh.c +++ b/contrib/libfido2/src/ecdh.c @@ -1,207 +1,207 @@ /* * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #if defined(LIBRESSL_VERSION_NUMBER) #include -#elif OPENSSL_VERSION_NUMBER >= 0x10100000L +#else #include #endif #include "fido.h" #include "fido/es256.h" -#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L +#if defined(LIBRESSL_VERSION_NUMBER) static int hkdf_sha256(uint8_t *key, const char *info, const fido_blob_t *secret) { const EVP_MD *md; uint8_t salt[32]; memset(salt, 0, sizeof(salt)); if ((md = EVP_sha256()) == NULL || HKDF(key, SHA256_DIGEST_LENGTH, md, secret->ptr, secret->len, salt, sizeof(salt), (const uint8_t *)info, strlen(info)) != 1) return -1; return 0; } #else static int hkdf_sha256(uint8_t *key, char *info, fido_blob_t *secret) { const EVP_MD *const_md; EVP_MD *md = NULL; EVP_PKEY_CTX *ctx = NULL; size_t keylen = SHA256_DIGEST_LENGTH; uint8_t salt[32]; int ok = -1; memset(salt, 0, sizeof(salt)); if (secret->len > INT_MAX || strlen(info) > INT_MAX) { fido_log_debug("%s: invalid param", __func__); goto fail; } if ((const_md = EVP_sha256()) == NULL || (md = EVP_MD_meth_dup(const_md)) == NULL || (ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL)) == NULL) { fido_log_debug("%s: init", __func__); goto fail; } if (EVP_PKEY_derive_init(ctx) < 1 || EVP_PKEY_CTX_set_hkdf_md(ctx, md) < 1 || EVP_PKEY_CTX_set1_hkdf_salt(ctx, salt, sizeof(salt)) < 1 || EVP_PKEY_CTX_set1_hkdf_key(ctx, secret->ptr, (int)secret->len) < 1 || - EVP_PKEY_CTX_add1_hkdf_info(ctx, info, (int)strlen(info)) < 1) { + EVP_PKEY_CTX_add1_hkdf_info(ctx, (void *)info, (int)strlen(info)) < 1) { fido_log_debug("%s: EVP_PKEY_CTX", __func__); goto fail; } if (EVP_PKEY_derive(ctx, key, &keylen) < 1) { fido_log_debug("%s: EVP_PKEY_derive", __func__); goto fail; } ok = 0; fail: if (md != NULL) EVP_MD_meth_free(md); if (ctx != NULL) EVP_PKEY_CTX_free(ctx); return ok; } -#endif /* defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L */ +#endif /* defined(LIBRESSL_VERSION_NUMBER) */ static int kdf(uint8_t prot, fido_blob_t *key, /* const */ fido_blob_t *secret) { char hmac_info[] = "CTAP2 HMAC key"; /* const */ char aes_info[] = "CTAP2 AES key"; /* const */ switch (prot) { case CTAP_PIN_PROTOCOL1: /* use sha256 on the resulting secret */ key->len = SHA256_DIGEST_LENGTH; if ((key->ptr = calloc(1, key->len)) == NULL || SHA256(secret->ptr, secret->len, key->ptr) != key->ptr) { fido_log_debug("%s: SHA256", __func__); return -1; } break; case CTAP_PIN_PROTOCOL2: /* use two instances of hkdf-sha256 on the resulting secret */ key->len = 2 * SHA256_DIGEST_LENGTH; if ((key->ptr = calloc(1, key->len)) == NULL || hkdf_sha256(key->ptr, hmac_info, secret) < 0 || hkdf_sha256(key->ptr + SHA256_DIGEST_LENGTH, aes_info, secret) < 0) { fido_log_debug("%s: hkdf", __func__); return -1; } break; default: fido_log_debug("%s: unknown pin protocol %u", __func__, prot); return -1; } return 0; } static int do_ecdh(const fido_dev_t *dev, const es256_sk_t *sk, const es256_pk_t *pk, fido_blob_t **ecdh) { EVP_PKEY *pk_evp = NULL; EVP_PKEY *sk_evp = NULL; EVP_PKEY_CTX *ctx = NULL; fido_blob_t *secret = NULL; int ok = -1; *ecdh = NULL; if ((secret = fido_blob_new()) == NULL || (*ecdh = fido_blob_new()) == NULL) goto fail; if ((pk_evp = es256_pk_to_EVP_PKEY(pk)) == NULL || (sk_evp = es256_sk_to_EVP_PKEY(sk)) == NULL) { fido_log_debug("%s: es256_to_EVP_PKEY", __func__); goto fail; } if ((ctx = EVP_PKEY_CTX_new(sk_evp, NULL)) == NULL || EVP_PKEY_derive_init(ctx) <= 0 || EVP_PKEY_derive_set_peer(ctx, pk_evp) <= 0) { fido_log_debug("%s: EVP_PKEY_derive_init", __func__); goto fail; } if (EVP_PKEY_derive(ctx, NULL, &secret->len) <= 0 || (secret->ptr = calloc(1, secret->len)) == NULL || EVP_PKEY_derive(ctx, secret->ptr, &secret->len) <= 0) { fido_log_debug("%s: EVP_PKEY_derive", __func__); goto fail; } if (kdf(fido_dev_get_pin_protocol(dev), *ecdh, secret) < 0) { fido_log_debug("%s: kdf", __func__); goto fail; } ok = 0; fail: if (pk_evp != NULL) EVP_PKEY_free(pk_evp); if (sk_evp != NULL) EVP_PKEY_free(sk_evp); if (ctx != NULL) EVP_PKEY_CTX_free(ctx); if (ok < 0) fido_blob_free(ecdh); fido_blob_free(&secret); return ok; } int -fido_do_ecdh(fido_dev_t *dev, es256_pk_t **pk, fido_blob_t **ecdh) +fido_do_ecdh(fido_dev_t *dev, es256_pk_t **pk, fido_blob_t **ecdh, int *ms) { es256_sk_t *sk = NULL; /* our private key */ es256_pk_t *ak = NULL; /* authenticator's public key */ int r; *pk = NULL; *ecdh = NULL; if ((sk = es256_sk_new()) == NULL || (*pk = es256_pk_new()) == NULL) { r = FIDO_ERR_INTERNAL; goto fail; } if (es256_sk_create(sk) < 0 || es256_derive_pk(sk, *pk) < 0) { fido_log_debug("%s: es256_derive_pk", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if ((ak = es256_pk_new()) == NULL || - fido_dev_authkey(dev, ak) != FIDO_OK) { + fido_dev_authkey(dev, ak, ms) != FIDO_OK) { fido_log_debug("%s: fido_dev_authkey", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (do_ecdh(dev, sk, ak, ecdh) < 0) { fido_log_debug("%s: do_ecdh", __func__); r = FIDO_ERR_INTERNAL; goto fail; } r = FIDO_OK; fail: es256_sk_free(&sk); es256_pk_free(&ak); if (r != FIDO_OK) { es256_pk_free(pk); fido_blob_free(ecdh); } return r; } diff --git a/contrib/libfido2/src/eddsa.c b/contrib/libfido2/src/eddsa.c index 89b84c5a6bd4..d228149ebf4d 100644 --- a/contrib/libfido2/src/eddsa.c +++ b/contrib/libfido2/src/eddsa.c @@ -1,172 +1,218 @@ /* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include "fido.h" #include "fido/eddsa.h" -#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10101000L +#if defined(LIBRESSL_VERSION_NUMBER) EVP_PKEY * EVP_PKEY_new_raw_public_key(int type, ENGINE *e, const unsigned char *key, size_t keylen) { (void)type; (void)e; (void)key; (void)keylen; fido_log_debug("%s: unimplemented", __func__); return (NULL); } int EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub, size_t *len) { (void)pkey; (void)pub; (void)len; fido_log_debug("%s: unimplemented", __func__); return (0); } int EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen, const unsigned char *tbs, size_t tbslen) { (void)ctx; (void)sigret; (void)siglen; (void)tbs; (void)tbslen; fido_log_debug("%s: unimplemented", __func__); return (0); } -#endif /* LIBRESSL_VERSION_NUMBER || OPENSSL_VERSION_NUMBER < 0x10101000L */ - -#if OPENSSL_VERSION_NUMBER < 0x10100000L -EVP_MD_CTX * -EVP_MD_CTX_new(void) -{ - fido_log_debug("%s: unimplemented", __func__); - - return (NULL); -} - -void -EVP_MD_CTX_free(EVP_MD_CTX *ctx) -{ - (void)ctx; -} -#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ +#endif /* LIBRESSL_VERSION_NUMBER */ static int decode_coord(const cbor_item_t *item, void *xy, size_t xy_len) { if (cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false || cbor_bytestring_length(item) != xy_len) { fido_log_debug("%s: cbor type", __func__); return (-1); } memcpy(xy, cbor_bytestring_handle(item), xy_len); return (0); } static int decode_pubkey_point(const cbor_item_t *key, const cbor_item_t *val, void *arg) { eddsa_pk_t *k = arg; if (cbor_isa_negint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) return (0); /* ignore */ switch (cbor_get_uint8(key)) { case 1: /* x coordinate */ return (decode_coord(val, &k->x, sizeof(k->x))); } return (0); /* ignore */ } int eddsa_pk_decode(const cbor_item_t *item, eddsa_pk_t *k) { if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, k, decode_pubkey_point) < 0) { fido_log_debug("%s: cbor type", __func__); return (-1); } return (0); } eddsa_pk_t * eddsa_pk_new(void) { return (calloc(1, sizeof(eddsa_pk_t))); } void eddsa_pk_free(eddsa_pk_t **pkp) { eddsa_pk_t *pk; if (pkp == NULL || (pk = *pkp) == NULL) return; freezero(pk, sizeof(*pk)); *pkp = NULL; } int eddsa_pk_from_ptr(eddsa_pk_t *pk, const void *ptr, size_t len) { if (len < sizeof(*pk)) return (FIDO_ERR_INVALID_ARGUMENT); memcpy(pk, ptr, sizeof(*pk)); return (FIDO_OK); } EVP_PKEY * eddsa_pk_to_EVP_PKEY(const eddsa_pk_t *k) { EVP_PKEY *pkey = NULL; if ((pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, k->x, sizeof(k->x))) == NULL) fido_log_debug("%s: EVP_PKEY_new_raw_public_key", __func__); return (pkey); } int eddsa_pk_from_EVP_PKEY(eddsa_pk_t *pk, const EVP_PKEY *pkey) { size_t len = 0; if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1 || len != sizeof(pk->x)) return (FIDO_ERR_INTERNAL); if (EVP_PKEY_get_raw_public_key(pkey, pk->x, &len) != 1 || len != sizeof(pk->x)) return (FIDO_ERR_INTERNAL); return (FIDO_OK); } + +int +eddsa_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey, + const fido_blob_t *sig) +{ + EVP_MD_CTX *mdctx = NULL; + int ok = -1; + + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_ED25519) { + fido_log_debug("%s: EVP_PKEY_base_id", __func__); + goto fail; + } + + /* EVP_DigestVerify needs ints */ + if (dgst->len > INT_MAX || sig->len > INT_MAX) { + fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__, + dgst->len, sig->len); + return (-1); + } + + if ((mdctx = EVP_MD_CTX_new()) == NULL) { + fido_log_debug("%s: EVP_MD_CTX_new", __func__); + goto fail; + } + + if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) { + fido_log_debug("%s: EVP_DigestVerifyInit", __func__); + goto fail; + } + + if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr, + dgst->len) != 1) { + fido_log_debug("%s: EVP_DigestVerify", __func__); + goto fail; + } + + ok = 0; +fail: + EVP_MD_CTX_free(mdctx); + + return (ok); +} + +int +eddsa_pk_verify_sig(const fido_blob_t *dgst, const eddsa_pk_t *pk, + const fido_blob_t *sig) +{ + EVP_PKEY *pkey; + int ok = -1; + + if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL || + eddsa_verify_sig(dgst, pkey, sig) < 0) { + fido_log_debug("%s: eddsa_verify_sig", __func__); + goto fail; + } + + ok = 0; +fail: + EVP_PKEY_free(pkey); + + return (ok); +} diff --git a/contrib/libfido2/src/es256.c b/contrib/libfido2/src/es256.c index 9cdb48e4832d..eb4cc63525aa 100644 --- a/contrib/libfido2/src/es256.c +++ b/contrib/libfido2/src/es256.c @@ -1,453 +1,513 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include +#include #include #include "fido.h" #include "fido/es256.h" static int decode_coord(const cbor_item_t *item, void *xy, size_t xy_len) { if (cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false || cbor_bytestring_length(item) != xy_len) { fido_log_debug("%s: cbor type", __func__); return (-1); } memcpy(xy, cbor_bytestring_handle(item), xy_len); return (0); } static int decode_pubkey_point(const cbor_item_t *key, const cbor_item_t *val, void *arg) { es256_pk_t *k = arg; if (cbor_isa_negint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) return (0); /* ignore */ switch (cbor_get_uint8(key)) { case 1: /* x coordinate */ return (decode_coord(val, &k->x, sizeof(k->x))); case 2: /* y coordinate */ return (decode_coord(val, &k->y, sizeof(k->y))); } return (0); /* ignore */ } int es256_pk_decode(const cbor_item_t *item, es256_pk_t *k) { if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, k, decode_pubkey_point) < 0) { fido_log_debug("%s: cbor type", __func__); return (-1); } return (0); } cbor_item_t * es256_pk_encode(const es256_pk_t *pk, int ecdh) { cbor_item_t *item = NULL; struct cbor_pair argv[5]; int alg; int ok = -1; memset(argv, 0, sizeof(argv)); if ((item = cbor_new_definite_map(5)) == NULL) goto fail; /* kty */ if ((argv[0].key = cbor_build_uint8(1)) == NULL || (argv[0].value = cbor_build_uint8(2)) == NULL || !cbor_map_add(item, argv[0])) goto fail; /* * "The COSEAlgorithmIdentifier used is -25 (ECDH-ES + * HKDF-256) although this is NOT the algorithm actually * used. Setting this to a different value may result in * compatibility issues." */ if (ecdh) alg = COSE_ECDH_ES256; else alg = COSE_ES256; /* alg */ if ((argv[1].key = cbor_build_uint8(3)) == NULL || (argv[1].value = cbor_build_negint8((uint8_t)(-alg - 1))) == NULL || !cbor_map_add(item, argv[1])) goto fail; /* crv */ if ((argv[2].key = cbor_build_negint8(0)) == NULL || (argv[2].value = cbor_build_uint8(1)) == NULL || !cbor_map_add(item, argv[2])) goto fail; /* x */ if ((argv[3].key = cbor_build_negint8(1)) == NULL || (argv[3].value = cbor_build_bytestring(pk->x, sizeof(pk->x))) == NULL || !cbor_map_add(item, argv[3])) goto fail; /* y */ if ((argv[4].key = cbor_build_negint8(2)) == NULL || (argv[4].value = cbor_build_bytestring(pk->y, sizeof(pk->y))) == NULL || !cbor_map_add(item, argv[4])) goto fail; ok = 0; fail: if (ok < 0) { if (item != NULL) { cbor_decref(&item); item = NULL; } } for (size_t i = 0; i < 5; i++) { if (argv[i].key) cbor_decref(&argv[i].key); if (argv[i].value) cbor_decref(&argv[i].value); } return (item); } es256_sk_t * es256_sk_new(void) { return (calloc(1, sizeof(es256_sk_t))); } void es256_sk_free(es256_sk_t **skp) { es256_sk_t *sk; if (skp == NULL || (sk = *skp) == NULL) return; freezero(sk, sizeof(*sk)); *skp = NULL; } es256_pk_t * es256_pk_new(void) { return (calloc(1, sizeof(es256_pk_t))); } void es256_pk_free(es256_pk_t **pkp) { es256_pk_t *pk; if (pkp == NULL || (pk = *pkp) == NULL) return; freezero(pk, sizeof(*pk)); *pkp = NULL; } int es256_pk_from_ptr(es256_pk_t *pk, const void *ptr, size_t len) { const uint8_t *p = ptr; if (len < sizeof(*pk)) return (FIDO_ERR_INVALID_ARGUMENT); if (len == sizeof(*pk) + 1 && *p == 0x04) memcpy(pk, ++p, sizeof(*pk)); /* uncompressed format */ else memcpy(pk, ptr, sizeof(*pk)); /* libfido2 x||y format */ return (FIDO_OK); } int es256_pk_set_x(es256_pk_t *pk, const unsigned char *x) { memcpy(pk->x, x, sizeof(pk->x)); return (0); } int es256_pk_set_y(es256_pk_t *pk, const unsigned char *y) { memcpy(pk->y, y, sizeof(pk->y)); return (0); } int es256_sk_create(es256_sk_t *key) { EVP_PKEY_CTX *pctx = NULL; EVP_PKEY_CTX *kctx = NULL; EVP_PKEY *p = NULL; EVP_PKEY *k = NULL; const EC_KEY *ec; const BIGNUM *d; const int nid = NID_X9_62_prime256v1; int n; int ok = -1; if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL || EVP_PKEY_paramgen_init(pctx) <= 0 || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) <= 0 || EVP_PKEY_paramgen(pctx, &p) <= 0) { fido_log_debug("%s: EVP_PKEY_paramgen", __func__); goto fail; } if ((kctx = EVP_PKEY_CTX_new(p, NULL)) == NULL || EVP_PKEY_keygen_init(kctx) <= 0 || EVP_PKEY_keygen(kctx, &k) <= 0) { fido_log_debug("%s: EVP_PKEY_keygen", __func__); goto fail; } if ((ec = EVP_PKEY_get0_EC_KEY(k)) == NULL || (d = EC_KEY_get0_private_key(ec)) == NULL || (n = BN_num_bytes(d)) < 0 || (size_t)n > sizeof(key->d) || (n = BN_bn2bin(d, key->d)) < 0 || (size_t)n > sizeof(key->d)) { fido_log_debug("%s: EC_KEY_get0_private_key", __func__); goto fail; } ok = 0; fail: if (p != NULL) EVP_PKEY_free(p); if (k != NULL) EVP_PKEY_free(k); if (pctx != NULL) EVP_PKEY_CTX_free(pctx); if (kctx != NULL) EVP_PKEY_CTX_free(kctx); return (ok); } EVP_PKEY * es256_pk_to_EVP_PKEY(const es256_pk_t *k) { BN_CTX *bnctx = NULL; EC_KEY *ec = NULL; EC_POINT *q = NULL; EVP_PKEY *pkey = NULL; BIGNUM *x = NULL; BIGNUM *y = NULL; const EC_GROUP *g = NULL; const int nid = NID_X9_62_prime256v1; int ok = -1; if ((bnctx = BN_CTX_new()) == NULL) goto fail; BN_CTX_start(bnctx); if ((x = BN_CTX_get(bnctx)) == NULL || (y = BN_CTX_get(bnctx)) == NULL) goto fail; if (BN_bin2bn(k->x, sizeof(k->x), x) == NULL || BN_bin2bn(k->y, sizeof(k->y), y) == NULL) { fido_log_debug("%s: BN_bin2bn", __func__); goto fail; } if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL || (g = EC_KEY_get0_group(ec)) == NULL) { fido_log_debug("%s: EC_KEY init", __func__); goto fail; } if ((q = EC_POINT_new(g)) == NULL || EC_POINT_set_affine_coordinates_GFp(g, q, x, y, bnctx) == 0 || EC_KEY_set_public_key(ec, q) == 0) { fido_log_debug("%s: EC_KEY_set_public_key", __func__); goto fail; } if ((pkey = EVP_PKEY_new()) == NULL || EVP_PKEY_assign_EC_KEY(pkey, ec) == 0) { fido_log_debug("%s: EVP_PKEY_assign_EC_KEY", __func__); goto fail; } ec = NULL; /* at this point, ec belongs to evp */ ok = 0; fail: if (bnctx != NULL) { BN_CTX_end(bnctx); BN_CTX_free(bnctx); } if (ec != NULL) EC_KEY_free(ec); if (q != NULL) EC_POINT_free(q); if (ok < 0 && pkey != NULL) { EVP_PKEY_free(pkey); pkey = NULL; } return (pkey); } int es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec) { BN_CTX *bnctx = NULL; BIGNUM *x = NULL; BIGNUM *y = NULL; const EC_POINT *q = NULL; const EC_GROUP *g = NULL; int ok = FIDO_ERR_INTERNAL; int n; if ((q = EC_KEY_get0_public_key(ec)) == NULL || (g = EC_KEY_get0_group(ec)) == NULL || (bnctx = BN_CTX_new()) == NULL) goto fail; BN_CTX_start(bnctx); if ((x = BN_CTX_get(bnctx)) == NULL || (y = BN_CTX_get(bnctx)) == NULL) goto fail; if (EC_POINT_get_affine_coordinates_GFp(g, q, x, y, bnctx) == 0 || (n = BN_num_bytes(x)) < 0 || (size_t)n > sizeof(pk->x) || (n = BN_num_bytes(y)) < 0 || (size_t)n > sizeof(pk->y)) { fido_log_debug("%s: EC_POINT_get_affine_coordinates_GFp", __func__); goto fail; } if ((n = BN_bn2bin(x, pk->x)) < 0 || (size_t)n > sizeof(pk->x) || (n = BN_bn2bin(y, pk->y)) < 0 || (size_t)n > sizeof(pk->y)) { fido_log_debug("%s: BN_bn2bin", __func__); goto fail; } ok = FIDO_OK; fail: if (bnctx != NULL) { BN_CTX_end(bnctx); BN_CTX_free(bnctx); } return (ok); } +int +es256_pk_from_EVP_PKEY(es256_pk_t *pk, const EVP_PKEY *pkey) +{ + EC_KEY *ec; + + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC || + (ec = EVP_PKEY_get0(pkey)) == NULL) + return (FIDO_ERR_INVALID_ARGUMENT); + + return (es256_pk_from_EC_KEY(pk, ec)); +} + EVP_PKEY * es256_sk_to_EVP_PKEY(const es256_sk_t *k) { BN_CTX *bnctx = NULL; EC_KEY *ec = NULL; EVP_PKEY *pkey = NULL; BIGNUM *d = NULL; const int nid = NID_X9_62_prime256v1; int ok = -1; if ((bnctx = BN_CTX_new()) == NULL) goto fail; BN_CTX_start(bnctx); if ((d = BN_CTX_get(bnctx)) == NULL || BN_bin2bn(k->d, sizeof(k->d), d) == NULL) { fido_log_debug("%s: BN_bin2bn", __func__); goto fail; } if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL || EC_KEY_set_private_key(ec, d) == 0) { fido_log_debug("%s: EC_KEY_set_private_key", __func__); goto fail; } if ((pkey = EVP_PKEY_new()) == NULL || EVP_PKEY_assign_EC_KEY(pkey, ec) == 0) { fido_log_debug("%s: EVP_PKEY_assign_EC_KEY", __func__); goto fail; } ec = NULL; /* at this point, ec belongs to evp */ ok = 0; fail: if (bnctx != NULL) { BN_CTX_end(bnctx); BN_CTX_free(bnctx); } if (ec != NULL) EC_KEY_free(ec); if (ok < 0 && pkey != NULL) { EVP_PKEY_free(pkey); pkey = NULL; } return (pkey); } int es256_derive_pk(const es256_sk_t *sk, es256_pk_t *pk) { BIGNUM *d = NULL; EC_KEY *ec = NULL; EC_POINT *q = NULL; const EC_GROUP *g = NULL; const int nid = NID_X9_62_prime256v1; int ok = -1; if ((d = BN_bin2bn(sk->d, (int)sizeof(sk->d), NULL)) == NULL || (ec = EC_KEY_new_by_curve_name(nid)) == NULL || (g = EC_KEY_get0_group(ec)) == NULL || (q = EC_POINT_new(g)) == NULL) { fido_log_debug("%s: get", __func__); goto fail; } if (EC_POINT_mul(g, q, d, NULL, NULL, NULL) == 0 || EC_KEY_set_public_key(ec, q) == 0 || es256_pk_from_EC_KEY(pk, ec) != FIDO_OK) { fido_log_debug("%s: set", __func__); goto fail; } ok = 0; fail: if (d != NULL) BN_clear_free(d); if (q != NULL) EC_POINT_free(q); if (ec != NULL) EC_KEY_free(ec); return (ok); } + +int +es256_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey, + const fido_blob_t *sig) +{ + EVP_PKEY_CTX *pctx = NULL; + int ok = -1; + + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) { + fido_log_debug("%s: EVP_PKEY_base_id", __func__); + goto fail; + } + + if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL || + EVP_PKEY_verify_init(pctx) != 1 || + EVP_PKEY_verify(pctx, sig->ptr, sig->len, dgst->ptr, + dgst->len) != 1) { + fido_log_debug("%s: EVP_PKEY_verify", __func__); + goto fail; + } + + ok = 0; +fail: + EVP_PKEY_CTX_free(pctx); + + return (ok); +} + +int +es256_pk_verify_sig(const fido_blob_t *dgst, const es256_pk_t *pk, + const fido_blob_t *sig) +{ + EVP_PKEY *pkey; + int ok = -1; + + if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL || + es256_verify_sig(dgst, pkey, sig) < 0) { + fido_log_debug("%s: es256_verify_sig", __func__); + goto fail; + } + + ok = 0; +fail: + EVP_PKEY_free(pkey); + + return (ok); +} diff --git a/contrib/libfido2/src/export.gnu b/contrib/libfido2/src/export.gnu index 40dc7915e6e2..2a8ad24b4c3c 100644 --- a/contrib/libfido2/src/export.gnu +++ b/contrib/libfido2/src/export.gnu @@ -1,234 +1,243 @@ { global: eddsa_pk_free; eddsa_pk_from_EVP_PKEY; eddsa_pk_from_ptr; eddsa_pk_new; eddsa_pk_to_EVP_PKEY; es256_pk_free; es256_pk_from_EC_KEY; + es256_pk_from_EVP_PKEY; es256_pk_from_ptr; es256_pk_new; es256_pk_to_EVP_PKEY; fido_assert_allow_cred; fido_assert_authdata_len; fido_assert_authdata_ptr; fido_assert_blob_len; fido_assert_blob_ptr; fido_assert_clientdata_hash_len; fido_assert_clientdata_hash_ptr; fido_assert_count; fido_assert_flags; fido_assert_free; fido_assert_hmac_secret_len; fido_assert_hmac_secret_ptr; fido_assert_id_len; fido_assert_id_ptr; fido_assert_largeblob_key_len; fido_assert_largeblob_key_ptr; fido_assert_new; fido_assert_rp_id; fido_assert_set_authdata; fido_assert_set_authdata_raw; fido_assert_set_clientdata; fido_assert_set_clientdata_hash; fido_assert_set_count; fido_assert_set_extensions; fido_assert_set_hmac_salt; fido_assert_set_hmac_secret; fido_assert_set_options; fido_assert_set_rp; fido_assert_set_sig; fido_assert_set_up; fido_assert_set_uv; fido_assert_sigcount; fido_assert_sig_len; fido_assert_sig_ptr; fido_assert_user_display_name; fido_assert_user_icon; fido_assert_user_id_len; fido_assert_user_id_ptr; fido_assert_user_name; fido_assert_verify; fido_bio_dev_enroll_begin; fido_bio_dev_enroll_cancel; fido_bio_dev_enroll_continue; fido_bio_dev_enroll_remove; fido_bio_dev_get_info; fido_bio_dev_get_template_array; fido_bio_dev_set_template_name; fido_bio_enroll_free; fido_bio_enroll_last_status; fido_bio_enroll_new; fido_bio_enroll_remaining_samples; fido_bio_info_free; fido_bio_info_max_samples; fido_bio_info_new; fido_bio_info_type; fido_bio_template; fido_bio_template_array_count; fido_bio_template_array_free; fido_bio_template_array_new; fido_bio_template_free; fido_bio_template_id_len; fido_bio_template_id_ptr; fido_bio_template_name; fido_bio_template_new; fido_bio_template_set_id; fido_bio_template_set_name; fido_cbor_info_aaguid_len; fido_cbor_info_aaguid_ptr; fido_cbor_info_algorithm_cose; fido_cbor_info_algorithm_count; fido_cbor_info_algorithm_type; fido_cbor_info_extensions_len; fido_cbor_info_extensions_ptr; fido_cbor_info_free; fido_cbor_info_maxmsgsiz; fido_cbor_info_maxcredbloblen; fido_cbor_info_maxcredcntlst; fido_cbor_info_maxcredidlen; fido_cbor_info_fwversion; fido_cbor_info_new; fido_cbor_info_options_len; fido_cbor_info_options_name_ptr; fido_cbor_info_options_value_ptr; fido_cbor_info_protocols_len; fido_cbor_info_protocols_ptr; fido_cbor_info_transports_len; fido_cbor_info_transports_ptr; fido_cbor_info_versions_len; fido_cbor_info_versions_ptr; + fido_cred_attstmt_len; + fido_cred_attstmt_ptr; fido_cred_authdata_len; fido_cred_authdata_ptr; fido_cred_authdata_raw_len; fido_cred_authdata_raw_ptr; fido_cred_clientdata_hash_len; fido_cred_clientdata_hash_ptr; fido_cred_display_name; fido_cred_exclude; fido_cred_flags; fido_cred_largeblob_key_len; fido_cred_largeblob_key_ptr; fido_cred_sigcount; fido_cred_fmt; fido_cred_free; fido_cred_id_len; fido_cred_id_ptr; fido_cred_aaguid_len; fido_cred_aaguid_ptr; fido_credman_del_dev_rk; fido_credman_get_dev_metadata; fido_credman_get_dev_rk; fido_credman_get_dev_rp; fido_credman_metadata_free; fido_credman_metadata_new; fido_credman_rk; fido_credman_rk_count; fido_credman_rk_existing; fido_credman_rk_free; fido_credman_rk_new; fido_credman_rk_remaining; fido_credman_rp_count; fido_credman_rp_free; fido_credman_rp_id; fido_credman_rp_id_hash_len; fido_credman_rp_id_hash_ptr; fido_credman_rp_name; fido_credman_rp_new; fido_credman_set_dev_rk; fido_cred_new; + fido_cred_pin_minlen; fido_cred_prot; fido_cred_pubkey_len; fido_cred_pubkey_ptr; fido_cred_rp_id; fido_cred_rp_name; + fido_cred_set_attstmt; fido_cred_set_authdata; fido_cred_set_authdata_raw; fido_cred_set_blob; fido_cred_set_clientdata; fido_cred_set_clientdata_hash; fido_cred_set_extensions; fido_cred_set_fmt; fido_cred_set_id; fido_cred_set_options; + fido_cred_set_pin_minlen; fido_cred_set_prot; fido_cred_set_rk; fido_cred_set_rp; fido_cred_set_sig; fido_cred_set_type; fido_cred_set_user; fido_cred_set_uv; fido_cred_set_x509; fido_cred_sig_len; fido_cred_sig_ptr; fido_cred_type; fido_cred_user_id_len; fido_cred_user_id_ptr; fido_cred_user_name; fido_cred_verify; fido_cred_verify_self; fido_cred_x5c_len; fido_cred_x5c_ptr; fido_dev_build; fido_dev_cancel; fido_dev_close; fido_dev_enable_entattest; fido_dev_flags; fido_dev_force_fido2; fido_dev_force_pin_change; fido_dev_force_u2f; fido_dev_free; fido_dev_get_assert; fido_dev_get_cbor_info; fido_dev_get_retry_count; fido_dev_get_uv_retry_count; fido_dev_get_touch_begin; fido_dev_get_touch_status; fido_dev_has_pin; fido_dev_has_uv; fido_dev_info_free; fido_dev_info_manifest; fido_dev_info_manufacturer_string; fido_dev_info_new; fido_dev_info_path; fido_dev_info_product; fido_dev_info_product_string; fido_dev_info_ptr; fido_dev_info_vendor; fido_dev_is_fido2; fido_dev_is_winhello; fido_dev_major; fido_dev_make_cred; fido_dev_minor; fido_dev_new; fido_dev_open; fido_dev_protocol; fido_dev_reset; fido_dev_set_io_functions; fido_dev_set_pin; fido_dev_set_pin_minlen; + fido_dev_set_pin_minlen_rpid; fido_dev_set_sigmask; + fido_dev_set_timeout; fido_dev_set_transport_functions; fido_dev_supports_cred_prot; fido_dev_supports_credman; fido_dev_supports_permissions; fido_dev_supports_pin; fido_dev_supports_uv; fido_dev_toggle_always_uv; fido_dev_largeblob_get; fido_dev_largeblob_get_array; fido_dev_largeblob_remove; fido_dev_largeblob_set; fido_dev_largeblob_set_array; fido_init; fido_set_log_handler; fido_strerr; rs256_pk_free; rs256_pk_from_ptr; + rs256_pk_from_EVP_PKEY; rs256_pk_from_RSA; rs256_pk_new; rs256_pk_to_EVP_PKEY; local: *; }; diff --git a/contrib/libfido2/src/export.llvm b/contrib/libfido2/src/export.llvm index 8d3810f92ce9..e163afecedce 100644 --- a/contrib/libfido2/src/export.llvm +++ b/contrib/libfido2/src/export.llvm @@ -1,229 +1,238 @@ _eddsa_pk_free _eddsa_pk_from_EVP_PKEY _eddsa_pk_from_ptr _eddsa_pk_new _eddsa_pk_to_EVP_PKEY _es256_pk_free _es256_pk_from_EC_KEY +_es256_pk_from_EVP_PKEY _es256_pk_from_ptr _es256_pk_new _es256_pk_to_EVP_PKEY _fido_assert_allow_cred _fido_assert_authdata_len _fido_assert_authdata_ptr _fido_assert_blob_len _fido_assert_blob_ptr _fido_assert_clientdata_hash_len _fido_assert_clientdata_hash_ptr _fido_assert_count _fido_assert_flags _fido_assert_free _fido_assert_hmac_secret_len _fido_assert_hmac_secret_ptr _fido_assert_id_len _fido_assert_id_ptr _fido_assert_largeblob_key_len _fido_assert_largeblob_key_ptr _fido_assert_new _fido_assert_rp_id _fido_assert_set_authdata _fido_assert_set_authdata_raw _fido_assert_set_clientdata _fido_assert_set_clientdata_hash _fido_assert_set_count _fido_assert_set_extensions _fido_assert_set_hmac_salt _fido_assert_set_hmac_secret _fido_assert_set_options _fido_assert_set_rp _fido_assert_set_sig _fido_assert_set_up _fido_assert_set_uv _fido_assert_sigcount _fido_assert_sig_len _fido_assert_sig_ptr _fido_assert_user_display_name _fido_assert_user_icon _fido_assert_user_id_len _fido_assert_user_id_ptr _fido_assert_user_name _fido_assert_verify _fido_bio_dev_enroll_begin _fido_bio_dev_enroll_cancel _fido_bio_dev_enroll_continue _fido_bio_dev_enroll_remove _fido_bio_dev_get_info _fido_bio_dev_get_template_array _fido_bio_dev_set_template_name _fido_bio_enroll_free _fido_bio_enroll_last_status _fido_bio_enroll_new _fido_bio_enroll_remaining_samples _fido_bio_info_free _fido_bio_info_max_samples _fido_bio_info_new _fido_bio_info_type _fido_bio_template _fido_bio_template_array_count _fido_bio_template_array_free _fido_bio_template_array_new _fido_bio_template_free _fido_bio_template_id_len _fido_bio_template_id_ptr _fido_bio_template_name _fido_bio_template_new _fido_bio_template_set_id _fido_bio_template_set_name _fido_cbor_info_aaguid_len _fido_cbor_info_aaguid_ptr _fido_cbor_info_algorithm_cose _fido_cbor_info_algorithm_count _fido_cbor_info_algorithm_type _fido_cbor_info_extensions_len _fido_cbor_info_extensions_ptr _fido_cbor_info_free _fido_cbor_info_maxmsgsiz _fido_cbor_info_maxcredbloblen _fido_cbor_info_maxcredcntlst _fido_cbor_info_maxcredidlen _fido_cbor_info_fwversion _fido_cbor_info_new _fido_cbor_info_options_len _fido_cbor_info_options_name_ptr _fido_cbor_info_options_value_ptr _fido_cbor_info_protocols_len _fido_cbor_info_protocols_ptr _fido_cbor_info_transports_len _fido_cbor_info_transports_ptr _fido_cbor_info_versions_len _fido_cbor_info_versions_ptr +_fido_cred_attstmt_len +_fido_cred_attstmt_ptr _fido_cred_authdata_len _fido_cred_authdata_ptr _fido_cred_authdata_raw_len _fido_cred_authdata_raw_ptr _fido_cred_clientdata_hash_len _fido_cred_clientdata_hash_ptr _fido_cred_display_name _fido_cred_exclude _fido_cred_flags _fido_cred_largeblob_key_len _fido_cred_largeblob_key_ptr _fido_cred_sigcount _fido_cred_fmt _fido_cred_free _fido_cred_id_len _fido_cred_id_ptr _fido_cred_aaguid_len _fido_cred_aaguid_ptr _fido_credman_del_dev_rk _fido_credman_get_dev_metadata _fido_credman_get_dev_rk _fido_credman_get_dev_rp _fido_credman_metadata_free _fido_credman_metadata_new _fido_credman_rk _fido_credman_rk_count _fido_credman_rk_existing _fido_credman_rk_free _fido_credman_rk_new _fido_credman_rk_remaining _fido_credman_rp_count _fido_credman_rp_free _fido_credman_rp_id _fido_credman_rp_id_hash_len _fido_credman_rp_id_hash_ptr _fido_credman_rp_name _fido_credman_rp_new _fido_credman_set_dev_rk _fido_cred_new +_fido_cred_pin_minlen _fido_cred_prot _fido_cred_pubkey_len _fido_cred_pubkey_ptr _fido_cred_rp_id _fido_cred_rp_name +_fido_cred_set_attstmt _fido_cred_set_authdata _fido_cred_set_authdata_raw _fido_cred_set_blob _fido_cred_set_clientdata _fido_cred_set_clientdata_hash _fido_cred_set_extensions _fido_cred_set_fmt _fido_cred_set_id _fido_cred_set_options +_fido_cred_set_pin_minlen _fido_cred_set_prot _fido_cred_set_rk _fido_cred_set_rp _fido_cred_set_sig _fido_cred_set_type _fido_cred_set_user _fido_cred_set_uv _fido_cred_set_x509 _fido_cred_sig_len _fido_cred_sig_ptr _fido_cred_type _fido_cred_user_id_len _fido_cred_user_id_ptr _fido_cred_user_name _fido_cred_verify _fido_cred_verify_self _fido_cred_x5c_len _fido_cred_x5c_ptr _fido_dev_build _fido_dev_cancel _fido_dev_close _fido_dev_enable_entattest _fido_dev_flags _fido_dev_force_fido2 _fido_dev_force_pin_change _fido_dev_force_u2f _fido_dev_free _fido_dev_get_assert _fido_dev_get_cbor_info _fido_dev_get_retry_count _fido_dev_get_uv_retry_count _fido_dev_get_touch_begin _fido_dev_get_touch_status _fido_dev_has_pin _fido_dev_has_uv _fido_dev_info_free _fido_dev_info_manifest _fido_dev_info_manufacturer_string _fido_dev_info_new _fido_dev_info_path _fido_dev_info_product _fido_dev_info_product_string _fido_dev_info_ptr _fido_dev_info_vendor _fido_dev_is_fido2 _fido_dev_is_winhello _fido_dev_major _fido_dev_make_cred _fido_dev_minor _fido_dev_new _fido_dev_open _fido_dev_protocol _fido_dev_reset _fido_dev_set_io_functions _fido_dev_set_pin _fido_dev_set_pin_minlen +_fido_dev_set_pin_minlen_rpid _fido_dev_set_sigmask +_fido_dev_set_timeout _fido_dev_set_transport_functions _fido_dev_supports_cred_prot _fido_dev_supports_credman _fido_dev_supports_permissions _fido_dev_supports_pin _fido_dev_supports_uv _fido_dev_toggle_always_uv _fido_dev_largeblob_get _fido_dev_largeblob_get_array _fido_dev_largeblob_remove _fido_dev_largeblob_set _fido_dev_largeblob_set_array _fido_init _fido_set_log_handler _fido_strerr _rs256_pk_free _rs256_pk_from_ptr +_rs256_pk_from_EVP_PKEY _rs256_pk_from_RSA _rs256_pk_new _rs256_pk_to_EVP_PKEY diff --git a/contrib/libfido2/src/export.msvc b/contrib/libfido2/src/export.msvc index ca4971dec2d1..9fc24e335e8d 100644 --- a/contrib/libfido2/src/export.msvc +++ b/contrib/libfido2/src/export.msvc @@ -1,230 +1,239 @@ EXPORTS eddsa_pk_free eddsa_pk_from_EVP_PKEY eddsa_pk_from_ptr eddsa_pk_new eddsa_pk_to_EVP_PKEY es256_pk_free es256_pk_from_EC_KEY +es256_pk_from_EVP_PKEY es256_pk_from_ptr es256_pk_new es256_pk_to_EVP_PKEY fido_assert_allow_cred fido_assert_authdata_len fido_assert_authdata_ptr fido_assert_blob_len fido_assert_blob_ptr fido_assert_clientdata_hash_len fido_assert_clientdata_hash_ptr fido_assert_count fido_assert_flags fido_assert_free fido_assert_hmac_secret_len fido_assert_hmac_secret_ptr fido_assert_id_len fido_assert_id_ptr fido_assert_largeblob_key_len fido_assert_largeblob_key_ptr fido_assert_new fido_assert_rp_id fido_assert_set_authdata fido_assert_set_authdata_raw fido_assert_set_clientdata fido_assert_set_clientdata_hash fido_assert_set_count fido_assert_set_extensions fido_assert_set_hmac_salt fido_assert_set_hmac_secret fido_assert_set_options fido_assert_set_rp fido_assert_set_sig fido_assert_set_up fido_assert_set_uv fido_assert_sigcount fido_assert_sig_len fido_assert_sig_ptr fido_assert_user_display_name fido_assert_user_icon fido_assert_user_id_len fido_assert_user_id_ptr fido_assert_user_name fido_assert_verify fido_bio_dev_enroll_begin fido_bio_dev_enroll_cancel fido_bio_dev_enroll_continue fido_bio_dev_enroll_remove fido_bio_dev_get_info fido_bio_dev_get_template_array fido_bio_dev_set_template_name fido_bio_enroll_free fido_bio_enroll_last_status fido_bio_enroll_new fido_bio_enroll_remaining_samples fido_bio_info_free fido_bio_info_max_samples fido_bio_info_new fido_bio_info_type fido_bio_template fido_bio_template_array_count fido_bio_template_array_free fido_bio_template_array_new fido_bio_template_free fido_bio_template_id_len fido_bio_template_id_ptr fido_bio_template_name fido_bio_template_new fido_bio_template_set_id fido_bio_template_set_name fido_cbor_info_aaguid_len fido_cbor_info_aaguid_ptr fido_cbor_info_algorithm_cose fido_cbor_info_algorithm_count fido_cbor_info_algorithm_type fido_cbor_info_extensions_len fido_cbor_info_extensions_ptr fido_cbor_info_free fido_cbor_info_maxmsgsiz fido_cbor_info_maxcredbloblen fido_cbor_info_maxcredcntlst fido_cbor_info_maxcredidlen fido_cbor_info_fwversion fido_cbor_info_new fido_cbor_info_options_len fido_cbor_info_options_name_ptr fido_cbor_info_options_value_ptr fido_cbor_info_protocols_len fido_cbor_info_protocols_ptr fido_cbor_info_transports_len fido_cbor_info_transports_ptr fido_cbor_info_versions_len fido_cbor_info_versions_ptr +fido_cred_attstmt_len +fido_cred_attstmt_ptr fido_cred_authdata_len fido_cred_authdata_ptr fido_cred_authdata_raw_len fido_cred_authdata_raw_ptr fido_cred_clientdata_hash_len fido_cred_clientdata_hash_ptr fido_cred_display_name fido_cred_exclude fido_cred_flags fido_cred_largeblob_key_len fido_cred_largeblob_key_ptr fido_cred_sigcount fido_cred_fmt fido_cred_free fido_cred_id_len fido_cred_id_ptr fido_cred_aaguid_len fido_cred_aaguid_ptr fido_credman_del_dev_rk fido_credman_get_dev_metadata fido_credman_get_dev_rk fido_credman_get_dev_rp fido_credman_metadata_free fido_credman_metadata_new fido_credman_rk fido_credman_rk_count fido_credman_rk_existing fido_credman_rk_free fido_credman_rk_new fido_credman_rk_remaining fido_credman_rp_count fido_credman_rp_free fido_credman_rp_id fido_credman_rp_id_hash_len fido_credman_rp_id_hash_ptr fido_credman_rp_name fido_credman_rp_new fido_credman_set_dev_rk fido_cred_new +fido_cred_pin_minlen fido_cred_prot fido_cred_pubkey_len fido_cred_pubkey_ptr fido_cred_rp_id fido_cred_rp_name +fido_cred_set_attstmt fido_cred_set_authdata fido_cred_set_authdata_raw fido_cred_set_blob fido_cred_set_clientdata fido_cred_set_clientdata_hash fido_cred_set_extensions fido_cred_set_fmt fido_cred_set_id fido_cred_set_options +fido_cred_set_pin_minlen fido_cred_set_prot fido_cred_set_rk fido_cred_set_rp fido_cred_set_sig fido_cred_set_type fido_cred_set_user fido_cred_set_uv fido_cred_set_x509 fido_cred_sig_len fido_cred_sig_ptr fido_cred_type fido_cred_user_id_len fido_cred_user_id_ptr fido_cred_user_name fido_cred_verify fido_cred_verify_self fido_cred_x5c_len fido_cred_x5c_ptr fido_dev_build fido_dev_cancel fido_dev_close fido_dev_enable_entattest fido_dev_flags fido_dev_force_fido2 fido_dev_force_pin_change fido_dev_force_u2f fido_dev_free fido_dev_get_assert fido_dev_get_cbor_info fido_dev_get_retry_count fido_dev_get_uv_retry_count fido_dev_get_touch_begin fido_dev_get_touch_status fido_dev_has_pin fido_dev_has_uv fido_dev_info_free fido_dev_info_manifest fido_dev_info_manufacturer_string fido_dev_info_new fido_dev_info_path fido_dev_info_product fido_dev_info_product_string fido_dev_info_ptr fido_dev_info_vendor fido_dev_is_fido2 fido_dev_is_winhello fido_dev_major fido_dev_make_cred fido_dev_minor fido_dev_new fido_dev_open fido_dev_protocol fido_dev_reset fido_dev_set_io_functions fido_dev_set_pin fido_dev_set_pin_minlen +fido_dev_set_pin_minlen_rpid fido_dev_set_sigmask +fido_dev_set_timeout fido_dev_set_transport_functions fido_dev_supports_cred_prot fido_dev_supports_credman fido_dev_supports_permissions fido_dev_supports_pin fido_dev_supports_uv fido_dev_toggle_always_uv fido_dev_largeblob_get fido_dev_largeblob_get_array fido_dev_largeblob_remove fido_dev_largeblob_set fido_dev_largeblob_set_array fido_init fido_set_log_handler fido_strerr rs256_pk_free rs256_pk_from_ptr +rs256_pk_from_EVP_PKEY rs256_pk_from_RSA rs256_pk_new rs256_pk_to_EVP_PKEY diff --git a/contrib/libfido2/src/extern.h b/contrib/libfido2/src/extern.h index 3be33236f2b1..dc6bddd7b912 100644 --- a/contrib/libfido2/src/extern.h +++ b/contrib/libfido2/src/extern.h @@ -1,240 +1,259 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _EXTERN_H #define _EXTERN_H #ifdef __MINGW32__ #include #endif #ifdef HAVE_SIGNAL_H #include #endif #include #include "fido/types.h" #include "blob.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* aes256 */ int aes256_cbc_dec(const fido_dev_t *dev, const fido_blob_t *, const fido_blob_t *, fido_blob_t *); int aes256_cbc_enc(const fido_dev_t *dev, const fido_blob_t *, const fido_blob_t *, fido_blob_t *); int aes256_gcm_dec(const fido_blob_t *, const fido_blob_t *, const fido_blob_t *, const fido_blob_t *, fido_blob_t *); int aes256_gcm_enc(const fido_blob_t *, const fido_blob_t *, const fido_blob_t *, const fido_blob_t *, fido_blob_t *); /* cbor encoding functions */ cbor_item_t *cbor_build_uint(const uint64_t); cbor_item_t *cbor_flatten_vector(cbor_item_t **, size_t); cbor_item_t *cbor_encode_assert_opt(fido_opt_t, fido_opt_t); cbor_item_t *cbor_encode_change_pin_auth(const fido_dev_t *, const fido_blob_t *, const fido_blob_t *, const fido_blob_t *); cbor_item_t *cbor_encode_cred_ext(const fido_cred_ext_t *, const fido_blob_t *); cbor_item_t *cbor_encode_assert_ext(fido_dev_t *, const fido_assert_ext_t *, const fido_blob_t *, const es256_pk_t *); cbor_item_t *cbor_encode_cred_opt(fido_opt_t, fido_opt_t); cbor_item_t *cbor_encode_pin_auth(const fido_dev_t *, const fido_blob_t *, const fido_blob_t *); cbor_item_t *cbor_encode_pin_opt(const fido_dev_t *); cbor_item_t *cbor_encode_pubkey(const fido_blob_t *); cbor_item_t *cbor_encode_pubkey_list(const fido_blob_array_t *); cbor_item_t *cbor_encode_pubkey_param(int); cbor_item_t *cbor_encode_rp_entity(const fido_rp_t *); +cbor_item_t *cbor_encode_str_array(const fido_str_array_t *); cbor_item_t *cbor_encode_user_entity(const fido_user_t *); cbor_item_t *es256_pk_encode(const es256_pk_t *, int); /* cbor decoding functions */ int cbor_decode_attstmt(const cbor_item_t *, fido_attstmt_t *); int cbor_decode_cred_authdata(const cbor_item_t *, int, fido_blob_t *, fido_authdata_t *, fido_attcred_t *, fido_cred_ext_t *); int cbor_decode_assert_authdata(const cbor_item_t *, fido_blob_t *, fido_authdata_t *, fido_assert_extattr_t *); int cbor_decode_cred_id(const cbor_item_t *, fido_blob_t *); int cbor_decode_fmt(const cbor_item_t *, char **); int cbor_decode_pubkey(const cbor_item_t *, int *, void *); int cbor_decode_rp_entity(const cbor_item_t *, fido_rp_t *); int cbor_decode_uint64(const cbor_item_t *, uint64_t *); int cbor_decode_user(const cbor_item_t *, fido_user_t *); int es256_pk_decode(const cbor_item_t *, es256_pk_t *); int rs256_pk_decode(const cbor_item_t *, rs256_pk_t *); int eddsa_pk_decode(const cbor_item_t *, eddsa_pk_t *); /* auxiliary cbor routines */ int cbor_add_bool(cbor_item_t *, const char *, fido_opt_t); int cbor_add_bytestring(cbor_item_t *, const char *, const unsigned char *, size_t); int cbor_add_string(cbor_item_t *, const char *, const char *); int cbor_array_iter(const cbor_item_t *, void *, int(*)(const cbor_item_t *, void *)); int cbor_build_frame(uint8_t, cbor_item_t *[], size_t, fido_blob_t *); int cbor_bytestring_copy(const cbor_item_t *, unsigned char **, size_t *); int cbor_map_iter(const cbor_item_t *, void *, int(*)(const cbor_item_t *, const cbor_item_t *, void *)); int cbor_string_copy(const cbor_item_t *, char **); int cbor_parse_reply(const unsigned char *, size_t, void *, int(*)(const cbor_item_t *, const cbor_item_t *, void *)); int cbor_add_uv_params(fido_dev_t *, uint8_t, const fido_blob_t *, const es256_pk_t *, const fido_blob_t *, const char *, const char *, - cbor_item_t **, cbor_item_t **); + cbor_item_t **, cbor_item_t **, int *); void cbor_vector_free(cbor_item_t **, size_t); int cbor_array_append(cbor_item_t **, cbor_item_t *); int cbor_array_drop(cbor_item_t **, size_t); /* deflate */ int fido_compress(fido_blob_t *, const fido_blob_t *); int fido_uncompress(fido_blob_t *, const fido_blob_t *, size_t); #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) #endif /* buf */ int fido_buf_read(const unsigned char **, size_t *, void *, size_t); int fido_buf_write(unsigned char **, size_t *, const void *, size_t); /* hid i/o */ void *fido_hid_open(const char *); void fido_hid_close(void *); int fido_hid_read(void *, unsigned char *, size_t, int); int fido_hid_write(void *, const unsigned char *, size_t); int fido_hid_get_usage(const uint8_t *, size_t, uint32_t *); int fido_hid_get_report_len(const uint8_t *, size_t, size_t *, size_t *); int fido_hid_unix_open(const char *); int fido_hid_unix_wait(int, int, const fido_sigset_t *); int fido_hid_set_sigmask(void *, const fido_sigset_t *); size_t fido_hid_report_in_len(void *); size_t fido_hid_report_out_len(void *); /* nfc i/o */ void *fido_nfc_open(const char *); void fido_nfc_close(void *); int fido_nfc_read(void *, unsigned char *, size_t, int); int fido_nfc_write(void *, const unsigned char *, size_t); int fido_nfc_rx(fido_dev_t *, uint8_t, unsigned char *, size_t, int); int fido_nfc_tx(fido_dev_t *, uint8_t, const unsigned char *, size_t); int fido_nfc_set_sigmask(void *, const fido_sigset_t *); /* windows hello */ int fido_winhello_manifest(fido_dev_info_t *, size_t, size_t *); int fido_winhello_open(fido_dev_t *); int fido_winhello_close(fido_dev_t *); int fido_winhello_cancel(fido_dev_t *); -int fido_winhello_get_assert(fido_dev_t *, fido_assert_t *, const char *); +int fido_winhello_get_assert(fido_dev_t *, fido_assert_t *, const char *, int); int fido_winhello_get_cbor_info(fido_dev_t *, fido_cbor_info_t *); -int fido_winhello_make_cred(fido_dev_t *, fido_cred_t *, const char *); +int fido_winhello_make_cred(fido_dev_t *, fido_cred_t *, const char *, int); /* generic i/o */ -int fido_rx_cbor_status(fido_dev_t *, int); -int fido_rx(fido_dev_t *, uint8_t, void *, size_t, int); -int fido_tx(fido_dev_t *, uint8_t, const void *, size_t); +int fido_rx_cbor_status(fido_dev_t *, int *); +int fido_rx(fido_dev_t *, uint8_t, void *, size_t, int *); +int fido_tx(fido_dev_t *, uint8_t, const void *, size_t, int *); /* log */ #ifdef FIDO_NO_DIAGNOSTIC #define fido_log_init(...) do { /* nothing */ } while (0) #define fido_log_debug(...) do { /* nothing */ } while (0) #define fido_log_xxd(...) do { /* nothing */ } while (0) #define fido_log_error(...) do { /* nothing */ } while (0) #else #ifdef __GNUC__ void fido_log_init(void); void fido_log_debug(const char *, ...) __attribute__((__format__ (printf, 1, 2))); void fido_log_xxd(const void *, size_t, const char *, ...) __attribute__((__format__ (printf, 3, 4))); void fido_log_error(int, const char *, ...) __attribute__((__format__ (printf, 2, 3))); #else void fido_log_init(void); void fido_log_debug(const char *, ...); void fido_log_xxd(const void *, size_t, const char *, ...); void fido_log_error(int, const char *, ...); #endif /* __GNUC__ */ #endif /* FIDO_NO_DIAGNOSTIC */ /* u2f */ -int u2f_register(fido_dev_t *, fido_cred_t *, int); -int u2f_authenticate(fido_dev_t *, fido_assert_t *, int); -int u2f_get_touch_begin(fido_dev_t *); -int u2f_get_touch_status(fido_dev_t *, int *, int); +int u2f_register(fido_dev_t *, fido_cred_t *, int *); +int u2f_authenticate(fido_dev_t *, fido_assert_t *, int *); +int u2f_get_touch_begin(fido_dev_t *, int *); +int u2f_get_touch_status(fido_dev_t *, int *, int *); /* unexposed fido ops */ uint8_t fido_dev_get_pin_protocol(const fido_dev_t *); -int fido_dev_authkey(fido_dev_t *, es256_pk_t *); -int fido_dev_get_cbor_info_wait(fido_dev_t *, fido_cbor_info_t *, int); +int fido_dev_authkey(fido_dev_t *, es256_pk_t *, int *); +int fido_dev_get_cbor_info_wait(fido_dev_t *, fido_cbor_info_t *, int *); int fido_dev_get_uv_token(fido_dev_t *, uint8_t, const char *, - const fido_blob_t *, const es256_pk_t *, const char *, fido_blob_t *); + const fido_blob_t *, const es256_pk_t *, const char *, fido_blob_t *, + int *); uint64_t fido_dev_maxmsgsize(const fido_dev_t *); -int fido_do_ecdh(fido_dev_t *, es256_pk_t **, fido_blob_t **); +int fido_do_ecdh(fido_dev_t *, es256_pk_t **, fido_blob_t **, int *); bool fido_dev_supports_permissions(const fido_dev_t *); +/* types */ +void fido_algo_array_free(fido_algo_array_t *); +void fido_byte_array_free(fido_byte_array_t *); +void fido_opt_array_free(fido_opt_array_t *); +void fido_str_array_free(fido_str_array_t *); +void fido_algo_free(fido_algo_t *); +int fido_str_array_pack(fido_str_array_t *, const char * const *, size_t); + /* misc */ void fido_assert_reset_rx(fido_assert_t *); void fido_assert_reset_tx(fido_assert_t *); void fido_cred_reset_rx(fido_cred_t *); void fido_cred_reset_tx(fido_cred_t *); void fido_cbor_info_reset(fido_cbor_info_t *); int fido_blob_serialise(fido_blob_t *, const cbor_item_t *); int fido_check_flags(uint8_t, fido_opt_t, fido_opt_t); int fido_check_rp_id(const char *, const unsigned char *); int fido_get_random(void *, size_t); int fido_sha256(fido_blob_t *, const u_char *, size_t); +int fido_time_now(struct timespec *); +int fido_time_delta(const struct timespec *, int *); /* crypto */ -int fido_verify_sig_es256(const fido_blob_t *, const es256_pk_t *, +int es256_verify_sig(const fido_blob_t *, EVP_PKEY *, const fido_blob_t *); +int rs256_verify_sig(const fido_blob_t *, EVP_PKEY *, const fido_blob_t *); +int eddsa_verify_sig(const fido_blob_t *, EVP_PKEY *, const fido_blob_t *); +int rs1_verify_sig(const fido_blob_t *, EVP_PKEY *, const fido_blob_t *); +int es256_pk_verify_sig(const fido_blob_t *, const es256_pk_t *, const fido_blob_t *); -int fido_verify_sig_rs256(const fido_blob_t *, const rs256_pk_t *, +int rs256_pk_verify_sig(const fido_blob_t *, const rs256_pk_t *, const fido_blob_t *); -int fido_verify_sig_eddsa(const fido_blob_t *, const eddsa_pk_t *, +int eddsa_pk_verify_sig(const fido_blob_t *, const eddsa_pk_t *, const fido_blob_t *); int fido_get_signed_hash(int, fido_blob_t *, const fido_blob_t *, const fido_blob_t *); +int fido_get_signed_hash_tpm(fido_blob_t *, const fido_blob_t *, + const fido_blob_t *, const fido_attstmt_t *, const fido_attcred_t *); /* device manifest functions */ int fido_hid_manifest(fido_dev_info_t *, size_t, size_t *); int fido_nfc_manifest(fido_dev_info_t *, size_t, size_t *); /* device manifest registration */ typedef int (*dev_manifest_func_t)(fido_dev_info_t *, size_t, size_t *); int fido_dev_register_manifest_func(const dev_manifest_func_t); void fido_dev_unregister_manifest_func(const dev_manifest_func_t); /* fuzzing instrumentation */ #ifdef FIDO_FUZZ uint32_t uniform_random(uint32_t); #endif /* internal device capability flags */ #define FIDO_DEV_PIN_SET 0x001 #define FIDO_DEV_PIN_UNSET 0x002 #define FIDO_DEV_CRED_PROT 0x004 #define FIDO_DEV_CREDMAN 0x008 #define FIDO_DEV_PIN_PROTOCOL1 0x010 #define FIDO_DEV_PIN_PROTOCOL2 0x020 #define FIDO_DEV_UV_SET 0x040 #define FIDO_DEV_UV_UNSET 0x080 #define FIDO_DEV_TOKEN_PERMS 0x100 #define FIDO_DEV_WINHELLO 0x200 /* miscellanea */ #define FIDO_DUMMY_CLIENTDATA "" #define FIDO_DUMMY_RP_ID "localhost" #define FIDO_DUMMY_USER_NAME "dummy" #define FIDO_DUMMY_USER_ID 1 #define FIDO_WINHELLO_PATH "windows://hello" +#define FIDO_NFC_PREFIX "nfc:" #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* !_EXTERN_H */ diff --git a/contrib/libfido2/src/fido.h b/contrib/libfido2/src/fido.h index d5446516f972..51bdb526d3f0 100644 --- a/contrib/libfido2/src/fido.h +++ b/contrib/libfido2/src/fido.h @@ -1,228 +1,234 @@ /* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _FIDO_H #define _FIDO_H #include #include #include #include #include #ifdef _FIDO_INTERNAL #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "blob.h" #include "iso7816.h" #include "extern.h" #endif #include "fido/err.h" #include "fido/param.h" #include "fido/types.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ fido_assert_t *fido_assert_new(void); fido_cred_t *fido_cred_new(void); fido_dev_t *fido_dev_new(void); fido_dev_t *fido_dev_new_with_info(const fido_dev_info_t *); fido_dev_info_t *fido_dev_info_new(size_t); fido_cbor_info_t *fido_cbor_info_new(void); void fido_assert_free(fido_assert_t **); void fido_cbor_info_free(fido_cbor_info_t **); void fido_cred_free(fido_cred_t **); void fido_dev_force_fido2(fido_dev_t *); void fido_dev_force_u2f(fido_dev_t *); void fido_dev_free(fido_dev_t **); void fido_dev_info_free(fido_dev_info_t **, size_t); /* fido_init() flags. */ #define FIDO_DEBUG 0x01 #define FIDO_DISABLE_U2F_FALLBACK 0x02 void fido_init(int); void fido_set_log_handler(fido_log_handler_t *); const unsigned char *fido_assert_authdata_ptr(const fido_assert_t *, size_t); const unsigned char *fido_assert_clientdata_hash_ptr(const fido_assert_t *); const unsigned char *fido_assert_hmac_secret_ptr(const fido_assert_t *, size_t); const unsigned char *fido_assert_id_ptr(const fido_assert_t *, size_t); const unsigned char *fido_assert_largeblob_key_ptr(const fido_assert_t *, size_t); const unsigned char *fido_assert_sig_ptr(const fido_assert_t *, size_t); const unsigned char *fido_assert_user_id_ptr(const fido_assert_t *, size_t); const unsigned char *fido_assert_blob_ptr(const fido_assert_t *, size_t); char **fido_cbor_info_extensions_ptr(const fido_cbor_info_t *); char **fido_cbor_info_options_name_ptr(const fido_cbor_info_t *); char **fido_cbor_info_transports_ptr(const fido_cbor_info_t *); char **fido_cbor_info_versions_ptr(const fido_cbor_info_t *); const bool *fido_cbor_info_options_value_ptr(const fido_cbor_info_t *); const char *fido_assert_rp_id(const fido_assert_t *); const char *fido_assert_user_display_name(const fido_assert_t *, size_t); const char *fido_assert_user_icon(const fido_assert_t *, size_t); const char *fido_assert_user_name(const fido_assert_t *, size_t); const char *fido_cbor_info_algorithm_type(const fido_cbor_info_t *, size_t); const char *fido_cred_display_name(const fido_cred_t *); const char *fido_cred_fmt(const fido_cred_t *); const char *fido_cred_rp_id(const fido_cred_t *); const char *fido_cred_rp_name(const fido_cred_t *); const char *fido_cred_user_name(const fido_cred_t *); const char *fido_dev_info_manufacturer_string(const fido_dev_info_t *); const char *fido_dev_info_path(const fido_dev_info_t *); const char *fido_dev_info_product_string(const fido_dev_info_t *); const fido_dev_info_t *fido_dev_info_ptr(const fido_dev_info_t *, size_t); const uint8_t *fido_cbor_info_protocols_ptr(const fido_cbor_info_t *); const unsigned char *fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *); +const unsigned char *fido_cred_aaguid_ptr(const fido_cred_t *); +const unsigned char *fido_cred_attstmt_ptr(const fido_cred_t *); const unsigned char *fido_cred_authdata_ptr(const fido_cred_t *); const unsigned char *fido_cred_authdata_raw_ptr(const fido_cred_t *); const unsigned char *fido_cred_clientdata_hash_ptr(const fido_cred_t *); const unsigned char *fido_cred_id_ptr(const fido_cred_t *); -const unsigned char *fido_cred_aaguid_ptr(const fido_cred_t *); -const unsigned char *fido_cred_user_id_ptr(const fido_cred_t *); +const unsigned char *fido_cred_largeblob_key_ptr(const fido_cred_t *); const unsigned char *fido_cred_pubkey_ptr(const fido_cred_t *); const unsigned char *fido_cred_sig_ptr(const fido_cred_t *); +const unsigned char *fido_cred_user_id_ptr(const fido_cred_t *); const unsigned char *fido_cred_x5c_ptr(const fido_cred_t *); -const unsigned char *fido_cred_largeblob_key_ptr(const fido_cred_t *); int fido_assert_allow_cred(fido_assert_t *, const unsigned char *, size_t); int fido_assert_set_authdata(fido_assert_t *, size_t, const unsigned char *, size_t); int fido_assert_set_authdata_raw(fido_assert_t *, size_t, const unsigned char *, size_t); int fido_assert_set_clientdata(fido_assert_t *, const unsigned char *, size_t); int fido_assert_set_clientdata_hash(fido_assert_t *, const unsigned char *, size_t); int fido_assert_set_count(fido_assert_t *, size_t); int fido_assert_set_extensions(fido_assert_t *, int); int fido_assert_set_hmac_salt(fido_assert_t *, const unsigned char *, size_t); int fido_assert_set_hmac_secret(fido_assert_t *, size_t, const unsigned char *, size_t); int fido_assert_set_options(fido_assert_t *, bool, bool); int fido_assert_set_rp(fido_assert_t *, const char *); int fido_assert_set_up(fido_assert_t *, fido_opt_t); int fido_assert_set_uv(fido_assert_t *, fido_opt_t); int fido_assert_set_sig(fido_assert_t *, size_t, const unsigned char *, size_t); int fido_assert_verify(const fido_assert_t *, size_t, int, const void *); int fido_cbor_info_algorithm_cose(const fido_cbor_info_t *, size_t); int fido_cred_exclude(fido_cred_t *, const unsigned char *, size_t); int fido_cred_prot(const fido_cred_t *); +int fido_cred_set_attstmt(fido_cred_t *, const unsigned char *, size_t); int fido_cred_set_authdata(fido_cred_t *, const unsigned char *, size_t); int fido_cred_set_authdata_raw(fido_cred_t *, const unsigned char *, size_t); int fido_cred_set_blob(fido_cred_t *, const unsigned char *, size_t); int fido_cred_set_clientdata(fido_cred_t *, const unsigned char *, size_t); int fido_cred_set_clientdata_hash(fido_cred_t *, const unsigned char *, size_t); int fido_cred_set_extensions(fido_cred_t *, int); int fido_cred_set_fmt(fido_cred_t *, const char *); int fido_cred_set_id(fido_cred_t *, const unsigned char *, size_t); int fido_cred_set_options(fido_cred_t *, bool, bool); +int fido_cred_set_pin_minlen(fido_cred_t *, size_t); int fido_cred_set_prot(fido_cred_t *, int); int fido_cred_set_rk(fido_cred_t *, fido_opt_t); int fido_cred_set_rp(fido_cred_t *, const char *, const char *); int fido_cred_set_sig(fido_cred_t *, const unsigned char *, size_t); int fido_cred_set_type(fido_cred_t *, int); int fido_cred_set_uv(fido_cred_t *, fido_opt_t); int fido_cred_type(const fido_cred_t *); int fido_cred_set_user(fido_cred_t *, const unsigned char *, size_t, const char *, const char *, const char *); int fido_cred_set_x509(fido_cred_t *, const unsigned char *, size_t); int fido_cred_verify(const fido_cred_t *); int fido_cred_verify_self(const fido_cred_t *); int fido_dev_set_sigmask(fido_dev_t *, const fido_sigset_t *); int fido_dev_cancel(fido_dev_t *); int fido_dev_close(fido_dev_t *); int fido_dev_get_assert(fido_dev_t *, fido_assert_t *, const char *); int fido_dev_get_cbor_info(fido_dev_t *, fido_cbor_info_t *); int fido_dev_get_retry_count(fido_dev_t *, int *); int fido_dev_get_uv_retry_count(fido_dev_t *, int *); int fido_dev_get_touch_begin(fido_dev_t *); int fido_dev_get_touch_status(fido_dev_t *, int *, int); int fido_dev_info_manifest(fido_dev_info_t *, size_t, size_t *); int fido_dev_make_cred(fido_dev_t *, fido_cred_t *, const char *); int fido_dev_open_with_info(fido_dev_t *); int fido_dev_open(fido_dev_t *, const char *); int fido_dev_reset(fido_dev_t *); int fido_dev_set_io_functions(fido_dev_t *, const fido_dev_io_t *); int fido_dev_set_pin(fido_dev_t *, const char *, const char *); int fido_dev_set_transport_functions(fido_dev_t *, const fido_dev_transport_t *); +int fido_dev_set_timeout(fido_dev_t *, int); size_t fido_assert_authdata_len(const fido_assert_t *, size_t); size_t fido_assert_clientdata_hash_len(const fido_assert_t *); size_t fido_assert_count(const fido_assert_t *); size_t fido_assert_hmac_secret_len(const fido_assert_t *, size_t); size_t fido_assert_id_len(const fido_assert_t *, size_t); size_t fido_assert_largeblob_key_len(const fido_assert_t *, size_t); size_t fido_assert_sig_len(const fido_assert_t *, size_t); size_t fido_assert_user_id_len(const fido_assert_t *, size_t); size_t fido_assert_blob_len(const fido_assert_t *, size_t); size_t fido_cbor_info_aaguid_len(const fido_cbor_info_t *); size_t fido_cbor_info_algorithm_count(const fido_cbor_info_t *); size_t fido_cbor_info_extensions_len(const fido_cbor_info_t *); size_t fido_cbor_info_options_len(const fido_cbor_info_t *); size_t fido_cbor_info_protocols_len(const fido_cbor_info_t *); size_t fido_cbor_info_transports_len(const fido_cbor_info_t *); size_t fido_cbor_info_versions_len(const fido_cbor_info_t *); +size_t fido_cred_aaguid_len(const fido_cred_t *); +size_t fido_cred_attstmt_len(const fido_cred_t *); size_t fido_cred_authdata_len(const fido_cred_t *); size_t fido_cred_authdata_raw_len(const fido_cred_t *); size_t fido_cred_clientdata_hash_len(const fido_cred_t *); size_t fido_cred_id_len(const fido_cred_t *); -size_t fido_cred_aaguid_len(const fido_cred_t *); -size_t fido_cred_user_id_len(const fido_cred_t *); +size_t fido_cred_largeblob_key_len(const fido_cred_t *); +size_t fido_cred_pin_minlen(const fido_cred_t *); size_t fido_cred_pubkey_len(const fido_cred_t *); size_t fido_cred_sig_len(const fido_cred_t *); +size_t fido_cred_user_id_len(const fido_cred_t *); size_t fido_cred_x5c_len(const fido_cred_t *); -size_t fido_cred_largeblob_key_len(const fido_cred_t *); uint8_t fido_assert_flags(const fido_assert_t *, size_t); uint32_t fido_assert_sigcount(const fido_assert_t *, size_t); uint8_t fido_cred_flags(const fido_cred_t *); uint32_t fido_cred_sigcount(const fido_cred_t *); uint8_t fido_dev_protocol(const fido_dev_t *); uint8_t fido_dev_major(const fido_dev_t *); uint8_t fido_dev_minor(const fido_dev_t *); uint8_t fido_dev_build(const fido_dev_t *); uint8_t fido_dev_flags(const fido_dev_t *); int16_t fido_dev_info_vendor(const fido_dev_info_t *); int16_t fido_dev_info_product(const fido_dev_info_t *); uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *); uint64_t fido_cbor_info_maxcredbloblen(const fido_cbor_info_t *); uint64_t fido_cbor_info_maxcredcntlst(const fido_cbor_info_t *); uint64_t fido_cbor_info_maxcredidlen(const fido_cbor_info_t *); uint64_t fido_cbor_info_fwversion(const fido_cbor_info_t *); bool fido_dev_has_pin(const fido_dev_t *); bool fido_dev_has_uv(const fido_dev_t *); bool fido_dev_is_fido2(const fido_dev_t *); bool fido_dev_is_winhello(const fido_dev_t *); bool fido_dev_supports_pin(const fido_dev_t *); bool fido_dev_supports_cred_prot(const fido_dev_t *); bool fido_dev_supports_credman(const fido_dev_t *); bool fido_dev_supports_uv(const fido_dev_t *); int fido_dev_largeblob_get(fido_dev_t *, const unsigned char *, size_t, unsigned char **, size_t *); int fido_dev_largeblob_set(fido_dev_t *, const unsigned char *, size_t, const unsigned char *, size_t, const char *); int fido_dev_largeblob_remove(fido_dev_t *, const unsigned char *, size_t, const char *); int fido_dev_largeblob_get_array(fido_dev_t *, unsigned char **, size_t *); int fido_dev_largeblob_set_array(fido_dev_t *, const unsigned char *, size_t, const char *); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* !_FIDO_H */ diff --git a/contrib/libfido2/src/fido/config.h b/contrib/libfido2/src/fido/config.h index 869927df914b..d8134a3c7b6c 100644 --- a/contrib/libfido2/src/fido/config.h +++ b/contrib/libfido2/src/fido/config.h @@ -1,34 +1,36 @@ /* * Copyright (c) 2020 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _FIDO_CONFIG_H #define _FIDO_CONFIG_H #ifdef _FIDO_INTERNAL #include "blob.h" #include "fido/err.h" #include "fido/param.h" #include "fido/types.h" #else #include #include #include #endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ int fido_dev_enable_entattest(fido_dev_t *, const char *); int fido_dev_force_pin_change(fido_dev_t *, const char *); int fido_dev_toggle_always_uv(fido_dev_t *, const char *); int fido_dev_set_pin_minlen(fido_dev_t *, size_t, const char *); +int fido_dev_set_pin_minlen_rpid(fido_dev_t *, const char * const *, size_t, + const char *); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* !_FIDO_CONFIG_H */ diff --git a/contrib/libfido2/src/fido/eddsa.h b/contrib/libfido2/src/fido/eddsa.h index 4a810179b6fa..083721cc3d3f 100644 --- a/contrib/libfido2/src/fido/eddsa.h +++ b/contrib/libfido2/src/fido/eddsa.h @@ -1,54 +1,49 @@ /* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _FIDO_EDDSA_H #define _FIDO_EDDSA_H #include #include #include #ifdef _FIDO_INTERNAL #include "types.h" #else #include #endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ eddsa_pk_t *eddsa_pk_new(void); void eddsa_pk_free(eddsa_pk_t **); EVP_PKEY *eddsa_pk_to_EVP_PKEY(const eddsa_pk_t *); int eddsa_pk_from_EVP_PKEY(eddsa_pk_t *, const EVP_PKEY *); int eddsa_pk_from_ptr(eddsa_pk_t *, const void *, size_t); #ifdef _FIDO_INTERNAL -#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10101000L +#if defined(LIBRESSL_VERSION_NUMBER) #define EVP_PKEY_ED25519 EVP_PKEY_NONE int EVP_PKEY_get_raw_public_key(const EVP_PKEY *, unsigned char *, size_t *); EVP_PKEY *EVP_PKEY_new_raw_public_key(int, ENGINE *, const unsigned char *, size_t); int EVP_DigestVerify(EVP_MD_CTX *, const unsigned char *, size_t, const unsigned char *, size_t); -#endif /* LIBRESSL_VERSION_NUMBER || OPENSSL_VERSION_NUMBER < 0x10101000L */ - -#if OPENSSL_VERSION_NUMBER < 0x10100000L -EVP_MD_CTX *EVP_MD_CTX_new(void); -void EVP_MD_CTX_free(EVP_MD_CTX *); -#endif +#endif /* LIBRESSL_VERSION_NUMBER */ #endif /* _FIDO_INTERNAL */ #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* !_FIDO_EDDSA_H */ diff --git a/contrib/libfido2/src/fido/es256.h b/contrib/libfido2/src/fido/es256.h index 80f4db39c7b0..683494dadfe2 100644 --- a/contrib/libfido2/src/fido/es256.h +++ b/contrib/libfido2/src/fido/es256.h @@ -1,48 +1,49 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _FIDO_ES256_H #define _FIDO_ES256_H #include #include #include #ifdef _FIDO_INTERNAL #include "types.h" #else #include #endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ es256_pk_t *es256_pk_new(void); void es256_pk_free(es256_pk_t **); EVP_PKEY *es256_pk_to_EVP_PKEY(const es256_pk_t *); int es256_pk_from_EC_KEY(es256_pk_t *, const EC_KEY *); +int es256_pk_from_EVP_PKEY(es256_pk_t *, const EVP_PKEY *); int es256_pk_from_ptr(es256_pk_t *, const void *, size_t); #ifdef _FIDO_INTERNAL es256_sk_t *es256_sk_new(void); void es256_sk_free(es256_sk_t **); EVP_PKEY *es256_sk_to_EVP_PKEY(const es256_sk_t *); int es256_derive_pk(const es256_sk_t *, es256_pk_t *); int es256_sk_create(es256_sk_t *); int es256_pk_set_x(es256_pk_t *, const unsigned char *); int es256_pk_set_y(es256_pk_t *, const unsigned char *); #endif #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* !_FIDO_ES256_H */ diff --git a/contrib/libfido2/src/fido/param.h b/contrib/libfido2/src/fido/param.h index 025bb57dd81c..7c6db98cfd5d 100644 --- a/contrib/libfido2/src/fido/param.h +++ b/contrib/libfido2/src/fido/param.h @@ -1,117 +1,121 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _FIDO_PARAM_H #define _FIDO_PARAM_H /* Authentication data flags. */ #define CTAP_AUTHDATA_USER_PRESENT 0x01 #define CTAP_AUTHDATA_USER_VERIFIED 0x04 #define CTAP_AUTHDATA_ATT_CRED 0x40 #define CTAP_AUTHDATA_EXT_DATA 0x80 /* CTAPHID command opcodes. */ #define CTAP_CMD_PING 0x01 #define CTAP_CMD_MSG 0x03 #define CTAP_CMD_LOCK 0x04 #define CTAP_CMD_INIT 0x06 #define CTAP_CMD_WINK 0x08 #define CTAP_CMD_CBOR 0x10 #define CTAP_CMD_CANCEL 0x11 #define CTAP_KEEPALIVE 0x3b #define CTAP_FRAME_INIT 0x80 /* CTAPHID CBOR command opcodes. */ #define CTAP_CBOR_MAKECRED 0x01 #define CTAP_CBOR_ASSERT 0x02 #define CTAP_CBOR_GETINFO 0x04 #define CTAP_CBOR_CLIENT_PIN 0x06 #define CTAP_CBOR_RESET 0x07 #define CTAP_CBOR_NEXT_ASSERT 0x08 #define CTAP_CBOR_LARGEBLOB 0x0c #define CTAP_CBOR_CONFIG 0x0d #define CTAP_CBOR_BIO_ENROLL_PRE 0x40 #define CTAP_CBOR_CRED_MGMT_PRE 0x41 /* Supported CTAP PIN/UV Auth Protocols. */ #define CTAP_PIN_PROTOCOL1 1 #define CTAP_PIN_PROTOCOL2 2 /* U2F command opcodes. */ #define U2F_CMD_REGISTER 0x01 #define U2F_CMD_AUTH 0x02 /* U2F command flags. */ #define U2F_AUTH_SIGN 0x03 #define U2F_AUTH_CHECK 0x07 /* ISO7816-4 status words. */ #define SW1_MORE_DATA 0x61 #define SW_CONDITIONS_NOT_SATISFIED 0x6985 #define SW_WRONG_DATA 0x6a80 #define SW_NO_ERROR 0x9000 /* HID Broadcast channel ID. */ #define CTAP_CID_BROADCAST 0xffffffff #define CTAP_INIT_HEADER_LEN 7 #define CTAP_CONT_HEADER_LEN 5 /* Maximum length of a CTAP HID report in bytes. */ #define CTAP_MAX_REPORT_LEN 64 /* Minimum length of a CTAP HID report in bytes. */ #define CTAP_MIN_REPORT_LEN (CTAP_INIT_HEADER_LEN + 1) /* Randomness device on UNIX-like platforms. */ #ifndef FIDO_RANDOM_DEV #define FIDO_RANDOM_DEV "/dev/urandom" #endif /* Maximum message size in bytes. */ #ifndef FIDO_MAXMSG #define FIDO_MAXMSG 2048 #endif /* CTAP capability bits. */ #define FIDO_CAP_WINK 0x01 /* if set, device supports CTAP_CMD_WINK */ #define FIDO_CAP_CBOR 0x04 /* if set, device supports CTAP_CMD_CBOR */ #define FIDO_CAP_NMSG 0x08 /* if set, device doesn't support CTAP_CMD_MSG */ /* Supported COSE algorithms. */ +#define COSE_UNSPEC 0 #define COSE_ES256 -7 #define COSE_EDDSA -8 #define COSE_ECDH_ES256 -25 #define COSE_RS256 -257 +#define COSE_RS1 -65535 /* Supported COSE types. */ #define COSE_KTY_OKP 1 #define COSE_KTY_EC2 2 #define COSE_KTY_RSA 3 /* Supported curves. */ #define COSE_P256 1 #define COSE_ED25519 6 /* Supported extensions. */ #define FIDO_EXT_HMAC_SECRET 0x01 #define FIDO_EXT_CRED_PROTECT 0x02 #define FIDO_EXT_LARGEBLOB_KEY 0x04 #define FIDO_EXT_CRED_BLOB 0x08 +#define FIDO_EXT_MINPINLEN 0x10 /* Supported credential protection policies. */ #define FIDO_CRED_PROT_UV_OPTIONAL 0x01 #define FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID 0x02 #define FIDO_CRED_PROT_UV_REQUIRED 0x03 #ifdef _FIDO_INTERNAL #define FIDO_EXT_ASSERT_MASK (FIDO_EXT_HMAC_SECRET|FIDO_EXT_LARGEBLOB_KEY| \ FIDO_EXT_CRED_BLOB) #define FIDO_EXT_CRED_MASK (FIDO_EXT_HMAC_SECRET|FIDO_EXT_CRED_PROTECT| \ - FIDO_EXT_LARGEBLOB_KEY|FIDO_EXT_CRED_BLOB) + FIDO_EXT_LARGEBLOB_KEY|FIDO_EXT_CRED_BLOB| \ + FIDO_EXT_MINPINLEN) #endif /* _FIDO_INTERNAL */ #endif /* !_FIDO_PARAM_H */ diff --git a/contrib/libfido2/src/fido/rs256.h b/contrib/libfido2/src/fido/rs256.h index 2b08d59980c1..039816191783 100644 --- a/contrib/libfido2/src/fido/rs256.h +++ b/contrib/libfido2/src/fido/rs256.h @@ -1,36 +1,37 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _FIDO_RS256_H #define _FIDO_RS256_H #include #include #include #ifdef _FIDO_INTERNAL #include "types.h" #else #include #endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ rs256_pk_t *rs256_pk_new(void); void rs256_pk_free(rs256_pk_t **); EVP_PKEY *rs256_pk_to_EVP_PKEY(const rs256_pk_t *); +int rs256_pk_from_EVP_PKEY(rs256_pk_t *, const EVP_PKEY *); int rs256_pk_from_RSA(rs256_pk_t *, const RSA *); int rs256_pk_from_ptr(rs256_pk_t *, const void *, size_t); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* !_FIDO_RS256_H */ diff --git a/contrib/libfido2/src/fido/types.h b/contrib/libfido2/src/fido/types.h index 00b6058c7e13..92f55d979fdc 100644 --- a/contrib/libfido2/src/fido/types.h +++ b/contrib/libfido2/src/fido/types.h @@ -1,281 +1,287 @@ /* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _FIDO_TYPES_H #define _FIDO_TYPES_H #ifdef __MINGW32__ #include #endif #include #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ struct fido_dev; typedef void *fido_dev_io_open_t(const char *); typedef void fido_dev_io_close_t(void *); typedef int fido_dev_io_read_t(void *, unsigned char *, size_t, int); typedef int fido_dev_io_write_t(void *, const unsigned char *, size_t); typedef int fido_dev_rx_t(struct fido_dev *, uint8_t, unsigned char *, size_t, int); typedef int fido_dev_tx_t(struct fido_dev *, uint8_t, const unsigned char *, size_t); typedef struct fido_dev_io { fido_dev_io_open_t *open; fido_dev_io_close_t *close; fido_dev_io_read_t *read; fido_dev_io_write_t *write; } fido_dev_io_t; typedef struct fido_dev_transport { fido_dev_rx_t *rx; fido_dev_tx_t *tx; } fido_dev_transport_t; typedef enum { FIDO_OPT_OMIT = 0, /* use authenticator's default */ FIDO_OPT_FALSE, /* explicitly set option to false */ FIDO_OPT_TRUE, /* explicitly set option to true */ } fido_opt_t; typedef void fido_log_handler_t(const char *); #ifdef _WIN32 typedef int fido_sigset_t; #else typedef sigset_t fido_sigset_t; #endif #ifdef _FIDO_INTERNAL #include "packed.h" #include "blob.h" /* COSE ES256 (ECDSA over P-256 with SHA-256) public key */ typedef struct es256_pk { unsigned char x[32]; unsigned char y[32]; } es256_pk_t; /* COSE ES256 (ECDSA over P-256 with SHA-256) (secret) key */ typedef struct es256_sk { unsigned char d[32]; } es256_sk_t; /* COSE RS256 (2048-bit RSA with PKCS1 padding and SHA-256) public key */ typedef struct rs256_pk { unsigned char n[256]; unsigned char e[3]; } rs256_pk_t; /* COSE EDDSA (ED25519) */ typedef struct eddsa_pk { unsigned char x[32]; } eddsa_pk_t; PACKED_TYPE(fido_authdata_t, struct fido_authdata { unsigned char rp_id_hash[32]; /* sha256 of fido_rp.id */ uint8_t flags; /* user present/verified */ uint32_t sigcount; /* signature counter */ /* actually longer */ }) PACKED_TYPE(fido_attcred_raw_t, struct fido_attcred_raw { unsigned char aaguid[16]; /* credential's aaguid */ uint16_t id_len; /* credential id length */ uint8_t body[]; /* credential id + pubkey */ }) typedef struct fido_attcred { unsigned char aaguid[16]; /* credential's aaguid */ fido_blob_t id; /* credential id */ int type; /* credential's cose algorithm */ union { /* credential's public key */ es256_pk_t es256; rs256_pk_t rs256; eddsa_pk_t eddsa; } pubkey; } fido_attcred_t; typedef struct fido_attstmt { - fido_blob_t x5c; /* attestation certificate */ - fido_blob_t sig; /* attestation signature */ + fido_blob_t certinfo; /* tpm attestation TPMS_ATTEST structure */ + fido_blob_t pubarea; /* tpm attestation TPMT_PUBLIC structure */ + fido_blob_t cbor; /* cbor-encoded attestation statement */ + fido_blob_t x5c; /* attestation certificate */ + fido_blob_t sig; /* attestation signature */ + int alg; /* attestation algorithm (cose) */ } fido_attstmt_t; typedef struct fido_rp { char *id; /* relying party id */ char *name; /* relying party name */ } fido_rp_t; typedef struct fido_user { fido_blob_t id; /* required */ char *icon; /* optional */ char *name; /* optional */ char *display_name; /* required */ } fido_user_t; typedef struct fido_cred_ext { - int mask; /* enabled extensions */ - int prot; /* protection policy */ + int mask; /* enabled extensions */ + int prot; /* protection policy */ + size_t minpinlen; /* minimum pin length */ } fido_cred_ext_t; typedef struct fido_cred { fido_blob_t cd; /* client data */ fido_blob_t cdh; /* client data hash */ fido_rp_t rp; /* relying party */ fido_user_t user; /* user entity */ fido_blob_array_t excl; /* list of credential ids to exclude */ fido_opt_t rk; /* resident key */ fido_opt_t uv; /* user verification */ fido_cred_ext_t ext; /* extensions */ int type; /* cose algorithm */ char *fmt; /* credential format */ fido_cred_ext_t authdata_ext; /* decoded extensions */ fido_blob_t authdata_cbor; /* cbor-encoded payload */ fido_blob_t authdata_raw; /* cbor-decoded payload */ fido_authdata_t authdata; /* decoded authdata payload */ fido_attcred_t attcred; /* returned credential (key + id) */ fido_attstmt_t attstmt; /* attestation statement (x509 + sig) */ fido_blob_t largeblob_key; /* decoded large blob key */ fido_blob_t blob; /* FIDO 2.1 credBlob */ } fido_cred_t; typedef struct fido_assert_extattr { int mask; /* decoded extensions */ fido_blob_t hmac_secret_enc; /* hmac secret, encrypted */ fido_blob_t blob; /* decoded FIDO 2.1 credBlob */ } fido_assert_extattr_t; typedef struct _fido_assert_stmt { fido_blob_t id; /* credential id */ fido_user_t user; /* user attributes */ fido_blob_t hmac_secret; /* hmac secret */ fido_assert_extattr_t authdata_ext; /* decoded extensions */ fido_blob_t authdata_cbor; /* raw cbor payload */ fido_authdata_t authdata; /* decoded authdata payload */ fido_blob_t sig; /* signature of cdh + authdata */ fido_blob_t largeblob_key; /* decoded large blob key */ } fido_assert_stmt; typedef struct fido_assert_ext { int mask; /* enabled extensions */ fido_blob_t hmac_salt; /* optional hmac-secret salt */ } fido_assert_ext_t; typedef struct fido_assert { char *rp_id; /* relying party id */ fido_blob_t cd; /* client data */ fido_blob_t cdh; /* client data hash */ fido_blob_array_t allow_list; /* list of allowed credentials */ fido_opt_t up; /* user presence */ fido_opt_t uv; /* user verification */ fido_assert_ext_t ext; /* enabled extensions */ fido_assert_stmt *stmt; /* array of expected assertions */ size_t stmt_cnt; /* number of allocated assertions */ size_t stmt_len; /* number of received assertions */ } fido_assert_t; typedef struct fido_opt_array { char **name; bool *value; size_t len; } fido_opt_array_t; typedef struct fido_str_array { char **ptr; size_t len; } fido_str_array_t; typedef struct fido_byte_array { uint8_t *ptr; size_t len; } fido_byte_array_t; typedef struct fido_algo { char *type; int cose; } fido_algo_t; typedef struct fido_algo_array { fido_algo_t *ptr; size_t len; } fido_algo_array_t; typedef struct fido_cbor_info { fido_str_array_t versions; /* supported versions: fido2|u2f */ fido_str_array_t extensions; /* list of supported extensions */ fido_str_array_t transports; /* list of supported transports */ unsigned char aaguid[16]; /* aaguid */ fido_opt_array_t options; /* list of supported options */ uint64_t maxmsgsiz; /* maximum message size */ fido_byte_array_t protocols; /* supported pin protocols */ fido_algo_array_t algorithms; /* list of supported algorithms */ uint64_t maxcredcntlst; /* max number of credentials in list */ uint64_t maxcredidlen; /* max credential ID length */ uint64_t fwversion; /* firmware version */ uint64_t maxcredbloblen; /* max credBlob length */ } fido_cbor_info_t; typedef struct fido_dev_info { char *path; /* device path */ int16_t vendor_id; /* 2-byte vendor id */ int16_t product_id; /* 2-byte product id */ char *manufacturer; /* manufacturer string */ char *product; /* product string */ fido_dev_io_t io; /* i/o functions */ fido_dev_transport_t transport; /* transport functions */ } fido_dev_info_t; PACKED_TYPE(fido_ctap_info_t, /* defined in section 8.1.9.1.3 (CTAPHID_INIT) of the fido2 ctap spec */ struct fido_ctap_info { uint64_t nonce; /* echoed nonce */ uint32_t cid; /* channel id */ uint8_t protocol; /* ctaphid protocol id */ uint8_t major; /* major version number */ uint8_t minor; /* minor version number */ uint8_t build; /* build version number */ uint8_t flags; /* capabilities flags; see FIDO_CAP_* */ }) typedef struct fido_dev { uint64_t nonce; /* issued nonce */ fido_ctap_info_t attr; /* device attributes */ uint32_t cid; /* assigned channel id */ char *path; /* device path */ void *io_handle; /* abstract i/o handle */ fido_dev_io_t io; /* i/o functions */ bool io_own; /* device has own io/transport */ size_t rx_len; /* length of HID input reports */ size_t tx_len; /* length of HID output reports */ int flags; /* internal flags; see FIDO_DEV_* */ fido_dev_transport_t transport; /* transport functions */ uint64_t maxmsgsize; /* max message size */ + int timeout_ms; /* read timeout in ms */ } fido_dev_t; #else typedef struct fido_assert fido_assert_t; typedef struct fido_cbor_info fido_cbor_info_t; typedef struct fido_cred fido_cred_t; typedef struct fido_dev fido_dev_t; typedef struct fido_dev_info fido_dev_info_t; typedef struct es256_pk es256_pk_t; typedef struct es256_sk es256_sk_t; typedef struct rs256_pk rs256_pk_t; typedef struct eddsa_pk eddsa_pk_t; #endif /* _FIDO_INTERNAL */ #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* !_FIDO_TYPES_H */ diff --git a/contrib/libfido2/src/hid_freebsd.c b/contrib/libfido2/src/hid_freebsd.c index 86c1854e9c8c..5aefe69c1bec 100644 --- a/contrib/libfido2/src/hid_freebsd.c +++ b/contrib/libfido2/src/hid_freebsd.c @@ -1,253 +1,259 @@ /* * Copyright (c) 2020 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "fido.h" +#if defined(__MidnightBSD__) +#define UHID_VENDOR "MidnightBSD" +#else +#define UHID_VENDOR "FreeBSD" +#endif + #define MAX_UHID 64 struct hid_freebsd { int fd; size_t report_in_len; size_t report_out_len; sigset_t sigmask; const sigset_t *sigmaskp; }; static bool is_fido(int fd) { char buf[64]; struct usb_gen_descriptor ugd; uint32_t usage_page = 0; memset(&buf, 0, sizeof(buf)); memset(&ugd, 0, sizeof(ugd)); ugd.ugd_report_type = UHID_FEATURE_REPORT; ugd.ugd_data = buf; ugd.ugd_maxlen = sizeof(buf); if (ioctl(fd, IOCTL_REQ(USB_GET_REPORT_DESC), &ugd) == -1) { fido_log_error(errno, "%s: ioctl", __func__); return (false); } if (ugd.ugd_actlen > sizeof(buf) || fido_hid_get_usage(ugd.ugd_data, ugd.ugd_actlen, &usage_page) < 0) { fido_log_debug("%s: fido_hid_get_usage", __func__); return (false); } return (usage_page == 0xf1d0); } static int copy_info(fido_dev_info_t *di, const char *path) { int fd = -1; int ok = -1; struct usb_device_info udi; memset(di, 0, sizeof(*di)); memset(&udi, 0, sizeof(udi)); if ((fd = fido_hid_unix_open(path)) == -1 || is_fido(fd) == 0) goto fail; if (ioctl(fd, IOCTL_REQ(USB_GET_DEVICEINFO), &udi) == -1) { fido_log_error(errno, "%s: ioctl", __func__); - strlcpy(udi.udi_vendor, "FreeBSD", sizeof(udi.udi_vendor)); + strlcpy(udi.udi_vendor, UHID_VENDOR, sizeof(udi.udi_vendor)); strlcpy(udi.udi_product, "uhid(4)", sizeof(udi.udi_product)); udi.udi_vendorNo = 0x0b5d; /* stolen from PCI_VENDOR_OPENBSD */ } if ((di->path = strdup(path)) == NULL || (di->manufacturer = strdup(udi.udi_vendor)) == NULL || (di->product = strdup(udi.udi_product)) == NULL) goto fail; di->vendor_id = (int16_t)udi.udi_vendorNo; di->product_id = (int16_t)udi.udi_productNo; ok = 0; fail: if (fd != -1) close(fd); if (ok < 0) { free(di->path); free(di->manufacturer); free(di->product); explicit_bzero(di, sizeof(*di)); } return (ok); } int fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { char path[64]; size_t i; *olen = 0; if (ilen == 0) return (FIDO_OK); /* nothing to do */ if (devlist == NULL || olen == NULL) return (FIDO_ERR_INVALID_ARGUMENT); for (i = *olen = 0; i < MAX_UHID && *olen < ilen; i++) { snprintf(path, sizeof(path), "/dev/uhid%zu", i); if (copy_info(&devlist[*olen], path) == 0) { devlist[*olen].io = (fido_dev_io_t) { fido_hid_open, fido_hid_close, fido_hid_read, fido_hid_write, }; ++(*olen); } } return (FIDO_OK); } void * fido_hid_open(const char *path) { char buf[64]; struct hid_freebsd *ctx; struct usb_gen_descriptor ugd; int r; memset(&buf, 0, sizeof(buf)); memset(&ugd, 0, sizeof(ugd)); if ((ctx = calloc(1, sizeof(*ctx))) == NULL) return (NULL); if ((ctx->fd = fido_hid_unix_open(path)) == -1) { free(ctx); return (NULL); } ugd.ugd_report_type = UHID_FEATURE_REPORT; ugd.ugd_data = buf; ugd.ugd_maxlen = sizeof(buf); if ((r = ioctl(ctx->fd, IOCTL_REQ(USB_GET_REPORT_DESC), &ugd) == -1) || ugd.ugd_actlen > sizeof(buf) || fido_hid_get_report_len(ugd.ugd_data, ugd.ugd_actlen, &ctx->report_in_len, &ctx->report_out_len) < 0) { if (r == -1) fido_log_error(errno, "%s: ioctl", __func__); fido_log_debug("%s: using default report sizes", __func__); ctx->report_in_len = CTAP_MAX_REPORT_LEN; ctx->report_out_len = CTAP_MAX_REPORT_LEN; } return (ctx); } void fido_hid_close(void *handle) { struct hid_freebsd *ctx = handle; if (close(ctx->fd) == -1) fido_log_error(errno, "%s: close", __func__); free(ctx); } int fido_hid_set_sigmask(void *handle, const fido_sigset_t *sigmask) { struct hid_freebsd *ctx = handle; ctx->sigmask = *sigmask; ctx->sigmaskp = &ctx->sigmask; return (FIDO_OK); } int fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) { struct hid_freebsd *ctx = handle; ssize_t r; if (len != ctx->report_in_len) { fido_log_debug("%s: len %zu", __func__, len); return (-1); } if (fido_hid_unix_wait(ctx->fd, ms, ctx->sigmaskp) < 0) { fido_log_debug("%s: fd not ready", __func__); return (-1); } if ((r = read(ctx->fd, buf, len)) == -1) { fido_log_error(errno, "%s: read", __func__); return (-1); } if (r < 0 || (size_t)r != len) { fido_log_debug("%s: %zd != %zu", __func__, r, len); return (-1); } return ((int)r); } int fido_hid_write(void *handle, const unsigned char *buf, size_t len) { struct hid_freebsd *ctx = handle; ssize_t r; if (len != ctx->report_out_len + 1) { fido_log_debug("%s: len %zu", __func__, len); return (-1); } if ((r = write(ctx->fd, buf + 1, len - 1)) == -1) { fido_log_error(errno, "%s: write", __func__); return (-1); } if (r < 0 || (size_t)r != len - 1) { fido_log_debug("%s: %zd != %zu", __func__, r, len - 1); return (-1); } return ((int)len); } size_t fido_hid_report_in_len(void *handle) { struct hid_freebsd *ctx = handle; return (ctx->report_in_len); } size_t fido_hid_report_out_len(void *handle) { struct hid_freebsd *ctx = handle; return (ctx->report_out_len); } diff --git a/contrib/libfido2/src/hid_linux.c b/contrib/libfido2/src/hid_linux.c index c622880a2594..c4ce4fd578a6 100644 --- a/contrib/libfido2/src/hid_linux.c +++ b/contrib/libfido2/src/hid_linux.c @@ -1,375 +1,375 @@ /* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include #include #include #include "fido.h" struct hid_linux { int fd; size_t report_in_len; size_t report_out_len; sigset_t sigmask; const sigset_t *sigmaskp; }; static int get_report_descriptor(int fd, struct hidraw_report_descriptor *hrd) { int s = -1; if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESCSIZE), &s) == -1) { fido_log_error(errno, "%s: ioctl HIDIOCGRDESCSIZE", __func__); return (-1); } if (s < 0 || (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) { fido_log_debug("%s: HIDIOCGRDESCSIZE %d", __func__, s); return (-1); } hrd->size = (unsigned)s; if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESC), hrd) == -1) { fido_log_error(errno, "%s: ioctl HIDIOCGRDESC", __func__); return (-1); } return (0); } static bool is_fido(const char *path) { int fd; uint32_t usage_page = 0; struct hidraw_report_descriptor hrd; memset(&hrd, 0, sizeof(hrd)); if ((fd = fido_hid_unix_open(path)) == -1) return (false); if (get_report_descriptor(fd, &hrd) < 0 || fido_hid_get_usage(hrd.value, hrd.size, &usage_page) < 0) usage_page = 0; if (close(fd) == -1) fido_log_error(errno, "%s: close", __func__); return (usage_page == 0xf1d0); } static int parse_uevent(const char *uevent, int *bus, int16_t *vendor_id, int16_t *product_id) { char *cp; char *p; char *s; int ok = -1; short unsigned int x; short unsigned int y; short unsigned int z; if ((s = cp = strdup(uevent)) == NULL) return (-1); while ((p = strsep(&cp, "\n")) != NULL && *p != '\0') { if (strncmp(p, "HID_ID=", 7) == 0) { if (sscanf(p + 7, "%hx:%hx:%hx", &x, &y, &z) == 3) { *bus = (int)x; *vendor_id = (int16_t)y; *product_id = (int16_t)z; ok = 0; break; } } } free(s); return (ok); } static char * get_parent_attr(struct udev_device *dev, const char *subsystem, const char *devtype, const char *attr) { struct udev_device *parent; const char *value; if ((parent = udev_device_get_parent_with_subsystem_devtype(dev, subsystem, devtype)) == NULL || (value = udev_device_get_sysattr_value(parent, attr)) == NULL) return (NULL); return (strdup(value)); } static char * get_usb_attr(struct udev_device *dev, const char *attr) { return (get_parent_attr(dev, "usb", "usb_device", attr)); } static int copy_info(fido_dev_info_t *di, struct udev *udev, struct udev_list_entry *udev_entry) { const char *name; const char *path; char *uevent = NULL; struct udev_device *dev = NULL; int bus = 0; int ok = -1; memset(di, 0, sizeof(*di)); if ((name = udev_list_entry_get_name(udev_entry)) == NULL || (dev = udev_device_new_from_syspath(udev, name)) == NULL || (path = udev_device_get_devnode(dev)) == NULL || is_fido(path) == 0) goto fail; if ((uevent = get_parent_attr(dev, "hid", NULL, "uevent")) == NULL || parse_uevent(uevent, &bus, &di->vendor_id, &di->product_id) < 0) { fido_log_debug("%s: uevent", __func__); goto fail; } #ifndef FIDO_HID_ANY if (bus != BUS_USB) { fido_log_debug("%s: bus", __func__); goto fail; } #endif di->path = strdup(path); if ((di->manufacturer = get_usb_attr(dev, "manufacturer")) == NULL) - di->manufacturer = strdup("unknown"); + di->manufacturer = strdup(""); if ((di->product = get_usb_attr(dev, "product")) == NULL) - di->product = strdup("unknown"); + di->product = strdup(""); if (di->path == NULL || di->manufacturer == NULL || di->product == NULL) goto fail; ok = 0; fail: if (dev != NULL) udev_device_unref(dev); free(uevent); if (ok < 0) { free(di->path); free(di->manufacturer); free(di->product); explicit_bzero(di, sizeof(*di)); } return (ok); } int fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { struct udev *udev = NULL; struct udev_enumerate *udev_enum = NULL; struct udev_list_entry *udev_list; struct udev_list_entry *udev_entry; int r = FIDO_ERR_INTERNAL; *olen = 0; if (ilen == 0) return (FIDO_OK); /* nothing to do */ if (devlist == NULL) return (FIDO_ERR_INVALID_ARGUMENT); if ((udev = udev_new()) == NULL || (udev_enum = udev_enumerate_new(udev)) == NULL) goto fail; if (udev_enumerate_add_match_subsystem(udev_enum, "hidraw") < 0 || udev_enumerate_scan_devices(udev_enum) < 0) goto fail; if ((udev_list = udev_enumerate_get_list_entry(udev_enum)) == NULL) { r = FIDO_OK; /* zero hidraw devices */ goto fail; } udev_list_entry_foreach(udev_entry, udev_list) { if (copy_info(&devlist[*olen], udev, udev_entry) == 0) { devlist[*olen].io = (fido_dev_io_t) { fido_hid_open, fido_hid_close, fido_hid_read, fido_hid_write, }; if (++(*olen) == ilen) break; } } r = FIDO_OK; fail: if (udev_enum != NULL) udev_enumerate_unref(udev_enum); if (udev != NULL) udev_unref(udev); return (r); } void * fido_hid_open(const char *path) { struct hid_linux *ctx; struct hidraw_report_descriptor hrd; struct timespec tv_pause; long interval_ms, retries = 0; if ((ctx = calloc(1, sizeof(*ctx))) == NULL || (ctx->fd = fido_hid_unix_open(path)) == -1) { free(ctx); return (NULL); } while (flock(ctx->fd, LOCK_EX|LOCK_NB) == -1) { if (errno != EWOULDBLOCK) { fido_log_error(errno, "%s: flock", __func__); fido_hid_close(ctx); return (NULL); } if (retries++ >= 15) { fido_log_debug("%s: flock timeout", __func__); fido_hid_close(ctx); return (NULL); } interval_ms = retries * 100000000L; tv_pause.tv_sec = interval_ms / 1000000000L; tv_pause.tv_nsec = interval_ms % 1000000000L; if (nanosleep(&tv_pause, NULL) == -1) { fido_log_error(errno, "%s: nanosleep", __func__); fido_hid_close(ctx); return (NULL); } } if (get_report_descriptor(ctx->fd, &hrd) < 0 || fido_hid_get_report_len(hrd.value, hrd.size, &ctx->report_in_len, &ctx->report_out_len) < 0 || ctx->report_in_len == 0 || ctx->report_out_len == 0) { fido_log_debug("%s: using default report sizes", __func__); ctx->report_in_len = CTAP_MAX_REPORT_LEN; ctx->report_out_len = CTAP_MAX_REPORT_LEN; } return (ctx); } void fido_hid_close(void *handle) { struct hid_linux *ctx = handle; if (close(ctx->fd) == -1) fido_log_error(errno, "%s: close", __func__); free(ctx); } int fido_hid_set_sigmask(void *handle, const fido_sigset_t *sigmask) { struct hid_linux *ctx = handle; ctx->sigmask = *sigmask; ctx->sigmaskp = &ctx->sigmask; return (FIDO_OK); } int fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) { struct hid_linux *ctx = handle; ssize_t r; if (len != ctx->report_in_len) { fido_log_debug("%s: len %zu", __func__, len); return (-1); } if (fido_hid_unix_wait(ctx->fd, ms, ctx->sigmaskp) < 0) { fido_log_debug("%s: fd not ready", __func__); return (-1); } if ((r = read(ctx->fd, buf, len)) == -1) { fido_log_error(errno, "%s: read", __func__); return (-1); } if (r < 0 || (size_t)r != len) { fido_log_debug("%s: %zd != %zu", __func__, r, len); return (-1); } return ((int)r); } int fido_hid_write(void *handle, const unsigned char *buf, size_t len) { struct hid_linux *ctx = handle; ssize_t r; if (len != ctx->report_out_len + 1) { fido_log_debug("%s: len %zu", __func__, len); return (-1); } if ((r = write(ctx->fd, buf, len)) == -1) { fido_log_error(errno, "%s: write", __func__); return (-1); } if (r < 0 || (size_t)r != len) { fido_log_debug("%s: %zd != %zu", __func__, r, len); return (-1); } return ((int)r); } size_t fido_hid_report_in_len(void *handle) { struct hid_linux *ctx = handle; return (ctx->report_in_len); } size_t fido_hid_report_out_len(void *handle) { struct hid_linux *ctx = handle; return (ctx->report_out_len); } diff --git a/contrib/libfido2/src/hid_openbsd.c b/contrib/libfido2/src/hid_openbsd.c index fbf10fd11ab9..d3d3bff0fc8b 100644 --- a/contrib/libfido2/src/hid_openbsd.c +++ b/contrib/libfido2/src/hid_openbsd.c @@ -1,260 +1,267 @@ /* * Copyright (c) 2019 Google LLC. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include #include #include "fido.h" #define MAX_UHID 64 struct hid_openbsd { int fd; size_t report_in_len; size_t report_out_len; + sigset_t sigmask; + const sigset_t *sigmaskp; }; int fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { size_t i; char path[64]; int fd; struct usb_device_info udi; fido_dev_info_t *di; if (ilen == 0) return (FIDO_OK); /* nothing to do */ if (devlist == NULL || olen == NULL) return (FIDO_ERR_INVALID_ARGUMENT); for (i = *olen = 0; i < MAX_UHID && *olen < ilen; i++) { snprintf(path, sizeof(path), "/dev/fido/%zu", i); if ((fd = fido_hid_unix_open(path)) == -1) continue; memset(&udi, 0, sizeof(udi)); if (ioctl(fd, IOCTL_REQ(USB_GET_DEVICEINFO), &udi) == -1) { fido_log_error(errno, "%s: get device info %s", __func__, path); if (close(fd) == -1) fido_log_error(errno, "%s: close", __func__); continue; } if (close(fd) == -1) fido_log_error(errno, "%s: close", __func__); fido_log_debug("%s: %s: bus = 0x%02x, addr = 0x%02x", __func__, path, udi.udi_bus, udi.udi_addr); fido_log_debug("%s: %s: vendor = \"%s\", product = \"%s\"", __func__, path, udi.udi_vendor, udi.udi_product); fido_log_debug("%s: %s: productNo = 0x%04x, vendorNo = 0x%04x, " "releaseNo = 0x%04x", __func__, path, udi.udi_productNo, udi.udi_vendorNo, udi.udi_releaseNo); di = &devlist[*olen]; memset(di, 0, sizeof(*di)); di->io = (fido_dev_io_t) { fido_hid_open, fido_hid_close, fido_hid_read, fido_hid_write, }; if ((di->path = strdup(path)) == NULL || (di->manufacturer = strdup(udi.udi_vendor)) == NULL || (di->product = strdup(udi.udi_product)) == NULL) { free(di->path); free(di->manufacturer); free(di->product); explicit_bzero(di, sizeof(*di)); return FIDO_ERR_INTERNAL; } di->vendor_id = (int16_t)udi.udi_vendorNo; di->product_id = (int16_t)udi.udi_productNo; (*olen)++; } return FIDO_OK; } /* * Workaround for OpenBSD <=6.6-current (as of 201910) bug that loses * sync of DATA0/DATA1 sequence bit across uhid open/close. * Send pings until we get a response - early pings with incorrect * sequence bits will be ignored as duplicate packets by the device. */ static int terrible_ping_kludge(struct hid_openbsd *ctx) { u_char data[256]; int i, n; struct pollfd pfd; if (sizeof(data) < ctx->report_out_len + 1) return -1; for (i = 0; i < 4; i++) { memset(data, 0, sizeof(data)); /* broadcast channel ID */ data[1] = 0xff; data[2] = 0xff; data[3] = 0xff; data[4] = 0xff; /* Ping command */ data[5] = 0x81; /* One byte ping only, Vasili */ data[6] = 0; data[7] = 1; fido_log_debug("%s: send ping %d", __func__, i); if (fido_hid_write(ctx, data, ctx->report_out_len + 1) == -1) return -1; fido_log_debug("%s: wait reply", __func__); memset(&pfd, 0, sizeof(pfd)); pfd.fd = ctx->fd; pfd.events = POLLIN; if ((n = poll(&pfd, 1, 100)) == -1) { fido_log_error(errno, "%s: poll", __func__); return -1; } else if (n == 0) { fido_log_debug("%s: timed out", __func__); continue; } if (fido_hid_read(ctx, data, ctx->report_out_len, 250) == -1) return -1; /* * Ping isn't always supported on the broadcast channel, * so we might get an error, but we don't care - we're * synched now. */ fido_log_xxd(data, ctx->report_out_len, "%s: got reply", __func__); return 0; } fido_log_debug("%s: no response", __func__); return -1; } void * fido_hid_open(const char *path) { struct hid_openbsd *ret = NULL; if ((ret = calloc(1, sizeof(*ret))) == NULL || (ret->fd = fido_hid_unix_open(path)) == -1) { free(ret); return (NULL); } ret->report_in_len = ret->report_out_len = CTAP_MAX_REPORT_LEN; fido_log_debug("%s: inlen = %zu outlen = %zu", __func__, ret->report_in_len, ret->report_out_len); /* * OpenBSD (as of 201910) has a bug that causes it to lose * track of the DATA0/DATA1 sequence toggle across uhid device * open and close. This is a terrible hack to work around it. */ if (terrible_ping_kludge(ret) != 0) { fido_hid_close(ret); return NULL; } return (ret); } void fido_hid_close(void *handle) { struct hid_openbsd *ctx = (struct hid_openbsd *)handle; if (close(ctx->fd) == -1) fido_log_error(errno, "%s: close", __func__); free(ctx); } int fido_hid_set_sigmask(void *handle, const fido_sigset_t *sigmask) { - (void)handle; - (void)sigmask; + struct hid_openbsd *ctx = handle; + + ctx->sigmask = *sigmask; + ctx->sigmaskp = &ctx->sigmask; - return (FIDO_ERR_INTERNAL); + return (FIDO_OK); } int fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) { struct hid_openbsd *ctx = (struct hid_openbsd *)handle; ssize_t r; - (void)ms; /* XXX */ - if (len != ctx->report_in_len) { fido_log_debug("%s: invalid len: got %zu, want %zu", __func__, len, ctx->report_in_len); return (-1); } + if (fido_hid_unix_wait(ctx->fd, ms, ctx->sigmaskp) < 0) { + fido_log_debug("%s: fd not ready", __func__); + return (-1); + } + if ((r = read(ctx->fd, buf, len)) == -1) { fido_log_error(errno, "%s: read", __func__); return (-1); } if (r < 0 || (size_t)r != len) { fido_log_debug("%s: %zd != %zu", __func__, r, len); return (-1); } return ((int)len); } int fido_hid_write(void *handle, const unsigned char *buf, size_t len) { struct hid_openbsd *ctx = (struct hid_openbsd *)handle; ssize_t r; if (len != ctx->report_out_len + 1) { fido_log_debug("%s: invalid len: got %zu, want %zu", __func__, len, ctx->report_out_len); return (-1); } if ((r = write(ctx->fd, buf + 1, len - 1)) == -1) { fido_log_error(errno, "%s: write", __func__); return (-1); } if (r < 0 || (size_t)r != len - 1) { fido_log_debug("%s: %zd != %zu", __func__, r, len - 1); return (-1); } return ((int)len); } size_t fido_hid_report_in_len(void *handle) { struct hid_openbsd *ctx = handle; return (ctx->report_in_len); } size_t fido_hid_report_out_len(void *handle) { struct hid_openbsd *ctx = handle; return (ctx->report_out_len); } diff --git a/contrib/libfido2/src/hid_osx.c b/contrib/libfido2/src/hid_osx.c index e9866658a4eb..1f8b37a65597 100644 --- a/contrib/libfido2/src/hid_osx.c +++ b/contrib/libfido2/src/hid_osx.c @@ -1,571 +1,571 @@ /* * Copyright (c) 2019 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include +#include #include #include #include #include #include "fido.h" +#if __MAC_OS_X_VERSION_MIN_REQUIRED < 120000 +#define kIOMainPortDefault kIOMasterPortDefault +#endif + struct hid_osx { IOHIDDeviceRef ref; CFStringRef loop_id; int report_pipe[2]; size_t report_in_len; size_t report_out_len; unsigned char report[CTAP_MAX_REPORT_LEN]; }; static int get_int32(IOHIDDeviceRef dev, CFStringRef key, int32_t *v) { CFTypeRef ref; if ((ref = IOHIDDeviceGetProperty(dev, key)) == NULL || CFGetTypeID(ref) != CFNumberGetTypeID()) { fido_log_debug("%s: IOHIDDeviceGetProperty", __func__); return (-1); } if (CFNumberGetType(ref) != kCFNumberSInt32Type && CFNumberGetType(ref) != kCFNumberSInt64Type) { fido_log_debug("%s: CFNumberGetType", __func__); return (-1); } if (CFNumberGetValue(ref, kCFNumberSInt32Type, v) == false) { fido_log_debug("%s: CFNumberGetValue", __func__); return (-1); } return (0); } static int get_utf8(IOHIDDeviceRef dev, CFStringRef key, void *buf, size_t len) { CFTypeRef ref; memset(buf, 0, len); if ((ref = IOHIDDeviceGetProperty(dev, key)) == NULL || CFGetTypeID(ref) != CFStringGetTypeID()) { fido_log_debug("%s: IOHIDDeviceGetProperty", __func__); return (-1); } if (CFStringGetCString(ref, buf, (long)len, kCFStringEncodingUTF8) == false) { fido_log_debug("%s: CFStringGetCString", __func__); return (-1); } return (0); } static int get_report_len(IOHIDDeviceRef dev, int dir, size_t *report_len) { CFStringRef key; int32_t v; if (dir == 0) key = CFSTR(kIOHIDMaxInputReportSizeKey); else key = CFSTR(kIOHIDMaxOutputReportSizeKey); if (get_int32(dev, key, &v) < 0) { fido_log_debug("%s: get_int32/%d", __func__, dir); return (-1); } if ((*report_len = (size_t)v) > CTAP_MAX_REPORT_LEN) { fido_log_debug("%s: report_len=%zu", __func__, *report_len); return (-1); } return (0); } static int get_id(IOHIDDeviceRef dev, int16_t *vendor_id, int16_t *product_id) { int32_t vendor; int32_t product; if (get_int32(dev, CFSTR(kIOHIDVendorIDKey), &vendor) < 0 || vendor > UINT16_MAX) { fido_log_debug("%s: get_int32 vendor", __func__); return (-1); } if (get_int32(dev, CFSTR(kIOHIDProductIDKey), &product) < 0 || product > UINT16_MAX) { fido_log_debug("%s: get_int32 product", __func__); return (-1); } *vendor_id = (int16_t)vendor; *product_id = (int16_t)product; return (0); } static int get_str(IOHIDDeviceRef dev, char **manufacturer, char **product) { char buf[512]; int ok = -1; *manufacturer = NULL; *product = NULL; - if (get_utf8(dev, CFSTR(kIOHIDManufacturerKey), buf, sizeof(buf)) < 0) { - fido_log_debug("%s: get_utf8 manufacturer", __func__); - goto fail; - } - - if ((*manufacturer = strdup(buf)) == NULL) { - fido_log_debug("%s: strdup manufacturer", __func__); - goto fail; - } + if (get_utf8(dev, CFSTR(kIOHIDManufacturerKey), buf, sizeof(buf)) < 0) + *manufacturer = strdup(""); + else + *manufacturer = strdup(buf); - if (get_utf8(dev, CFSTR(kIOHIDProductKey), buf, sizeof(buf)) < 0) { - fido_log_debug("%s: get_utf8 product", __func__); - goto fail; - } + if (get_utf8(dev, CFSTR(kIOHIDProductKey), buf, sizeof(buf)) < 0) + *product = strdup(""); + else + *product = strdup(buf); - if ((*product = strdup(buf)) == NULL) { - fido_log_debug("%s: strdup product", __func__); + if (*manufacturer == NULL || *product == NULL) { + fido_log_debug("%s: strdup", __func__); goto fail; } ok = 0; fail: if (ok < 0) { free(*manufacturer); free(*product); *manufacturer = NULL; *product = NULL; } return (ok); } static char * get_path(IOHIDDeviceRef dev) { io_service_t s; io_string_t path; if ((s = IOHIDDeviceGetService(dev)) == MACH_PORT_NULL) { fido_log_debug("%s: IOHIDDeviceGetService", __func__); return (NULL); } if (IORegistryEntryGetPath(s, kIOServicePlane, path) != KERN_SUCCESS) { fido_log_debug("%s: IORegistryEntryGetPath", __func__); return (NULL); } return (strdup(path)); } static bool is_fido(IOHIDDeviceRef dev) { char buf[32]; uint32_t usage_page; if (get_int32(dev, CFSTR(kIOHIDPrimaryUsagePageKey), (int32_t *)&usage_page) < 0 || usage_page != 0xf1d0) return (false); if (get_utf8(dev, CFSTR(kIOHIDTransportKey), buf, sizeof(buf)) < 0) { fido_log_debug("%s: get_utf8 transport", __func__); return (false); } #ifndef FIDO_HID_ANY if (strcasecmp(buf, "usb") != 0) { fido_log_debug("%s: transport", __func__); return (false); } #endif return (true); } static int copy_info(fido_dev_info_t *di, IOHIDDeviceRef dev) { memset(di, 0, sizeof(*di)); if (is_fido(dev) == false) return (-1); if (get_id(dev, &di->vendor_id, &di->product_id) < 0 || get_str(dev, &di->manufacturer, &di->product) < 0 || (di->path = get_path(dev)) == NULL) { free(di->path); free(di->manufacturer); free(di->product); explicit_bzero(di, sizeof(*di)); return (-1); } return (0); } int fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { IOHIDManagerRef manager = NULL; CFSetRef devset = NULL; size_t devcnt; CFIndex n; IOHIDDeviceRef *devs = NULL; int r = FIDO_ERR_INTERNAL; *olen = 0; if (ilen == 0) return (FIDO_OK); /* nothing to do */ if (devlist == NULL) return (FIDO_ERR_INVALID_ARGUMENT); if ((manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDManagerOptionNone)) == NULL) { fido_log_debug("%s: IOHIDManagerCreate", __func__); goto fail; } IOHIDManagerSetDeviceMatching(manager, NULL); if ((devset = IOHIDManagerCopyDevices(manager)) == NULL) { fido_log_debug("%s: IOHIDManagerCopyDevices", __func__); goto fail; } if ((n = CFSetGetCount(devset)) < 0) { fido_log_debug("%s: CFSetGetCount", __func__); goto fail; } devcnt = (size_t)n; if ((devs = calloc(devcnt, sizeof(*devs))) == NULL) { fido_log_debug("%s: calloc", __func__); goto fail; } CFSetGetValues(devset, (void *)devs); for (size_t i = 0; i < devcnt; i++) { if (copy_info(&devlist[*olen], devs[i]) == 0) { devlist[*olen].io = (fido_dev_io_t) { fido_hid_open, fido_hid_close, fido_hid_read, fido_hid_write, }; if (++(*olen) == ilen) break; } } r = FIDO_OK; fail: if (manager != NULL) CFRelease(manager); if (devset != NULL) CFRelease(devset); free(devs); return (r); } static void report_callback(void *context, IOReturn result, void *dev, IOHIDReportType type, uint32_t id, uint8_t *ptr, CFIndex len) { struct hid_osx *ctx = context; ssize_t r; (void)dev; if (result != kIOReturnSuccess || type != kIOHIDReportTypeInput || id != 0 || len < 0 || (size_t)len != ctx->report_in_len) { fido_log_debug("%s: io error", __func__); return; } if ((r = write(ctx->report_pipe[1], ptr, (size_t)len)) == -1) { fido_log_error(errno, "%s: write", __func__); return; } if (r < 0 || (size_t)r != (size_t)len) { fido_log_debug("%s: %zd != %zu", __func__, r, (size_t)len); return; } } static void removal_callback(void *context, IOReturn result, void *sender) { (void)context; (void)result; (void)sender; CFRunLoopStop(CFRunLoopGetCurrent()); } static int set_nonblock(int fd) { int flags; if ((flags = fcntl(fd, F_GETFL)) == -1) { fido_log_error(errno, "%s: fcntl F_GETFL", __func__); return (-1); } if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { fido_log_error(errno, "%s: fcntl F_SETFL", __func__); return (-1); } return (0); } static int disable_sigpipe(int fd) { int disabled = 1; if (fcntl(fd, F_SETNOSIGPIPE, &disabled) == -1) { fido_log_error(errno, "%s: fcntl F_SETNOSIGPIPE", __func__); return (-1); } return (0); } void * fido_hid_open(const char *path) { struct hid_osx *ctx; io_registry_entry_t entry = MACH_PORT_NULL; char loop_id[32]; int ok = -1; int r; if ((ctx = calloc(1, sizeof(*ctx))) == NULL) { fido_log_debug("%s: calloc", __func__); goto fail; } ctx->report_pipe[0] = -1; ctx->report_pipe[1] = -1; if (pipe(ctx->report_pipe) == -1) { fido_log_error(errno, "%s: pipe", __func__); goto fail; } if (set_nonblock(ctx->report_pipe[0]) < 0 || set_nonblock(ctx->report_pipe[1]) < 0) { fido_log_debug("%s: set_nonblock", __func__); goto fail; } if (disable_sigpipe(ctx->report_pipe[1]) < 0) { fido_log_debug("%s: disable_sigpipe", __func__); goto fail; } - if ((entry = IORegistryEntryFromPath(kIOMasterPortDefault, + if ((entry = IORegistryEntryFromPath(kIOMainPortDefault, path)) == MACH_PORT_NULL) { fido_log_debug("%s: IORegistryEntryFromPath", __func__); goto fail; } if ((ctx->ref = IOHIDDeviceCreate(kCFAllocatorDefault, entry)) == NULL) { fido_log_debug("%s: IOHIDDeviceCreate", __func__); goto fail; } if (get_report_len(ctx->ref, 0, &ctx->report_in_len) < 0 || get_report_len(ctx->ref, 1, &ctx->report_out_len) < 0) { fido_log_debug("%s: get_report_len", __func__); goto fail; } if (ctx->report_in_len > sizeof(ctx->report)) { fido_log_debug("%s: report_in_len=%zu", __func__, ctx->report_in_len); goto fail; } if (IOHIDDeviceOpen(ctx->ref, kIOHIDOptionsTypeSeizeDevice) != kIOReturnSuccess) { fido_log_debug("%s: IOHIDDeviceOpen", __func__); goto fail; } if ((r = snprintf(loop_id, sizeof(loop_id), "fido2-%p", (void *)ctx->ref)) < 0 || (size_t)r >= sizeof(loop_id)) { fido_log_debug("%s: snprintf", __func__); goto fail; } if ((ctx->loop_id = CFStringCreateWithCString(NULL, loop_id, kCFStringEncodingASCII)) == NULL) { fido_log_debug("%s: CFStringCreateWithCString", __func__); goto fail; } IOHIDDeviceRegisterInputReportCallback(ctx->ref, ctx->report, (long)ctx->report_in_len, &report_callback, ctx); IOHIDDeviceRegisterRemovalCallback(ctx->ref, &removal_callback, ctx); ok = 0; fail: if (entry != MACH_PORT_NULL) IOObjectRelease(entry); if (ok < 0 && ctx != NULL) { if (ctx->ref != NULL) CFRelease(ctx->ref); if (ctx->loop_id != NULL) CFRelease(ctx->loop_id); if (ctx->report_pipe[0] != -1) close(ctx->report_pipe[0]); if (ctx->report_pipe[1] != -1) close(ctx->report_pipe[1]); free(ctx); ctx = NULL; } return (ctx); } void fido_hid_close(void *handle) { struct hid_osx *ctx = handle; IOHIDDeviceRegisterInputReportCallback(ctx->ref, ctx->report, (long)ctx->report_in_len, NULL, ctx); IOHIDDeviceRegisterRemovalCallback(ctx->ref, NULL, ctx); if (IOHIDDeviceClose(ctx->ref, kIOHIDOptionsTypeSeizeDevice) != kIOReturnSuccess) fido_log_debug("%s: IOHIDDeviceClose", __func__); CFRelease(ctx->ref); CFRelease(ctx->loop_id); explicit_bzero(ctx->report, sizeof(ctx->report)); close(ctx->report_pipe[0]); close(ctx->report_pipe[1]); free(ctx); } int fido_hid_set_sigmask(void *handle, const fido_sigset_t *sigmask) { (void)handle; (void)sigmask; return (FIDO_ERR_INTERNAL); } int fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) { struct hid_osx *ctx = handle; ssize_t r; explicit_bzero(buf, len); explicit_bzero(ctx->report, sizeof(ctx->report)); if (len != ctx->report_in_len || len > sizeof(ctx->report)) { fido_log_debug("%s: len %zu", __func__, len); return (-1); } IOHIDDeviceScheduleWithRunLoop(ctx->ref, CFRunLoopGetCurrent(), ctx->loop_id); if (ms == -1) ms = 5000; /* wait 5 seconds by default */ CFRunLoopRunInMode(ctx->loop_id, (double)ms/1000.0, true); IOHIDDeviceUnscheduleFromRunLoop(ctx->ref, CFRunLoopGetCurrent(), ctx->loop_id); if ((r = read(ctx->report_pipe[0], buf, len)) == -1) { fido_log_error(errno, "%s: read", __func__); return (-1); } if (r < 0 || (size_t)r != len) { fido_log_debug("%s: %zd != %zu", __func__, r, len); return (-1); } return ((int)len); } int fido_hid_write(void *handle, const unsigned char *buf, size_t len) { struct hid_osx *ctx = handle; if (len != ctx->report_out_len + 1 || len > LONG_MAX) { fido_log_debug("%s: len %zu", __func__, len); return (-1); } if (IOHIDDeviceSetReport(ctx->ref, kIOHIDReportTypeOutput, 0, buf + 1, (long)(len - 1)) != kIOReturnSuccess) { fido_log_debug("%s: IOHIDDeviceSetReport", __func__); return (-1); } return ((int)len); } size_t fido_hid_report_in_len(void *handle) { struct hid_osx *ctx = handle; return (ctx->report_in_len); } size_t fido_hid_report_out_len(void *handle) { struct hid_osx *ctx = handle; return (ctx->report_out_len); } diff --git a/contrib/libfido2/src/hid_unix.c b/contrib/libfido2/src/hid_unix.c index 4b2aff9d67f6..946b2dc3b65f 100644 --- a/contrib/libfido2/src/hid_unix.c +++ b/contrib/libfido2/src/hid_unix.c @@ -1,76 +1,75 @@ /* * Copyright (c) 2020 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "fido.h" #ifdef __NetBSD__ #define ppoll pollts #endif int fido_hid_unix_open(const char *path) { int fd; struct stat st; if ((fd = open(path, O_RDWR)) == -1) { if (errno != ENOENT && errno != ENXIO) fido_log_error(errno, "%s: open %s", __func__, path); return (-1); } if (fstat(fd, &st) == -1) { fido_log_error(errno, "%s: fstat %s", __func__, path); if (close(fd) == -1) fido_log_error(errno, "%s: close", __func__); return (-1); } if (S_ISCHR(st.st_mode) == 0) { fido_log_debug("%s: S_ISCHR %s", __func__, path); if (close(fd) == -1) fido_log_error(errno, "%s: close", __func__); return (-1); } return (fd); } int fido_hid_unix_wait(int fd, int ms, const fido_sigset_t *sigmask) { struct timespec ts; struct pollfd pfd; int r; memset(&pfd, 0, sizeof(pfd)); pfd.events = POLLIN; pfd.fd = fd; #ifdef FIDO_FUZZ - if (ms < 0) - return (0); + return (0); #endif if (ms > -1) { ts.tv_sec = ms / 1000; ts.tv_nsec = (ms % 1000) * 1000000; } if ((r = ppoll(&pfd, 1, ms > -1 ? &ts : NULL, sigmask)) < 1) { if (r == -1) fido_log_error(errno, "%s: ppoll", __func__); return (-1); } return (0); } diff --git a/contrib/libfido2/src/hid_win.c b/contrib/libfido2/src/hid_win.c index 455cf8bae835..c29ef70253d7 100644 --- a/contrib/libfido2/src/hid_win.c +++ b/contrib/libfido2/src/hid_win.c @@ -1,540 +1,570 @@ /* - * Copyright (c) 2019 Yubico AB. All rights reserved. + * Copyright (c) 2019-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include #include #include #include #include "fido.h" #if defined(__MINGW32__) && __MINGW64_VERSION_MAJOR < 6 WINSETUPAPI WINBOOL WINAPI SetupDiGetDevicePropertyW(HDEVINFO, PSP_DEVINFO_DATA, const DEVPROPKEY *, DEVPROPTYPE *, PBYTE, DWORD, PDWORD, DWORD); #endif #if defined(__MINGW32__) DEFINE_DEVPROPKEY(DEVPKEY_Device_Parent, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 8); #endif struct hid_win { HANDLE dev; OVERLAPPED overlap; int report_pending; size_t report_in_len; size_t report_out_len; unsigned char report[1 + CTAP_MAX_REPORT_LEN]; }; static bool is_fido(HANDLE dev) { PHIDP_PREPARSED_DATA data = NULL; HIDP_CAPS caps; int fido = 0; if (HidD_GetPreparsedData(dev, &data) == false) { fido_log_debug("%s: HidD_GetPreparsedData", __func__); goto fail; } if (HidP_GetCaps(data, &caps) != HIDP_STATUS_SUCCESS) { fido_log_debug("%s: HidP_GetCaps", __func__); goto fail; } fido = (uint16_t)caps.UsagePage == 0xf1d0; fail: if (data != NULL) HidD_FreePreparsedData(data); return (fido); } static int get_report_len(HANDLE dev, int dir, size_t *report_len) { PHIDP_PREPARSED_DATA data = NULL; HIDP_CAPS caps; USHORT v; int ok = -1; if (HidD_GetPreparsedData(dev, &data) == false) { fido_log_debug("%s: HidD_GetPreparsedData/%d", __func__, dir); goto fail; } if (HidP_GetCaps(data, &caps) != HIDP_STATUS_SUCCESS) { fido_log_debug("%s: HidP_GetCaps/%d", __func__, dir); goto fail; } if (dir == 0) v = caps.InputReportByteLength; else v = caps.OutputReportByteLength; if ((*report_len = (size_t)v) == 0) { fido_log_debug("%s: report_len == 0", __func__); goto fail; } ok = 0; fail: if (data != NULL) HidD_FreePreparsedData(data); return (ok); } static int -get_int(HANDLE dev, int16_t *vendor_id, int16_t *product_id) +get_id(HANDLE dev, int16_t *vendor_id, int16_t *product_id) { HIDD_ATTRIBUTES attr; attr.Size = sizeof(attr); if (HidD_GetAttributes(dev, &attr) == false) { fido_log_debug("%s: HidD_GetAttributes", __func__); return (-1); } *vendor_id = (int16_t)attr.VendorID; *product_id = (int16_t)attr.ProductID; return (0); } static int -get_str(HANDLE dev, char **manufacturer, char **product) +get_manufacturer(HANDLE dev, char **manufacturer) { wchar_t buf[512]; int utf8_len; int ok = -1; *manufacturer = NULL; - *product = NULL; if (HidD_GetManufacturerString(dev, &buf, sizeof(buf)) == false) { fido_log_debug("%s: HidD_GetManufacturerString", __func__); goto fail; } if ((utf8_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, buf, -1, NULL, 0, NULL, NULL)) <= 0 || utf8_len > 128) { fido_log_debug("%s: WideCharToMultiByte", __func__); goto fail; } if ((*manufacturer = malloc((size_t)utf8_len)) == NULL) { fido_log_debug("%s: malloc", __func__); goto fail; } if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, buf, -1, *manufacturer, utf8_len, NULL, NULL) != utf8_len) { fido_log_debug("%s: WideCharToMultiByte", __func__); goto fail; } + ok = 0; +fail: + if (ok < 0) { + free(*manufacturer); + *manufacturer = NULL; + } + + return (ok); +} + +static int +get_product(HANDLE dev, char **product) +{ + wchar_t buf[512]; + int utf8_len; + int ok = -1; + + *product = NULL; + if (HidD_GetProductString(dev, &buf, sizeof(buf)) == false) { fido_log_debug("%s: HidD_GetProductString", __func__); goto fail; } if ((utf8_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, buf, -1, NULL, 0, NULL, NULL)) <= 0 || utf8_len > 128) { fido_log_debug("%s: WideCharToMultiByte", __func__); goto fail; } if ((*product = malloc((size_t)utf8_len)) == NULL) { fido_log_debug("%s: malloc", __func__); goto fail; } if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, buf, -1, *product, utf8_len, NULL, NULL) != utf8_len) { fido_log_debug("%s: WideCharToMultiByte", __func__); goto fail; } ok = 0; fail: if (ok < 0) { - free(*manufacturer); free(*product); - *manufacturer = NULL; *product = NULL; } return (ok); } static char * get_path(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *ifdata) { SP_DEVICE_INTERFACE_DETAIL_DATA_A *ifdetail = NULL; char *path = NULL; DWORD len = 0; /* * "Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail * with a NULL DeviceInterfaceDetailData pointer, a * DeviceInterfaceDetailDataSize of zero, and a valid RequiredSize * variable. In response to such a call, this function returns the * required buffer size at RequiredSize and fails with GetLastError * returning ERROR_INSUFFICIENT_BUFFER." */ if (SetupDiGetDeviceInterfaceDetailA(devinfo, ifdata, NULL, 0, &len, NULL) != false || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { fido_log_debug("%s: SetupDiGetDeviceInterfaceDetailA 1", __func__); goto fail; } if ((ifdetail = malloc(len)) == NULL) { fido_log_debug("%s: malloc", __func__); goto fail; } ifdetail->cbSize = sizeof(*ifdetail); if (SetupDiGetDeviceInterfaceDetailA(devinfo, ifdata, ifdetail, len, NULL, NULL) == false) { fido_log_debug("%s: SetupDiGetDeviceInterfaceDetailA 2", __func__); goto fail; } if ((path = strdup(ifdetail->DevicePath)) == NULL) { fido_log_debug("%s: strdup", __func__); goto fail; } fail: free(ifdetail); return (path); } #ifndef FIDO_HID_ANY static bool hid_ok(HDEVINFO devinfo, DWORD idx) { SP_DEVINFO_DATA devinfo_data; wchar_t *parent = NULL; DWORD parent_type = DEVPROP_TYPE_STRING; DWORD len = 0; bool ok = false; memset(&devinfo_data, 0, sizeof(devinfo_data)); devinfo_data.cbSize = sizeof(devinfo_data); if (SetupDiEnumDeviceInfo(devinfo, idx, &devinfo_data) == false) { fido_log_debug("%s: SetupDiEnumDeviceInfo", __func__); goto fail; } if (SetupDiGetDevicePropertyW(devinfo, &devinfo_data, &DEVPKEY_Device_Parent, &parent_type, NULL, 0, &len, 0) != false || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { fido_log_debug("%s: SetupDiGetDevicePropertyW 1", __func__); goto fail; } if ((parent = malloc(len)) == NULL) { fido_log_debug("%s: malloc", __func__); goto fail; } if (SetupDiGetDevicePropertyW(devinfo, &devinfo_data, &DEVPKEY_Device_Parent, &parent_type, (PBYTE)parent, len, NULL, 0) == false) { fido_log_debug("%s: SetupDiGetDevicePropertyW 2", __func__); goto fail; } ok = wcsncmp(parent, L"USB\\", 4) == 0; fail: free(parent); return (ok); } #endif static int copy_info(fido_dev_info_t *di, HDEVINFO devinfo, DWORD idx, SP_DEVICE_INTERFACE_DATA *ifdata) { HANDLE dev = INVALID_HANDLE_VALUE; int ok = -1; memset(di, 0, sizeof(*di)); if ((di->path = get_path(devinfo, ifdata)) == NULL) { fido_log_debug("%s: get_path", __func__); goto fail; } fido_log_debug("%s: path=%s", __func__, di->path); #ifndef FIDO_HID_ANY if (hid_ok(devinfo, idx) == false) { fido_log_debug("%s: hid_ok", __func__); goto fail; } #endif dev = CreateFileA(di->path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (dev == INVALID_HANDLE_VALUE) { fido_log_debug("%s: CreateFileA", __func__); goto fail; } if (is_fido(dev) == false) { fido_log_debug("%s: is_fido", __func__); goto fail; } - if (get_int(dev, &di->vendor_id, &di->product_id) < 0 || - get_str(dev, &di->manufacturer, &di->product) < 0) { - fido_log_debug("%s: get_int/get_str", __func__); + if (get_id(dev, &di->vendor_id, &di->product_id) < 0) { + fido_log_debug("%s: get_id", __func__); + goto fail; + } + + if (get_manufacturer(dev, &di->manufacturer) < 0) { + fido_log_debug("%s: get_manufacturer", __func__); + di->manufacturer = strdup(""); + } + + if (get_product(dev, &di->product) < 0) { + fido_log_debug("%s: get_product", __func__); + di->product = strdup(""); + } + + if (di->manufacturer == NULL || di->product == NULL) { + fido_log_debug("%s: manufacturer/product", __func__); goto fail; } ok = 0; fail: if (dev != INVALID_HANDLE_VALUE) CloseHandle(dev); if (ok < 0) { free(di->path); free(di->manufacturer); free(di->product); explicit_bzero(di, sizeof(*di)); } return (ok); } int fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { GUID hid_guid = GUID_DEVINTERFACE_HID; HDEVINFO devinfo = INVALID_HANDLE_VALUE; SP_DEVICE_INTERFACE_DATA ifdata; DWORD idx; int r = FIDO_ERR_INTERNAL; *olen = 0; if (ilen == 0) return (FIDO_OK); /* nothing to do */ if (devlist == NULL) return (FIDO_ERR_INVALID_ARGUMENT); if ((devinfo = SetupDiGetClassDevsA(&hid_guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT)) == INVALID_HANDLE_VALUE) { fido_log_debug("%s: SetupDiGetClassDevsA", __func__); goto fail; } ifdata.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); for (idx = 0; SetupDiEnumDeviceInterfaces(devinfo, NULL, &hid_guid, idx, &ifdata) == true; idx++) { if (copy_info(&devlist[*olen], devinfo, idx, &ifdata) == 0) { devlist[*olen].io = (fido_dev_io_t) { fido_hid_open, fido_hid_close, fido_hid_read, fido_hid_write, }; if (++(*olen) == ilen) break; } } r = FIDO_OK; fail: if (devinfo != INVALID_HANDLE_VALUE) SetupDiDestroyDeviceInfoList(devinfo); return (r); } void * fido_hid_open(const char *path) { struct hid_win *ctx; if ((ctx = calloc(1, sizeof(*ctx))) == NULL) return (NULL); ctx->dev = CreateFileA(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (ctx->dev == INVALID_HANDLE_VALUE) { free(ctx); return (NULL); } if ((ctx->overlap.hEvent = CreateEventA(NULL, FALSE, FALSE, NULL)) == NULL) { fido_log_debug("%s: CreateEventA", __func__); fido_hid_close(ctx); return (NULL); } if (get_report_len(ctx->dev, 0, &ctx->report_in_len) < 0 || get_report_len(ctx->dev, 1, &ctx->report_out_len) < 0) { fido_log_debug("%s: get_report_len", __func__); fido_hid_close(ctx); return (NULL); } return (ctx); } void fido_hid_close(void *handle) { struct hid_win *ctx = handle; if (ctx->overlap.hEvent != NULL) { if (ctx->report_pending) { fido_log_debug("%s: report_pending", __func__); if (CancelIoEx(ctx->dev, &ctx->overlap) == 0) fido_log_debug("%s CancelIoEx: 0x%lx", __func__, GetLastError()); } CloseHandle(ctx->overlap.hEvent); } explicit_bzero(ctx->report, sizeof(ctx->report)); CloseHandle(ctx->dev); free(ctx); } int fido_hid_set_sigmask(void *handle, const fido_sigset_t *sigmask) { (void)handle; (void)sigmask; return (FIDO_ERR_INTERNAL); } int fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) { struct hid_win *ctx = handle; DWORD n; if (len != ctx->report_in_len - 1 || len > sizeof(ctx->report) - 1) { fido_log_debug("%s: len %zu", __func__, len); return (-1); } if (ctx->report_pending == 0) { memset(&ctx->report, 0, sizeof(ctx->report)); ResetEvent(ctx->overlap.hEvent); if (ReadFile(ctx->dev, ctx->report, (DWORD)(len + 1), &n, &ctx->overlap) == 0 && GetLastError() != ERROR_IO_PENDING) { CancelIo(ctx->dev); fido_log_debug("%s: ReadFile", __func__); return (-1); } ctx->report_pending = 1; } if (ms > -1 && WaitForSingleObject(ctx->overlap.hEvent, (DWORD)ms) != WAIT_OBJECT_0) return (0); ctx->report_pending = 0; if (GetOverlappedResult(ctx->dev, &ctx->overlap, &n, TRUE) == 0) { fido_log_debug("%s: GetOverlappedResult", __func__); return (-1); } if (n != len + 1) { fido_log_debug("%s: expected %zu, got %zu", __func__, len + 1, (size_t)n); return (-1); } memcpy(buf, ctx->report + 1, len); explicit_bzero(ctx->report, sizeof(ctx->report)); return ((int)len); } int fido_hid_write(void *handle, const unsigned char *buf, size_t len) { struct hid_win *ctx = handle; OVERLAPPED overlap; DWORD n; memset(&overlap, 0, sizeof(overlap)); if (len != ctx->report_out_len) { fido_log_debug("%s: len %zu", __func__, len); return (-1); } if (WriteFile(ctx->dev, buf, (DWORD)len, NULL, &overlap) == 0 && GetLastError() != ERROR_IO_PENDING) { fido_log_debug("%s: WriteFile", __func__); return (-1); } if (GetOverlappedResult(ctx->dev, &overlap, &n, TRUE) == 0) { fido_log_debug("%s: GetOverlappedResult", __func__); return (-1); } if (n != len) { fido_log_debug("%s: expected %zu, got %zu", __func__, len, (size_t)n); return (-1); } return ((int)len); } size_t fido_hid_report_in_len(void *handle) { struct hid_win *ctx = handle; return (ctx->report_in_len - 1); } size_t fido_hid_report_out_len(void *handle) { struct hid_win *ctx = handle; return (ctx->report_out_len - 1); } diff --git a/contrib/libfido2/src/info.c b/contrib/libfido2/src/info.c index 57bc8de44063..167a1d30ecaa 100644 --- a/contrib/libfido2/src/info.c +++ b/contrib/libfido2/src/info.c @@ -1,553 +1,504 @@ /* * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include "fido.h" static int decode_string(const cbor_item_t *item, void *arg) { fido_str_array_t *a = arg; const size_t i = a->len; /* keep ptr[x] and len consistent */ if (cbor_string_copy(item, &a->ptr[i]) < 0) { fido_log_debug("%s: cbor_string_copy", __func__); return (-1); } a->len++; return (0); } static int decode_string_array(const cbor_item_t *item, fido_str_array_t *v) { v->ptr = NULL; v->len = 0; if (cbor_isa_array(item) == false || cbor_array_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } v->ptr = calloc(cbor_array_size(item), sizeof(char *)); if (v->ptr == NULL) return (-1); if (cbor_array_iter(item, v, decode_string) < 0) { fido_log_debug("%s: decode_string", __func__); return (-1); } return (0); } static int decode_aaguid(const cbor_item_t *item, unsigned char *aaguid, size_t aaguid_len) { if (cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false || cbor_bytestring_length(item) != aaguid_len) { fido_log_debug("%s: cbor type", __func__); return (-1); } memcpy(aaguid, cbor_bytestring_handle(item), aaguid_len); return (0); } static int decode_option(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_opt_array_t *o = arg; const size_t i = o->len; if (cbor_isa_float_ctrl(val) == false || cbor_float_get_width(val) != CBOR_FLOAT_0 || cbor_is_bool(val) == false) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } if (cbor_string_copy(key, &o->name[i]) < 0) { fido_log_debug("%s: cbor_string_copy", __func__); return (0); /* ignore */ } /* keep name/value and len consistent */ o->value[i] = cbor_ctrl_value(val) == CBOR_CTRL_TRUE; o->len++; return (0); } static int decode_options(const cbor_item_t *item, fido_opt_array_t *o) { o->name = NULL; o->value = NULL; o->len = 0; if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } o->name = calloc(cbor_map_size(item), sizeof(char *)); o->value = calloc(cbor_map_size(item), sizeof(bool)); if (o->name == NULL || o->value == NULL) return (-1); return (cbor_map_iter(item, o, decode_option)); } static int decode_protocol(const cbor_item_t *item, void *arg) { fido_byte_array_t *p = arg; const size_t i = p->len; if (cbor_isa_uint(item) == false || cbor_int_get_width(item) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (-1); } /* keep ptr[x] and len consistent */ p->ptr[i] = cbor_get_uint8(item); p->len++; return (0); } static int decode_protocols(const cbor_item_t *item, fido_byte_array_t *p) { p->ptr = NULL; p->len = 0; if (cbor_isa_array(item) == false || cbor_array_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } p->ptr = calloc(cbor_array_size(item), sizeof(uint8_t)); if (p->ptr == NULL) return (-1); if (cbor_array_iter(item, p, decode_protocol) < 0) { fido_log_debug("%s: decode_protocol", __func__); return (-1); } return (0); } static int decode_algorithm_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_algo_t *alg = arg; char *name = NULL; int ok = -1; if (cbor_string_copy(key, &name) < 0) { fido_log_debug("%s: cbor type", __func__); ok = 0; /* ignore */ goto out; } if (!strcmp(name, "alg")) { if (cbor_isa_negint(val) == false || cbor_get_int(val) > INT_MAX || alg->cose != 0) { fido_log_debug("%s: alg", __func__); goto out; } alg->cose = -(int)cbor_get_int(val) - 1; } else if (!strcmp(name, "type")) { if (cbor_string_copy(val, &alg->type) < 0) { fido_log_debug("%s: type", __func__); goto out; } } ok = 0; out: free(name); return (ok); } -static void -free_algo(fido_algo_t *a) -{ - free(a->type); - a->type = NULL; - a->cose = 0; -} - static int decode_algorithm(const cbor_item_t *item, void *arg) { fido_algo_array_t *aa = arg; const size_t i = aa->len; if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } memset(&aa->ptr[i], 0, sizeof(aa->ptr[i])); if (cbor_map_iter(item, &aa->ptr[i], decode_algorithm_entry) < 0) { fido_log_debug("%s: decode_algorithm_entry", __func__); - free_algo(&aa->ptr[i]); + fido_algo_free(&aa->ptr[i]); return (-1); } /* keep ptr[x] and len consistent */ aa->len++; return (0); } static int decode_algorithms(const cbor_item_t *item, fido_algo_array_t *aa) { aa->ptr = NULL; aa->len = 0; if (cbor_isa_array(item) == false || cbor_array_is_definite(item) == false) { fido_log_debug("%s: cbor type", __func__); return (-1); } aa->ptr = calloc(cbor_array_size(item), sizeof(fido_algo_t)); if (aa->ptr == NULL) return (-1); if (cbor_array_iter(item, aa, decode_algorithm) < 0) { fido_log_debug("%s: decode_algorithm", __func__); return (-1); } return (0); } static int parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_cbor_info_t *ci = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } switch (cbor_get_uint8(key)) { case 1: /* versions */ return (decode_string_array(val, &ci->versions)); case 2: /* extensions */ return (decode_string_array(val, &ci->extensions)); case 3: /* aaguid */ return (decode_aaguid(val, ci->aaguid, sizeof(ci->aaguid))); case 4: /* options */ return (decode_options(val, &ci->options)); case 5: /* maxMsgSize */ return (cbor_decode_uint64(val, &ci->maxmsgsiz)); case 6: /* pinProtocols */ return (decode_protocols(val, &ci->protocols)); case 7: /* maxCredentialCountInList */ return (cbor_decode_uint64(val, &ci->maxcredcntlst)); case 8: /* maxCredentialIdLength */ return (cbor_decode_uint64(val, &ci->maxcredidlen)); case 9: /* transports */ return (decode_string_array(val, &ci->transports)); case 10: /* algorithms */ return (decode_algorithms(val, &ci->algorithms)); case 14: /* fwVersion */ return (cbor_decode_uint64(val, &ci->fwversion)); case 15: /* maxCredBlobLen */ return (cbor_decode_uint64(val, &ci->maxcredbloblen)); default: /* ignore */ fido_log_debug("%s: cbor type", __func__); return (0); } } static int -fido_dev_get_cbor_info_tx(fido_dev_t *dev) +fido_dev_get_cbor_info_tx(fido_dev_t *dev, int *ms) { const unsigned char cbor[] = { CTAP_CBOR_GETINFO }; fido_log_debug("%s: dev=%p", __func__, (void *)dev); - if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor)) < 0) { + if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor), ms) < 0) { fido_log_debug("%s: fido_tx", __func__); return (FIDO_ERR_TX); } return (FIDO_OK); } static int -fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) +fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; fido_log_debug("%s: dev=%p, ci=%p, ms=%d", __func__, (void *)dev, - (void *)ci, ms); + (void *)ci, *ms); fido_cbor_info_reset(ci); if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } return (cbor_parse_reply(reply, (size_t)reply_len, ci, parse_reply_element)); } int -fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) +fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int *ms) { int r; #ifdef USE_WINHELLO if (dev->flags & FIDO_DEV_WINHELLO) return (fido_winhello_get_cbor_info(dev, ci)); #endif - if ((r = fido_dev_get_cbor_info_tx(dev)) != FIDO_OK || + if ((r = fido_dev_get_cbor_info_tx(dev, ms)) != FIDO_OK || (r = fido_dev_get_cbor_info_rx(dev, ci, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_dev_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci) { - return (fido_dev_get_cbor_info_wait(dev, ci, -1)); + int ms = dev->timeout_ms; + + return (fido_dev_get_cbor_info_wait(dev, ci, &ms)); } /* * get/set functions for fido_cbor_info_t; always at the end of the file */ fido_cbor_info_t * fido_cbor_info_new(void) { return (calloc(1, sizeof(fido_cbor_info_t))); } -static void -free_str_array(fido_str_array_t *sa) -{ - for (size_t i = 0; i < sa->len; i++) - free(sa->ptr[i]); - - free(sa->ptr); - sa->ptr = NULL; - sa->len = 0; -} - -static void -free_opt_array(fido_opt_array_t *oa) -{ - for (size_t i = 0; i < oa->len; i++) - free(oa->name[i]); - - free(oa->name); - free(oa->value); - oa->name = NULL; - oa->value = NULL; -} - -static void -free_byte_array(fido_byte_array_t *ba) -{ - free(ba->ptr); - - ba->ptr = NULL; - ba->len = 0; -} - -static void -free_algo_array(fido_algo_array_t *aa) -{ - for (size_t i = 0; i < aa->len; i++) - free_algo(&aa->ptr[i]); - - free(aa->ptr); - aa->ptr = NULL; - aa->len = 0; -} - void fido_cbor_info_reset(fido_cbor_info_t *ci) { - free_str_array(&ci->versions); - free_str_array(&ci->extensions); - free_str_array(&ci->transports); - free_opt_array(&ci->options); - free_byte_array(&ci->protocols); - free_algo_array(&ci->algorithms); + fido_str_array_free(&ci->versions); + fido_str_array_free(&ci->extensions); + fido_str_array_free(&ci->transports); + fido_opt_array_free(&ci->options); + fido_byte_array_free(&ci->protocols); + fido_algo_array_free(&ci->algorithms); } void fido_cbor_info_free(fido_cbor_info_t **ci_p) { fido_cbor_info_t *ci; if (ci_p == NULL || (ci = *ci_p) == NULL) return; fido_cbor_info_reset(ci); free(ci); *ci_p = NULL; } char ** fido_cbor_info_versions_ptr(const fido_cbor_info_t *ci) { return (ci->versions.ptr); } size_t fido_cbor_info_versions_len(const fido_cbor_info_t *ci) { return (ci->versions.len); } char ** fido_cbor_info_extensions_ptr(const fido_cbor_info_t *ci) { return (ci->extensions.ptr); } size_t fido_cbor_info_extensions_len(const fido_cbor_info_t *ci) { return (ci->extensions.len); } char ** fido_cbor_info_transports_ptr(const fido_cbor_info_t *ci) { return (ci->transports.ptr); } size_t fido_cbor_info_transports_len(const fido_cbor_info_t *ci) { return (ci->transports.len); } const unsigned char * fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *ci) { return (ci->aaguid); } size_t fido_cbor_info_aaguid_len(const fido_cbor_info_t *ci) { return (sizeof(ci->aaguid)); } char ** fido_cbor_info_options_name_ptr(const fido_cbor_info_t *ci) { return (ci->options.name); } const bool * fido_cbor_info_options_value_ptr(const fido_cbor_info_t *ci) { return (ci->options.value); } size_t fido_cbor_info_options_len(const fido_cbor_info_t *ci) { return (ci->options.len); } uint64_t fido_cbor_info_maxcredbloblen(const fido_cbor_info_t *ci) { return (ci->maxcredbloblen); } uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci) { return (ci->maxmsgsiz); } uint64_t fido_cbor_info_maxcredcntlst(const fido_cbor_info_t *ci) { return (ci->maxcredcntlst); } uint64_t fido_cbor_info_maxcredidlen(const fido_cbor_info_t *ci) { return (ci->maxcredidlen); } uint64_t fido_cbor_info_fwversion(const fido_cbor_info_t *ci) { return (ci->fwversion); } const uint8_t * fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci) { return (ci->protocols.ptr); } size_t fido_cbor_info_protocols_len(const fido_cbor_info_t *ci) { return (ci->protocols.len); } size_t fido_cbor_info_algorithm_count(const fido_cbor_info_t *ci) { return (ci->algorithms.len); } const char * fido_cbor_info_algorithm_type(const fido_cbor_info_t *ci, size_t idx) { if (idx >= ci->algorithms.len) return (NULL); return (ci->algorithms.ptr[idx].type); } int fido_cbor_info_algorithm_cose(const fido_cbor_info_t *ci, size_t idx) { if (idx >= ci->algorithms.len) return (0); return (ci->algorithms.ptr[idx].cose); } diff --git a/contrib/libfido2/src/io.c b/contrib/libfido2/src/io.c index e2594203efb0..70f777fb49a0 100644 --- a/contrib/libfido2/src/io.c +++ b/contrib/libfido2/src/io.c @@ -1,288 +1,344 @@ /* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include "fido.h" #include "packed.h" PACKED_TYPE(frame_t, struct frame { uint32_t cid; /* channel id */ union { uint8_t type; struct { uint8_t cmd; uint8_t bcnth; uint8_t bcntl; uint8_t data[CTAP_MAX_REPORT_LEN - CTAP_INIT_HEADER_LEN]; } init; struct { uint8_t seq; uint8_t data[CTAP_MAX_REPORT_LEN - CTAP_CONT_HEADER_LEN]; } cont; } body; }) #ifndef MIN #define MIN(x, y) ((x) > (y) ? (y) : (x)) #endif static int -tx_empty(fido_dev_t *d, uint8_t cmd) +tx_pkt(fido_dev_t *d, const void *pkt, size_t len, int *ms) +{ + struct timespec ts; + int n; + + if (fido_time_now(&ts) != 0) + return (-1); + + n = d->io.write(d->io_handle, pkt, len); + + if (fido_time_delta(&ts, ms) != 0) + return (-1); + + return (n); +} + +static int +tx_empty(fido_dev_t *d, uint8_t cmd, int *ms) { struct frame *fp; unsigned char pkt[sizeof(*fp) + 1]; const size_t len = d->tx_len + 1; int n; memset(&pkt, 0, sizeof(pkt)); fp = (struct frame *)(pkt + 1); fp->cid = d->cid; fp->body.init.cmd = CTAP_FRAME_INIT | cmd; - if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt, - len)) < 0 || (size_t)n != len) + if (len > sizeof(pkt) || (n = tx_pkt(d, pkt, len, ms)) < 0 || + (size_t)n != len) return (-1); return (0); } static size_t -tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count) +tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count, int *ms) { struct frame *fp; unsigned char pkt[sizeof(*fp) + 1]; const size_t len = d->tx_len + 1; int n; if (d->tx_len - CTAP_INIT_HEADER_LEN > sizeof(fp->body.init.data)) return (0); memset(&pkt, 0, sizeof(pkt)); fp = (struct frame *)(pkt + 1); fp->cid = d->cid; fp->body.init.cmd = CTAP_FRAME_INIT | cmd; fp->body.init.bcnth = (count >> 8) & 0xff; fp->body.init.bcntl = count & 0xff; count = MIN(count, d->tx_len - CTAP_INIT_HEADER_LEN); memcpy(&fp->body.init.data, buf, count); - if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt, - len)) < 0 || (size_t)n != len) + if (len > sizeof(pkt) || (n = tx_pkt(d, pkt, len, ms)) < 0 || + (size_t)n != len) return (0); return (count); } static size_t -tx_frame(fido_dev_t *d, uint8_t seq, const void *buf, size_t count) +tx_frame(fido_dev_t *d, uint8_t seq, const void *buf, size_t count, int *ms) { struct frame *fp; unsigned char pkt[sizeof(*fp) + 1]; const size_t len = d->tx_len + 1; int n; if (d->tx_len - CTAP_CONT_HEADER_LEN > sizeof(fp->body.cont.data)) return (0); memset(&pkt, 0, sizeof(pkt)); fp = (struct frame *)(pkt + 1); fp->cid = d->cid; fp->body.cont.seq = seq; count = MIN(count, d->tx_len - CTAP_CONT_HEADER_LEN); memcpy(&fp->body.cont.data, buf, count); - if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt, - len)) < 0 || (size_t)n != len) + if (len > sizeof(pkt) || (n = tx_pkt(d, pkt, len, ms)) < 0 || + (size_t)n != len) return (0); return (count); } static int -tx(fido_dev_t *d, uint8_t cmd, const unsigned char *buf, size_t count) +tx(fido_dev_t *d, uint8_t cmd, const unsigned char *buf, size_t count, int *ms) { size_t n, sent; - if ((sent = tx_preamble(d, cmd, buf, count)) == 0) { + if ((sent = tx_preamble(d, cmd, buf, count, ms)) == 0) { fido_log_debug("%s: tx_preamble", __func__); return (-1); } for (uint8_t seq = 0; sent < count; sent += n) { if (seq & 0x80) { fido_log_debug("%s: seq & 0x80", __func__); return (-1); } - if ((n = tx_frame(d, seq++, buf + sent, count - sent)) == 0) { + if ((n = tx_frame(d, seq++, buf + sent, count - sent, + ms)) == 0) { fido_log_debug("%s: tx_frame", __func__); return (-1); } } return (0); } +static int +transport_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count, int *ms) +{ + struct timespec ts; + int n; + + if (fido_time_now(&ts) != 0) + return (-1); + + n = d->transport.tx(d, cmd, buf, count); + + if (fido_time_delta(&ts, ms) != 0) + return (-1); + + return (n); +} + int -fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count) +fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count, int *ms) { fido_log_debug("%s: dev=%p, cmd=0x%02x", __func__, (void *)d, cmd); fido_log_xxd(buf, count, "%s", __func__); if (d->transport.tx != NULL) - return (d->transport.tx(d, cmd, buf, count)); + return (transport_tx(d, cmd, buf, count, ms)); if (d->io_handle == NULL || d->io.write == NULL || count > UINT16_MAX) { fido_log_debug("%s: invalid argument", __func__); return (-1); } - return (count == 0 ? tx_empty(d, cmd) : tx(d, cmd, buf, count)); + return (count == 0 ? tx_empty(d, cmd, ms) : tx(d, cmd, buf, count, ms)); } static int -rx_frame(fido_dev_t *d, struct frame *fp, int ms) +rx_frame(fido_dev_t *d, struct frame *fp, int *ms) { + struct timespec ts; int n; memset(fp, 0, sizeof(*fp)); + if (fido_time_now(&ts) != 0) + return (-1); + if (d->rx_len > sizeof(*fp) || (n = d->io.read(d->io_handle, - (unsigned char *)fp, d->rx_len, ms)) < 0 || (size_t)n != d->rx_len) + (unsigned char *)fp, d->rx_len, *ms)) < 0 || (size_t)n != d->rx_len) return (-1); - return (0); + return (fido_time_delta(&ts, ms)); } static int -rx_preamble(fido_dev_t *d, uint8_t cmd, struct frame *fp, int ms) +rx_preamble(fido_dev_t *d, uint8_t cmd, struct frame *fp, int *ms) { do { if (rx_frame(d, fp, ms) < 0) return (-1); #ifdef FIDO_FUZZ fp->cid = d->cid; #endif } while (fp->cid != d->cid || (fp->cid == d->cid && fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE))); if (d->rx_len > sizeof(*fp)) return (-1); fido_log_xxd(fp, d->rx_len, "%s", __func__); #ifdef FIDO_FUZZ fp->body.init.cmd = (CTAP_FRAME_INIT | cmd); #endif if (fp->cid != d->cid || fp->body.init.cmd != (CTAP_FRAME_INIT | cmd)) { fido_log_debug("%s: cid (0x%x, 0x%x), cmd (0x%02x, 0x%02x)", __func__, fp->cid, d->cid, fp->body.init.cmd, cmd); return (-1); } return (0); } static int -rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms) +rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int *ms) { struct frame f; size_t r, payload_len, init_data_len, cont_data_len; if (d->rx_len <= CTAP_INIT_HEADER_LEN || d->rx_len <= CTAP_CONT_HEADER_LEN) return (-1); init_data_len = d->rx_len - CTAP_INIT_HEADER_LEN; cont_data_len = d->rx_len - CTAP_CONT_HEADER_LEN; if (init_data_len > sizeof(f.body.init.data) || cont_data_len > sizeof(f.body.cont.data)) return (-1); if (rx_preamble(d, cmd, &f, ms) < 0) { fido_log_debug("%s: rx_preamble", __func__); return (-1); } payload_len = (size_t)((f.body.init.bcnth << 8) | f.body.init.bcntl); fido_log_debug("%s: payload_len=%zu", __func__, payload_len); if (count < payload_len) { fido_log_debug("%s: count < payload_len", __func__); return (-1); } if (payload_len < init_data_len) { memcpy(buf, f.body.init.data, payload_len); return ((int)payload_len); } memcpy(buf, f.body.init.data, init_data_len); r = init_data_len; for (int seq = 0; r < payload_len; seq++) { if (rx_frame(d, &f, ms) < 0) { fido_log_debug("%s: rx_frame", __func__); return (-1); } fido_log_xxd(&f, d->rx_len, "%s", __func__); #ifdef FIDO_FUZZ f.cid = d->cid; f.body.cont.seq = (uint8_t)seq; #endif if (f.cid != d->cid || f.body.cont.seq != seq) { fido_log_debug("%s: cid (0x%x, 0x%x), seq (%d, %d)", __func__, f.cid, d->cid, f.body.cont.seq, seq); return (-1); } if (payload_len - r > cont_data_len) { memcpy(buf + r, f.body.cont.data, cont_data_len); r += cont_data_len; } else { memcpy(buf + r, f.body.cont.data, payload_len - r); r += payload_len - r; /* break */ } } return ((int)r); } +static int +transport_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int *ms) +{ + struct timespec ts; + int n; + + if (fido_time_now(&ts) != 0) + return (-1); + + n = d->transport.rx(d, cmd, buf, count, *ms); + + if (fido_time_delta(&ts, ms) != 0) + return (-1); + + return (n); +} + int -fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms) +fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int *ms) { int n; fido_log_debug("%s: dev=%p, cmd=0x%02x, ms=%d", __func__, (void *)d, - cmd, ms); + cmd, *ms); if (d->transport.rx != NULL) - return (d->transport.rx(d, cmd, buf, count, ms)); + return (transport_rx(d, cmd, buf, count, ms)); if (d->io_handle == NULL || d->io.read == NULL || count > UINT16_MAX) { fido_log_debug("%s: invalid argument", __func__); return (-1); } if ((n = rx(d, cmd, buf, count, ms)) >= 0) fido_log_xxd(buf, (size_t)n, "%s", __func__); return (n); } int -fido_rx_cbor_status(fido_dev_t *d, int ms) +fido_rx_cbor_status(fido_dev_t *d, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; if ((reply_len = fido_rx(d, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0 || (size_t)reply_len < 1) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } return (reply[0]); } diff --git a/contrib/libfido2/src/largeblob.c b/contrib/libfido2/src/largeblob.c index fa453f5de33a..c8173170766d 100644 --- a/contrib/libfido2/src/largeblob.c +++ b/contrib/libfido2/src/largeblob.c @@ -1,881 +1,890 @@ /* * Copyright (c) 2020 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include "fido.h" #include "fido/es256.h" #define LARGEBLOB_DIGEST_LENGTH 16 #define LARGEBLOB_NONCE_LENGTH 12 #define LARGEBLOB_TAG_LENGTH 16 typedef struct largeblob { size_t origsiz; fido_blob_t ciphertext; fido_blob_t nonce; } largeblob_t; static largeblob_t * largeblob_new(void) { return calloc(1, sizeof(largeblob_t)); } static void largeblob_reset(largeblob_t *blob) { fido_blob_reset(&blob->ciphertext); fido_blob_reset(&blob->nonce); blob->origsiz = 0; } static void largeblob_free(largeblob_t **blob_ptr) { largeblob_t *blob; if (blob_ptr == NULL || (blob = *blob_ptr) == NULL) return; largeblob_reset(blob); free(blob); *blob_ptr = NULL; } static int largeblob_aad(fido_blob_t *aad, uint64_t size) { uint8_t buf[4 + sizeof(uint64_t)]; buf[0] = 0x62; /* b */ buf[1] = 0x6c; /* l */ buf[2] = 0x6f; /* o */ buf[3] = 0x62; /* b */ size = htole64(size); memcpy(&buf[4], &size, sizeof(uint64_t)); return fido_blob_set(aad, buf, sizeof(buf)); } static fido_blob_t * largeblob_decrypt(const largeblob_t *blob, const fido_blob_t *key) { fido_blob_t *plaintext = NULL, *aad = NULL; int ok = -1; if ((plaintext = fido_blob_new()) == NULL || (aad = fido_blob_new()) == NULL) { fido_log_debug("%s: fido_blob_new", __func__); goto fail; } if (largeblob_aad(aad, blob->origsiz) < 0) { fido_log_debug("%s: largeblob_aad", __func__); goto fail; } if (aes256_gcm_dec(key, &blob->nonce, aad, &blob->ciphertext, plaintext) < 0) { fido_log_debug("%s: aes256_gcm_dec", __func__); goto fail; } ok = 0; fail: fido_blob_free(&aad); if (ok < 0) fido_blob_free(&plaintext); return plaintext; } static int largeblob_get_nonce(largeblob_t *blob) { uint8_t buf[LARGEBLOB_NONCE_LENGTH]; int ok = -1; if (fido_get_random(buf, sizeof(buf)) < 0) { fido_log_debug("%s: fido_get_random", __func__); goto fail; } if (fido_blob_set(&blob->nonce, buf, sizeof(buf)) < 0) { fido_log_debug("%s: fido_blob_set", __func__); goto fail; } ok = 0; fail: explicit_bzero(buf, sizeof(buf)); return ok; } static int largeblob_seal(largeblob_t *blob, const fido_blob_t *body, const fido_blob_t *key) { fido_blob_t *plaintext = NULL, *aad = NULL; int ok = -1; if ((plaintext = fido_blob_new()) == NULL || (aad = fido_blob_new()) == NULL) { fido_log_debug("%s: fido_blob_new", __func__); goto fail; } if (fido_compress(plaintext, body) != FIDO_OK) { fido_log_debug("%s: fido_compress", __func__); goto fail; } if (largeblob_aad(aad, body->len) < 0) { fido_log_debug("%s: largeblob_aad", __func__); goto fail; } if (largeblob_get_nonce(blob) < 0) { fido_log_debug("%s: largeblob_get_nonce", __func__); goto fail; } if (aes256_gcm_enc(key, &blob->nonce, aad, plaintext, &blob->ciphertext) < 0) { fido_log_debug("%s: aes256_gcm_enc", __func__); goto fail; } blob->origsiz = body->len; ok = 0; fail: fido_blob_free(&plaintext); fido_blob_free(&aad); return ok; } static int -largeblob_get_tx(fido_dev_t *dev, size_t offset, size_t count) +largeblob_get_tx(fido_dev_t *dev, size_t offset, size_t count, int *ms) { fido_blob_t f; cbor_item_t *argv[3]; int r; memset(argv, 0, sizeof(argv)); memset(&f, 0, sizeof(f)); if ((argv[0] = cbor_build_uint(count)) == NULL || (argv[2] = cbor_build_uint(offset)) == NULL) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (cbor_build_frame(CTAP_CBOR_LARGEBLOB, argv, nitems(argv), &f) < 0 || - fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { + fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); free(f.ptr); return r; } static int parse_largeblob_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg) { if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != 1) { fido_log_debug("%s: cbor type", __func__); return 0; /* ignore */ } return fido_blob_decode(val, arg); } static int -largeblob_get_rx(fido_dev_t *dev, fido_blob_t **chunk, int ms) +largeblob_get_rx(fido_dev_t *dev, fido_blob_t **chunk, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len, r; *chunk = NULL; if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return FIDO_ERR_RX; } if ((*chunk = fido_blob_new()) == NULL) { fido_log_debug("%s: fido_blob_new", __func__); return FIDO_ERR_INTERNAL; } if ((r = cbor_parse_reply(reply, (size_t)reply_len, *chunk, parse_largeblob_reply)) != FIDO_OK) { fido_log_debug("%s: parse_largeblob_reply", __func__); fido_blob_free(chunk); return r; } return FIDO_OK; } static cbor_item_t * largeblob_array_load(const uint8_t *ptr, size_t len) { struct cbor_load_result cbor; cbor_item_t *item; if (len < LARGEBLOB_DIGEST_LENGTH) { fido_log_debug("%s: len", __func__); return NULL; } len -= LARGEBLOB_DIGEST_LENGTH; if ((item = cbor_load(ptr, len, &cbor)) == NULL) { fido_log_debug("%s: cbor_load", __func__); return NULL; } if (!cbor_isa_array(item) || !cbor_array_is_definite(item)) { fido_log_debug("%s: cbor type", __func__); cbor_decref(&item); return NULL; } return item; } static size_t get_chunklen(fido_dev_t *dev) { uint64_t maxchunklen; if ((maxchunklen = fido_dev_maxmsgsize(dev)) > SIZE_MAX) maxchunklen = SIZE_MAX; if (maxchunklen > FIDO_MAXMSG) maxchunklen = FIDO_MAXMSG; maxchunklen = maxchunklen > 64 ? maxchunklen - 64 : 0; return (size_t)maxchunklen; } static int largeblob_do_decode(const cbor_item_t *key, const cbor_item_t *val, void *arg) { largeblob_t *blob = arg; uint64_t origsiz; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { fido_log_debug("%s: cbor type", __func__); return 0; /* ignore */ } switch (cbor_get_uint8(key)) { case 1: /* ciphertext */ if (fido_blob_decode(val, &blob->ciphertext) < 0 || blob->ciphertext.len < LARGEBLOB_TAG_LENGTH) return -1; return 0; case 2: /* nonce */ if (fido_blob_decode(val, &blob->nonce) < 0 || blob->nonce.len != LARGEBLOB_NONCE_LENGTH) return -1; return 0; case 3: /* origSize */ if (!cbor_isa_uint(val) || (origsiz = cbor_get_int(val)) > SIZE_MAX) return -1; blob->origsiz = (size_t)origsiz; return 0; default: /* ignore */ fido_log_debug("%s: cbor type", __func__); return 0; } } static int largeblob_decode(largeblob_t *blob, const cbor_item_t *item) { if (!cbor_isa_map(item) || !cbor_map_is_definite(item)) { fido_log_debug("%s: cbor type", __func__); return -1; } if (cbor_map_iter(item, blob, largeblob_do_decode) < 0) { fido_log_debug("%s: cbor_map_iter", __func__); return -1; } if (fido_blob_is_empty(&blob->ciphertext) || fido_blob_is_empty(&blob->nonce) || blob->origsiz == 0) { fido_log_debug("%s: incomplete blob", __func__); return -1; } return 0; } static cbor_item_t * largeblob_encode(const fido_blob_t *body, const fido_blob_t *key) { largeblob_t *blob; cbor_item_t *argv[3], *item = NULL; memset(argv, 0, sizeof(argv)); if ((blob = largeblob_new()) == NULL || largeblob_seal(blob, body, key) < 0) { fido_log_debug("%s: largeblob_seal", __func__); goto fail; } if ((argv[0] = fido_blob_encode(&blob->ciphertext)) == NULL || (argv[1] = fido_blob_encode(&blob->nonce)) == NULL || (argv[2] = cbor_build_uint(blob->origsiz)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } item = cbor_flatten_vector(argv, nitems(argv)); fail: cbor_vector_free(argv, nitems(argv)); largeblob_free(&blob); return item; } static int largeblob_array_lookup(fido_blob_t *out, size_t *idx, const cbor_item_t *item, const fido_blob_t *key) { cbor_item_t **v; fido_blob_t *plaintext = NULL; largeblob_t blob; int r; memset(&blob, 0, sizeof(blob)); if (idx != NULL) *idx = 0; if ((v = cbor_array_handle(item)) == NULL) return FIDO_ERR_INVALID_ARGUMENT; for (size_t i = 0; i < cbor_array_size(item); i++) { if (largeblob_decode(&blob, v[i]) < 0 || (plaintext = largeblob_decrypt(&blob, key)) == NULL) { fido_log_debug("%s: largeblob_decode", __func__); largeblob_reset(&blob); continue; } if (idx != NULL) *idx = i; break; } if (plaintext == NULL) { fido_log_debug("%s: not found", __func__); return FIDO_ERR_NOTFOUND; } if (out != NULL) r = fido_uncompress(out, plaintext, blob.origsiz); else r = FIDO_OK; fido_blob_free(&plaintext); largeblob_reset(&blob); return r; } static int largeblob_array_digest(u_char out[LARGEBLOB_DIGEST_LENGTH], const u_char *data, size_t len) { u_char dgst[SHA256_DIGEST_LENGTH]; if (data == NULL || len == 0) return -1; if (SHA256(data, len, dgst) != dgst) return -1; memcpy(out, dgst, LARGEBLOB_DIGEST_LENGTH); return 0; } static int largeblob_array_check(const fido_blob_t *array) { u_char expected_hash[LARGEBLOB_DIGEST_LENGTH]; size_t body_len; fido_log_xxd(array->ptr, array->len, __func__); if (array->len < sizeof(expected_hash)) { fido_log_debug("%s: len %zu", __func__, array->len); return -1; } body_len = array->len - sizeof(expected_hash); if (largeblob_array_digest(expected_hash, array->ptr, body_len) < 0) { fido_log_debug("%s: largeblob_array_digest", __func__); return -1; } return timingsafe_bcmp(expected_hash, array->ptr + body_len, sizeof(expected_hash)); } static int -largeblob_get_array(fido_dev_t *dev, cbor_item_t **item) +largeblob_get_array(fido_dev_t *dev, cbor_item_t **item, int *ms) { fido_blob_t *array, *chunk = NULL; size_t n; int r; *item = NULL; if ((n = get_chunklen(dev)) == 0) return FIDO_ERR_INVALID_ARGUMENT; if ((array = fido_blob_new()) == NULL) return FIDO_ERR_INTERNAL; do { fido_blob_free(&chunk); - if ((r = largeblob_get_tx(dev, array->len, n)) != FIDO_OK || - (r = largeblob_get_rx(dev, &chunk, -1)) != FIDO_OK) { + if ((r = largeblob_get_tx(dev, array->len, n, ms)) != FIDO_OK || + (r = largeblob_get_rx(dev, &chunk, ms)) != FIDO_OK) { fido_log_debug("%s: largeblob_get_wait %zu/%zu", __func__, array->len, n); goto fail; } if (fido_blob_append(array, chunk->ptr, chunk->len) < 0) { fido_log_debug("%s: fido_blob_append", __func__); r = FIDO_ERR_INTERNAL; goto fail; } } while (chunk->len == n); if (largeblob_array_check(array) != 0) *item = cbor_new_definite_array(0); /* per spec */ else *item = largeblob_array_load(array->ptr, array->len); if (*item == NULL) r = FIDO_ERR_INTERNAL; else r = FIDO_OK; fail: fido_blob_free(&array); fido_blob_free(&chunk); return r; } static int prepare_hmac(size_t offset, const u_char *data, size_t len, fido_blob_t *hmac) { uint8_t buf[32 + 2 + sizeof(uint32_t) + SHA256_DIGEST_LENGTH]; uint32_t u32_offset; if (data == NULL || len == 0) { fido_log_debug("%s: invalid data=%p, len=%zu", __func__, (const void *)data, len); return -1; } if (offset > UINT32_MAX) { fido_log_debug("%s: invalid offset=%zu", __func__, offset); return -1; } memset(buf, 0xff, 32); buf[32] = CTAP_CBOR_LARGEBLOB; buf[33] = 0x00; u32_offset = htole32((uint32_t)offset); memcpy(&buf[34], &u32_offset, sizeof(uint32_t)); if (SHA256(data, len, &buf[38]) != &buf[38]) { fido_log_debug("%s: SHA256", __func__); return -1; } return fido_blob_set(hmac, buf, sizeof(buf)); } static int largeblob_set_tx(fido_dev_t *dev, const fido_blob_t *token, const u_char *chunk, - size_t chunk_len, size_t offset, size_t totalsiz) + size_t chunk_len, size_t offset, size_t totalsiz, int *ms) { fido_blob_t *hmac = NULL, f; cbor_item_t *argv[6]; int r; memset(argv, 0, sizeof(argv)); memset(&f, 0, sizeof(f)); if ((argv[1] = cbor_build_bytestring(chunk, chunk_len)) == NULL || (argv[2] = cbor_build_uint(offset)) == NULL || (offset == 0 && (argv[3] = cbor_build_uint(totalsiz)) == NULL)) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (token != NULL) { if ((hmac = fido_blob_new()) == NULL || prepare_hmac(offset, chunk, chunk_len, hmac) < 0 || (argv[4] = cbor_encode_pin_auth(dev, token, hmac)) == NULL || (argv[5] = cbor_encode_pin_opt(dev)) == NULL) { fido_log_debug("%s: cbor_encode_pin_auth", __func__); r = FIDO_ERR_INTERNAL; goto fail; } } if (cbor_build_frame(CTAP_CBOR_LARGEBLOB, argv, nitems(argv), &f) < 0 || - fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { + fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); fido_blob_free(&hmac); free(f.ptr); return r; } static int -largeblob_get_uv_token(fido_dev_t *dev, const char *pin, fido_blob_t **token) +largeblob_get_uv_token(fido_dev_t *dev, const char *pin, fido_blob_t **token, + int *ms) { es256_pk_t *pk = NULL; fido_blob_t *ecdh = NULL; int r; if ((*token = fido_blob_new()) == NULL) return FIDO_ERR_INTERNAL; - if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { + if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } if ((r = fido_dev_get_uv_token(dev, CTAP_CBOR_LARGEBLOB, pin, ecdh, pk, - NULL, *token)) != FIDO_OK) { + NULL, *token, ms)) != FIDO_OK) { fido_log_debug("%s: fido_dev_get_uv_token", __func__); goto fail; } r = FIDO_OK; fail: if (r != FIDO_OK) fido_blob_free(token); fido_blob_free(&ecdh); es256_pk_free(&pk); return r; } static int -largeblob_set_array(fido_dev_t *dev, const cbor_item_t *item, const char *pin) +largeblob_set_array(fido_dev_t *dev, const cbor_item_t *item, const char *pin, + int *ms) { unsigned char dgst[SHA256_DIGEST_LENGTH]; fido_blob_t cbor, *token = NULL; size_t chunklen, maxchunklen, totalsize; int r; memset(&cbor, 0, sizeof(cbor)); if ((maxchunklen = get_chunklen(dev)) == 0) { fido_log_debug("%s: maxchunklen=%zu", __func__, maxchunklen); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if (!cbor_isa_array(item) || !cbor_array_is_definite(item)) { fido_log_debug("%s: cbor type", __func__); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if ((fido_blob_serialise(&cbor, item)) < 0) { fido_log_debug("%s: fido_blob_serialise", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (cbor.len > SIZE_MAX - sizeof(dgst)) { fido_log_debug("%s: cbor.len=%zu", __func__, cbor.len); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if (SHA256(cbor.ptr, cbor.len, dgst) != dgst) { fido_log_debug("%s: SHA256", __func__); r = FIDO_ERR_INTERNAL; goto fail; } totalsize = cbor.len + sizeof(dgst) - 16; /* the first 16 bytes only */ if (pin != NULL || fido_dev_supports_permissions(dev)) { - if ((r = largeblob_get_uv_token(dev, pin, &token)) != FIDO_OK) { + if ((r = largeblob_get_uv_token(dev, pin, &token, + ms)) != FIDO_OK) { fido_log_debug("%s: largeblob_get_uv_token", __func__); goto fail; } } for (size_t offset = 0; offset < cbor.len; offset += chunklen) { if ((chunklen = cbor.len - offset) > maxchunklen) chunklen = maxchunklen; if ((r = largeblob_set_tx(dev, token, cbor.ptr + offset, - chunklen, offset, totalsize)) != FIDO_OK || - (r = fido_rx_cbor_status(dev, -1)) != FIDO_OK) { + chunklen, offset, totalsize, ms)) != FIDO_OK || + (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { fido_log_debug("%s: body", __func__); goto fail; } } if ((r = largeblob_set_tx(dev, token, dgst, sizeof(dgst) - 16, cbor.len, - totalsize)) != FIDO_OK || - (r = fido_rx_cbor_status(dev, -1)) != FIDO_OK) { + totalsize, ms)) != FIDO_OK || + (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { fido_log_debug("%s: dgst", __func__); goto fail; } r = FIDO_OK; fail: fido_blob_free(&token); fido_blob_reset(&cbor); return r; } static int largeblob_add(fido_dev_t *dev, const fido_blob_t *key, cbor_item_t *item, - const char *pin) + const char *pin, int *ms) { cbor_item_t *array = NULL; size_t idx; int r; - if ((r = largeblob_get_array(dev, &array)) != FIDO_OK) { + if ((r = largeblob_get_array(dev, &array, ms)) != FIDO_OK) { fido_log_debug("%s: largeblob_get_array", __func__); goto fail; } switch (r = largeblob_array_lookup(NULL, &idx, array, key)) { case FIDO_OK: if (!cbor_array_replace(array, idx, item)) { r = FIDO_ERR_INTERNAL; goto fail; } break; case FIDO_ERR_NOTFOUND: if (cbor_array_append(&array, item) < 0) { r = FIDO_ERR_INTERNAL; goto fail; } break; default: fido_log_debug("%s: largeblob_array_lookup", __func__); goto fail; } - if ((r = largeblob_set_array(dev, array, pin)) != FIDO_OK) { + if ((r = largeblob_set_array(dev, array, pin, ms)) != FIDO_OK) { fido_log_debug("%s: largeblob_set_array", __func__); goto fail; } r = FIDO_OK; fail: if (array != NULL) cbor_decref(&array); return r; } static int -largeblob_drop(fido_dev_t *dev, const fido_blob_t *key, const char *pin) +largeblob_drop(fido_dev_t *dev, const fido_blob_t *key, const char *pin, + int *ms) { cbor_item_t *array = NULL; size_t idx; int r; - if ((r = largeblob_get_array(dev, &array)) != FIDO_OK) { + if ((r = largeblob_get_array(dev, &array, ms)) != FIDO_OK) { fido_log_debug("%s: largeblob_get_array", __func__); goto fail; } if ((r = largeblob_array_lookup(NULL, &idx, array, key)) != FIDO_OK) { fido_log_debug("%s: largeblob_array_lookup", __func__); goto fail; } if (cbor_array_drop(&array, idx) < 0) { fido_log_debug("%s: cbor_array_drop", __func__); r = FIDO_ERR_INTERNAL; goto fail; } - if ((r = largeblob_set_array(dev, array, pin)) != FIDO_OK) { + if ((r = largeblob_set_array(dev, array, pin, ms)) != FIDO_OK) { fido_log_debug("%s: largeblob_set_array", __func__); goto fail; } r = FIDO_OK; fail: if (array != NULL) cbor_decref(&array); return r; } int fido_dev_largeblob_get(fido_dev_t *dev, const unsigned char *key_ptr, size_t key_len, unsigned char **blob_ptr, size_t *blob_len) { cbor_item_t *item = NULL; fido_blob_t key, body; + int ms = dev->timeout_ms; int r; memset(&key, 0, sizeof(key)); memset(&body, 0, sizeof(body)); if (key_len != 32) { fido_log_debug("%s: invalid key len %zu", __func__, key_len); return FIDO_ERR_INVALID_ARGUMENT; } if (blob_ptr == NULL || blob_len == NULL) { fido_log_debug("%s: invalid blob_ptr=%p, blob_len=%p", __func__, (const void *)blob_ptr, (const void *)blob_len); return FIDO_ERR_INVALID_ARGUMENT; } *blob_ptr = NULL; *blob_len = 0; if (fido_blob_set(&key, key_ptr, key_len) < 0) { fido_log_debug("%s: fido_blob_set", __func__); return FIDO_ERR_INTERNAL; } - if ((r = largeblob_get_array(dev, &item)) != FIDO_OK) { + if ((r = largeblob_get_array(dev, &item, &ms)) != FIDO_OK) { fido_log_debug("%s: largeblob_get_array", __func__); goto fail; } if ((r = largeblob_array_lookup(&body, NULL, item, &key)) != FIDO_OK) fido_log_debug("%s: largeblob_array_lookup", __func__); else { *blob_ptr = body.ptr; *blob_len = body.len; } fail: if (item != NULL) cbor_decref(&item); fido_blob_reset(&key); return r; } int fido_dev_largeblob_set(fido_dev_t *dev, const unsigned char *key_ptr, size_t key_len, const unsigned char *blob_ptr, size_t blob_len, const char *pin) { cbor_item_t *item = NULL; fido_blob_t key, body; + int ms = dev->timeout_ms; int r; memset(&key, 0, sizeof(key)); memset(&body, 0, sizeof(body)); if (key_len != 32) { fido_log_debug("%s: invalid key len %zu", __func__, key_len); return FIDO_ERR_INVALID_ARGUMENT; } if (blob_ptr == NULL || blob_len == 0) { fido_log_debug("%s: invalid blob_ptr=%p, blob_len=%zu", __func__, (const void *)blob_ptr, blob_len); return FIDO_ERR_INVALID_ARGUMENT; } if (fido_blob_set(&key, key_ptr, key_len) < 0 || fido_blob_set(&body, blob_ptr, blob_len) < 0) { fido_log_debug("%s: fido_blob_set", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if ((item = largeblob_encode(&body, &key)) == NULL) { fido_log_debug("%s: largeblob_encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } - if ((r = largeblob_add(dev, &key, item, pin)) != FIDO_OK) + if ((r = largeblob_add(dev, &key, item, pin, &ms)) != FIDO_OK) fido_log_debug("%s: largeblob_add", __func__); fail: if (item != NULL) cbor_decref(&item); fido_blob_reset(&key); fido_blob_reset(&body); return r; } int fido_dev_largeblob_remove(fido_dev_t *dev, const unsigned char *key_ptr, size_t key_len, const char *pin) { fido_blob_t key; + int ms = dev->timeout_ms; int r; memset(&key, 0, sizeof(key)); if (key_len != 32) { fido_log_debug("%s: invalid key len %zu", __func__, key_len); return FIDO_ERR_INVALID_ARGUMENT; } if (fido_blob_set(&key, key_ptr, key_len) < 0) { fido_log_debug("%s: fido_blob_set", __func__); return FIDO_ERR_INTERNAL; } - if ((r = largeblob_drop(dev, &key, pin)) != FIDO_OK) + if ((r = largeblob_drop(dev, &key, pin, &ms)) != FIDO_OK) fido_log_debug("%s: largeblob_drop", __func__); fido_blob_reset(&key); return r; } int fido_dev_largeblob_get_array(fido_dev_t *dev, unsigned char **cbor_ptr, size_t *cbor_len) { cbor_item_t *item = NULL; fido_blob_t cbor; + int ms = dev->timeout_ms; int r; memset(&cbor, 0, sizeof(cbor)); if (cbor_ptr == NULL || cbor_len == NULL) { fido_log_debug("%s: invalid cbor_ptr=%p, cbor_len=%p", __func__, (const void *)cbor_ptr, (const void *)cbor_len); return FIDO_ERR_INVALID_ARGUMENT; } *cbor_ptr = NULL; *cbor_len = 0; - if ((r = largeblob_get_array(dev, &item)) != FIDO_OK) { + if ((r = largeblob_get_array(dev, &item, &ms)) != FIDO_OK) { fido_log_debug("%s: largeblob_get_array", __func__); return r; } if (fido_blob_serialise(&cbor, item) < 0) { fido_log_debug("%s: fido_blob_serialise", __func__); r = FIDO_ERR_INTERNAL; } else { *cbor_ptr = cbor.ptr; *cbor_len = cbor.len; } cbor_decref(&item); return r; } int fido_dev_largeblob_set_array(fido_dev_t *dev, const unsigned char *cbor_ptr, size_t cbor_len, const char *pin) { cbor_item_t *item = NULL; struct cbor_load_result cbor_result; + int ms = dev->timeout_ms; int r; if (cbor_ptr == NULL || cbor_len == 0) { fido_log_debug("%s: invalid cbor_ptr=%p, cbor_len=%zu", __func__, (const void *)cbor_ptr, cbor_len); return FIDO_ERR_INVALID_ARGUMENT; } if ((item = cbor_load(cbor_ptr, cbor_len, &cbor_result)) == NULL) { fido_log_debug("%s: cbor_load", __func__); return FIDO_ERR_INVALID_ARGUMENT; } - if ((r = largeblob_set_array(dev, item, pin)) != FIDO_OK) + if ((r = largeblob_set_array(dev, item, pin, &ms)) != FIDO_OK) fido_log_debug("%s: largeblob_set_array", __func__); cbor_decref(&item); return r; } diff --git a/contrib/libfido2/src/netlink.c b/contrib/libfido2/src/netlink.c index 6fd9f63cb937..8f14e2c3bac3 100644 --- a/contrib/libfido2/src/netlink.c +++ b/contrib/libfido2/src/netlink.c @@ -1,782 +1,784 @@ /* * Copyright (c) 2020 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include "fido.h" #include "netlink.h" #ifdef FIDO_FUZZ static ssize_t (*fuzz_read)(int, void *, size_t); static ssize_t (*fuzz_write)(int, const void *, size_t); # define READ fuzz_read # define WRITE fuzz_write #else # define READ read # define WRITE write #endif #ifndef SOL_NETLINK #define SOL_NETLINK 270 #endif +#define NETLINK_POLL_MS 100 + /* XXX avoid signed NLA_ALIGNTO */ #undef NLA_HDRLEN #define NLA_HDRLEN NLMSG_ALIGN(sizeof(struct nlattr)) typedef struct nlmsgbuf { size_t siz; /* alloc size */ size_t len; /* of payload */ unsigned char *ptr; /* in payload */ union { struct nlmsghdr nlmsg; char buf[NLMSG_HDRLEN]; /* align */ } u; unsigned char payload[]; } nlmsgbuf_t; typedef struct genlmsgbuf { union { struct genlmsghdr genl; char buf[GENL_HDRLEN]; /* align */ } u; } genlmsgbuf_t; typedef struct nlamsgbuf { size_t siz; /* alloc size */ size_t len; /* of payload */ unsigned char *ptr; /* in payload */ union { struct nlattr nla; char buf[NLA_HDRLEN]; /* align */ } u; unsigned char payload[]; } nlamsgbuf_t; typedef struct nl_family { uint16_t id; uint32_t mcastgrp; } nl_family_t; typedef struct nl_poll { uint32_t dev; unsigned int eventcnt; } nl_poll_t; typedef struct nl_target { int found; uint32_t *value; } nl_target_t; static const void * nlmsg_ptr(const nlmsgbuf_t *m) { return (&m->u.nlmsg); } static size_t nlmsg_len(const nlmsgbuf_t *m) { return (m->u.nlmsg.nlmsg_len); } static uint16_t nlmsg_type(const nlmsgbuf_t *m) { return (m->u.nlmsg.nlmsg_type); } static nlmsgbuf_t * nlmsg_new(uint16_t type, uint16_t flags, size_t len) { nlmsgbuf_t *m; size_t siz; if (len > SIZE_MAX - sizeof(*m) || (siz = sizeof(*m) + len) > UINT16_MAX || (m = calloc(1, siz)) == NULL) return (NULL); m->siz = siz; m->len = len; m->ptr = m->payload; m->u.nlmsg.nlmsg_type = type; m->u.nlmsg.nlmsg_flags = NLM_F_REQUEST | flags; m->u.nlmsg.nlmsg_len = NLMSG_HDRLEN; return (m); } static nlamsgbuf_t * nla_from_buf(const unsigned char **ptr, size_t *len) { nlamsgbuf_t h, *a; size_t nlalen, skip; if (*len < sizeof(h.u)) return (NULL); memset(&h, 0, sizeof(h)); memcpy(&h.u, *ptr, sizeof(h.u)); if ((nlalen = h.u.nla.nla_len) < sizeof(h.u) || nlalen > *len || nlalen - sizeof(h.u) > UINT16_MAX || nlalen > SIZE_MAX - sizeof(*a) || (skip = NLMSG_ALIGN(nlalen)) > *len || (a = calloc(1, sizeof(*a) + nlalen - sizeof(h.u))) == NULL) return (NULL); memcpy(&a->u, *ptr, nlalen); a->siz = sizeof(*a) + nlalen - sizeof(h.u); a->ptr = a->payload; a->len = nlalen - sizeof(h.u); *ptr += skip; *len -= skip; return (a); } static nlamsgbuf_t * nla_getattr(nlamsgbuf_t *a) { return (nla_from_buf((void *)&a->ptr, &a->len)); } static uint16_t nla_type(const nlamsgbuf_t *a) { return (a->u.nla.nla_type); } static nlamsgbuf_t * nlmsg_getattr(nlmsgbuf_t *m) { return (nla_from_buf((void *)&m->ptr, &m->len)); } static int nla_read(nlamsgbuf_t *a, void *buf, size_t cnt) { if (cnt > a->u.nla.nla_len || fido_buf_read((void *)&a->ptr, &a->len, buf, cnt) < 0) return (-1); a->u.nla.nla_len = (uint16_t)(a->u.nla.nla_len - cnt); return (0); } static nlmsgbuf_t * nlmsg_from_buf(const unsigned char **ptr, size_t *len) { nlmsgbuf_t h, *m; size_t msglen, skip; if (*len < sizeof(h.u)) return (NULL); memset(&h, 0, sizeof(h)); memcpy(&h.u, *ptr, sizeof(h.u)); if ((msglen = h.u.nlmsg.nlmsg_len) < sizeof(h.u) || msglen > *len || msglen - sizeof(h.u) > UINT16_MAX || (skip = NLMSG_ALIGN(msglen)) > *len || (m = nlmsg_new(0, 0, msglen - sizeof(h.u))) == NULL) return (NULL); memcpy(&m->u, *ptr, msglen); *ptr += skip; *len -= skip; return (m); } static int nlmsg_read(nlmsgbuf_t *m, void *buf, size_t cnt) { if (cnt > m->u.nlmsg.nlmsg_len || fido_buf_read((void *)&m->ptr, &m->len, buf, cnt) < 0) return (-1); m->u.nlmsg.nlmsg_len = (uint32_t)(m->u.nlmsg.nlmsg_len - cnt); return (0); } static int nlmsg_write(nlmsgbuf_t *m, const void *buf, size_t cnt) { if (cnt > UINT32_MAX - m->u.nlmsg.nlmsg_len || fido_buf_write(&m->ptr, &m->len, buf, cnt) < 0) return (-1); m->u.nlmsg.nlmsg_len = (uint32_t)(m->u.nlmsg.nlmsg_len + cnt); return (0); } static int nlmsg_set_genl(nlmsgbuf_t *m, uint8_t cmd) { genlmsgbuf_t g; memset(&g, 0, sizeof(g)); g.u.genl.cmd = cmd; g.u.genl.version = NFC_GENL_VERSION; return (nlmsg_write(m, &g, sizeof(g))); } static int nlmsg_get_genl(nlmsgbuf_t *m, uint8_t cmd) { genlmsgbuf_t g; memset(&g, 0, sizeof(g)); if (nlmsg_read(m, &g, sizeof(g)) < 0 || g.u.genl.cmd != cmd) return (-1); return (0); } static int nlmsg_get_status(nlmsgbuf_t *m) { int status; if (nlmsg_read(m, &status, sizeof(status)) < 0 || status == INT_MIN) return (-1); if (status < 0) status = -status; return (status); } static int nlmsg_setattr(nlmsgbuf_t *m, uint16_t type, const void *ptr, size_t len) { int r; char *padding; size_t skip; nlamsgbuf_t a; if ((skip = NLMSG_ALIGN(len)) > UINT16_MAX - sizeof(a.u) || skip < len || (padding = calloc(1, skip - len)) == NULL) return (-1); memset(&a, 0, sizeof(a)); a.u.nla.nla_type = type; a.u.nla.nla_len = (uint16_t)(len + sizeof(a.u)); r = nlmsg_write(m, &a.u, sizeof(a.u)) < 0 || nlmsg_write(m, ptr, len) < 0 || nlmsg_write(m, padding, skip - len) < 0 ? -1 : 0; free(padding); return (r); } static int nlmsg_set_u16(nlmsgbuf_t *m, uint16_t type, uint16_t val) { return (nlmsg_setattr(m, type, &val, sizeof(val))); } static int nlmsg_set_u32(nlmsgbuf_t *m, uint16_t type, uint32_t val) { return (nlmsg_setattr(m, type, &val, sizeof(val))); } static int nlmsg_set_str(nlmsgbuf_t *m, uint16_t type, const char *val) { return (nlmsg_setattr(m, type, val, strlen(val) + 1)); } static int nla_get_u16(nlamsgbuf_t *a, uint16_t *v) { return (nla_read(a, v, sizeof(*v))); } static int nla_get_u32(nlamsgbuf_t *a, uint32_t *v) { return (nla_read(a, v, sizeof(*v))); } static char * nla_get_str(nlamsgbuf_t *a) { size_t n; char *s = NULL; if ((n = a->len) < 1 || a->ptr[n - 1] != '\0' || (s = calloc(1, n)) == NULL || nla_read(a, s, n) < 0) { free(s); return (NULL); } s[n - 1] = '\0'; return (s); } static int nlmsg_tx(int fd, const nlmsgbuf_t *m) { ssize_t r; if ((r = WRITE(fd, nlmsg_ptr(m), nlmsg_len(m))) == -1) { fido_log_error(errno, "%s: write", __func__); return (-1); } if (r < 0 || (size_t)r != nlmsg_len(m)) { fido_log_debug("%s: %zd != %zu", __func__, r, nlmsg_len(m)); return (-1); } fido_log_xxd(nlmsg_ptr(m), nlmsg_len(m), "%s", __func__); return (0); } static ssize_t nlmsg_rx(int fd, unsigned char *ptr, size_t len, int ms) { ssize_t r; if (len > SSIZE_MAX) { fido_log_debug("%s: len", __func__); return (-1); } if (fido_hid_unix_wait(fd, ms, NULL) < 0) { fido_log_debug("%s: fido_hid_unix_wait", __func__); return (-1); } if ((r = READ(fd, ptr, len)) == -1) { fido_log_error(errno, "%s: read %zd", __func__, r); return (-1); } fido_log_xxd(ptr, (size_t)r, "%s", __func__); return (r); } static int nlmsg_iter(nlmsgbuf_t *m, void *arg, int (*parser)(nlamsgbuf_t *, void *)) { nlamsgbuf_t *a; int r; while ((a = nlmsg_getattr(m)) != NULL) { r = parser(a, arg); free(a); if (r < 0) { fido_log_debug("%s: parser", __func__); return (-1); } } return (0); } static int nla_iter(nlamsgbuf_t *g, void *arg, int (*parser)(nlamsgbuf_t *, void *)) { nlamsgbuf_t *a; int r; while ((a = nla_getattr(g)) != NULL) { r = parser(a, arg); free(a); if (r < 0) { fido_log_debug("%s: parser", __func__); return (-1); } } return (0); } static int nl_parse_reply(const uint8_t *blob, size_t blob_len, uint16_t msg_type, uint8_t genl_cmd, void *arg, int (*parser)(nlamsgbuf_t *, void *)) { nlmsgbuf_t *m; int r; while (blob_len) { if ((m = nlmsg_from_buf(&blob, &blob_len)) == NULL) { fido_log_debug("%s: nlmsg", __func__); return (-1); } if (nlmsg_type(m) == NLMSG_ERROR) { r = nlmsg_get_status(m); free(m); return (r); } if (nlmsg_type(m) != msg_type || nlmsg_get_genl(m, genl_cmd) < 0) { fido_log_debug("%s: skipping", __func__); free(m); continue; } if (parser != NULL && nlmsg_iter(m, arg, parser) < 0) { fido_log_debug("%s: nlmsg_iter", __func__); free(m); return (-1); } free(m); } return (0); } static int parse_mcastgrp(nlamsgbuf_t *a, void *arg) { nl_family_t *family = arg; char *name; switch (nla_type(a)) { case CTRL_ATTR_MCAST_GRP_NAME: if ((name = nla_get_str(a)) == NULL || strcmp(name, NFC_GENL_MCAST_EVENT_NAME) != 0) { free(name); return (-1); /* XXX skip? */ } free(name); return (0); case CTRL_ATTR_MCAST_GRP_ID: if (family->mcastgrp) break; if (nla_get_u32(a, &family->mcastgrp) < 0) { fido_log_debug("%s: group", __func__); return (-1); } return (0); } fido_log_debug("%s: ignoring nla 0x%x", __func__, nla_type(a)); return (0); } static int parse_mcastgrps(nlamsgbuf_t *a, void *arg) { return (nla_iter(a, arg, parse_mcastgrp)); } static int parse_family(nlamsgbuf_t *a, void *arg) { nl_family_t *family = arg; switch (nla_type(a)) { case CTRL_ATTR_FAMILY_ID: if (family->id) break; if (nla_get_u16(a, &family->id) < 0) { fido_log_debug("%s: id", __func__); return (-1); } return (0); case CTRL_ATTR_MCAST_GROUPS: return (nla_iter(a, family, parse_mcastgrps)); } fido_log_debug("%s: ignoring nla 0x%x", __func__, nla_type(a)); return (0); } static int nl_get_nfc_family(int fd, uint16_t *type, uint32_t *mcastgrp) { nlmsgbuf_t *m; uint8_t reply[512]; nl_family_t family; ssize_t r; int ok; if ((m = nlmsg_new(GENL_ID_CTRL, 0, 64)) == NULL || nlmsg_set_genl(m, CTRL_CMD_GETFAMILY) < 0 || nlmsg_set_u16(m, CTRL_ATTR_FAMILY_ID, GENL_ID_CTRL) < 0 || nlmsg_set_str(m, CTRL_ATTR_FAMILY_NAME, NFC_GENL_NAME) < 0 || nlmsg_tx(fd, m) < 0) { free(m); return (-1); } free(m); memset(&family, 0, sizeof(family)); if ((r = nlmsg_rx(fd, reply, sizeof(reply), -1)) < 0) { fido_log_debug("%s: nlmsg_rx", __func__); return (-1); } if ((ok = nl_parse_reply(reply, (size_t)r, GENL_ID_CTRL, CTRL_CMD_NEWFAMILY, &family, parse_family)) != 0) { fido_log_debug("%s: nl_parse_reply: %d", __func__, ok); return (-1); } if (family.id == 0 || family.mcastgrp == 0) { fido_log_debug("%s: missing attr", __func__); return (-1); } *type = family.id; *mcastgrp = family.mcastgrp; return (0); } static int parse_target(nlamsgbuf_t *a, void *arg) { nl_target_t *t = arg; if (t->found || nla_type(a) != NFC_ATTR_TARGET_INDEX) { fido_log_debug("%s: ignoring nla 0x%x", __func__, nla_type(a)); return (0); } if (nla_get_u32(a, t->value) < 0) { fido_log_debug("%s: target", __func__); return (-1); } t->found = 1; return (0); } int fido_nl_power_nfc(fido_nl_t *nl, uint32_t dev) { nlmsgbuf_t *m; uint8_t reply[512]; ssize_t r; int ok; if ((m = nlmsg_new(nl->nfc_type, NLM_F_ACK, 64)) == NULL || nlmsg_set_genl(m, NFC_CMD_DEV_UP) < 0 || nlmsg_set_u32(m, NFC_ATTR_DEVICE_INDEX, dev) < 0 || nlmsg_tx(nl->fd, m) < 0) { free(m); return (-1); } free(m); if ((r = nlmsg_rx(nl->fd, reply, sizeof(reply), -1)) < 0) { fido_log_debug("%s: nlmsg_rx", __func__); return (-1); } if ((ok = nl_parse_reply(reply, (size_t)r, nl->nfc_type, NFC_CMD_DEV_UP, NULL, NULL)) != 0 && ok != EALREADY) { fido_log_debug("%s: nl_parse_reply: %d", __func__, ok); return (-1); } return (0); } static int nl_nfc_poll(fido_nl_t *nl, uint32_t dev) { nlmsgbuf_t *m; uint8_t reply[512]; ssize_t r; int ok; if ((m = nlmsg_new(nl->nfc_type, NLM_F_ACK, 64)) == NULL || nlmsg_set_genl(m, NFC_CMD_START_POLL) < 0 || nlmsg_set_u32(m, NFC_ATTR_DEVICE_INDEX, dev) < 0 || nlmsg_set_u32(m, NFC_ATTR_PROTOCOLS, NFC_PROTO_ISO14443_MASK) < 0 || nlmsg_tx(nl->fd, m) < 0) { free(m); return (-1); } free(m); if ((r = nlmsg_rx(nl->fd, reply, sizeof(reply), -1)) < 0) { fido_log_debug("%s: nlmsg_rx", __func__); return (-1); } if ((ok = nl_parse_reply(reply, (size_t)r, nl->nfc_type, NFC_CMD_START_POLL, NULL, NULL)) != 0) { fido_log_debug("%s: nl_parse_reply: %d", __func__, ok); return (-1); } return (0); } static int nl_dump_nfc_target(fido_nl_t *nl, uint32_t dev, uint32_t *target, int ms) { nlmsgbuf_t *m; nl_target_t t; uint8_t reply[512]; ssize_t r; int ok; if ((m = nlmsg_new(nl->nfc_type, NLM_F_DUMP, 64)) == NULL || nlmsg_set_genl(m, NFC_CMD_GET_TARGET) < 0 || nlmsg_set_u32(m, NFC_ATTR_DEVICE_INDEX, dev) < 0 || nlmsg_tx(nl->fd, m) < 0) { free(m); return (-1); } free(m); if ((r = nlmsg_rx(nl->fd, reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: nlmsg_rx", __func__); return (-1); } memset(&t, 0, sizeof(t)); t.value = target; if ((ok = nl_parse_reply(reply, (size_t)r, nl->nfc_type, NFC_CMD_GET_TARGET, &t, parse_target)) != 0) { fido_log_debug("%s: nl_parse_reply: %d", __func__, ok); return (-1); } if (!t.found) { fido_log_debug("%s: target not found", __func__); return (-1); } return (0); } static int parse_nfc_event(nlamsgbuf_t *a, void *arg) { nl_poll_t *ctx = arg; uint32_t dev; if (nla_type(a) != NFC_ATTR_DEVICE_INDEX) { fido_log_debug("%s: ignoring nla 0x%x", __func__, nla_type(a)); return (0); } if (nla_get_u32(a, &dev) < 0) { fido_log_debug("%s: dev", __func__); return (-1); } if (dev == ctx->dev) ctx->eventcnt++; else fido_log_debug("%s: ignoring dev 0x%x", __func__, dev); return (0); } int fido_nl_get_nfc_target(fido_nl_t *nl, uint32_t dev, uint32_t *target) { uint8_t reply[512]; nl_poll_t ctx; ssize_t r; int ok; if (nl_nfc_poll(nl, dev) < 0) { fido_log_debug("%s: nl_nfc_poll", __func__); return (-1); } #ifndef FIDO_FUZZ if (setsockopt(nl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &nl->nfc_mcastgrp, sizeof(nl->nfc_mcastgrp)) == -1) { fido_log_error(errno, "%s: setsockopt add", __func__); return (-1); } #endif - r = nlmsg_rx(nl->fd, reply, sizeof(reply), -1); + r = nlmsg_rx(nl->fd, reply, sizeof(reply), NETLINK_POLL_MS); #ifndef FIDO_FUZZ if (setsockopt(nl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, &nl->nfc_mcastgrp, sizeof(nl->nfc_mcastgrp)) == -1) { fido_log_error(errno, "%s: setsockopt drop", __func__); return (-1); } #endif if (r < 0) { fido_log_debug("%s: nlmsg_rx", __func__); return (-1); } memset(&ctx, 0, sizeof(ctx)); ctx.dev = dev; if ((ok = nl_parse_reply(reply, (size_t)r, nl->nfc_type, NFC_EVENT_TARGETS_FOUND, &ctx, parse_nfc_event)) != 0) { fido_log_debug("%s: nl_parse_reply: %d", __func__, ok); return (-1); } if (ctx.eventcnt == 0) { fido_log_debug("%s: dev 0x%x not observed", __func__, dev); return (-1); } if (nl_dump_nfc_target(nl, dev, target, -1) < 0) { fido_log_debug("%s: nl_dump_nfc_target", __func__); return (-1); } return (0); } void fido_nl_free(fido_nl_t **nlp) { fido_nl_t *nl; if (nlp == NULL || (nl = *nlp) == NULL) return; if (nl->fd != -1 && close(nl->fd) == -1) fido_log_error(errno, "%s: close", __func__); free(nl); *nlp = NULL; } fido_nl_t * fido_nl_new(void) { fido_nl_t *nl; int ok = -1; if ((nl = calloc(1, sizeof(*nl))) == NULL) return (NULL); if ((nl->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_GENERIC)) == -1) { fido_log_error(errno, "%s: socket", __func__); goto fail; } nl->saddr.nl_family = AF_NETLINK; if (bind(nl->fd, (struct sockaddr *)&nl->saddr, sizeof(nl->saddr)) == -1) { fido_log_error(errno, "%s: bind", __func__); goto fail; } if (nl_get_nfc_family(nl->fd, &nl->nfc_type, &nl->nfc_mcastgrp) < 0) { fido_log_debug("%s: nl_get_nfc_family", __func__); goto fail; } ok = 0; fail: if (ok < 0) fido_nl_free(&nl); return (nl); } #ifdef FIDO_FUZZ void set_netlink_io_functions(ssize_t (*read_f)(int, void *, size_t), ssize_t (*write_f)(int, const void *, size_t)) { fuzz_read = read_f; fuzz_write = write_f; } #endif diff --git a/contrib/libfido2/src/nfc_linux.c b/contrib/libfido2/src/nfc_linux.c index dea9f3f98fd0..d5f9ec048052 100644 --- a/contrib/libfido2/src/nfc_linux.c +++ b/contrib/libfido2/src/nfc_linux.c @@ -1,631 +1,653 @@ /* * Copyright (c) 2020 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include #include +#include +#include #include #include "fido.h" #include "fido/param.h" #include "netlink.h" #include "iso7816.h" #define TX_CHUNK_SIZE 240 static const uint8_t aid[] = { 0xa0, 0x00, 0x00, 0x06, 0x47, 0x2f, 0x00, 0x01 }; static const uint8_t v_u2f[] = { 'U', '2', 'F', '_', 'V', '2' }; static const uint8_t v_fido[] = { 'F', 'I', 'D', 'O', '_', '2', '_', '0' }; struct nfc_linux { int fd; uint32_t dev; uint32_t target; sigset_t sigmask; const sigset_t *sigmaskp; struct fido_nl *nl; }; static int tx_short_apdu(fido_dev_t *d, const iso7816_header_t *h, const uint8_t *payload, uint8_t payload_len, uint8_t cla_flags) { uint8_t apdu[5 + UINT8_MAX + 1]; uint8_t sw[2]; size_t apdu_len; int ok = -1; memset(&apdu, 0, sizeof(apdu)); apdu[0] = h->cla | cla_flags; apdu[1] = h->ins; apdu[2] = h->p1; apdu[3] = h->p2; apdu[4] = payload_len; memcpy(&apdu[5], payload, payload_len); apdu_len = (size_t)(5 + payload_len + 1); if (d->io.write(d->io_handle, apdu, apdu_len) < 0) { fido_log_debug("%s: write", __func__); goto fail; } if (cla_flags & 0x10) { if (d->io.read(d->io_handle, sw, sizeof(sw), -1) != 2) { fido_log_debug("%s: read", __func__); goto fail; } if ((sw[0] << 8 | sw[1]) != SW_NO_ERROR) { fido_log_debug("%s: unexpected sw", __func__); goto fail; } } ok = 0; fail: explicit_bzero(apdu, sizeof(apdu)); return (ok); } static int nfc_do_tx(fido_dev_t *d, const uint8_t *apdu_ptr, size_t apdu_len) { iso7816_header_t h; if (fido_buf_read(&apdu_ptr, &apdu_len, &h, sizeof(h)) < 0) { fido_log_debug("%s: header", __func__); return (-1); } if (apdu_len < 2) { fido_log_debug("%s: apdu_len %zu", __func__, apdu_len); return (-1); } apdu_len -= 2; /* trim le1 le2 */ while (apdu_len > TX_CHUNK_SIZE) { if (tx_short_apdu(d, &h, apdu_ptr, TX_CHUNK_SIZE, 0x10) < 0) { fido_log_debug("%s: chain", __func__); return (-1); } apdu_ptr += TX_CHUNK_SIZE; apdu_len -= TX_CHUNK_SIZE; } if (tx_short_apdu(d, &h, apdu_ptr, (uint8_t)apdu_len, 0) < 0) { fido_log_debug("%s: tx_short_apdu", __func__); return (-1); } return (0); } int fido_nfc_tx(fido_dev_t *d, uint8_t cmd, const unsigned char *buf, size_t count) { iso7816_apdu_t *apdu = NULL; const uint8_t *ptr; size_t len; int ok = -1; switch (cmd) { case CTAP_CMD_INIT: /* select */ if ((apdu = iso7816_new(0, 0xa4, 0x04, sizeof(aid))) == NULL || iso7816_add(apdu, aid, sizeof(aid)) < 0) { fido_log_debug("%s: iso7816", __func__); goto fail; } break; case CTAP_CMD_CBOR: /* wrap cbor */ if (count > UINT16_MAX || (apdu = iso7816_new(0x80, 0x10, 0x80, (uint16_t)count)) == NULL || iso7816_add(apdu, buf, count) < 0) { fido_log_debug("%s: iso7816", __func__); goto fail; } break; case CTAP_CMD_MSG: /* already an apdu */ break; default: fido_log_debug("%s: cmd=%02x", __func__, cmd); goto fail; } if (apdu != NULL) { ptr = iso7816_ptr(apdu); len = iso7816_len(apdu); } else { ptr = buf; len = count; } if (nfc_do_tx(d, ptr, len) < 0) { fido_log_debug("%s: nfc_do_tx", __func__); goto fail; } ok = 0; fail: iso7816_free(&apdu); return (ok); } static int rx_init(fido_dev_t *d, unsigned char *buf, size_t count, int ms) { fido_ctap_info_t *attr = (fido_ctap_info_t *)buf; uint8_t f[64]; int n; if (count != sizeof(*attr)) { fido_log_debug("%s: count=%zu", __func__, count); return (-1); } memset(attr, 0, sizeof(*attr)); if ((n = d->io.read(d->io_handle, f, sizeof(f), ms)) < 2 || (f[n - 2] << 8 | f[n - 1]) != SW_NO_ERROR) { fido_log_debug("%s: read", __func__); return (-1); } n -= 2; if (n == sizeof(v_u2f) && memcmp(f, v_u2f, sizeof(v_u2f)) == 0) attr->flags = FIDO_CAP_CBOR; else if (n == sizeof(v_fido) && memcmp(f, v_fido, sizeof(v_fido)) == 0) attr->flags = FIDO_CAP_CBOR | FIDO_CAP_NMSG; else { fido_log_debug("%s: unknown version string", __func__); #ifdef FIDO_FUZZ attr->flags = FIDO_CAP_CBOR | FIDO_CAP_NMSG; #else return (-1); #endif } memcpy(&attr->nonce, &d->nonce, sizeof(attr->nonce)); /* XXX */ return ((int)count); } static int tx_get_response(fido_dev_t *d, uint8_t count) { uint8_t apdu[5]; memset(apdu, 0, sizeof(apdu)); apdu[1] = 0xc0; /* GET_RESPONSE */ apdu[4] = count; if (d->io.write(d->io_handle, apdu, sizeof(apdu)) < 0) { fido_log_debug("%s: write", __func__); return (-1); } return (0); } static int -rx_apdu(fido_dev_t *d, uint8_t sw[2], unsigned char **buf, size_t *count, int ms) +rx_apdu(fido_dev_t *d, uint8_t sw[2], unsigned char **buf, size_t *count, int *ms) { uint8_t f[256 + 2]; + struct timespec ts; int n, ok = -1; - if ((n = d->io.read(d->io_handle, f, sizeof(f), ms)) < 2) { + if (fido_time_now(&ts) != 0) + goto fail; + + if ((n = d->io.read(d->io_handle, f, sizeof(f), *ms)) < 2) { fido_log_debug("%s: read", __func__); goto fail; } + if (fido_time_delta(&ts, ms) != 0) + goto fail; + if (fido_buf_write(buf, count, f, (size_t)(n - 2)) < 0) { fido_log_debug("%s: fido_buf_write", __func__); goto fail; } memcpy(sw, f + n - 2, 2); ok = 0; fail: explicit_bzero(f, sizeof(f)); return (ok); } static int rx_msg(fido_dev_t *d, unsigned char *buf, size_t count, int ms) { uint8_t sw[2]; const size_t bufsiz = count; - if (rx_apdu(d, sw, &buf, &count, ms) < 0) { + if (rx_apdu(d, sw, &buf, &count, &ms) < 0) { fido_log_debug("%s: preamble", __func__); return (-1); } while (sw[0] == SW1_MORE_DATA) if (tx_get_response(d, sw[1]) < 0 || - rx_apdu(d, sw, &buf, &count, ms) < 0) { + rx_apdu(d, sw, &buf, &count, &ms) < 0) { fido_log_debug("%s: chain", __func__); return (-1); } if (fido_buf_write(&buf, &count, sw, sizeof(sw)) < 0) { fido_log_debug("%s: sw", __func__); return (-1); } if (bufsiz - count > INT_MAX) { fido_log_debug("%s: bufsiz", __func__); return (-1); } return ((int)(bufsiz - count)); } static int rx_cbor(fido_dev_t *d, unsigned char *buf, size_t count, int ms) { int r; if ((r = rx_msg(d, buf, count, ms)) < 2) return (-1); return (r - 2); } int fido_nfc_rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms) { switch (cmd) { case CTAP_CMD_INIT: return (rx_init(d, buf, count, ms)); case CTAP_CMD_CBOR: return (rx_cbor(d, buf, count, ms)); case CTAP_CMD_MSG: return (rx_msg(d, buf, count, ms)); default: fido_log_debug("%s: cmd=%02x", __func__, cmd); return (-1); } } static char * get_parent_attr(struct udev_device *dev, const char *subsystem, const char *devtype, const char *attr) { struct udev_device *parent; const char *value; if ((parent = udev_device_get_parent_with_subsystem_devtype(dev, subsystem, devtype)) == NULL || (value = udev_device_get_sysattr_value(parent, attr)) == NULL) return (NULL); return (strdup(value)); } static char * get_usb_attr(struct udev_device *dev, const char *attr) { return (get_parent_attr(dev, "usb", "usb_device", attr)); } static int to_int(const char *str, int base) { char *ep; long long ll; ll = strtoll(str, &ep, base); if (str == ep || *ep != '\0') return (-1); else if (ll == LLONG_MIN && errno == ERANGE) return (-1); else if (ll == LLONG_MAX && errno == ERANGE) return (-1); else if (ll < 0 || ll > INT_MAX) return (-1); return ((int)ll); } static int copy_info(fido_dev_info_t *di, struct udev *udev, struct udev_list_entry *udev_entry) { const char *name; char *str; struct udev_device *dev = NULL; + void *ctx = NULL; int id, ok = -1; memset(di, 0, sizeof(*di)); if ((name = udev_list_entry_get_name(udev_entry)) == NULL || (dev = udev_device_new_from_syspath(udev, name)) == NULL) goto fail; - - if ((di->path = strdup(name)) == NULL || - (di->manufacturer = get_usb_attr(dev, "manufacturer")) == NULL || - (di->product = get_usb_attr(dev, "product")) == NULL) + if (asprintf(&di->path, "%s/%s", FIDO_NFC_PREFIX, name) == -1) + goto fail; + if ((di->manufacturer = get_usb_attr(dev, "manufacturer")) == NULL) + di->manufacturer = strdup(""); + if ((di->product = get_usb_attr(dev, "product")) == NULL) + di->product = strdup(""); + if (di->manufacturer == NULL || di->product == NULL) goto fail; - /* XXX assumes USB for vendor/product info */ if ((str = get_usb_attr(dev, "idVendor")) != NULL && (id = to_int(str, 16)) > 0 && id <= UINT16_MAX) di->vendor_id = (int16_t)id; free(str); - if ((str = get_usb_attr(dev, "idProduct")) != NULL && (id = to_int(str, 16)) > 0 && id <= UINT16_MAX) di->product_id = (int16_t)id; free(str); + if ((ctx = fido_nfc_open(di->path)) == NULL) { + fido_log_debug("%s: fido_nfc_open", __func__); + goto fail; + } + ok = 0; fail: if (dev != NULL) udev_device_unref(dev); + if (ctx != NULL) + fido_nfc_close(ctx); if (ok < 0) { free(di->path); free(di->manufacturer); free(di->product); explicit_bzero(di, sizeof(*di)); } return (ok); } static int sysnum_from_syspath(const char *path) { struct udev *udev = NULL; struct udev_device *dev = NULL; const char *str; int idx; if ((udev = udev_new()) == NULL || (dev = udev_device_new_from_syspath(udev, path)) == NULL || (str = udev_device_get_sysnum(dev)) == NULL) idx = -1; else idx = to_int(str, 10); if (dev != NULL) udev_device_unref(dev); if (udev != NULL) udev_unref(udev); return (idx); } int fido_nfc_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { struct udev *udev = NULL; struct udev_enumerate *udev_enum = NULL; struct udev_list_entry *udev_list; struct udev_list_entry *udev_entry; int r = FIDO_ERR_INTERNAL; *olen = 0; if (ilen == 0) return (FIDO_OK); if (devlist == NULL) return (FIDO_ERR_INVALID_ARGUMENT); if ((udev = udev_new()) == NULL || (udev_enum = udev_enumerate_new(udev)) == NULL) goto fail; if (udev_enumerate_add_match_subsystem(udev_enum, "nfc") < 0 || udev_enumerate_scan_devices(udev_enum) < 0) goto fail; if ((udev_list = udev_enumerate_get_list_entry(udev_enum)) == NULL) { r = FIDO_OK; /* zero nfc devices */ goto fail; } udev_list_entry_foreach(udev_entry, udev_list) { if (copy_info(&devlist[*olen], udev, udev_entry) == 0) { devlist[*olen].io = (fido_dev_io_t) { fido_nfc_open, fido_nfc_close, fido_nfc_read, fido_nfc_write, }; devlist[*olen].transport = (fido_dev_transport_t) { fido_nfc_rx, fido_nfc_tx, }; if (++(*olen) == ilen) break; } } r = FIDO_OK; fail: if (udev_enum != NULL) udev_enumerate_unref(udev_enum); if (udev != NULL) udev_unref(udev); return (r); } static int nfc_target_connect(struct nfc_linux *ctx) { struct sockaddr_nfc sa; memset(&sa, 0, sizeof(sa)); sa.sa_family = AF_NFC; sa.dev_idx = ctx->dev; sa.target_idx = ctx->target; sa.nfc_protocol = NFC_PROTO_ISO14443; if ((ctx->fd = socket(AF_NFC, SOCK_SEQPACKET | SOCK_CLOEXEC, NFC_SOCKPROTO_RAW)) == -1) { fido_log_error(errno, "%s: socket", __func__); return (-1); } if (connect(ctx->fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { fido_log_error(errno, "%s: connect", __func__); if (close(ctx->fd) == -1) fido_log_error(errno, "%s: close", __func__); ctx->fd = -1; return (-1); } return (0); } static void nfc_free(struct nfc_linux **ctx_p) { struct nfc_linux *ctx; if (ctx_p == NULL || (ctx = *ctx_p) == NULL) return; if (ctx->fd != -1 && close(ctx->fd) == -1) fido_log_error(errno, "%s: close", __func__); if (ctx->nl != NULL) fido_nl_free(&ctx->nl); free(ctx); *ctx_p = NULL; } static struct nfc_linux * nfc_new(uint32_t dev) { struct nfc_linux *ctx; if ((ctx = calloc(1, sizeof(*ctx))) == NULL || (ctx->nl = fido_nl_new()) == NULL) { nfc_free(&ctx); return (NULL); } ctx->fd = -1; ctx->dev = dev; return (ctx); } void * fido_nfc_open(const char *path) { struct nfc_linux *ctx = NULL; int idx; - if ((idx = sysnum_from_syspath(path)) < 0 || + if (strncmp(path, FIDO_NFC_PREFIX, strlen(FIDO_NFC_PREFIX)) != 0) { + fido_log_debug("%s: bad prefix", __func__); + goto fail; + } + if ((idx = sysnum_from_syspath(path + strlen(FIDO_NFC_PREFIX))) < 0 || (ctx = nfc_new((uint32_t)idx)) == NULL) { fido_log_debug("%s: nfc_new", __func__); goto fail; } if (fido_nl_power_nfc(ctx->nl, ctx->dev) < 0 || fido_nl_get_nfc_target(ctx->nl, ctx->dev, &ctx->target) < 0 || nfc_target_connect(ctx) < 0) { fido_log_debug("%s: netlink", __func__); goto fail; } return (ctx); fail: nfc_free(&ctx); return (NULL); } void fido_nfc_close(void *handle) { struct nfc_linux *ctx = handle; nfc_free(&ctx); } int fido_nfc_set_sigmask(void *handle, const fido_sigset_t *sigmask) { struct nfc_linux *ctx = handle; ctx->sigmask = *sigmask; ctx->sigmaskp = &ctx->sigmask; return (FIDO_OK); } int fido_nfc_read(void *handle, unsigned char *buf, size_t len, int ms) { struct nfc_linux *ctx = handle; struct iovec iov[2]; uint8_t preamble; ssize_t r; memset(&iov, 0, sizeof(iov)); iov[0].iov_base = &preamble; iov[0].iov_len = sizeof(preamble); iov[1].iov_base = buf; iov[1].iov_len = len; if (fido_hid_unix_wait(ctx->fd, ms, ctx->sigmaskp) < 0) { fido_log_debug("%s: fido_hid_unix_wait", __func__); return (-1); } if ((r = readv(ctx->fd, iov, nitems(iov))) == -1) { fido_log_error(errno, "%s: read", __func__); return (-1); } if (r < 1) { fido_log_debug("%s: %zd < 1", __func__, r); return (-1); } if (preamble != 0x00) { fido_log_debug("%s: preamble", __func__); return (-1); } r--; fido_log_xxd(buf, (size_t)r, "%s", __func__); return ((int)r); } int fido_nfc_write(void *handle, const unsigned char *buf, size_t len) { struct nfc_linux *ctx = handle; ssize_t r; fido_log_xxd(buf, len, "%s", __func__); if (len > INT_MAX) { fido_log_debug("%s: len", __func__); return (-1); } if ((r = write(ctx->fd, buf, len)) == -1) { fido_log_error(errno, "%s: write", __func__); return (-1); } if (r < 0 || (size_t)r != len) { fido_log_debug("%s: %zd != %zu", __func__, r, len); return (-1); } return ((int)r); } diff --git a/contrib/libfido2/src/pin.c b/contrib/libfido2/src/pin.c index d3104e0ca6ec..30eeb086a6ef 100644 --- a/contrib/libfido2/src/pin.c +++ b/contrib/libfido2/src/pin.c @@ -1,690 +1,698 @@ /* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include "fido.h" #include "fido/es256.h" #define CTAP21_UV_TOKEN_PERM_MAKECRED 0x01 #define CTAP21_UV_TOKEN_PERM_ASSERT 0x02 #define CTAP21_UV_TOKEN_PERM_CRED_MGMT 0x04 #define CTAP21_UV_TOKEN_PERM_BIO 0x08 #define CTAP21_UV_TOKEN_PERM_LARGEBLOB 0x10 #define CTAP21_UV_TOKEN_PERM_CONFIG 0x20 int fido_sha256(fido_blob_t *digest, const u_char *data, size_t data_len) { if ((digest->ptr = calloc(1, SHA256_DIGEST_LENGTH)) == NULL) return (-1); digest->len = SHA256_DIGEST_LENGTH; if (SHA256(data, data_len, digest->ptr) != digest->ptr) { fido_blob_reset(digest); return (-1); } return (0); } static int pin_sha256_enc(const fido_dev_t *dev, const fido_blob_t *shared, const fido_blob_t *pin, fido_blob_t **out) { fido_blob_t *ph = NULL; int r; if ((*out = fido_blob_new()) == NULL || (ph = fido_blob_new()) == NULL) { r = FIDO_ERR_INTERNAL; goto fail; } if (fido_sha256(ph, pin->ptr, pin->len) < 0 || ph->len < 16) { fido_log_debug("%s: SHA256", __func__); r = FIDO_ERR_INTERNAL; goto fail; } ph->len = 16; /* first 16 bytes */ if (aes256_cbc_enc(dev, shared, ph, *out) < 0) { fido_log_debug("%s: aes256_cbc_enc", __func__); r = FIDO_ERR_INTERNAL; goto fail; } r = FIDO_OK; fail: fido_blob_free(&ph); return (r); } static int pad64(const char *pin, fido_blob_t **ppin) { size_t pin_len; size_t ppin_len; pin_len = strlen(pin); if (pin_len < 4 || pin_len > 255) { fido_log_debug("%s: invalid pin length", __func__); return (FIDO_ERR_PIN_POLICY_VIOLATION); } if ((*ppin = fido_blob_new()) == NULL) return (FIDO_ERR_INTERNAL); ppin_len = (pin_len + 63U) & ~63U; if (ppin_len < pin_len || ((*ppin)->ptr = calloc(1, ppin_len)) == NULL) { fido_blob_free(ppin); return (FIDO_ERR_INTERNAL); } memcpy((*ppin)->ptr, pin, pin_len); (*ppin)->len = ppin_len; return (FIDO_OK); } static int pin_pad64_enc(const fido_dev_t *dev, const fido_blob_t *shared, const char *pin, fido_blob_t **out) { fido_blob_t *ppin = NULL; int r; if ((r = pad64(pin, &ppin)) != FIDO_OK) { fido_log_debug("%s: pad64", __func__); goto fail; } if ((*out = fido_blob_new()) == NULL) { r = FIDO_ERR_INTERNAL; goto fail; } if (aes256_cbc_enc(dev, shared, ppin, *out) < 0) { fido_log_debug("%s: aes256_cbc_enc", __func__); r = FIDO_ERR_INTERNAL; goto fail; } r = FIDO_OK; fail: fido_blob_free(&ppin); return (r); } static cbor_item_t * encode_uv_permission(uint8_t cmd) { switch (cmd) { case CTAP_CBOR_ASSERT: return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_ASSERT)); case CTAP_CBOR_BIO_ENROLL_PRE: return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_BIO)); case CTAP_CBOR_CONFIG: return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_CONFIG)); case CTAP_CBOR_MAKECRED: return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_MAKECRED)); case CTAP_CBOR_CRED_MGMT_PRE: return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_CRED_MGMT)); case CTAP_CBOR_LARGEBLOB: return (cbor_build_uint8(CTAP21_UV_TOKEN_PERM_LARGEBLOB)); default: fido_log_debug("%s: cmd 0x%02x", __func__, cmd); return (NULL); } } static int ctap20_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh, - const es256_pk_t *pk) + const es256_pk_t *pk, int *ms) { fido_blob_t f; fido_blob_t *p = NULL; fido_blob_t *phe = NULL; cbor_item_t *argv[6]; int r; memset(&f, 0, sizeof(f)); memset(argv, 0, sizeof(argv)); if (pin == NULL) { fido_log_debug("%s: NULL pin", __func__); r = FIDO_ERR_PIN_REQUIRED; goto fail; } if ((p = fido_blob_new()) == NULL || fido_blob_set(p, (const unsigned char *)pin, strlen(pin)) < 0) { fido_log_debug("%s: fido_blob_set", __func__); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if ((r = pin_sha256_enc(dev, ecdh, p, &phe)) != FIDO_OK) { fido_log_debug("%s: pin_sha256_enc", __func__); goto fail; } if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL || (argv[1] = cbor_build_uint8(5)) == NULL || (argv[2] = es256_pk_encode(pk, 1)) == NULL || (argv[5] = fido_blob_encode(phe)) == NULL) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), - &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { + &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); fido_blob_free(&p); fido_blob_free(&phe); free(f.ptr); return (r); } static int ctap21_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh, - const es256_pk_t *pk, uint8_t cmd, const char *rpid) + const es256_pk_t *pk, uint8_t cmd, const char *rpid, int *ms) { fido_blob_t f; fido_blob_t *p = NULL; fido_blob_t *phe = NULL; cbor_item_t *argv[10]; uint8_t subcmd; int r; memset(&f, 0, sizeof(f)); memset(argv, 0, sizeof(argv)); if (pin != NULL) { if ((p = fido_blob_new()) == NULL || fido_blob_set(p, (const unsigned char *)pin, strlen(pin)) < 0) { fido_log_debug("%s: fido_blob_set", __func__); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } if ((r = pin_sha256_enc(dev, ecdh, p, &phe)) != FIDO_OK) { fido_log_debug("%s: pin_sha256_enc", __func__); goto fail; } subcmd = 9; /* getPinUvAuthTokenUsingPinWithPermissions */ } else { if (fido_dev_has_uv(dev) == false) { fido_log_debug("%s: fido_dev_has_uv", __func__); r = FIDO_ERR_PIN_REQUIRED; goto fail; } subcmd = 6; /* getPinUvAuthTokenUsingUvWithPermissions */ } if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL || (argv[1] = cbor_build_uint8(subcmd)) == NULL || (argv[2] = es256_pk_encode(pk, 1)) == NULL || (phe != NULL && (argv[5] = fido_blob_encode(phe)) == NULL) || (argv[8] = encode_uv_permission(cmd)) == NULL || (rpid != NULL && (argv[9] = cbor_build_string(rpid)) == NULL)) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), - &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { + &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); fido_blob_free(&p); fido_blob_free(&phe); free(f.ptr); return (r); } static int parse_uv_token(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_blob_t *token = arg; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != 2) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } return (fido_blob_decode(val, token)); } static int uv_token_rx(fido_dev_t *dev, const fido_blob_t *ecdh, fido_blob_t *token, - int ms) + int *ms) { fido_blob_t *aes_token = NULL; unsigned char reply[FIDO_MAXMSG]; int reply_len; int r; if ((aes_token = fido_blob_new()) == NULL) { r = FIDO_ERR_INTERNAL; goto fail; } if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); r = FIDO_ERR_RX; goto fail; } if ((r = cbor_parse_reply(reply, (size_t)reply_len, aes_token, parse_uv_token)) != FIDO_OK) { fido_log_debug("%s: parse_uv_token", __func__); goto fail; } if (aes256_cbc_dec(dev, ecdh, aes_token, token) < 0) { fido_log_debug("%s: aes256_cbc_dec", __func__); r = FIDO_ERR_RX; goto fail; } r = FIDO_OK; fail: fido_blob_free(&aes_token); return (r); } static int uv_token_wait(fido_dev_t *dev, uint8_t cmd, const char *pin, const fido_blob_t *ecdh, const es256_pk_t *pk, const char *rpid, - fido_blob_t *token, int ms) + fido_blob_t *token, int *ms) { int r; if (ecdh == NULL || pk == NULL) return (FIDO_ERR_INVALID_ARGUMENT); if (fido_dev_supports_permissions(dev)) - r = ctap21_uv_token_tx(dev, pin, ecdh, pk, cmd, rpid); + r = ctap21_uv_token_tx(dev, pin, ecdh, pk, cmd, rpid, ms); else - r = ctap20_uv_token_tx(dev, pin, ecdh, pk); + r = ctap20_uv_token_tx(dev, pin, ecdh, pk, ms); if (r != FIDO_OK) return (r); return (uv_token_rx(dev, ecdh, token, ms)); } int fido_dev_get_uv_token(fido_dev_t *dev, uint8_t cmd, const char *pin, const fido_blob_t *ecdh, const es256_pk_t *pk, const char *rpid, - fido_blob_t *token) + fido_blob_t *token, int *ms) { - return (uv_token_wait(dev, cmd, pin, ecdh, pk, rpid, token, -1)); + return (uv_token_wait(dev, cmd, pin, ecdh, pk, rpid, token, ms)); } static int -fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin) +fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin, + int *ms) { fido_blob_t f; fido_blob_t *ppine = NULL; fido_blob_t *ecdh = NULL; fido_blob_t *opin = NULL; fido_blob_t *opinhe = NULL; cbor_item_t *argv[6]; es256_pk_t *pk = NULL; int r; memset(&f, 0, sizeof(f)); memset(argv, 0, sizeof(argv)); if ((opin = fido_blob_new()) == NULL || fido_blob_set(opin, (const unsigned char *)oldpin, strlen(oldpin)) < 0) { fido_log_debug("%s: fido_blob_set", __func__); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } - if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { + if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } /* pad and encrypt new pin */ if ((r = pin_pad64_enc(dev, ecdh, pin, &ppine)) != FIDO_OK) { fido_log_debug("%s: pin_pad64_enc", __func__); goto fail; } /* hash and encrypt old pin */ if ((r = pin_sha256_enc(dev, ecdh, opin, &opinhe)) != FIDO_OK) { fido_log_debug("%s: pin_sha256_enc", __func__); goto fail; } if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL || (argv[1] = cbor_build_uint8(4)) == NULL || (argv[2] = es256_pk_encode(pk, 1)) == NULL || (argv[3] = cbor_encode_change_pin_auth(dev, ecdh, ppine, opinhe)) == NULL || (argv[4] = fido_blob_encode(ppine)) == NULL || (argv[5] = fido_blob_encode(opinhe)) == NULL) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), - &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { + &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); es256_pk_free(&pk); fido_blob_free(&ppine); fido_blob_free(&ecdh); fido_blob_free(&opin); fido_blob_free(&opinhe); free(f.ptr); return (r); } static int -fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin) +fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin, int *ms) { fido_blob_t f; fido_blob_t *ppine = NULL; fido_blob_t *ecdh = NULL; cbor_item_t *argv[5]; es256_pk_t *pk = NULL; int r; memset(&f, 0, sizeof(f)); memset(argv, 0, sizeof(argv)); - if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { + if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } if ((r = pin_pad64_enc(dev, ecdh, pin, &ppine)) != FIDO_OK) { fido_log_debug("%s: pin_pad64_enc", __func__); goto fail; } if ((argv[0] = cbor_encode_pin_opt(dev)) == NULL || (argv[1] = cbor_build_uint8(3)) == NULL || (argv[2] = es256_pk_encode(pk, 1)) == NULL || (argv[3] = cbor_encode_pin_auth(dev, ecdh, ppine)) == NULL || (argv[4] = fido_blob_encode(ppine)) == NULL) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), - &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { + &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); es256_pk_free(&pk); fido_blob_free(&ppine); fido_blob_free(&ecdh); free(f.ptr); return (r); } static int fido_dev_set_pin_wait(fido_dev_t *dev, const char *pin, const char *oldpin, - int ms) + int *ms) { int r; if (oldpin != NULL) { - if ((r = fido_dev_change_pin_tx(dev, pin, oldpin)) != FIDO_OK) { + if ((r = fido_dev_change_pin_tx(dev, pin, oldpin, + ms)) != FIDO_OK) { fido_log_debug("%s: fido_dev_change_pin_tx", __func__); return (r); } } else { - if ((r = fido_dev_set_pin_tx(dev, pin)) != FIDO_OK) { + if ((r = fido_dev_set_pin_tx(dev, pin, ms)) != FIDO_OK) { fido_log_debug("%s: fido_dev_set_pin_tx", __func__); return (r); } } if ((r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { fido_log_debug("%s: fido_rx_cbor_status", __func__); return (r); } if (dev->flags & FIDO_DEV_PIN_UNSET) { dev->flags &= ~FIDO_DEV_PIN_UNSET; dev->flags |= FIDO_DEV_PIN_SET; } return (FIDO_OK); } int fido_dev_set_pin(fido_dev_t *dev, const char *pin, const char *oldpin) { - return (fido_dev_set_pin_wait(dev, pin, oldpin, -1)); + int ms = dev->timeout_ms; + + return (fido_dev_set_pin_wait(dev, pin, oldpin, &ms)); } static int parse_retry_count(const uint8_t keyval, const cbor_item_t *key, const cbor_item_t *val, void *arg) { int *retries = arg; uint64_t n; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8 || cbor_get_uint8(key) != keyval) { fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ } if (cbor_decode_uint64(val, &n) < 0 || n > INT_MAX) { fido_log_debug("%s: cbor_decode_uint64", __func__); return (-1); } *retries = (int)n; return (0); } static int parse_pin_retry_count(const cbor_item_t *key, const cbor_item_t *val, void *arg) { return (parse_retry_count(3, key, val, arg)); } static int parse_uv_retry_count(const cbor_item_t *key, const cbor_item_t *val, void *arg) { return (parse_retry_count(5, key, val, arg)); } static int -fido_dev_get_retry_count_tx(fido_dev_t *dev, uint8_t subcmd) +fido_dev_get_retry_count_tx(fido_dev_t *dev, uint8_t subcmd, int *ms) { fido_blob_t f; cbor_item_t *argv[2]; int r; memset(&f, 0, sizeof(f)); memset(argv, 0, sizeof(argv)); if ((argv[0] = cbor_build_uint8(1)) == NULL || (argv[1] = cbor_build_uint8(subcmd)) == NULL) { r = FIDO_ERR_INTERNAL; goto fail; } if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv), - &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { + &f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: cbor_vector_free(argv, nitems(argv)); free(f.ptr); return (r); } static int -fido_dev_get_pin_retry_count_rx(fido_dev_t *dev, int *retries, int ms) +fido_dev_get_pin_retry_count_rx(fido_dev_t *dev, int *retries, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; int r; *retries = 0; if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, retries, parse_pin_retry_count)) != FIDO_OK) { fido_log_debug("%s: parse_pin_retry_count", __func__); return (r); } return (FIDO_OK); } static int -fido_dev_get_pin_retry_count_wait(fido_dev_t *dev, int *retries, int ms) +fido_dev_get_pin_retry_count_wait(fido_dev_t *dev, int *retries, int *ms) { int r; - if ((r = fido_dev_get_retry_count_tx(dev, 1)) != FIDO_OK || + if ((r = fido_dev_get_retry_count_tx(dev, 1, ms)) != FIDO_OK || (r = fido_dev_get_pin_retry_count_rx(dev, retries, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_dev_get_retry_count(fido_dev_t *dev, int *retries) { - return (fido_dev_get_pin_retry_count_wait(dev, retries, -1)); + int ms = dev->timeout_ms; + + return (fido_dev_get_pin_retry_count_wait(dev, retries, &ms)); } static int -fido_dev_get_uv_retry_count_rx(fido_dev_t *dev, int *retries, int ms) +fido_dev_get_uv_retry_count_rx(fido_dev_t *dev, int *retries, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; int r; *retries = 0; if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_ERR_RX); } if ((r = cbor_parse_reply(reply, (size_t)reply_len, retries, parse_uv_retry_count)) != FIDO_OK) { fido_log_debug("%s: parse_uv_retry_count", __func__); return (r); } return (FIDO_OK); } static int -fido_dev_get_uv_retry_count_wait(fido_dev_t *dev, int *retries, int ms) +fido_dev_get_uv_retry_count_wait(fido_dev_t *dev, int *retries, int *ms) { int r; - if ((r = fido_dev_get_retry_count_tx(dev, 7)) != FIDO_OK || + if ((r = fido_dev_get_retry_count_tx(dev, 7, ms)) != FIDO_OK || (r = fido_dev_get_uv_retry_count_rx(dev, retries, ms)) != FIDO_OK) return (r); return (FIDO_OK); } int fido_dev_get_uv_retry_count(fido_dev_t *dev, int *retries) { - return (fido_dev_get_uv_retry_count_wait(dev, retries, -1)); + int ms = dev->timeout_ms; + + return (fido_dev_get_uv_retry_count_wait(dev, retries, &ms)); } int cbor_add_uv_params(fido_dev_t *dev, uint8_t cmd, const fido_blob_t *hmac_data, const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, - const char *rpid, cbor_item_t **auth, cbor_item_t **opt) + const char *rpid, cbor_item_t **auth, cbor_item_t **opt, int *ms) { fido_blob_t *token = NULL; int r; if ((token = fido_blob_new()) == NULL) { r = FIDO_ERR_INTERNAL; goto fail; } if ((r = fido_dev_get_uv_token(dev, cmd, pin, ecdh, pk, rpid, - token)) != FIDO_OK) { + token, ms)) != FIDO_OK) { fido_log_debug("%s: fido_dev_get_uv_token", __func__); goto fail; } if ((*auth = cbor_encode_pin_auth(dev, token, hmac_data)) == NULL || (*opt = cbor_encode_pin_opt(dev)) == NULL) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; } r = FIDO_OK; fail: fido_blob_free(&token); return (r); } diff --git a/contrib/libfido2/src/reset.c b/contrib/libfido2/src/reset.c index 11380cea0904..c5fe6dfe7ac1 100644 --- a/contrib/libfido2/src/reset.c +++ b/contrib/libfido2/src/reset.c @@ -1,43 +1,45 @@ /* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include "fido.h" static int -fido_dev_reset_tx(fido_dev_t *dev) +fido_dev_reset_tx(fido_dev_t *dev, int *ms) { const unsigned char cbor[] = { CTAP_CBOR_RESET }; - if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor)) < 0) { + if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor), ms) < 0) { fido_log_debug("%s: fido_tx", __func__); return (FIDO_ERR_TX); } return (FIDO_OK); } static int -fido_dev_reset_wait(fido_dev_t *dev, int ms) +fido_dev_reset_wait(fido_dev_t *dev, int *ms) { int r; - if ((r = fido_dev_reset_tx(dev)) != FIDO_OK || + if ((r = fido_dev_reset_tx(dev, ms)) != FIDO_OK || (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) return (r); if (dev->flags & FIDO_DEV_PIN_SET) { dev->flags &= ~FIDO_DEV_PIN_SET; dev->flags |= FIDO_DEV_PIN_UNSET; } return (FIDO_OK); } int fido_dev_reset(fido_dev_t *dev) { - return (fido_dev_reset_wait(dev, -1)); + int ms = dev->timeout_ms; + + return (fido_dev_reset_wait(dev, &ms)); } diff --git a/contrib/libfido2/src/rs1.c b/contrib/libfido2/src/rs1.c new file mode 100644 index 000000000000..37aa9f073bed --- /dev/null +++ b/contrib/libfido2/src/rs1.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2021 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + +#include +#include + +#include "fido.h" + +#if defined(LIBRESSL_VERSION_NUMBER) +static EVP_MD * +rs1_get_EVP_MD(void) +{ + const EVP_MD *from; + EVP_MD *to = NULL; + + if ((from = EVP_sha1()) != NULL && (to = malloc(sizeof(*to))) != NULL) + memcpy(to, from, sizeof(*to)); + + return (to); +} + +static void +rs1_free_EVP_MD(EVP_MD *md) +{ + freezero(md, sizeof(*md)); +} +#elif OPENSSL_VERSION_NUMBER >= 0x30000000 +static EVP_MD * +rs1_get_EVP_MD(void) +{ + return (EVP_MD_fetch(NULL, "SHA-1", NULL)); +} + +static void +rs1_free_EVP_MD(EVP_MD *md) +{ + EVP_MD_free(md); +} +#else +static EVP_MD * +rs1_get_EVP_MD(void) +{ + const EVP_MD *md; + + if ((md = EVP_sha1()) == NULL) + return (NULL); + + return (EVP_MD_meth_dup(md)); +} + +static void +rs1_free_EVP_MD(EVP_MD *md) +{ + EVP_MD_meth_free(md); +} +#endif /* LIBRESSL_VERSION_NUMBER */ + +int +rs1_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey, + const fido_blob_t *sig) +{ + EVP_PKEY_CTX *pctx = NULL; + EVP_MD *md = NULL; + int ok = -1; + + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) { + fido_log_debug("%s: EVP_PKEY_base_id", __func__); + goto fail; + } + + if ((md = rs1_get_EVP_MD()) == NULL) { + fido_log_debug("%s: rs1_get_EVP_MD", __func__); + goto fail; + } + + if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL || + EVP_PKEY_verify_init(pctx) != 1 || + EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) != 1 || + EVP_PKEY_CTX_set_signature_md(pctx, md) != 1) { + fido_log_debug("%s: EVP_PKEY_CTX", __func__); + goto fail; + } + + if (EVP_PKEY_verify(pctx, sig->ptr, sig->len, dgst->ptr, + dgst->len) != 1) { + fido_log_debug("%s: EVP_PKEY_verify", __func__); + goto fail; + } + + ok = 0; +fail: + EVP_PKEY_CTX_free(pctx); + rs1_free_EVP_MD(md); + + return (ok); +} diff --git a/contrib/libfido2/src/rs256.c b/contrib/libfido2/src/rs256.c index c6d87a3ea22c..29fcedbdee20 100644 --- a/contrib/libfido2/src/rs256.c +++ b/contrib/libfido2/src/rs256.c @@ -1,200 +1,295 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include "fido.h" #include "fido/rs256.h" -#if OPENSSL_VERSION_NUMBER < 0x10100000L -static int -RSA_bits(const RSA *r) +#if defined(LIBRESSL_VERSION_NUMBER) +static EVP_MD * +rs256_get_EVP_MD(void) { - return (BN_num_bits(r->n)); + const EVP_MD *from; + EVP_MD *to = NULL; + + if ((from = EVP_sha256()) != NULL && (to = malloc(sizeof(*to))) != NULL) + memcpy(to, from, sizeof(*to)); + + return (to); } -static int -RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) +static void +rs256_free_EVP_MD(EVP_MD *md) +{ + freezero(md, sizeof(*md)); +} +#elif OPENSSL_VERSION_NUMBER >= 0x30000000 +static EVP_MD * +rs256_get_EVP_MD(void) { - r->n = n; - r->e = e; - r->d = d; + return (EVP_MD_fetch(NULL, "SHA2-256", NULL)); +} + +static void +rs256_free_EVP_MD(EVP_MD *md) +{ + EVP_MD_free(md); +} +#else +static EVP_MD * +rs256_get_EVP_MD(void) +{ + const EVP_MD *md; + + if ((md = EVP_sha256()) == NULL) + return (NULL); - return (1); + return (EVP_MD_meth_dup(md)); } static void -RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) +rs256_free_EVP_MD(EVP_MD *md) { - *n = r->n; - *e = r->e; - *d = r->d; + EVP_MD_meth_free(md); } -#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */ +#endif /* LIBRESSL_VERSION_NUMBER */ static int decode_bignum(const cbor_item_t *item, void *ptr, size_t len) { if (cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false || cbor_bytestring_length(item) != len) { fido_log_debug("%s: cbor type", __func__); return (-1); } memcpy(ptr, cbor_bytestring_handle(item), len); return (0); } static int decode_rsa_pubkey(const cbor_item_t *key, const cbor_item_t *val, void *arg) { rs256_pk_t *k = arg; if (cbor_isa_negint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) return (0); /* ignore */ switch (cbor_get_uint8(key)) { case 0: /* modulus */ return (decode_bignum(val, &k->n, sizeof(k->n))); case 1: /* public exponent */ return (decode_bignum(val, &k->e, sizeof(k->e))); } return (0); /* ignore */ } int rs256_pk_decode(const cbor_item_t *item, rs256_pk_t *k) { if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || cbor_map_iter(item, k, decode_rsa_pubkey) < 0) { fido_log_debug("%s: cbor type", __func__); return (-1); } return (0); } rs256_pk_t * rs256_pk_new(void) { return (calloc(1, sizeof(rs256_pk_t))); } void rs256_pk_free(rs256_pk_t **pkp) { rs256_pk_t *pk; if (pkp == NULL || (pk = *pkp) == NULL) return; freezero(pk, sizeof(*pk)); *pkp = NULL; } int rs256_pk_from_ptr(rs256_pk_t *pk, const void *ptr, size_t len) { if (len < sizeof(*pk)) return (FIDO_ERR_INVALID_ARGUMENT); memcpy(pk, ptr, sizeof(*pk)); return (FIDO_OK); } EVP_PKEY * rs256_pk_to_EVP_PKEY(const rs256_pk_t *k) { RSA *rsa = NULL; EVP_PKEY *pkey = NULL; BIGNUM *n = NULL; BIGNUM *e = NULL; int ok = -1; if ((n = BN_new()) == NULL || (e = BN_new()) == NULL) goto fail; if (BN_bin2bn(k->n, sizeof(k->n), n) == NULL || BN_bin2bn(k->e, sizeof(k->e), e) == NULL) { fido_log_debug("%s: BN_bin2bn", __func__); goto fail; } if ((rsa = RSA_new()) == NULL || RSA_set0_key(rsa, n, e, NULL) == 0) { fido_log_debug("%s: RSA_set0_key", __func__); goto fail; } /* at this point, n and e belong to rsa */ n = NULL; e = NULL; if ((pkey = EVP_PKEY_new()) == NULL || EVP_PKEY_assign_RSA(pkey, rsa) == 0) { fido_log_debug("%s: EVP_PKEY_assign_RSA", __func__); goto fail; } rsa = NULL; /* at this point, rsa belongs to evp */ ok = 0; fail: if (n != NULL) BN_free(n); if (e != NULL) BN_free(e); if (rsa != NULL) RSA_free(rsa); if (ok < 0 && pkey != NULL) { EVP_PKEY_free(pkey); pkey = NULL; } return (pkey); } int rs256_pk_from_RSA(rs256_pk_t *pk, const RSA *rsa) { const BIGNUM *n = NULL; const BIGNUM *e = NULL; const BIGNUM *d = NULL; int k; if (RSA_bits(rsa) != 2048) { fido_log_debug("%s: invalid key length", __func__); return (FIDO_ERR_INVALID_ARGUMENT); } RSA_get0_key(rsa, &n, &e, &d); if (n == NULL || e == NULL) { fido_log_debug("%s: RSA_get0_key", __func__); return (FIDO_ERR_INTERNAL); } if ((k = BN_num_bytes(n)) < 0 || (size_t)k > sizeof(pk->n) || (k = BN_num_bytes(e)) < 0 || (size_t)k > sizeof(pk->e)) { fido_log_debug("%s: invalid key", __func__); return (FIDO_ERR_INTERNAL); } if ((k = BN_bn2bin(n, pk->n)) < 0 || (size_t)k > sizeof(pk->n) || (k = BN_bn2bin(e, pk->e)) < 0 || (size_t)k > sizeof(pk->e)) { fido_log_debug("%s: BN_bn2bin", __func__); return (FIDO_ERR_INTERNAL); } return (FIDO_OK); } + +int +rs256_pk_from_EVP_PKEY(rs256_pk_t *pk, const EVP_PKEY *pkey) +{ + RSA *rsa; + + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA || + (rsa = EVP_PKEY_get0(pkey)) == NULL) + return (FIDO_ERR_INVALID_ARGUMENT); + + return (rs256_pk_from_RSA(pk, rsa)); +} + +int +rs256_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey, + const fido_blob_t *sig) +{ + EVP_PKEY_CTX *pctx = NULL; + EVP_MD *md = NULL; + int ok = -1; + + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) { + fido_log_debug("%s: EVP_PKEY_base_id", __func__); + goto fail; + } + + if ((md = rs256_get_EVP_MD()) == NULL) { + fido_log_debug("%s: rs256_get_EVP_MD", __func__); + goto fail; + } + + if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL || + EVP_PKEY_verify_init(pctx) != 1 || + EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) != 1 || + EVP_PKEY_CTX_set_signature_md(pctx, md) != 1) { + fido_log_debug("%s: EVP_PKEY_CTX", __func__); + goto fail; + } + + if (EVP_PKEY_verify(pctx, sig->ptr, sig->len, dgst->ptr, + dgst->len) != 1) { + fido_log_debug("%s: EVP_PKEY_verify", __func__); + goto fail; + } + + ok = 0; +fail: + EVP_PKEY_CTX_free(pctx); + rs256_free_EVP_MD(md); + + return (ok); +} + +int +rs256_pk_verify_sig(const fido_blob_t *dgst, const rs256_pk_t *pk, + const fido_blob_t *sig) +{ + EVP_PKEY *pkey; + int ok = -1; + + if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL || + rs256_verify_sig(dgst, pkey, sig) < 0) { + fido_log_debug("%s: rs256_verify_sig", __func__); + goto fail; + } + + ok = 0; +fail: + EVP_PKEY_free(pkey); + + return (ok); +} diff --git a/contrib/libfido2/src/time.c b/contrib/libfido2/src/time.c new file mode 100644 index 000000000000..b82b61874498 --- /dev/null +++ b/contrib/libfido2/src/time.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2021 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + +#include +#include "fido.h" + +static int +timespec_to_ms(const struct timespec *ts) +{ + int64_t x, y; + + if (ts->tv_sec < 0 || ts->tv_nsec < 0 || + ts->tv_nsec >= 1000000000LL) + return -1; + + if ((uint64_t)ts->tv_sec >= INT64_MAX / 1000LL) + return -1; + + x = ts->tv_sec * 1000LL; + y = ts->tv_nsec / 1000000LL; + + if (INT64_MAX - x < y || x + y > INT_MAX) + return -1; + + return (int)(x + y); +} + +int +fido_time_now(struct timespec *ts_now) +{ + if (clock_gettime(CLOCK_MONOTONIC, ts_now) != 0) { + fido_log_error(errno, "%s: clock_gettime", __func__); + return -1; + } + + return 0; +} + +int +fido_time_delta(const struct timespec *ts_start, int *ms_remain) +{ + struct timespec ts_end, ts_delta; + int ms; + + if (*ms_remain < 0) + return 0; + + if (clock_gettime(CLOCK_MONOTONIC, &ts_end) != 0) { + fido_log_error(errno, "%s: clock_gettime", __func__); + return -1; + } + + if (timespeccmp(&ts_end, ts_start, <)) { + fido_log_debug("%s: timespeccmp", __func__); + return -1; + } + + timespecsub(&ts_end, ts_start, &ts_delta); + + if ((ms = timespec_to_ms(&ts_delta)) < 0) { + fido_log_debug("%s: timespec_to_ms", __func__); + return -1; + } + + if (ms > *ms_remain) + ms = *ms_remain; + + *ms_remain -= ms; + + return 0; +} diff --git a/contrib/libfido2/src/tpm.c b/contrib/libfido2/src/tpm.c new file mode 100644 index 000000000000..74620a5e4865 --- /dev/null +++ b/contrib/libfido2/src/tpm.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2021 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + +/* + * Trusted Platform Module (TPM) 2.0 attestation support. Documentation + * references are relative to revision 01.38 of the TPM 2.0 specification. + */ + +#include + +#include "packed.h" +#include "fido.h" + +/* Part 1, 4.89: TPM_GENERATED_VALUE */ +#define TPM_MAGIC 0xff544347 + +/* Part 2, 6.3: TPM_ALG_ID */ +#define TPM_ALG_RSA 0x0001 +#define TPM_ALG_SHA256 0x000b +#define TPM_ALG_NULL 0x0010 + +/* Part 2, 6.9: TPM_ST_ATTEST_CERTIFY */ +#define TPM_ST_CERTIFY 0x8017 + +/* Part 2, 8.3: TPMA_OBJECT */ +#define TPMA_RESERVED 0xfff8f309 /* reserved bits; must be zero */ +#define TPMA_FIXED 0x00000002 /* object has fixed hierarchy */ +#define TPMA_CLEAR 0x00000004 /* object persists */ +#define TPMA_FIXED_P 0x00000010 /* object has fixed parent */ +#define TPMA_SENSITIVE 0x00000020 /* data originates within tpm */ +#define TPMA_SIGN 0x00020000 /* object may sign */ + +/* Part 2, 10.4.2: TPM2B_DIGEST */ +PACKED_TYPE(tpm_sha256_digest_t, +struct tpm_sha256_digest { + uint16_t size; /* sizeof(body) */ + uint8_t body[32]; +}) + +/* Part 2, 10.4.3: TPM2B_DATA */ +PACKED_TYPE(tpm_sha1_data_t, +struct tpm_sha1_data { + uint16_t size; /* sizeof(body */ + uint8_t body[20]; +}) + +/* Part 2, 10.5.3: TPM2B_NAME */ +PACKED_TYPE(tpm_sha256_name_t, +struct tpm_sha256_name { + uint16_t size; /* sizeof(alg) + sizeof(body) */ + uint16_t alg; /* TPM_ALG_SHA256 */ + uint8_t body[32]; +}) + +/* Part 2, 10.11.1: TPMS_CLOCK_INFO */ +PACKED_TYPE(tpm_clock_info_t, +struct tpm_clock_info { + uint64_t timestamp_ms; + uint32_t reset_count; /* obfuscated by tpm */ + uint32_t restart_count; /* obfuscated by tpm */ + uint8_t safe; /* 1 if timestamp_ms is current */ +}) + +/* Part 2, 10.12.8 TPMS_ATTEST */ +PACKED_TYPE(tpm_sha1_attest_t, +struct tpm_sha1_attest { + uint32_t magic; /* TPM_MAGIC */ + uint16_t type; /* TPM_ST_ATTEST_CERTIFY */ + tpm_sha256_name_t signer; /* full tpm path of signing key */ + tpm_sha1_data_t data; /* signed sha1 */ + tpm_clock_info_t clock; + uint64_t fwversion; /* obfuscated by tpm */ + tpm_sha256_name_t name; /* sha256 of tpm_rsa2048_pubarea_t */ + tpm_sha256_name_t qual_name; /* full tpm path of attested key */ +}) + +/* Part 2, 11.2.4.5: TPM2B_PUBLIC_KEY_RSA */ +PACKED_TYPE(tpm_rsa2048_key_t, +struct tpm_rsa2048_key { + uint16_t size; /* sizeof(body) */ + uint8_t body[256]; +}) + +/* Part 2, 12.2.3.5: TPMS_RSA_PARMS */ +PACKED_TYPE(tpm_rsa2048_param_t, +struct tpm_rsa2048_param { + uint16_t symmetric; /* TPM_ALG_NULL */ + uint16_t scheme; /* TPM_ALG_NULL */ + uint16_t keybits; /* 2048 */ + uint32_t exponent; /* zero (meaning 2^16 + 1) */ +}) + +/* Part 2, 12.2.4: TPMT_PUBLIC */ +PACKED_TYPE(tpm_rsa2048_pubarea_t, +struct tpm_rsa2048_pubarea { + uint16_t alg; /* TPM_ALG_RSA */ + uint16_t hash; /* TPM_ALG_SHA256 */ + uint32_t attr; + tpm_sha256_digest_t policy; /* must be present? */ + tpm_rsa2048_param_t param; + tpm_rsa2048_key_t key; +}) + +static int +get_signed_sha1(tpm_sha1_data_t *dgst, const fido_blob_t *authdata, + const fido_blob_t *clientdata) +{ + const EVP_MD *md = NULL; + EVP_MD_CTX *ctx = NULL; + int ok = -1; + + if ((dgst->size = sizeof(dgst->body)) != SHA_DIGEST_LENGTH || + (md = EVP_sha1()) == NULL || + (ctx = EVP_MD_CTX_new()) == NULL || + EVP_DigestInit_ex(ctx, md, NULL) != 1 || + EVP_DigestUpdate(ctx, authdata->ptr, authdata->len) != 1 || + EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 || + EVP_DigestFinal_ex(ctx, dgst->body, NULL) != 1) { + fido_log_debug("%s: sha1", __func__); + goto fail; + } + + ok = 0; +fail: + EVP_MD_CTX_free(ctx); + + return (ok); +} + +static int +get_signed_name(tpm_sha256_name_t *name, const fido_blob_t *pubarea) +{ + name->alg = TPM_ALG_SHA256; + name->size = sizeof(name->alg) + sizeof(name->body); + if (sizeof(name->body) != SHA256_DIGEST_LENGTH || + SHA256(pubarea->ptr, pubarea->len, name->body) != name->body) { + fido_log_debug("%s: sha256", __func__); + return -1; + } + + return 0; +} + +static void +bswap_rsa2048_pubarea(tpm_rsa2048_pubarea_t *x) +{ + x->alg = htobe16(x->alg); + x->hash = htobe16(x->hash); + x->attr = htobe32(x->attr); + x->policy.size = htobe16(x->policy.size); + x->param.symmetric = htobe16(x->param.symmetric); + x->param.scheme = htobe16(x->param.scheme); + x->param.keybits = htobe16(x->param.keybits); + x->key.size = htobe16(x->key.size); +} + +static void +bswap_sha1_certinfo(tpm_sha1_attest_t *x) +{ + x->magic = htobe32(x->magic); + x->type = htobe16(x->type); + x->signer.size = htobe16(x->signer.size); + x->data.size = htobe16(x->data.size); + x->name.alg = htobe16(x->name.alg); + x->name.size = htobe16(x->name.size); +} + +static int +check_rsa2048_pubarea(const fido_blob_t *buf, const rs256_pk_t *pk) +{ + const tpm_rsa2048_pubarea_t *actual; + tpm_rsa2048_pubarea_t expected; + int ok; + + if (buf->len != sizeof(*actual)) { + fido_log_debug("%s: buf->len=%zu", __func__, buf->len); + return -1; + } + actual = (const void *)buf->ptr; + + memset(&expected, 0, sizeof(expected)); + expected.alg = TPM_ALG_RSA; + expected.hash = TPM_ALG_SHA256; + expected.attr = be32toh(actual->attr); + expected.attr &= ~(TPMA_RESERVED|TPMA_CLEAR); + expected.attr |= (TPMA_FIXED|TPMA_FIXED_P|TPMA_SENSITIVE|TPMA_SIGN); + expected.policy = actual->policy; + expected.policy.size = sizeof(expected.policy.body); + expected.param.symmetric = TPM_ALG_NULL; + expected.param.scheme = TPM_ALG_NULL; + expected.param.keybits = 2048; + expected.param.exponent = 0; /* meaning 2^16+1 */ + expected.key.size = sizeof(expected.key.body); + memcpy(&expected.key.body, &pk->n, sizeof(expected.key.body)); + bswap_rsa2048_pubarea(&expected); + + ok = timingsafe_bcmp(&expected, actual, sizeof(expected)); + explicit_bzero(&expected, sizeof(expected)); + + return ok != 0 ? -1 : 0; +} + +static int +check_sha1_certinfo(const fido_blob_t *buf, const fido_blob_t *clientdata_hash, + const fido_blob_t *authdata_raw, const fido_blob_t *pubarea) +{ + const tpm_sha1_attest_t *actual; + tpm_sha1_attest_t expected; + tpm_sha1_data_t signed_data; + tpm_sha256_name_t signed_name; + int ok = -1; + + memset(&signed_data, 0, sizeof(signed_data)); + memset(&signed_name, 0, sizeof(signed_name)); + + if (get_signed_sha1(&signed_data, authdata_raw, clientdata_hash) < 0 || + get_signed_name(&signed_name, pubarea) < 0) { + fido_log_debug("%s: get_signed_sha1/name", __func__); + goto fail; + } + if (buf->len != sizeof(*actual)) { + fido_log_debug("%s: buf->len=%zu", __func__, buf->len); + goto fail; + } + actual = (const void *)buf->ptr; + + memset(&expected, 0, sizeof(expected)); + expected.magic = TPM_MAGIC; + expected.type = TPM_ST_CERTIFY; + expected.signer = actual->signer; + expected.signer.size = sizeof(expected.signer.alg) + + sizeof(expected.signer.body); + expected.data = signed_data; + expected.clock = actual->clock; + expected.clock.safe = 1; + expected.fwversion = actual->fwversion; + expected.name = signed_name; + expected.qual_name = actual->qual_name; + bswap_sha1_certinfo(&expected); + + ok = timingsafe_bcmp(&expected, actual, sizeof(expected)); +fail: + explicit_bzero(&expected, sizeof(expected)); + explicit_bzero(&signed_data, sizeof(signed_data)); + explicit_bzero(&signed_name, sizeof(signed_name)); + + return ok != 0 ? -1 : 0; +} + +int +fido_get_signed_hash_tpm(fido_blob_t *dgst, const fido_blob_t *clientdata_hash, + const fido_blob_t *authdata_raw, const fido_attstmt_t *attstmt, + const fido_attcred_t *attcred) +{ + const fido_blob_t *pubarea = &attstmt->pubarea; + const fido_blob_t *certinfo = &attstmt->certinfo; + + if (attstmt->alg != COSE_RS1 || attcred->type != COSE_RS256) { + fido_log_debug("%s: unsupported alg %d, type %d", __func__, + attstmt->alg, attcred->type); + return -1; + } + + if (check_rsa2048_pubarea(pubarea, &attcred->pubkey.rs256) < 0) { + fido_log_debug("%s: check_rsa2048_pubarea", __func__); + return -1; + } + + if (check_sha1_certinfo(certinfo, clientdata_hash, authdata_raw, + pubarea) < 0) { + fido_log_debug("%s: check_sha1_certinfo", __func__); + return -1; + } + + if (dgst->len < SHA_DIGEST_LENGTH || + SHA1(certinfo->ptr, certinfo->len, dgst->ptr) != dgst->ptr) { + fido_log_debug("%s: sha1", __func__); + return -1; + } + dgst->len = SHA_DIGEST_LENGTH; + + return 0; +} diff --git a/contrib/libfido2/src/types.c b/contrib/libfido2/src/types.c new file mode 100644 index 000000000000..54c0ca582865 --- /dev/null +++ b/contrib/libfido2/src/types.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + +#include "fido.h" + +void +fido_str_array_free(fido_str_array_t *sa) +{ + for (size_t i = 0; i < sa->len; i++) + free(sa->ptr[i]); + + free(sa->ptr); + sa->ptr = NULL; + sa->len = 0; +} + +void +fido_opt_array_free(fido_opt_array_t *oa) +{ + for (size_t i = 0; i < oa->len; i++) + free(oa->name[i]); + + free(oa->name); + free(oa->value); + oa->name = NULL; + oa->value = NULL; +} + +void +fido_byte_array_free(fido_byte_array_t *ba) +{ + free(ba->ptr); + + ba->ptr = NULL; + ba->len = 0; +} + +void +fido_algo_free(fido_algo_t *a) +{ + free(a->type); + a->type = NULL; + a->cose = 0; +} + +void +fido_algo_array_free(fido_algo_array_t *aa) +{ + for (size_t i = 0; i < aa->len; i++) + fido_algo_free(&aa->ptr[i]); + + free(aa->ptr); + aa->ptr = NULL; + aa->len = 0; +} + +int +fido_str_array_pack(fido_str_array_t *sa, const char * const *v, size_t n) +{ + if ((sa->ptr = calloc(n, sizeof(char *))) == NULL) { + fido_log_debug("%s: calloc", __func__); + return -1; + } + for (size_t i = 0; i < n; i++) { + if ((sa->ptr[i] = strdup(v[i])) == NULL) { + fido_log_debug("%s: strdup", __func__); + return -1; + } + sa->len++; + } + + return 0; +} diff --git a/contrib/libfido2/src/u2f.c b/contrib/libfido2/src/u2f.c index c5fbe0cfbb6c..6ebfcc7bb848 100644 --- a/contrib/libfido2/src/u2f.c +++ b/contrib/libfido2/src/u2f.c @@ -1,820 +1,910 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #ifdef HAVE_UNISTD_H #include #endif +#include #include "fido.h" #include "fido/es256.h" +#define U2F_PACE_MS (100) + #if defined(_MSC_VER) static int usleep(unsigned int usec) { Sleep(usec / 1000); return (0); } #endif +static int +delay_ms(unsigned int ms, int *ms_remain) +{ + if (*ms_remain > -1 && (unsigned int)*ms_remain < ms) + ms = (unsigned int)*ms_remain; + + if (ms > UINT_MAX / 1000) { + fido_log_debug("%s: ms=%u", __func__, ms); + return (-1); + } + + if (usleep(ms * 1000) < 0) { + fido_log_error(errno, "%s: usleep", __func__); + return (-1); + } + + if (*ms_remain > -1) + *ms_remain -= (int)ms; + + return (0); +} + static int sig_get(fido_blob_t *sig, const unsigned char **buf, size_t *len) { sig->len = *len; /* consume the whole buffer */ if ((sig->ptr = calloc(1, sig->len)) == NULL || fido_buf_read(buf, len, sig->ptr, sig->len) < 0) { fido_log_debug("%s: fido_buf_read", __func__); fido_blob_reset(sig); return (-1); } return (0); } static int x5c_get(fido_blob_t *x5c, const unsigned char **buf, size_t *len) { X509 *cert = NULL; int ok = -1; if (*len > LONG_MAX) { fido_log_debug("%s: invalid len %zu", __func__, *len); goto fail; } /* find out the certificate's length */ const unsigned char *end = *buf; if ((cert = d2i_X509(NULL, &end, (long)*len)) == NULL || end <= *buf || (x5c->len = (size_t)(end - *buf)) >= *len) { fido_log_debug("%s: d2i_X509", __func__); goto fail; } /* read accordingly */ if ((x5c->ptr = calloc(1, x5c->len)) == NULL || fido_buf_read(buf, len, x5c->ptr, x5c->len) < 0) { fido_log_debug("%s: fido_buf_read", __func__); goto fail; } ok = 0; fail: if (cert != NULL) X509_free(cert); if (ok < 0) fido_blob_reset(x5c); return (ok); } static int authdata_fake(const char *rp_id, uint8_t flags, uint32_t sigcount, fido_blob_t *fake_cbor_ad) { fido_authdata_t ad; cbor_item_t *item = NULL; size_t alloc_len; memset(&ad, 0, sizeof(ad)); if (SHA256((const void *)rp_id, strlen(rp_id), ad.rp_id_hash) != ad.rp_id_hash) { fido_log_debug("%s: sha256", __func__); return (-1); } ad.flags = flags; /* XXX translate? */ ad.sigcount = sigcount; if ((item = cbor_build_bytestring((const unsigned char *)&ad, sizeof(ad))) == NULL) { fido_log_debug("%s: cbor_build_bytestring", __func__); return (-1); } if (fake_cbor_ad->ptr != NULL || (fake_cbor_ad->len = cbor_serialize_alloc(item, &fake_cbor_ad->ptr, &alloc_len)) == 0) { fido_log_debug("%s: cbor_serialize_alloc", __func__); cbor_decref(&item); return (-1); } cbor_decref(&item); return (0); } /* TODO: use u2f_get_touch_begin & u2f_get_touch_status instead */ static int -send_dummy_register(fido_dev_t *dev, int ms) +send_dummy_register(fido_dev_t *dev, int *ms) { iso7816_apdu_t *apdu = NULL; unsigned char challenge[SHA256_DIGEST_LENGTH]; unsigned char application[SHA256_DIGEST_LENGTH]; unsigned char reply[FIDO_MAXMSG]; int r; -#ifdef FIDO_FUZZ - ms = 0; /* XXX */ -#endif - /* dummy challenge & application */ memset(&challenge, 0xff, sizeof(challenge)); memset(&application, 0xff, sizeof(application)); if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 * SHA256_DIGEST_LENGTH)) == NULL || iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 || iso7816_add(apdu, &application, sizeof(application)) < 0) { fido_log_debug("%s: iso7816", __func__); r = FIDO_ERR_INTERNAL; goto fail; } do { if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), - iso7816_len(apdu)) < 0) { + iso7816_len(apdu), ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } if (fido_rx(dev, CTAP_CMD_MSG, &reply, sizeof(reply), ms) < 2) { fido_log_debug("%s: fido_rx", __func__); r = FIDO_ERR_RX; goto fail; } - if (usleep((unsigned)(ms == -1 ? 100 : ms) * 1000) < 0) { - fido_log_debug("%s: usleep", __func__); + if (delay_ms(U2F_PACE_MS, ms) != 0) { + fido_log_debug("%s: delay_ms", __func__); r = FIDO_ERR_RX; goto fail; } } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED); r = FIDO_OK; fail: iso7816_free(&apdu); return (r); } static int key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id, - int *found, int ms) + int *found, int *ms) { iso7816_apdu_t *apdu = NULL; unsigned char challenge[SHA256_DIGEST_LENGTH]; unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; unsigned char reply[FIDO_MAXMSG]; uint8_t key_id_len; int r; if (key_id->len > UINT8_MAX || rp_id == NULL) { fido_log_debug("%s: key_id->len=%zu, rp_id=%p", __func__, key_id->len, (const void *)rp_id); r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } memset(&challenge, 0xff, sizeof(challenge)); memset(&rp_id_hash, 0, sizeof(rp_id_hash)); if (SHA256((const void *)rp_id, strlen(rp_id), rp_id_hash) != rp_id_hash) { fido_log_debug("%s: sha256", __func__); r = FIDO_ERR_INTERNAL; goto fail; } key_id_len = (uint8_t)key_id->len; if ((apdu = iso7816_new(0, U2F_CMD_AUTH, U2F_AUTH_CHECK, (uint16_t)(2 * SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL || iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 || iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 || iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 || iso7816_add(apdu, key_id->ptr, key_id_len) < 0) { fido_log_debug("%s: iso7816", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), - iso7816_len(apdu)) < 0) { + iso7816_len(apdu), ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } if (fido_rx(dev, CTAP_CMD_MSG, &reply, sizeof(reply), ms) != 2) { fido_log_debug("%s: fido_rx", __func__); r = FIDO_ERR_RX; goto fail; } switch ((reply[0] << 8) | reply[1]) { case SW_CONDITIONS_NOT_SATISFIED: *found = 1; /* key exists */ break; case SW_WRONG_DATA: *found = 0; /* key does not exist */ break; default: /* unexpected sw */ r = FIDO_ERR_INTERNAL; goto fail; } r = FIDO_OK; fail: iso7816_free(&apdu); return (r); } static int parse_auth_reply(fido_blob_t *sig, fido_blob_t *ad, const char *rp_id, const unsigned char *reply, size_t len) { uint8_t flags; uint32_t sigcount; if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) { fido_log_debug("%s: unexpected sw", __func__); return (FIDO_ERR_RX); } len -= 2; if (fido_buf_read(&reply, &len, &flags, sizeof(flags)) < 0 || fido_buf_read(&reply, &len, &sigcount, sizeof(sigcount)) < 0) { fido_log_debug("%s: fido_buf_read", __func__); return (FIDO_ERR_RX); } if (sig_get(sig, &reply, &len) < 0) { fido_log_debug("%s: sig_get", __func__); return (FIDO_ERR_RX); } if (authdata_fake(rp_id, flags, sigcount, ad) < 0) { fido_log_debug("%s; authdata_fake", __func__); return (FIDO_ERR_RX); } return (FIDO_OK); } static int do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id, - const fido_blob_t *key_id, fido_blob_t *sig, fido_blob_t *ad, int ms) + const fido_blob_t *key_id, fido_blob_t *sig, fido_blob_t *ad, int *ms) { iso7816_apdu_t *apdu = NULL; unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; unsigned char reply[FIDO_MAXMSG]; int reply_len; uint8_t key_id_len; int r; #ifdef FIDO_FUZZ - ms = 0; /* XXX */ + *ms = 0; /* XXX */ #endif if (cdh->len != SHA256_DIGEST_LENGTH || key_id->len > UINT8_MAX || rp_id == NULL) { r = FIDO_ERR_INVALID_ARGUMENT; goto fail; } memset(&rp_id_hash, 0, sizeof(rp_id_hash)); if (SHA256((const void *)rp_id, strlen(rp_id), rp_id_hash) != rp_id_hash) { fido_log_debug("%s: sha256", __func__); r = FIDO_ERR_INTERNAL; goto fail; } key_id_len = (uint8_t)key_id->len; if ((apdu = iso7816_new(0, U2F_CMD_AUTH, U2F_AUTH_SIGN, (uint16_t)(2 * SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL || iso7816_add(apdu, cdh->ptr, cdh->len) < 0 || iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 || iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 || iso7816_add(apdu, key_id->ptr, key_id_len) < 0) { fido_log_debug("%s: iso7816", __func__); r = FIDO_ERR_INTERNAL; goto fail; } do { if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), - iso7816_len(apdu)) < 0) { + iso7816_len(apdu), ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, &reply, sizeof(reply), ms)) < 2) { fido_log_debug("%s: fido_rx", __func__); r = FIDO_ERR_RX; goto fail; } - if (usleep((unsigned)(ms == -1 ? 100 : ms) * 1000) < 0) { - fido_log_debug("%s: usleep", __func__); + if (delay_ms(U2F_PACE_MS, ms) != 0) { + fido_log_debug("%s: delay_ms", __func__); r = FIDO_ERR_RX; goto fail; } } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED); if ((r = parse_auth_reply(sig, ad, rp_id, reply, (size_t)reply_len)) != FIDO_OK) { fido_log_debug("%s: parse_auth_reply", __func__); goto fail; } fail: iso7816_free(&apdu); return (r); } static int cbor_blob_from_ec_point(const uint8_t *ec_point, size_t ec_point_len, fido_blob_t *cbor_blob) { es256_pk_t *pk = NULL; cbor_item_t *pk_cbor = NULL; size_t alloc_len; int ok = -1; /* only handle uncompressed points */ if (ec_point_len != 65 || ec_point[0] != 0x04) { fido_log_debug("%s: unexpected format", __func__); goto fail; } if ((pk = es256_pk_new()) == NULL || es256_pk_set_x(pk, &ec_point[1]) < 0 || es256_pk_set_y(pk, &ec_point[33]) < 0) { fido_log_debug("%s: es256_pk_set", __func__); goto fail; } if ((pk_cbor = es256_pk_encode(pk, 0)) == NULL) { fido_log_debug("%s: es256_pk_encode", __func__); goto fail; } if ((cbor_blob->len = cbor_serialize_alloc(pk_cbor, &cbor_blob->ptr, &alloc_len)) != 77) { fido_log_debug("%s: cbor_serialize_alloc", __func__); goto fail; } ok = 0; fail: es256_pk_free(&pk); if (pk_cbor) cbor_decref(&pk_cbor); return (ok); } +static int +encode_cred_attstmt(int cose_alg, const fido_blob_t *x5c, + const fido_blob_t *sig, fido_blob_t *out) +{ + cbor_item_t *item = NULL; + cbor_item_t *x5c_cbor = NULL; + const uint8_t alg_cbor = (uint8_t)(-cose_alg - 1); + struct cbor_pair kv[3]; + size_t alloc_len; + int ok = -1; + + memset(&kv, 0, sizeof(kv)); + memset(out, 0, sizeof(*out)); + + if ((item = cbor_new_definite_map(3)) == NULL) { + fido_log_debug("%s: cbor_new_definite_map", __func__); + goto fail; + } + + if ((kv[0].key = cbor_build_string("alg")) == NULL || + (kv[0].value = cbor_build_negint8(alg_cbor)) == NULL || + !cbor_map_add(item, kv[0])) { + fido_log_debug("%s: alg", __func__); + goto fail; + } + + if ((kv[1].key = cbor_build_string("sig")) == NULL || + (kv[1].value = fido_blob_encode(sig)) == NULL || + !cbor_map_add(item, kv[1])) { + fido_log_debug("%s: sig", __func__); + goto fail; + } + + if ((kv[2].key = cbor_build_string("x5c")) == NULL || + (kv[2].value = cbor_new_definite_array(1)) == NULL || + (x5c_cbor = fido_blob_encode(x5c)) == NULL || + !cbor_array_push(kv[2].value, x5c_cbor) || + !cbor_map_add(item, kv[2])) { + fido_log_debug("%s: x5c", __func__); + goto fail; + } + + if ((out->len = cbor_serialize_alloc(item, &out->ptr, + &alloc_len)) == 0) { + fido_log_debug("%s: cbor_serialize_alloc", __func__); + goto fail; + } + + ok = 0; +fail: + if (item != NULL) + cbor_decref(&item); + if (x5c_cbor != NULL) + cbor_decref(&x5c_cbor); + + for (size_t i = 0; i < nitems(kv); i++) { + if (kv[i].key) + cbor_decref(&kv[i].key); + if (kv[i].value) + cbor_decref(&kv[i].value); + } + + return (ok); +} + static int encode_cred_authdata(const char *rp_id, const uint8_t *kh, uint8_t kh_len, const uint8_t *pubkey, size_t pubkey_len, fido_blob_t *out) { fido_authdata_t authdata; fido_attcred_raw_t attcred_raw; fido_blob_t pk_blob; fido_blob_t authdata_blob; cbor_item_t *authdata_cbor = NULL; unsigned char *ptr; size_t len; size_t alloc_len; int ok = -1; memset(&pk_blob, 0, sizeof(pk_blob)); memset(&authdata, 0, sizeof(authdata)); memset(&authdata_blob, 0, sizeof(authdata_blob)); memset(out, 0, sizeof(*out)); if (rp_id == NULL) { fido_log_debug("%s: NULL rp_id", __func__); goto fail; } if (cbor_blob_from_ec_point(pubkey, pubkey_len, &pk_blob) < 0) { fido_log_debug("%s: cbor_blob_from_ec_point", __func__); goto fail; } if (SHA256((const void *)rp_id, strlen(rp_id), authdata.rp_id_hash) != authdata.rp_id_hash) { fido_log_debug("%s: sha256", __func__); goto fail; } authdata.flags = (CTAP_AUTHDATA_ATT_CRED | CTAP_AUTHDATA_USER_PRESENT); authdata.sigcount = 0; memset(&attcred_raw.aaguid, 0, sizeof(attcred_raw.aaguid)); attcred_raw.id_len = htobe16(kh_len); len = authdata_blob.len = sizeof(authdata) + sizeof(attcred_raw) + kh_len + pk_blob.len; ptr = authdata_blob.ptr = calloc(1, authdata_blob.len); fido_log_debug("%s: ptr=%p, len=%zu", __func__, (void *)ptr, len); if (authdata_blob.ptr == NULL) goto fail; if (fido_buf_write(&ptr, &len, &authdata, sizeof(authdata)) < 0 || fido_buf_write(&ptr, &len, &attcred_raw, sizeof(attcred_raw)) < 0 || fido_buf_write(&ptr, &len, kh, kh_len) < 0 || fido_buf_write(&ptr, &len, pk_blob.ptr, pk_blob.len) < 0) { fido_log_debug("%s: fido_buf_write", __func__); goto fail; } if ((authdata_cbor = fido_blob_encode(&authdata_blob)) == NULL) { fido_log_debug("%s: fido_blob_encode", __func__); goto fail; } if ((out->len = cbor_serialize_alloc(authdata_cbor, &out->ptr, &alloc_len)) == 0) { fido_log_debug("%s: cbor_serialize_alloc", __func__); goto fail; } ok = 0; fail: if (authdata_cbor) cbor_decref(&authdata_cbor); fido_blob_reset(&pk_blob); fido_blob_reset(&authdata_blob); return (ok); } static int parse_register_reply(fido_cred_t *cred, const unsigned char *reply, size_t len) { fido_blob_t x5c; fido_blob_t sig; fido_blob_t ad; + fido_blob_t stmt; uint8_t dummy; uint8_t pubkey[65]; uint8_t kh_len = 0; uint8_t *kh = NULL; int r; memset(&x5c, 0, sizeof(x5c)); memset(&sig, 0, sizeof(sig)); memset(&ad, 0, sizeof(ad)); + memset(&stmt, 0, sizeof(stmt)); r = FIDO_ERR_RX; /* status word */ if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) { fido_log_debug("%s: unexpected sw", __func__); goto fail; } len -= 2; /* reserved byte */ if (fido_buf_read(&reply, &len, &dummy, sizeof(dummy)) < 0 || dummy != 0x05) { fido_log_debug("%s: reserved byte", __func__); goto fail; } /* pubkey + key handle */ if (fido_buf_read(&reply, &len, &pubkey, sizeof(pubkey)) < 0 || fido_buf_read(&reply, &len, &kh_len, sizeof(kh_len)) < 0 || (kh = calloc(1, kh_len)) == NULL || fido_buf_read(&reply, &len, kh, kh_len) < 0) { fido_log_debug("%s: fido_buf_read", __func__); goto fail; } /* x5c + sig */ if (x5c_get(&x5c, &reply, &len) < 0 || sig_get(&sig, &reply, &len) < 0) { fido_log_debug("%s: x5c || sig", __func__); goto fail; } + /* attstmt */ + if (encode_cred_attstmt(COSE_ES256, &x5c, &sig, &stmt) < 0) { + fido_log_debug("%s: encode_cred_attstmt", __func__); + goto fail; + } + /* authdata */ if (encode_cred_authdata(cred->rp.id, kh, kh_len, pubkey, sizeof(pubkey), &ad) < 0) { fido_log_debug("%s: encode_cred_authdata", __func__); goto fail; } if (fido_cred_set_fmt(cred, "fido-u2f") != FIDO_OK || fido_cred_set_authdata(cred, ad.ptr, ad.len) != FIDO_OK || - fido_cred_set_x509(cred, x5c.ptr, x5c.len) != FIDO_OK || - fido_cred_set_sig(cred, sig.ptr, sig.len) != FIDO_OK) { + fido_cred_set_attstmt(cred, stmt.ptr, stmt.len) != FIDO_OK) { fido_log_debug("%s: fido_cred_set", __func__); r = FIDO_ERR_INTERNAL; goto fail; } r = FIDO_OK; fail: freezero(kh, kh_len); fido_blob_reset(&x5c); fido_blob_reset(&sig); fido_blob_reset(&ad); + fido_blob_reset(&stmt); return (r); } int -u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms) +u2f_register(fido_dev_t *dev, fido_cred_t *cred, int *ms) { iso7816_apdu_t *apdu = NULL; unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; unsigned char reply[FIDO_MAXMSG]; int reply_len; int found; int r; -#ifdef FIDO_FUZZ - ms = 0; /* XXX */ -#endif - if (cred->rk == FIDO_OPT_TRUE || cred->uv == FIDO_OPT_TRUE) { fido_log_debug("%s: rk=%d, uv=%d", __func__, cred->rk, cred->uv); return (FIDO_ERR_UNSUPPORTED_OPTION); } if (cred->type != COSE_ES256 || cred->cdh.ptr == NULL || cred->rp.id == NULL || cred->cdh.len != SHA256_DIGEST_LENGTH) { fido_log_debug("%s: type=%d, cdh=(%p,%zu)" , __func__, cred->type, (void *)cred->cdh.ptr, cred->cdh.len); return (FIDO_ERR_INVALID_ARGUMENT); } for (size_t i = 0; i < cred->excl.len; i++) { if ((r = key_lookup(dev, cred->rp.id, &cred->excl.ptr[i], &found, ms)) != FIDO_OK) { fido_log_debug("%s: key_lookup", __func__); return (r); } if (found) { if ((r = send_dummy_register(dev, ms)) != FIDO_OK) { fido_log_debug("%s: send_dummy_register", __func__); return (r); } return (FIDO_ERR_CREDENTIAL_EXCLUDED); } } memset(&rp_id_hash, 0, sizeof(rp_id_hash)); if (SHA256((const void *)cred->rp.id, strlen(cred->rp.id), rp_id_hash) != rp_id_hash) { fido_log_debug("%s: sha256", __func__); return (FIDO_ERR_INTERNAL); } if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 * SHA256_DIGEST_LENGTH)) == NULL || iso7816_add(apdu, cred->cdh.ptr, cred->cdh.len) < 0 || iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) { fido_log_debug("%s: iso7816", __func__); r = FIDO_ERR_INTERNAL; goto fail; } do { if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), - iso7816_len(apdu)) < 0) { + iso7816_len(apdu), ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, &reply, sizeof(reply), ms)) < 2) { fido_log_debug("%s: fido_rx", __func__); r = FIDO_ERR_RX; goto fail; } - if (usleep((unsigned)(ms == -1 ? 100 : ms) * 1000) < 0) { - fido_log_debug("%s: usleep", __func__); + if (delay_ms(U2F_PACE_MS, ms) != 0) { + fido_log_debug("%s: delay_ms", __func__); r = FIDO_ERR_RX; goto fail; } } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED); if ((r = parse_register_reply(cred, reply, (size_t)reply_len)) != FIDO_OK) { fido_log_debug("%s: parse_register_reply", __func__); goto fail; } fail: iso7816_free(&apdu); return (r); } static int u2f_authenticate_single(fido_dev_t *dev, const fido_blob_t *key_id, - fido_assert_t *fa, size_t idx, int ms) + fido_assert_t *fa, size_t idx, int *ms) { fido_blob_t sig; fido_blob_t ad; int found; int r; memset(&sig, 0, sizeof(sig)); memset(&ad, 0, sizeof(ad)); if ((r = key_lookup(dev, fa->rp_id, key_id, &found, ms)) != FIDO_OK) { fido_log_debug("%s: key_lookup", __func__); goto fail; } if (!found) { fido_log_debug("%s: not found", __func__); r = FIDO_ERR_CREDENTIAL_EXCLUDED; goto fail; } if (fido_blob_set(&fa->stmt[idx].id, key_id->ptr, key_id->len) < 0) { fido_log_debug("%s: fido_blob_set", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (fa->up == FIDO_OPT_FALSE) { fido_log_debug("%s: checking for key existence only", __func__); r = FIDO_ERR_USER_PRESENCE_REQUIRED; goto fail; } if ((r = do_auth(dev, &fa->cdh, fa->rp_id, key_id, &sig, &ad, ms)) != FIDO_OK) { fido_log_debug("%s: do_auth", __func__); goto fail; } if (fido_assert_set_authdata(fa, idx, ad.ptr, ad.len) != FIDO_OK || fido_assert_set_sig(fa, idx, sig.ptr, sig.len) != FIDO_OK) { fido_log_debug("%s: fido_assert_set", __func__); r = FIDO_ERR_INTERNAL; goto fail; } r = FIDO_OK; fail: fido_blob_reset(&sig); fido_blob_reset(&ad); return (r); } int -u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms) +u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int *ms) { size_t nfound = 0; size_t nauth_ok = 0; int r; if (fa->uv == FIDO_OPT_TRUE || fa->allow_list.ptr == NULL) { fido_log_debug("%s: uv=%d, allow_list=%p", __func__, fa->uv, (void *)fa->allow_list.ptr); return (FIDO_ERR_UNSUPPORTED_OPTION); } if ((r = fido_assert_set_count(fa, fa->allow_list.len)) != FIDO_OK) { fido_log_debug("%s: fido_assert_set_count", __func__); return (r); } for (size_t i = 0; i < fa->allow_list.len; i++) { switch ((r = u2f_authenticate_single(dev, &fa->allow_list.ptr[i], fa, nfound, ms))) { case FIDO_OK: nauth_ok++; /* FALLTHROUGH */ case FIDO_ERR_USER_PRESENCE_REQUIRED: nfound++; break; default: if (r != FIDO_ERR_CREDENTIAL_EXCLUDED) { fido_log_debug("%s: u2f_authenticate_single", __func__); return (r); } /* ignore credentials that don't exist */ } } fa->stmt_len = nfound; if (nfound == 0) return (FIDO_ERR_NO_CREDENTIALS); if (nauth_ok == 0) return (FIDO_ERR_USER_PRESENCE_REQUIRED); return (FIDO_OK); } int -u2f_get_touch_begin(fido_dev_t *dev) +u2f_get_touch_begin(fido_dev_t *dev, int *ms) { iso7816_apdu_t *apdu = NULL; const char *clientdata = FIDO_DUMMY_CLIENTDATA; const char *rp_id = FIDO_DUMMY_RP_ID; unsigned char clientdata_hash[SHA256_DIGEST_LENGTH]; unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; unsigned char reply[FIDO_MAXMSG]; int r; memset(&clientdata_hash, 0, sizeof(clientdata_hash)); memset(&rp_id_hash, 0, sizeof(rp_id_hash)); if (SHA256((const void *)clientdata, strlen(clientdata), clientdata_hash) != clientdata_hash || SHA256((const void *)rp_id, strlen(rp_id), rp_id_hash) != rp_id_hash) { fido_log_debug("%s: sha256", __func__); return (FIDO_ERR_INTERNAL); } if ((apdu = iso7816_new(0, U2F_CMD_REGISTER, 0, 2 * SHA256_DIGEST_LENGTH)) == NULL || iso7816_add(apdu, clientdata_hash, sizeof(clientdata_hash)) < 0 || iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) { fido_log_debug("%s: iso7816", __func__); r = FIDO_ERR_INTERNAL; goto fail; } if (dev->attr.flags & FIDO_CAP_WINK) { - fido_tx(dev, CTAP_CMD_WINK, NULL, 0); - fido_rx(dev, CTAP_CMD_WINK, &reply, sizeof(reply), 200); + fido_tx(dev, CTAP_CMD_WINK, NULL, 0, ms); + fido_rx(dev, CTAP_CMD_WINK, &reply, sizeof(reply), ms); } if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), - iso7816_len(apdu)) < 0) { + iso7816_len(apdu), ms) < 0) { fido_log_debug("%s: fido_tx", __func__); r = FIDO_ERR_TX; goto fail; } r = FIDO_OK; fail: iso7816_free(&apdu); return (r); } int -u2f_get_touch_status(fido_dev_t *dev, int *touched, int ms) +u2f_get_touch_status(fido_dev_t *dev, int *touched, int *ms) { unsigned char reply[FIDO_MAXMSG]; int reply_len; int r; if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, &reply, sizeof(reply), ms)) < 2) { fido_log_debug("%s: fido_rx", __func__); return (FIDO_OK); /* ignore */ } switch ((reply[reply_len - 2] << 8) | reply[reply_len - 1]) { case SW_CONDITIONS_NOT_SATISFIED: - if ((r = u2f_get_touch_begin(dev)) != FIDO_OK) { + if ((r = u2f_get_touch_begin(dev, ms)) != FIDO_OK) { fido_log_debug("%s: u2f_get_touch_begin", __func__); return (r); } *touched = 0; break; case SW_NO_ERROR: *touched = 1; break; default: fido_log_debug("%s: unexpected sw", __func__); return (FIDO_ERR_RX); } return (FIDO_OK); } diff --git a/contrib/libfido2/src/webauthn.h b/contrib/libfido2/src/webauthn.h new file mode 100644 index 000000000000..5fbdd6faa927 --- /dev/null +++ b/contrib/libfido2/src/webauthn.h @@ -0,0 +1,839 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#ifndef __WEBAUTHN_H_ +#define __WEBAUTHN_H_ + +#pragma once + +#include + +#pragma region Desktop Family or OneCore Family +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WINAPI +#define WINAPI __stdcall +#endif + +#ifndef INITGUID +#define INITGUID +#include +#undef INITGUID +#else +#include +#endif + +//+------------------------------------------------------------------------------------------ +// API Version Information. +// Caller should check for WebAuthNGetApiVersionNumber to check the presence of relevant APIs +// and features for their usage. +//------------------------------------------------------------------------------------------- + +#define WEBAUTHN_API_VERSION_1 1 +// WEBAUTHN_API_VERSION_1 : Baseline Version +// Data Structures and their sub versions: +// - WEBAUTHN_RP_ENTITY_INFORMATION : 1 +// - WEBAUTHN_USER_ENTITY_INFORMATION : 1 +// - WEBAUTHN_CLIENT_DATA : 1 +// - WEBAUTHN_COSE_CREDENTIAL_PARAMETER : 1 +// - WEBAUTHN_COSE_CREDENTIAL_PARAMETERS : Not Applicable +// - WEBAUTHN_CREDENTIAL : 1 +// - WEBAUTHN_CREDENTIALS : Not Applicable +// - WEBAUTHN_CREDENTIAL_EX : 1 +// - WEBAUTHN_CREDENTIAL_LIST : Not Applicable +// - WEBAUTHN_EXTENSION : Not Applicable +// - WEBAUTHN_EXTENSIONS : Not Applicable +// - WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS : 3 +// - WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS : 4 +// - WEBAUTHN_COMMON_ATTESTATION : 1 +// - WEBAUTHN_CREDENTIAL_ATTESTATION : 3 +// - WEBAUTHN_ASSERTION : 1 +// Extensions: +// - WEBAUTHN_EXTENSIONS_IDENTIFIER_HMAC_SECRET +// APIs: +// - WebAuthNGetApiVersionNumber +// - WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable +// - WebAuthNAuthenticatorMakeCredential +// - WebAuthNAuthenticatorGetAssertion +// - WebAuthNFreeCredentialAttestation +// - WebAuthNFreeAssertion +// - WebAuthNGetCancellationId +// - WebAuthNCancelCurrentOperation +// - WebAuthNGetErrorName +// - WebAuthNGetW3CExceptionDOMError + +#define WEBAUTHN_API_VERSION_2 2 +// WEBAUTHN_API_VERSION_2 : Delta From WEBAUTHN_API_VERSION_1 +// Added Extensions: +// - WEBAUTHN_EXTENSIONS_IDENTIFIER_CRED_PROTECT +// + +#define WEBAUTHN_API_VERSION_3 3 +// WEBAUTHN_API_VERSION_3 : Delta From WEBAUTHN_API_VERSION_2 +// Data Structures and their sub versions: +// - WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS : 4 +// - WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS : 5 +// - WEBAUTHN_CREDENTIAL_ATTESTATION : 4 +// - WEBAUTHN_ASSERTION : 2 +// Added Extensions: +// - WEBAUTHN_EXTENSIONS_IDENTIFIER_CRED_BLOB +// - WEBAUTHN_EXTENSIONS_IDENTIFIER_MIN_PIN_LENGTH +// + +#define WEBAUTHN_API_CURRENT_VERSION WEBAUTHN_API_VERSION_3 + +//+------------------------------------------------------------------------------------------ +// Information about an RP Entity +//------------------------------------------------------------------------------------------- + +#define WEBAUTHN_RP_ENTITY_INFORMATION_CURRENT_VERSION 1 + +typedef struct _WEBAUTHN_RP_ENTITY_INFORMATION { + // Version of this structure, to allow for modifications in the future. + // This field is required and should be set to CURRENT_VERSION above. + DWORD dwVersion; + + // Identifier for the RP. This field is required. + PCWSTR pwszId; + + // Contains the friendly name of the Relying Party, such as "Acme Corporation", "Widgets Inc" or "Awesome Site". + // This field is required. + PCWSTR pwszName; + + // Optional URL pointing to RP's logo. + PCWSTR pwszIcon; +} WEBAUTHN_RP_ENTITY_INFORMATION, *PWEBAUTHN_RP_ENTITY_INFORMATION; +typedef const WEBAUTHN_RP_ENTITY_INFORMATION *PCWEBAUTHN_RP_ENTITY_INFORMATION; + +//+------------------------------------------------------------------------------------------ +// Information about an User Entity +//------------------------------------------------------------------------------------------- +#define WEBAUTHN_MAX_USER_ID_LENGTH 64 + +#define WEBAUTHN_USER_ENTITY_INFORMATION_CURRENT_VERSION 1 + +typedef struct _WEBAUTHN_USER_ENTITY_INFORMATION { + // Version of this structure, to allow for modifications in the future. + // This field is required and should be set to CURRENT_VERSION above. + DWORD dwVersion; + + // Identifier for the User. This field is required. + DWORD cbId; + _Field_size_bytes_(cbId) + PBYTE pbId; + + // Contains a detailed name for this account, such as "john.p.smith@example.com". + PCWSTR pwszName; + + // Optional URL that can be used to retrieve an image containing the user's current avatar, + // or a data URI that contains the image data. + PCWSTR pwszIcon; + + // For User: Contains the friendly name associated with the user account by the Relying Party, such as "John P. Smith". + PCWSTR pwszDisplayName; +} WEBAUTHN_USER_ENTITY_INFORMATION, *PWEBAUTHN_USER_ENTITY_INFORMATION; +typedef const WEBAUTHN_USER_ENTITY_INFORMATION *PCWEBAUTHN_USER_ENTITY_INFORMATION; + +//+------------------------------------------------------------------------------------------ +// Information about client data. +//------------------------------------------------------------------------------------------- + +#define WEBAUTHN_HASH_ALGORITHM_SHA_256 L"SHA-256" +#define WEBAUTHN_HASH_ALGORITHM_SHA_384 L"SHA-384" +#define WEBAUTHN_HASH_ALGORITHM_SHA_512 L"SHA-512" + +#define WEBAUTHN_CLIENT_DATA_CURRENT_VERSION 1 + +typedef struct _WEBAUTHN_CLIENT_DATA { + // Version of this structure, to allow for modifications in the future. + // This field is required and should be set to CURRENT_VERSION above. + DWORD dwVersion; + + // Size of the pbClientDataJSON field. + DWORD cbClientDataJSON; + // UTF-8 encoded JSON serialization of the client data. + _Field_size_bytes_(cbClientDataJSON) + PBYTE pbClientDataJSON; + + // Hash algorithm ID used to hash the pbClientDataJSON field. + LPCWSTR pwszHashAlgId; +} WEBAUTHN_CLIENT_DATA, *PWEBAUTHN_CLIENT_DATA; +typedef const WEBAUTHN_CLIENT_DATA *PCWEBAUTHN_CLIENT_DATA; + +//+------------------------------------------------------------------------------------------ +// Information about credential parameters. +//------------------------------------------------------------------------------------------- + +#define WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY L"public-key" + +#define WEBAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256 -7 +#define WEBAUTHN_COSE_ALGORITHM_ECDSA_P384_WITH_SHA384 -35 +#define WEBAUTHN_COSE_ALGORITHM_ECDSA_P521_WITH_SHA512 -36 + +#define WEBAUTHN_COSE_ALGORITHM_RSASSA_PKCS1_V1_5_WITH_SHA256 -257 +#define WEBAUTHN_COSE_ALGORITHM_RSASSA_PKCS1_V1_5_WITH_SHA384 -258 +#define WEBAUTHN_COSE_ALGORITHM_RSASSA_PKCS1_V1_5_WITH_SHA512 -259 + +#define WEBAUTHN_COSE_ALGORITHM_RSA_PSS_WITH_SHA256 -37 +#define WEBAUTHN_COSE_ALGORITHM_RSA_PSS_WITH_SHA384 -38 +#define WEBAUTHN_COSE_ALGORITHM_RSA_PSS_WITH_SHA512 -39 + +#define WEBAUTHN_COSE_CREDENTIAL_PARAMETER_CURRENT_VERSION 1 + +typedef struct _WEBAUTHN_COSE_CREDENTIAL_PARAMETER { + // Version of this structure, to allow for modifications in the future. + DWORD dwVersion; + + // Well-known credential type specifying a credential to create. + LPCWSTR pwszCredentialType; + + // Well-known COSE algorithm specifying the algorithm to use for the credential. + LONG lAlg; +} WEBAUTHN_COSE_CREDENTIAL_PARAMETER, *PWEBAUTHN_COSE_CREDENTIAL_PARAMETER; +typedef const WEBAUTHN_COSE_CREDENTIAL_PARAMETER *PCWEBAUTHN_COSE_CREDENTIAL_PARAMETER; + +typedef struct _WEBAUTHN_COSE_CREDENTIAL_PARAMETERS { + DWORD cCredentialParameters; + _Field_size_(cCredentialParameters) + PWEBAUTHN_COSE_CREDENTIAL_PARAMETER pCredentialParameters; +} WEBAUTHN_COSE_CREDENTIAL_PARAMETERS, *PWEBAUTHN_COSE_CREDENTIAL_PARAMETERS; +typedef const WEBAUTHN_COSE_CREDENTIAL_PARAMETERS *PCWEBAUTHN_COSE_CREDENTIAL_PARAMETERS; + +//+------------------------------------------------------------------------------------------ +// Information about credential. +//------------------------------------------------------------------------------------------- +#define WEBAUTHN_CREDENTIAL_CURRENT_VERSION 1 + +typedef struct _WEBAUTHN_CREDENTIAL { + // Version of this structure, to allow for modifications in the future. + DWORD dwVersion; + + // Size of pbID. + DWORD cbId; + // Unique ID for this particular credential. + _Field_size_bytes_(cbId) + PBYTE pbId; + + // Well-known credential type specifying what this particular credential is. + LPCWSTR pwszCredentialType; +} WEBAUTHN_CREDENTIAL, *PWEBAUTHN_CREDENTIAL; +typedef const WEBAUTHN_CREDENTIAL *PCWEBAUTHN_CREDENTIAL; + +typedef struct _WEBAUTHN_CREDENTIALS { + DWORD cCredentials; + _Field_size_(cCredentials) + PWEBAUTHN_CREDENTIAL pCredentials; +} WEBAUTHN_CREDENTIALS, *PWEBAUTHN_CREDENTIALS; +typedef const WEBAUTHN_CREDENTIALS *PCWEBAUTHN_CREDENTIALS; + +//+------------------------------------------------------------------------------------------ +// Information about credential with extra information, such as, dwTransports +//------------------------------------------------------------------------------------------- + +#define WEBAUTHN_CTAP_TRANSPORT_USB 0x00000001 +#define WEBAUTHN_CTAP_TRANSPORT_NFC 0x00000002 +#define WEBAUTHN_CTAP_TRANSPORT_BLE 0x00000004 +#define WEBAUTHN_CTAP_TRANSPORT_TEST 0x00000008 +#define WEBAUTHN_CTAP_TRANSPORT_INTERNAL 0x00000010 +#define WEBAUTHN_CTAP_TRANSPORT_FLAGS_MASK 0x0000001F + +#define WEBAUTHN_CREDENTIAL_EX_CURRENT_VERSION 1 + +typedef struct _WEBAUTHN_CREDENTIAL_EX { + // Version of this structure, to allow for modifications in the future. + DWORD dwVersion; + + // Size of pbID. + DWORD cbId; + // Unique ID for this particular credential. + _Field_size_bytes_(cbId) + PBYTE pbId; + + // Well-known credential type specifying what this particular credential is. + LPCWSTR pwszCredentialType; + + // Transports. 0 implies no transport restrictions. + DWORD dwTransports; +} WEBAUTHN_CREDENTIAL_EX, *PWEBAUTHN_CREDENTIAL_EX; +typedef const WEBAUTHN_CREDENTIAL_EX *PCWEBAUTHN_CREDENTIAL_EX; + +//+------------------------------------------------------------------------------------------ +// Information about credential list with extra information +//------------------------------------------------------------------------------------------- + +typedef struct _WEBAUTHN_CREDENTIAL_LIST { + DWORD cCredentials; + _Field_size_(cCredentials) + PWEBAUTHN_CREDENTIAL_EX *ppCredentials; +} WEBAUTHN_CREDENTIAL_LIST, *PWEBAUTHN_CREDENTIAL_LIST; +typedef const WEBAUTHN_CREDENTIAL_LIST *PCWEBAUTHN_CREDENTIAL_LIST; + +//+------------------------------------------------------------------------------------------ +// Hmac-Secret extension +//------------------------------------------------------------------------------------------- + +#define WEBAUTHN_EXTENSIONS_IDENTIFIER_HMAC_SECRET L"hmac-secret" +// Below type definitions is for WEBAUTHN_EXTENSIONS_IDENTIFIER_HMAC_SECRET +// MakeCredential Input Type: BOOL. +// - pvExtension must point to a BOOL with the value TRUE. +// - cbExtension must contain the sizeof(BOOL). +// MakeCredential Output Type: BOOL. +// - pvExtension will point to a BOOL with the value TRUE if credential +// was successfully created with HMAC_SECRET. +// - cbExtension will contain the sizeof(BOOL). +// GetAssertion Input Type: Not Supported +// GetAssertion Output Type: Not Supported + +//+------------------------------------------------------------------------------------------ +// credProtect extension +//------------------------------------------------------------------------------------------- + +#define WEBAUTHN_USER_VERIFICATION_ANY 0 +#define WEBAUTHN_USER_VERIFICATION_OPTIONAL 1 +#define WEBAUTHN_USER_VERIFICATION_OPTIONAL_WITH_CREDENTIAL_ID_LIST 2 +#define WEBAUTHN_USER_VERIFICATION_REQUIRED 3 + +typedef struct _WEBAUTHN_CRED_PROTECT_EXTENSION_IN { + // One of the above WEBAUTHN_USER_VERIFICATION_* values + DWORD dwCredProtect; + // Set the following to TRUE to require authenticator support for the credProtect extension + BOOL bRequireCredProtect; +} WEBAUTHN_CRED_PROTECT_EXTENSION_IN, *PWEBAUTHN_CRED_PROTECT_EXTENSION_IN; +typedef const WEBAUTHN_CRED_PROTECT_EXTENSION_IN *PCWEBAUTHN_CRED_PROTECT_EXTENSION_IN; + + +#define WEBAUTHN_EXTENSIONS_IDENTIFIER_CRED_PROTECT L"credProtect" +// Below type definitions is for WEBAUTHN_EXTENSIONS_IDENTIFIER_CRED_PROTECT +// MakeCredential Input Type: WEBAUTHN_CRED_PROTECT_EXTENSION_IN. +// - pvExtension must point to a WEBAUTHN_CRED_PROTECT_EXTENSION_IN struct +// - cbExtension will contain the sizeof(WEBAUTHN_CRED_PROTECT_EXTENSION_IN). +// MakeCredential Output Type: DWORD. +// - pvExtension will point to a DWORD with one of the above WEBAUTHN_USER_VERIFICATION_* values +// if credential was successfully created with CRED_PROTECT. +// - cbExtension will contain the sizeof(DWORD). +// GetAssertion Input Type: Not Supported +// GetAssertion Output Type: Not Supported + +//+------------------------------------------------------------------------------------------ +// credBlob extension +//------------------------------------------------------------------------------------------- + +typedef struct _WEBAUTHN_CRED_BLOB_EXTENSION { + // Size of pbCredBlob. + DWORD cbCredBlob; + _Field_size_bytes_(cbCredBlob) + PBYTE pbCredBlob; +} WEBAUTHN_CRED_BLOB_EXTENSION, *PWEBAUTHN_CRED_BLOB_EXTENSION; +typedef const WEBAUTHN_CRED_BLOB_EXTENSION *PCWEBAUTHN_CRED_BLOB_EXTENSION; + + +#define WEBAUTHN_EXTENSIONS_IDENTIFIER_CRED_BLOB L"credBlob" +// Below type definitions is for WEBAUTHN_EXTENSIONS_IDENTIFIER_CRED_BLOB +// MakeCredential Input Type: WEBAUTHN_CRED_BLOB_EXTENSION. +// - pvExtension must point to a WEBAUTHN_CRED_BLOB_EXTENSION struct +// - cbExtension must contain the sizeof(WEBAUTHN_CRED_BLOB_EXTENSION). +// MakeCredential Output Type: BOOL. +// - pvExtension will point to a BOOL with the value TRUE if credBlob was successfully created +// - cbExtension will contain the sizeof(BOOL). +// GetAssertion Input Type: BOOL. +// - pvExtension must point to a BOOL with the value TRUE to request the credBlob. +// - cbExtension must contain the sizeof(BOOL). +// GetAssertion Output Type: WEBAUTHN_CRED_BLOB_EXTENSION. +// - pvExtension will point to a WEBAUTHN_CRED_BLOB_EXTENSION struct if the authenticator +// returns the credBlob in the signed extensions +// - cbExtension will contain the sizeof(WEBAUTHN_CRED_BLOB_EXTENSION). + +//+------------------------------------------------------------------------------------------ +// minPinLength extension +//------------------------------------------------------------------------------------------- + +#define WEBAUTHN_EXTENSIONS_IDENTIFIER_MIN_PIN_LENGTH L"minPinLength" +// Below type definitions is for WEBAUTHN_EXTENSIONS_IDENTIFIER_MIN_PIN_LENGTH +// MakeCredential Input Type: BOOL. +// - pvExtension must point to a BOOL with the value TRUE to request the minPinLength. +// - cbExtension must contain the sizeof(BOOL). +// MakeCredential Output Type: DWORD. +// - pvExtension will point to a DWORD with the minimum pin length if returned by the authenticator +// - cbExtension will contain the sizeof(DWORD). +// GetAssertion Input Type: Not Supported +// GetAssertion Output Type: Not Supported + +//+------------------------------------------------------------------------------------------ +// Information about Extensions. +//------------------------------------------------------------------------------------------- +typedef struct _WEBAUTHN_EXTENSION { + LPCWSTR pwszExtensionIdentifier; + DWORD cbExtension; + PVOID pvExtension; +} WEBAUTHN_EXTENSION, *PWEBAUTHN_EXTENSION; +typedef const WEBAUTHN_EXTENSION *PCWEBAUTHN_EXTENSION; + +typedef struct _WEBAUTHN_EXTENSIONS { + DWORD cExtensions; + _Field_size_(cExtensions) + PWEBAUTHN_EXTENSION pExtensions; +} WEBAUTHN_EXTENSIONS, *PWEBAUTHN_EXTENSIONS; +typedef const WEBAUTHN_EXTENSIONS *PCWEBAUTHN_EXTENSIONS; + +//+------------------------------------------------------------------------------------------ +// Options. +//------------------------------------------------------------------------------------------- + +#define WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY 0 +#define WEBAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM 1 +#define WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM 2 +#define WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM_U2F_V2 3 + +#define WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY 0 +#define WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED 1 +#define WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED 2 +#define WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED 3 + +#define WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_ANY 0 +#define WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_NONE 1 +#define WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_INDIRECT 2 +#define WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT 3 + +#define WEBAUTHN_ENTERPRISE_ATTESTATION_NONE 0 +#define WEBAUTHN_ENTERPRISE_ATTESTATION_VENDOR_FACILITATED 1 +#define WEBAUTHN_ENTERPRISE_ATTESTATION_PLATFORM_MANAGED 2 + +#define WEBAUTHN_LARGE_BLOB_SUPPORT_NONE 0 +#define WEBAUTHN_LARGE_BLOB_SUPPORT_REQUIRED 1 +#define WEBAUTHN_LARGE_BLOB_SUPPORT_PREFERRED 2 + +#define WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_1 1 +#define WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_2 2 +#define WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_3 3 +#define WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_4 4 +#define WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_CURRENT_VERSION WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_4 + +typedef struct _WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS { + // Version of this structure, to allow for modifications in the future. + DWORD dwVersion; + + // Time that the operation is expected to complete within. + // This is used as guidance, and can be overridden by the platform. + DWORD dwTimeoutMilliseconds; + + // Credentials used for exclusion. + WEBAUTHN_CREDENTIALS CredentialList; + + // Optional extensions to parse when performing the operation. + WEBAUTHN_EXTENSIONS Extensions; + + // Optional. Platform vs Cross-Platform Authenticators. + DWORD dwAuthenticatorAttachment; + + // Optional. Require key to be resident or not. Defaulting to FALSE. + BOOL bRequireResidentKey; + + // User Verification Requirement. + DWORD dwUserVerificationRequirement; + + // Attestation Conveyance Preference. + DWORD dwAttestationConveyancePreference; + + // Reserved for future Use + DWORD dwFlags; + + // + // The following fields have been added in WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_2 + // + + // Cancellation Id - Optional - See WebAuthNGetCancellationId + GUID *pCancellationId; + + // + // The following fields have been added in WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_3 + // + + // Exclude Credential List. If present, "CredentialList" will be ignored. + PWEBAUTHN_CREDENTIAL_LIST pExcludeCredentialList; + + // + // The following fields have been added in WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_4 + // + + // Enterprise Attestation + DWORD dwEnterpriseAttestation; + + // Large Blob Support: none, required or preferred + // + // NTE_INVALID_PARAMETER when large blob required or preferred and + // both bRequireResidentKey and bPreferResidentKey are set to FALSE. + DWORD dwLargeBlobSupport; + + // Optional. Prefer key to be resident. Defaulting to FALSE. When TRUE, + // overrides the above bRequireResidentKey. + BOOL bPreferResidentKey; + +} WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS, *PWEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS; +typedef const WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS *PCWEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS; + +#define WEBAUTHN_CRED_LARGE_BLOB_OPERATION_NONE 0 +#define WEBAUTHN_CRED_LARGE_BLOB_OPERATION_GET 1 +#define WEBAUTHN_CRED_LARGE_BLOB_OPERATION_SET 2 +#define WEBAUTHN_CRED_LARGE_BLOB_OPERATION_DELETE 3 + +#define WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_1 1 +#define WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_2 2 +#define WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_3 3 +#define WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_4 4 +#define WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_5 5 +#define WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_CURRENT_VERSION WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_5 + +typedef struct _WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS { + // Version of this structure, to allow for modifications in the future. + DWORD dwVersion; + + // Time that the operation is expected to complete within. + // This is used as guidance, and can be overridden by the platform. + DWORD dwTimeoutMilliseconds; + + // Allowed Credentials List. + WEBAUTHN_CREDENTIALS CredentialList; + + // Optional extensions to parse when performing the operation. + WEBAUTHN_EXTENSIONS Extensions; + + // Optional. Platform vs Cross-Platform Authenticators. + DWORD dwAuthenticatorAttachment; + + // User Verification Requirement. + DWORD dwUserVerificationRequirement; + + // Reserved for future Use + DWORD dwFlags; + + // + // The following fields have been added in WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_2 + // + + // Optional identifier for the U2F AppId. Converted to UTF8 before being hashed. Not lower cased. + PCWSTR pwszU2fAppId; + + // If the following is non-NULL, then, set to TRUE if the above pwszU2fAppid was used instead of + // PCWSTR pwszRpId; + BOOL *pbU2fAppId; + + // + // The following fields have been added in WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_3 + // + + // Cancellation Id - Optional - See WebAuthNGetCancellationId + GUID *pCancellationId; + + // + // The following fields have been added in WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_4 + // + + // Allow Credential List. If present, "CredentialList" will be ignored. + PWEBAUTHN_CREDENTIAL_LIST pAllowCredentialList; + + // + // The following fields have been added in WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_5 + // + + DWORD dwCredLargeBlobOperation; + + // Size of pbCredLargeBlob + DWORD cbCredLargeBlob; + _Field_size_bytes_(cbCredLargeBlob) + PBYTE pbCredLargeBlob; +} WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS, *PWEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS; +typedef const WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS *PCWEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS; + + +//+------------------------------------------------------------------------------------------ +// Attestation Info. +// +//------------------------------------------------------------------------------------------- +#define WEBAUTHN_ATTESTATION_DECODE_NONE 0 +#define WEBAUTHN_ATTESTATION_DECODE_COMMON 1 +// WEBAUTHN_ATTESTATION_DECODE_COMMON supports format types +// L"packed" +// L"fido-u2f" + +#define WEBAUTHN_ATTESTATION_VER_TPM_2_0 L"2.0" + +typedef struct _WEBAUTHN_X5C { + // Length of X.509 encoded certificate + DWORD cbData; + // X.509 encoded certificate bytes + _Field_size_bytes_(cbData) + PBYTE pbData; +} WEBAUTHN_X5C, *PWEBAUTHN_X5C; + +// Supports either Self or Full Basic Attestation + +// Note, new fields will be added to the following data structure to +// support additional attestation format types, such as, TPM. +// When fields are added, the dwVersion will be incremented. +// +// Therefore, your code must make the following check: +// "if (dwVersion >= WEBAUTHN_COMMON_ATTESTATION_CURRENT_VERSION)" + +#define WEBAUTHN_COMMON_ATTESTATION_CURRENT_VERSION 1 + +typedef struct _WEBAUTHN_COMMON_ATTESTATION { + // Version of this structure, to allow for modifications in the future. + DWORD dwVersion; + + // Hash and Padding Algorithm + // + // The following won't be set for "fido-u2f" which assumes "ES256". + PCWSTR pwszAlg; + LONG lAlg; // COSE algorithm + + // Signature that was generated for this attestation. + DWORD cbSignature; + _Field_size_bytes_(cbSignature) + PBYTE pbSignature; + + // Following is set for Full Basic Attestation. If not, set then, this is Self Attestation. + // Array of X.509 DER encoded certificates. The first certificate is the signer, leaf certificate. + DWORD cX5c; + _Field_size_(cX5c) + PWEBAUTHN_X5C pX5c; + + // Following are also set for tpm + PCWSTR pwszVer; // L"2.0" + DWORD cbCertInfo; + _Field_size_bytes_(cbCertInfo) + PBYTE pbCertInfo; + DWORD cbPubArea; + _Field_size_bytes_(cbPubArea) + PBYTE pbPubArea; +} WEBAUTHN_COMMON_ATTESTATION, *PWEBAUTHN_COMMON_ATTESTATION; +typedef const WEBAUTHN_COMMON_ATTESTATION *PCWEBAUTHN_COMMON_ATTESTATION; + +#define WEBAUTHN_ATTESTATION_TYPE_PACKED L"packed" +#define WEBAUTHN_ATTESTATION_TYPE_U2F L"fido-u2f" +#define WEBAUTHN_ATTESTATION_TYPE_TPM L"tpm" +#define WEBAUTHN_ATTESTATION_TYPE_NONE L"none" + +#define WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_1 1 +#define WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_2 2 +#define WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_3 3 +#define WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_4 4 +#define WEBAUTHN_CREDENTIAL_ATTESTATION_CURRENT_VERSION WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_4 + +typedef struct _WEBAUTHN_CREDENTIAL_ATTESTATION { + // Version of this structure, to allow for modifications in the future. + DWORD dwVersion; + + // Attestation format type + PCWSTR pwszFormatType; + + // Size of cbAuthenticatorData. + DWORD cbAuthenticatorData; + // Authenticator data that was created for this credential. + _Field_size_bytes_(cbAuthenticatorData) + PBYTE pbAuthenticatorData; + + // Size of CBOR encoded attestation information + //0 => encoded as CBOR null value. + DWORD cbAttestation; + //Encoded CBOR attestation information + _Field_size_bytes_(cbAttestation) + PBYTE pbAttestation; + + DWORD dwAttestationDecodeType; + // Following depends on the dwAttestationDecodeType + // WEBAUTHN_ATTESTATION_DECODE_NONE + // NULL - not able to decode the CBOR attestation information + // WEBAUTHN_ATTESTATION_DECODE_COMMON + // PWEBAUTHN_COMMON_ATTESTATION; + PVOID pvAttestationDecode; + + // The CBOR encoded Attestation Object to be returned to the RP. + DWORD cbAttestationObject; + _Field_size_bytes_(cbAttestationObject) + PBYTE pbAttestationObject; + + // The CredentialId bytes extracted from the Authenticator Data. + // Used by Edge to return to the RP. + DWORD cbCredentialId; + _Field_size_bytes_(cbCredentialId) + PBYTE pbCredentialId; + + // + // Following fields have been added in WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_2 + // + + WEBAUTHN_EXTENSIONS Extensions; + + // + // Following fields have been added in WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_3 + // + + // One of the WEBAUTHN_CTAP_TRANSPORT_* bits will be set corresponding to + // the transport that was used. + DWORD dwUsedTransport; + + // + // Following fields have been added in WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_4 + // + + BOOL bEpAtt; + BOOL bLargeBlobSupported; + BOOL bResidentKey; + +} WEBAUTHN_CREDENTIAL_ATTESTATION, *PWEBAUTHN_CREDENTIAL_ATTESTATION; +typedef const WEBAUTHN_CREDENTIAL_ATTESTATION *PCWEBAUTHN_CREDENTIAL_ATTESTATION; + + +//+------------------------------------------------------------------------------------------ +// authenticatorGetAssertion output. +//------------------------------------------------------------------------------------------- + +#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_NONE 0 +#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_SUCCESS 1 +#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_NOT_SUPPORTED 2 +#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_INVALID_DATA 3 +#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_INVALID_PARAMETER 4 +#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_NOT_FOUND 5 +#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_MULTIPLE_CREDENTIALS 6 +#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_LACK_OF_SPACE 7 +#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_PLATFORM_ERROR 8 +#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_AUTHENTICATOR_ERROR 9 + +#define WEBAUTHN_ASSERTION_VERSION_1 1 +#define WEBAUTHN_ASSERTION_VERSION_2 2 +#define WEBAUTHN_ASSERTION_CURRENT_VERSION WEBAUTHN_ASSERTION_VERSION_2 + +typedef struct _WEBAUTHN_ASSERTION { + // Version of this structure, to allow for modifications in the future. + DWORD dwVersion; + + // Size of cbAuthenticatorData. + DWORD cbAuthenticatorData; + // Authenticator data that was created for this assertion. + _Field_size_bytes_(cbAuthenticatorData) + PBYTE pbAuthenticatorData; + + // Size of pbSignature. + DWORD cbSignature; + // Signature that was generated for this assertion. + _Field_size_bytes_(cbSignature) + PBYTE pbSignature; + + // Credential that was used for this assertion. + WEBAUTHN_CREDENTIAL Credential; + + // Size of User Id + DWORD cbUserId; + // UserId + _Field_size_bytes_(cbUserId) + PBYTE pbUserId; + + // + // Following fields have been added in WEBAUTHN_ASSERTION_VERSION_2 + // + + WEBAUTHN_EXTENSIONS Extensions; + + // Size of pbCredLargeBlob + DWORD cbCredLargeBlob; + _Field_size_bytes_(cbCredLargeBlob) + PBYTE pbCredLargeBlob; + + DWORD dwCredLargeBlobStatus; + +} WEBAUTHN_ASSERTION, *PWEBAUTHN_ASSERTION; +typedef const WEBAUTHN_ASSERTION *PCWEBAUTHN_ASSERTION; + +//+------------------------------------------------------------------------------------------ +// APIs. +//------------------------------------------------------------------------------------------- + +DWORD +WINAPI +WebAuthNGetApiVersionNumber(); + +HRESULT +WINAPI +WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable( + _Out_ BOOL *pbIsUserVerifyingPlatformAuthenticatorAvailable); + + +HRESULT +WINAPI +WebAuthNAuthenticatorMakeCredential( + _In_ HWND hWnd, + _In_ PCWEBAUTHN_RP_ENTITY_INFORMATION pRpInformation, + _In_ PCWEBAUTHN_USER_ENTITY_INFORMATION pUserInformation, + _In_ PCWEBAUTHN_COSE_CREDENTIAL_PARAMETERS pPubKeyCredParams, + _In_ PCWEBAUTHN_CLIENT_DATA pWebAuthNClientData, + _In_opt_ PCWEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS pWebAuthNMakeCredentialOptions, + _Outptr_result_maybenull_ PWEBAUTHN_CREDENTIAL_ATTESTATION *ppWebAuthNCredentialAttestation); + + +HRESULT +WINAPI +WebAuthNAuthenticatorGetAssertion( + _In_ HWND hWnd, + _In_ LPCWSTR pwszRpId, + _In_ PCWEBAUTHN_CLIENT_DATA pWebAuthNClientData, + _In_opt_ PCWEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS pWebAuthNGetAssertionOptions, + _Outptr_result_maybenull_ PWEBAUTHN_ASSERTION *ppWebAuthNAssertion); + +void +WINAPI +WebAuthNFreeCredentialAttestation( + _In_opt_ PWEBAUTHN_CREDENTIAL_ATTESTATION pWebAuthNCredentialAttestation); + +void +WINAPI +WebAuthNFreeAssertion( + _In_ PWEBAUTHN_ASSERTION pWebAuthNAssertion); + +HRESULT +WINAPI +WebAuthNGetCancellationId( + _Out_ GUID* pCancellationId); + +HRESULT +WINAPI +WebAuthNCancelCurrentOperation( + _In_ const GUID* pCancellationId); + +// +// Returns the following Error Names: +// L"Success" - S_OK +// L"InvalidStateError" - NTE_EXISTS +// L"ConstraintError" - HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED), +// NTE_NOT_SUPPORTED, +// NTE_TOKEN_KEYSET_STORAGE_FULL +// L"NotSupportedError" - NTE_INVALID_PARAMETER +// L"NotAllowedError" - NTE_DEVICE_NOT_FOUND, +// NTE_NOT_FOUND, +// HRESULT_FROM_WIN32(ERROR_CANCELLED), +// NTE_USER_CANCELLED, +// HRESULT_FROM_WIN32(ERROR_TIMEOUT) +// L"UnknownError" - All other hr values +// +PCWSTR +WINAPI +WebAuthNGetErrorName( + _In_ HRESULT hr); + +HRESULT +WINAPI +WebAuthNGetW3CExceptionDOMError( + _In_ HRESULT hr); + + +#ifdef __cplusplus +} // Balance extern "C" above +#endif + +#endif // WINAPI_FAMILY_PARTITION +#pragma endregion + +#endif // __WEBAUTHN_H_ diff --git a/contrib/libfido2/src/winhello.c b/contrib/libfido2/src/winhello.c index 0fe5b4cfe4c7..4797ac58281e 100644 --- a/contrib/libfido2/src/winhello.c +++ b/contrib/libfido2/src/winhello.c @@ -1,934 +1,941 @@ /* * Copyright (c) 2021 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include -#include #include "fido.h" +#include "webauthn.h" #define MAXCHARS 128 #define MAXCREDS 128 #define MAXMSEC 6000 * 1000 #define VENDORID 0x045e #define PRODID 0x0001 struct winhello_assert { WEBAUTHN_CLIENT_DATA cd; WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS opt; WEBAUTHN_ASSERTION *assert; wchar_t *rp_id; }; struct winhello_cred { WEBAUTHN_RP_ENTITY_INFORMATION rp; WEBAUTHN_USER_ENTITY_INFORMATION user; WEBAUTHN_COSE_CREDENTIAL_PARAMETER alg; WEBAUTHN_COSE_CREDENTIAL_PARAMETERS cose; WEBAUTHN_CLIENT_DATA cd; WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS opt; WEBAUTHN_CREDENTIAL_ATTESTATION *att; wchar_t *rp_id; wchar_t *rp_name; wchar_t *user_name; wchar_t *user_icon; wchar_t *display_name; }; +static TLS BOOL webauthn_loaded; +static TLS HMODULE webauthn_handle; +static TLS DWORD (*webauthn_get_api_version)(void); +static TLS PCWSTR (*webauthn_strerr)(HRESULT); +static TLS HRESULT (*webauthn_get_assert)(HWND, LPCWSTR, + PCWEBAUTHN_CLIENT_DATA, + PCWEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS, + PWEBAUTHN_ASSERTION *); +static TLS HRESULT (*webauthn_make_cred)(HWND, + PCWEBAUTHN_RP_ENTITY_INFORMATION, + PCWEBAUTHN_USER_ENTITY_INFORMATION, + PCWEBAUTHN_COSE_CREDENTIAL_PARAMETERS, + PCWEBAUTHN_CLIENT_DATA, + PCWEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS, + PWEBAUTHN_CREDENTIAL_ATTESTATION *); +static TLS void (*webauthn_free_assert)(PWEBAUTHN_ASSERTION); +static TLS void (*webauthn_free_attest)(PWEBAUTHN_CREDENTIAL_ATTESTATION); + +static int +webauthn_load(void) +{ + if (webauthn_loaded || webauthn_handle != NULL) { + fido_log_debug("%s: already loaded", __func__); + return -1; + } + if ((webauthn_handle = LoadLibrary("webauthn.dll")) == NULL) { + fido_log_debug("%s: LoadLibrary", __func__); + return -1; + } + + if ((webauthn_get_api_version = (void *)GetProcAddress(webauthn_handle, + "WebAuthNGetApiVersionNumber")) == NULL) { + fido_log_debug("%s: WebAuthNGetApiVersionNumber", __func__); + goto fail; + } + if ((webauthn_strerr = (void *)GetProcAddress(webauthn_handle, + "WebAuthNGetErrorName")) == NULL) { + fido_log_debug("%s: WebAuthNGetErrorName", __func__); + goto fail; + } + if ((webauthn_get_assert = (void *)GetProcAddress(webauthn_handle, + "WebAuthNAuthenticatorGetAssertion")) == NULL) { + fido_log_debug("%s: WebAuthNAuthenticatorGetAssertion", + __func__); + goto fail; + } + if ((webauthn_make_cred = (void *)GetProcAddress(webauthn_handle, + "WebAuthNAuthenticatorMakeCredential")) == NULL) { + fido_log_debug("%s: WebAuthNAuthenticatorMakeCredential", + __func__); + goto fail; + } + if ((webauthn_free_assert = (void *)GetProcAddress(webauthn_handle, + "WebAuthNFreeAssertion")) == NULL) { + fido_log_debug("%s: WebAuthNFreeAssertion", __func__); + goto fail; + } + if ((webauthn_free_attest = (void *)GetProcAddress(webauthn_handle, + "WebAuthNFreeCredentialAttestation")) == NULL) { + fido_log_debug("%s: WebAuthNFreeCredentialAttestation", + __func__); + goto fail; + } + + webauthn_loaded = true; + + return 0; +fail: + fido_log_debug("%s: GetProcAddress", __func__); + webauthn_get_api_version = NULL; + webauthn_strerr = NULL; + webauthn_get_assert = NULL; + webauthn_make_cred = NULL; + webauthn_free_assert = NULL; + webauthn_free_attest = NULL; + FreeLibrary(webauthn_handle); + webauthn_handle = NULL; + + return -1; +} + static wchar_t * to_utf16(const char *utf8) { int nch; wchar_t *utf16; if (utf8 == NULL) { fido_log_debug("%s: NULL", __func__); return NULL; } if ((nch = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0)) < 1 || (size_t)nch > MAXCHARS) { fido_log_debug("%s: MultiByteToWideChar %d", __func__, nch); return NULL; } if ((utf16 = calloc((size_t)nch, sizeof(*utf16))) == NULL) { fido_log_debug("%s: calloc", __func__); return NULL; } if (MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, nch) != nch) { fido_log_debug("%s: MultiByteToWideChar", __func__); free(utf16); return NULL; } return utf16; } static char * to_utf8(const wchar_t *utf16) { int nch; char *utf8; if (utf16 == NULL) { fido_log_debug("%s: NULL", __func__); return NULL; } if ((nch = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, utf16, -1, NULL, 0, NULL, NULL)) < 1 || (size_t)nch > MAXCHARS) { fido_log_debug("%s: WideCharToMultiByte %d", __func__); return NULL; } if ((utf8 = calloc((size_t)nch, sizeof(*utf8))) == NULL) { fido_log_debug("%s: calloc", __func__); return NULL; } if (WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, utf16, -1, utf8, nch, NULL, NULL) != nch) { fido_log_debug("%s: WideCharToMultiByte", __func__); free(utf8); return NULL; } return utf8; } -static int -to_fido_str_array(fido_str_array_t *sa, const char **v, size_t n) -{ - if ((sa->ptr = calloc(n, sizeof(char *))) == NULL) { - fido_log_debug("%s: calloc", __func__); - return -1; - } - for (size_t i = 0; i < n; i++) { - if ((sa->ptr[i] = strdup(v[i])) == NULL) { - fido_log_debug("%s: strdup", __func__); - return -1; - } - sa->len++; - } - - return 0; -} - static int to_fido(HRESULT hr) { switch (hr) { case NTE_NOT_SUPPORTED: return FIDO_ERR_UNSUPPORTED_OPTION; case NTE_INVALID_PARAMETER: return FIDO_ERR_INVALID_PARAMETER; case NTE_TOKEN_KEYSET_STORAGE_FULL: return FIDO_ERR_KEY_STORE_FULL; case NTE_DEVICE_NOT_FOUND: case NTE_NOT_FOUND: return FIDO_ERR_NOT_ALLOWED; default: fido_log_debug("%s: hr=0x%x", __func__, hr); return FIDO_ERR_INTERNAL; } } static int pack_cd(WEBAUTHN_CLIENT_DATA *out, const fido_blob_t *in) { if (in->ptr == NULL) { fido_log_debug("%s: NULL", __func__); return -1; } if (in->len > ULONG_MAX) { fido_log_debug("%s: in->len=%zu", __func__, in->len); return -1; } out->dwVersion = WEBAUTHN_CLIENT_DATA_CURRENT_VERSION; out->cbClientDataJSON = (DWORD)in->len; out->pbClientDataJSON = in->ptr; out->pwszHashAlgId = WEBAUTHN_HASH_ALGORITHM_SHA_256; return 0; } static int pack_credlist(WEBAUTHN_CREDENTIALS *out, const fido_blob_array_t *in) { WEBAUTHN_CREDENTIAL *c; if (in->len == 0) { return 0; /* nothing to do */ } if (in->len > MAXCREDS) { fido_log_debug("%s: in->len=%zu", __func__, in->len); return -1; } if ((out->pCredentials = calloc(in->len, sizeof(*c))) == NULL) { fido_log_debug("%s: calloc", __func__); return -1; } out->cCredentials = (DWORD)in->len; for (size_t i = 0; i < in->len; i++) { if (in->ptr[i].len > ULONG_MAX) { fido_log_debug("%s: %zu", __func__, in->ptr[i].len); return -1; } c = &out->pCredentials[i]; c->dwVersion = WEBAUTHN_CREDENTIAL_CURRENT_VERSION; c->cbId = (DWORD)in->ptr[i].len; c->pbId = in->ptr[i].ptr; c->pwszCredentialType = WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY; } return 0; } static int set_uv(DWORD *out, fido_opt_t uv, const char *pin) { if (pin) { *out = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED; return 0; } switch (uv) { case FIDO_OPT_OMIT: *out = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY; break; case FIDO_OPT_FALSE: *out = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED; break; case FIDO_OPT_TRUE: *out = WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED; break; } return 0; } static int pack_rp(wchar_t **id, wchar_t **name, WEBAUTHN_RP_ENTITY_INFORMATION *out, - fido_rp_t *in) + const fido_rp_t *in) { /* keep non-const copies of pwsz* for free() */ out->dwVersion = WEBAUTHN_RP_ENTITY_INFORMATION_CURRENT_VERSION; if ((out->pwszId = *id = to_utf16(in->id)) == NULL) { fido_log_debug("%s: id", __func__); return -1; } if (in->name && (out->pwszName = *name = to_utf16(in->name)) == NULL) { fido_log_debug("%s: name", __func__); return -1; } return 0; } static int pack_user(wchar_t **name, wchar_t **icon, wchar_t **display_name, - WEBAUTHN_USER_ENTITY_INFORMATION *out, fido_user_t *in) + WEBAUTHN_USER_ENTITY_INFORMATION *out, const fido_user_t *in) { if (in->id.ptr == NULL || in->id.len > ULONG_MAX) { fido_log_debug("%s: id", __func__); return -1; } out->dwVersion = WEBAUTHN_USER_ENTITY_INFORMATION_CURRENT_VERSION; out->cbId = (DWORD)in->id.len; out->pbId = in->id.ptr; /* keep non-const copies of pwsz* for free() */ if (in->name != NULL) { if ((out->pwszName = *name = to_utf16(in->name)) == NULL) { fido_log_debug("%s: name", __func__); return -1; } } if (in->icon != NULL) { if ((out->pwszIcon = *icon = to_utf16(in->icon)) == NULL) { fido_log_debug("%s: icon", __func__); return -1; } } if (in->display_name != NULL) { if ((out->pwszDisplayName = *display_name = to_utf16(in->display_name)) == NULL) { fido_log_debug("%s: display_name", __func__); return -1; } } return 0; } static int pack_cose(WEBAUTHN_COSE_CREDENTIAL_PARAMETER *alg, WEBAUTHN_COSE_CREDENTIAL_PARAMETERS *cose, int type) { switch (type) { case COSE_ES256: alg->lAlg = WEBAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256; break; case COSE_EDDSA: alg->lAlg = -8; /* XXX */; break; case COSE_RS256: alg->lAlg = WEBAUTHN_COSE_ALGORITHM_RSASSA_PKCS1_V1_5_WITH_SHA256; break; default: fido_log_debug("%s: type %d", __func__, type); return -1; } alg->dwVersion = WEBAUTHN_COSE_CREDENTIAL_PARAMETER_CURRENT_VERSION; alg->pwszCredentialType = WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY; cose->cCredentialParameters = 1; cose->pCredentialParameters = alg; return 0; } static int -pack_cred_ext(WEBAUTHN_EXTENSIONS *out, fido_cred_ext_t *in) +pack_cred_ext(WEBAUTHN_EXTENSIONS *out, const fido_cred_ext_t *in) { WEBAUTHN_EXTENSION *e; WEBAUTHN_CRED_PROTECT_EXTENSION_IN *p; BOOL *b; size_t n = 0, i = 0; if (in->mask == 0) { return 0; /* nothing to do */ } if (in->mask & ~(FIDO_EXT_HMAC_SECRET | FIDO_EXT_CRED_PROTECT)) { fido_log_debug("%s: mask 0x%x", in->mask); return -1; } if (in->mask & FIDO_EXT_HMAC_SECRET) n++; if (in->mask & FIDO_EXT_CRED_PROTECT) n++; if ((out->pExtensions = calloc(n, sizeof(*e))) == NULL) { fido_log_debug("%s: calloc", __func__); return -1; } out->cExtensions = (DWORD)n; if (in->mask & FIDO_EXT_HMAC_SECRET) { if ((b = calloc(1, sizeof(*b))) == NULL) { fido_log_debug("%s: calloc", __func__); return -1; } *b = true; e = &out->pExtensions[i]; e->pwszExtensionIdentifier = WEBAUTHN_EXTENSIONS_IDENTIFIER_HMAC_SECRET; e->pvExtension = b; e->cbExtension = sizeof(*b); i++; } if (in->mask & FIDO_EXT_CRED_PROTECT) { if ((p = calloc(1, sizeof(*p))) == NULL) { fido_log_debug("%s: calloc", __func__); return -1; } p->dwCredProtect = (DWORD)in->prot; p->bRequireCredProtect = true; e = &out->pExtensions[i]; e->pwszExtensionIdentifier = WEBAUTHN_EXTENSIONS_IDENTIFIER_CRED_PROTECT; e->pvExtension = p; e->cbExtension = sizeof(*p); i++; } return 0; } static int -unpack_fmt(fido_cred_t *cred, WEBAUTHN_CREDENTIAL_ATTESTATION *att) -{ - char *fmt; - int r; - - if ((fmt = to_utf8(att->pwszFormatType)) == NULL) { - fido_log_debug("%s: fmt", __func__); - return -1; - } - r = fido_cred_set_fmt(cred, fmt); - free(fmt); - fmt = NULL; - if (r != FIDO_OK) { - fido_log_debug("%s: fido_cred_set_fmt: %s", __func__, - fido_strerr(r)); - return -1; - } - - return 0; -} - -static int -unpack_cred_authdata(fido_cred_t *cred, WEBAUTHN_CREDENTIAL_ATTESTATION *att) -{ - int r; - - if (att->cbAuthenticatorData > SIZE_MAX) { - fido_log_debug("%s: cbAuthenticatorData", __func__); - return -1; - } - if ((r = fido_cred_set_authdata_raw(cred, att->pbAuthenticatorData, - (size_t)att->cbAuthenticatorData)) != FIDO_OK) { - fido_log_debug("%s: fido_cred_set_authdata_raw: %s", __func__, - fido_strerr(r)); - return -1; - } - - return 0; -} - -static int -unpack_cred_sig(fido_cred_t *cred, WEBAUTHN_COMMON_ATTESTATION *attr) -{ - int r; - - if (attr->cbSignature > SIZE_MAX) { - fido_log_debug("%s: cbSignature", __func__); - return -1; - } - if ((r = fido_cred_set_sig(cred, attr->pbSignature, - (size_t)attr->cbSignature)) != FIDO_OK) { - fido_log_debug("%s: fido_cred_set_sig: %s", __func__, - fido_strerr(r)); - return -1; - } - - return 0; -} - -static int -unpack_x5c(fido_cred_t *cred, WEBAUTHN_COMMON_ATTESTATION *attr) -{ - int r; - - fido_log_debug("%s: %u cert(s)", __func__, attr->cX5c); - - if (attr->cX5c == 0) - return 0; /* self-attestation */ - if (attr->lAlg != WEBAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256) { - fido_log_debug("%s: lAlg %d", __func__, attr->lAlg); - return -1; - } - if (attr->pX5c[0].cbData > SIZE_MAX) { - fido_log_debug("%s: cbData", __func__); - return -1; - } - if ((r = fido_cred_set_x509(cred, attr->pX5c[0].pbData, - (size_t)attr->pX5c[0].cbData)) != FIDO_OK) { - fido_log_debug("%s: fido_cred_set_x509: %s", __func__, - fido_strerr(r)); - return -1; - } - - return 0; -} - -static int -unpack_assert_authdata(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa) +unpack_assert_authdata(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa) { int r; if (wa->cbAuthenticatorData > SIZE_MAX) { fido_log_debug("%s: cbAuthenticatorData", __func__); return -1; } if ((r = fido_assert_set_authdata_raw(assert, 0, wa->pbAuthenticatorData, (size_t)wa->cbAuthenticatorData)) != FIDO_OK) { fido_log_debug("%s: fido_assert_set_authdata_raw: %s", __func__, fido_strerr(r)); return -1; } return 0; } static int -unpack_assert_sig(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa) +unpack_assert_sig(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa) { int r; if (wa->cbSignature > SIZE_MAX) { fido_log_debug("%s: cbSignature", __func__); return -1; } if ((r = fido_assert_set_sig(assert, 0, wa->pbSignature, (size_t)wa->cbSignature)) != FIDO_OK) { fido_log_debug("%s: fido_assert_set_sig: %s", __func__, fido_strerr(r)); return -1; } return 0; } static int -unpack_cred_id(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa) +unpack_cred_id(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa) { if (wa->Credential.cbId > SIZE_MAX) { fido_log_debug("%s: Credential.cbId", __func__); return -1; } if (fido_blob_set(&assert->stmt[0].id, wa->Credential.pbId, (size_t)wa->Credential.cbId) < 0) { fido_log_debug("%s: fido_blob_set", __func__); return -1; } return 0; } static int -unpack_user_id(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa) +unpack_user_id(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa) { if (wa->cbUserId == 0) return 0; /* user id absent */ if (wa->cbUserId > SIZE_MAX) { fido_log_debug("%s: cbUserId", __func__); return -1; } if (fido_blob_set(&assert->stmt[0].user.id, wa->pbUserId, (size_t)wa->cbUserId) < 0) { fido_log_debug("%s: fido_blob_set", __func__); return -1; } return 0; } static int -translate_fido_assert(struct winhello_assert *ctx, fido_assert_t *assert, - const char *pin) +translate_fido_assert(struct winhello_assert *ctx, const fido_assert_t *assert, + const char *pin, int ms) { WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS *opt; /* not supported by webauthn.h */ if (assert->up == FIDO_OPT_FALSE) { fido_log_debug("%s: up %d", __func__, assert->up); return FIDO_ERR_UNSUPPORTED_OPTION; } /* not implemented */ if (assert->ext.mask) { fido_log_debug("%s: ext 0x%x", __func__, assert->ext.mask); return FIDO_ERR_UNSUPPORTED_EXTENSION; } if ((ctx->rp_id = to_utf16(assert->rp_id)) == NULL) { fido_log_debug("%s: rp_id", __func__); return FIDO_ERR_INTERNAL; } if (pack_cd(&ctx->cd, &assert->cd) < 0) { fido_log_debug("%s: pack_cd", __func__); return FIDO_ERR_INTERNAL; } /* options */ opt = &ctx->opt; opt->dwVersion = WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_1; - opt->dwTimeoutMilliseconds = MAXMSEC; + opt->dwTimeoutMilliseconds = ms < 0 ? MAXMSEC : (DWORD)ms; if (pack_credlist(&opt->CredentialList, &assert->allow_list) < 0) { fido_log_debug("%s: pack_credlist", __func__); return FIDO_ERR_INTERNAL; } if (set_uv(&opt->dwUserVerificationRequirement, assert->uv, pin) < 0) { fido_log_debug("%s: set_uv", __func__); return FIDO_ERR_INTERNAL; } return FIDO_OK; } static int -translate_winhello_assert(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa) +translate_winhello_assert(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa) { int r; if (assert->stmt_len > 0) { fido_log_debug("%s: stmt_len=%zu", __func__, assert->stmt_len); return FIDO_ERR_INTERNAL; } if ((r = fido_assert_set_count(assert, 1)) != FIDO_OK) { fido_log_debug("%s: fido_assert_set_count: %s", __func__, fido_strerr(r)); return FIDO_ERR_INTERNAL; } if (unpack_assert_authdata(assert, wa) < 0) { fido_log_debug("%s: unpack_assert_authdata", __func__); return FIDO_ERR_INTERNAL; } if (unpack_assert_sig(assert, wa) < 0) { fido_log_debug("%s: unpack_assert_sig", __func__); return FIDO_ERR_INTERNAL; } if (unpack_cred_id(assert, wa) < 0) { fido_log_debug("%s: unpack_cred_id", __func__); return FIDO_ERR_INTERNAL; } if (unpack_user_id(assert, wa) < 0) { fido_log_debug("%s: unpack_user_id", __func__); return FIDO_ERR_INTERNAL; } return FIDO_OK; } static int -translate_fido_cred(struct winhello_cred *ctx, fido_cred_t *cred, - const char *pin) +translate_fido_cred(struct winhello_cred *ctx, const fido_cred_t *cred, + const char *pin, int ms) { WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS *opt; if (pack_rp(&ctx->rp_id, &ctx->rp_name, &ctx->rp, &cred->rp) < 0) { fido_log_debug("%s: pack_rp", __func__); return FIDO_ERR_INTERNAL; } if (pack_user(&ctx->user_name, &ctx->user_icon, &ctx->display_name, &ctx->user, &cred->user) < 0) { fido_log_debug("%s: pack_user", __func__); return FIDO_ERR_INTERNAL; } if (pack_cose(&ctx->alg, &ctx->cose, cred->type) < 0) { fido_log_debug("%s: pack_cose", __func__); return FIDO_ERR_INTERNAL; } if (pack_cd(&ctx->cd, &cred->cd) < 0) { fido_log_debug("%s: pack_cd", __func__); return FIDO_ERR_INTERNAL; } /* options */ opt = &ctx->opt; opt->dwVersion = WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_1; - opt->dwTimeoutMilliseconds = MAXMSEC; + opt->dwTimeoutMilliseconds = ms < 0 ? MAXMSEC : (DWORD)ms; + opt->dwAttestationConveyancePreference = + WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT; if (pack_credlist(&opt->CredentialList, &cred->excl) < 0) { fido_log_debug("%s: pack_credlist", __func__); return FIDO_ERR_INTERNAL; } if (pack_cred_ext(&opt->Extensions, &cred->ext) < 0) { fido_log_debug("%s: pack_cred_ext", __func__); return FIDO_ERR_UNSUPPORTED_EXTENSION; } - if (set_uv(&opt->dwUserVerificationRequirement, cred->uv, pin) < 0) { + if (set_uv(&opt->dwUserVerificationRequirement, (cred->ext.mask & + FIDO_EXT_CRED_PROTECT) ? FIDO_OPT_TRUE : cred->uv, pin) < 0) { fido_log_debug("%s: set_uv", __func__); return FIDO_ERR_INTERNAL; } if (cred->rk == FIDO_OPT_TRUE) { opt->bRequireResidentKey = true; } return FIDO_OK; } static int -translate_winhello_cred(fido_cred_t *cred, WEBAUTHN_CREDENTIAL_ATTESTATION *att) +decode_attobj(const cbor_item_t *key, const cbor_item_t *val, void *arg) { - if (unpack_fmt(cred, att) < 0) { - fido_log_debug("%s: unpack_fmt", __func__); - return FIDO_ERR_INTERNAL; - } - if (unpack_cred_authdata(cred, att) < 0) { - fido_log_debug("%s: unpack_cred_authdata", __func__); - return FIDO_ERR_INTERNAL; + fido_cred_t *cred = arg; + char *name = NULL; + int ok = -1; + + if (cbor_string_copy(key, &name) < 0) { + fido_log_debug("%s: cbor type", __func__); + ok = 0; /* ignore */ + goto fail; } - switch (att->dwAttestationDecodeType) { - case WEBAUTHN_ATTESTATION_DECODE_NONE: - if (att->pvAttestationDecode != NULL) { - fido_log_debug("%s: pvAttestationDecode", __func__); - return FIDO_ERR_INTERNAL; + if (!strcmp(name, "fmt")) { + if (cbor_decode_fmt(val, &cred->fmt) < 0) { + fido_log_debug("%s: cbor_decode_fmt", __func__); + goto fail; } - break; - case WEBAUTHN_ATTESTATION_DECODE_COMMON: - if (att->pvAttestationDecode == NULL) { - fido_log_debug("%s: pvAttestationDecode", __func__); - return FIDO_ERR_INTERNAL; + } else if (!strcmp(name, "attStmt")) { + if (cbor_decode_attstmt(val, &cred->attstmt) < 0) { + fido_log_debug("%s: cbor_decode_attstmt", __func__); + goto fail; } - if (unpack_cred_sig(cred, att->pvAttestationDecode) < 0) { - fido_log_debug("%s: unpack_cred_sig", __func__); - return FIDO_ERR_INTERNAL; + } else if (!strcmp(name, "authData")) { + if (cbor_decode_cred_authdata(val, cred->type, + &cred->authdata_cbor, &cred->authdata, &cred->attcred, + &cred->authdata_ext) < 0) { + fido_log_debug("%s: cbor_decode_cred_authdata", + __func__); + goto fail; } - if (unpack_x5c(cred, att->pvAttestationDecode) < 0) { - fido_log_debug("%s: unpack_x5c", __func__); - return FIDO_ERR_INTERNAL; - } - break; - default: - fido_log_debug("%s: dwAttestationDecodeType: %u", __func__, - att->dwAttestationDecodeType); - return FIDO_ERR_INTERNAL; } - return FIDO_OK; + ok = 0; +fail: + free(name); + + return (ok); } static int -winhello_manifest(BOOL *present) +translate_winhello_cred(fido_cred_t *cred, const WEBAUTHN_CREDENTIAL_ATTESTATION *att) +{ + + cbor_item_t *item = NULL; + struct cbor_load_result cbor; + int r = FIDO_ERR_INTERNAL; + + if (att->pbAttestationObject == NULL || + att->cbAttestationObject > SIZE_MAX) { + fido_log_debug("%s: pbAttestationObject", __func__); + goto fail; + } + if ((item = cbor_load(att->pbAttestationObject, + (size_t)att->cbAttestationObject, &cbor)) == NULL) { + fido_log_debug("%s: cbor_load", __func__); + goto fail; + } + if (cbor_isa_map(item) == false || + cbor_map_is_definite(item) == false || + cbor_map_iter(item, cred, decode_attobj) < 0) { + fido_log_debug("%s: cbor type", __func__); + goto fail; + } + + r = FIDO_OK; +fail: + if (item != NULL) + cbor_decref(&item); + + return r; +} + +static int +winhello_manifest(void) { DWORD n; - HRESULT hr; - int r = FIDO_OK; - if ((n = WebAuthNGetApiVersionNumber()) < 1) { + if (!webauthn_loaded && webauthn_load() < 0) { + fido_log_debug("%s: webauthn_load", __func__); + return FIDO_ERR_INTERNAL; + } + if ((n = webauthn_get_api_version()) < 1) { fido_log_debug("%s: unsupported api %u", __func__, n); return FIDO_ERR_INTERNAL; } fido_log_debug("%s: api version %u", __func__, n); - hr = WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable(present); - if (hr != S_OK) { - r = to_fido(hr); - fido_log_debug("%s: %ls -> %s", __func__, - WebAuthNGetErrorName(hr), fido_strerr(r)); - } - return r; + return FIDO_OK; } static int winhello_get_assert(HWND w, struct winhello_assert *ctx) { HRESULT hr; int r = FIDO_OK; - hr = WebAuthNAuthenticatorGetAssertion(w, ctx->rp_id, &ctx->cd, - &ctx->opt, &ctx->assert); - if (hr != S_OK) { + if ((hr = webauthn_get_assert(w, ctx->rp_id, &ctx->cd, &ctx->opt, + &ctx->assert)) != S_OK) { r = to_fido(hr); - fido_log_debug("%s: %ls -> %s", __func__, - WebAuthNGetErrorName(hr), fido_strerr(r)); + fido_log_debug("%s: %ls -> %s", __func__, webauthn_strerr(hr), + fido_strerr(r)); } return r; } static int winhello_make_cred(HWND w, struct winhello_cred *ctx) { HRESULT hr; int r = FIDO_OK; - hr = WebAuthNAuthenticatorMakeCredential(w, &ctx->rp, &ctx->user, - &ctx->cose, &ctx->cd, &ctx->opt, &ctx->att); - if (hr != S_OK) { + if ((hr = webauthn_make_cred(w, &ctx->rp, &ctx->user, &ctx->cose, + &ctx->cd, &ctx->opt, &ctx->att)) != S_OK) { r = to_fido(hr); - fido_log_debug("%s: %ls -> %s", __func__, - WebAuthNGetErrorName(hr), fido_strerr(r)); + fido_log_debug("%s: %ls -> %s", __func__, webauthn_strerr(hr), + fido_strerr(r)); } return r; } static void winhello_assert_free(struct winhello_assert *ctx) { if (ctx == NULL) return; if (ctx->assert != NULL) - WebAuthNFreeAssertion(ctx->assert); + webauthn_free_assert(ctx->assert); free(ctx->rp_id); free(ctx->opt.CredentialList.pCredentials); free(ctx); } static void winhello_cred_free(struct winhello_cred *ctx) { if (ctx == NULL) return; if (ctx->att != NULL) - WebAuthNFreeCredentialAttestation(ctx->att); + webauthn_free_attest(ctx->att); free(ctx->rp_id); free(ctx->rp_name); free(ctx->user_name); free(ctx->user_icon); free(ctx->display_name); free(ctx->opt.CredentialList.pCredentials); for (size_t i = 0; i < ctx->opt.Extensions.cExtensions; i++) { WEBAUTHN_EXTENSION *e; e = &ctx->opt.Extensions.pExtensions[i]; free(e->pvExtension); } free(ctx->opt.Extensions.pExtensions); free(ctx); } int fido_winhello_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { int r; - BOOL present; fido_dev_info_t *di; if (ilen == 0) { return FIDO_OK; } if (devlist == NULL) { return FIDO_ERR_INVALID_ARGUMENT; } - if ((r = winhello_manifest(&present)) != FIDO_OK) { + if ((r = winhello_manifest()) != FIDO_OK) { fido_log_debug("%s: winhello_manifest", __func__); return r; } - if (present == false) { - fido_log_debug("%s: not present", __func__); - return FIDO_OK; - } di = &devlist[*olen]; memset(di, 0, sizeof(*di)); di->path = strdup(FIDO_WINHELLO_PATH); di->manufacturer = strdup("Microsoft Corporation"); di->product = strdup("Windows Hello"); di->vendor_id = VENDORID; di->product_id = PRODID; if (di->path == NULL || di->manufacturer == NULL || di->product == NULL) { free(di->path); free(di->manufacturer); free(di->product); explicit_bzero(di, sizeof(*di)); return FIDO_ERR_INTERNAL; } ++(*olen); return FIDO_OK; } int fido_winhello_open(fido_dev_t *dev) { + if (!webauthn_loaded && webauthn_load() < 0) { + fido_log_debug("%s: webauthn_load", __func__); + return FIDO_ERR_INTERNAL; + } if (dev->flags != 0) return FIDO_ERR_INVALID_ARGUMENT; - dev->attr.flags = FIDO_CAP_CBOR | FIDO_CAP_WINK; dev->flags = FIDO_DEV_WINHELLO | FIDO_DEV_CRED_PROT | FIDO_DEV_PIN_SET; return FIDO_OK; } int fido_winhello_close(fido_dev_t *dev) { memset(dev, 0, sizeof(*dev)); return FIDO_OK; } int fido_winhello_cancel(fido_dev_t *dev) { (void)dev; return FIDO_ERR_INTERNAL; } int fido_winhello_get_assert(fido_dev_t *dev, fido_assert_t *assert, - const char *pin) + const char *pin, int ms) { HWND w; struct winhello_assert *ctx; int r = FIDO_ERR_INTERNAL; (void)dev; + fido_assert_reset_rx(assert); + if ((ctx = calloc(1, sizeof(*ctx))) == NULL) { fido_log_debug("%s: calloc", __func__); goto fail; } if ((w = GetForegroundWindow()) == NULL) { fido_log_debug("%s: GetForegroundWindow", __func__); goto fail; } - if ((r = translate_fido_assert(ctx, assert, pin)) != FIDO_OK) { + if ((r = translate_fido_assert(ctx, assert, pin, ms)) != FIDO_OK) { fido_log_debug("%s: translate_fido_assert", __func__); goto fail; } if ((r = winhello_get_assert(w, ctx)) != S_OK) { fido_log_debug("%s: winhello_get_assert", __func__); goto fail; } if ((r = translate_winhello_assert(assert, ctx->assert)) != FIDO_OK) { fido_log_debug("%s: translate_winhello_assert", __func__); goto fail; } fail: winhello_assert_free(ctx); return r; } int fido_winhello_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci) { const char *v[3] = { "U2F_V2", "FIDO_2_0", "FIDO_2_1_PRE" }; const char *e[2] = { "credProtect", "hmac-secret" }; const char *t[2] = { "nfc", "usb" }; const char *o[4] = { "rk", "up", "plat", "clientPin" }; (void)dev; fido_cbor_info_reset(ci); - if (to_fido_str_array(&ci->versions, v, nitems(v)) < 0 || - to_fido_str_array(&ci->extensions, e, nitems(e)) < 0 || - to_fido_str_array(&ci->transports, t, nitems(t)) < 0) { - fido_log_debug("%s: to_fido_str_array", __func__); + if (fido_str_array_pack(&ci->versions, v, nitems(v)) < 0 || + fido_str_array_pack(&ci->extensions, e, nitems(e)) < 0 || + fido_str_array_pack(&ci->transports, t, nitems(t)) < 0) { + fido_log_debug("%s: fido_str_array_pack", __func__); return FIDO_ERR_INTERNAL; } if ((ci->options.name = calloc(nitems(o), sizeof(char *))) == NULL || (ci->options.value = calloc(nitems(o), sizeof(bool))) == NULL) { fido_log_debug("%s: calloc", __func__); return FIDO_ERR_INTERNAL; } for (size_t i = 0; i < nitems(o); i++) { if ((ci->options.name[i] = strdup(o[i])) == NULL) { fido_log_debug("%s: strdup", __func__); return FIDO_ERR_INTERNAL; } ci->options.value[i] = true; ci->options.len++; } return FIDO_OK; } int -fido_winhello_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin) +fido_winhello_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin, + int ms) { HWND w; struct winhello_cred *ctx; int r = FIDO_ERR_INTERNAL; (void)dev; + fido_cred_reset_rx(cred); + if ((ctx = calloc(1, sizeof(*ctx))) == NULL) { fido_log_debug("%s: calloc", __func__); goto fail; } if ((w = GetForegroundWindow()) == NULL) { fido_log_debug("%s: GetForegroundWindow", __func__); goto fail; } - if ((r = translate_fido_cred(ctx, cred, pin)) != FIDO_OK) { + if ((r = translate_fido_cred(ctx, cred, pin, ms)) != FIDO_OK) { fido_log_debug("%s: translate_fido_cred", __func__); goto fail; } if ((r = winhello_make_cred(w, ctx)) != FIDO_OK) { fido_log_debug("%s: winhello_make_cred", __func__); goto fail; } if ((r = translate_winhello_cred(cred, ctx->att)) != FIDO_OK) { fido_log_debug("%s: translate_winhello_cred", __func__); goto fail; } r = FIDO_OK; fail: winhello_cred_free(ctx); return r; } diff --git a/contrib/libfido2/tools/CMakeLists.txt b/contrib/libfido2/tools/CMakeLists.txt index b1dde9949c4f..f37aa1d87c97 100644 --- a/contrib/libfido2/tools/CMakeLists.txt +++ b/contrib/libfido2/tools/CMakeLists.txt @@ -1,77 +1,80 @@ # Copyright (c) 2018 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. list(APPEND COMPAT_SOURCES + ../openbsd-compat/bsd-getpagesize.c ../openbsd-compat/explicit_bzero.c ../openbsd-compat/freezero.c + ../openbsd-compat/recallocarray.c ../openbsd-compat/strlcat.c ../openbsd-compat/strlcpy.c + ../openbsd-compat/strsep.c ) if(WIN32 AND NOT CYGWIN AND NOT MSYS) list(APPEND COMPAT_SOURCES ../openbsd-compat/bsd-getline.c ../openbsd-compat/endian_win32.c ../openbsd-compat/explicit_bzero_win32.c ../openbsd-compat/getopt_long.c ../openbsd-compat/readpassphrase_win32.c ) if (BUILD_SHARED_LIBS) list(APPEND COMPAT_SOURCES ../openbsd-compat/posix_win.c) endif() else() list(APPEND COMPAT_SOURCES ../openbsd-compat/readpassphrase.c) endif() if(NOT MSVC) set_source_files_properties(assert_get.c assert_verify.c base64.c bio.c config.c cred_make.c cred_verify.c credman.c fido2-assert.c fido2-cred.c fido2-token.c pin.c token.c util.c PROPERTIES COMPILE_FLAGS "-Wconversion -Wsign-conversion") endif() add_executable(fido2-cred fido2-cred.c cred_make.c cred_verify.c base64.c util.c ${COMPAT_SOURCES} ) add_executable(fido2-assert fido2-assert.c assert_get.c assert_verify.c base64.c util.c ${COMPAT_SOURCES} ) add_executable(fido2-token fido2-token.c base64.c bio.c config.c credman.c largeblob.c pin.c token.c util.c ${COMPAT_SOURCES} ) # set the library to link against if(BUILD_SHARED_LIBS) set(_FIDO2_LIBRARY fido2_shared) else() set(_FIDO2_LIBRARY fido2) endif() target_link_libraries(fido2-cred ${CRYPTO_LIBRARIES} ${_FIDO2_LIBRARY}) target_link_libraries(fido2-assert ${CRYPTO_LIBRARIES} ${_FIDO2_LIBRARY}) target_link_libraries(fido2-token ${CRYPTO_LIBRARIES} ${_FIDO2_LIBRARY}) install(TARGETS fido2-cred fido2-assert fido2-token DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/contrib/libfido2/tools/config.c b/contrib/libfido2/tools/config.c index 17dfe4457902..3eea4c9b6cf6 100644 --- a/contrib/libfido2/tools/config.c +++ b/contrib/libfido2/tools/config.c @@ -1,149 +1,197 @@ /* * Copyright (c) 2020 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" int config_entattest(char *path) { fido_dev_t *dev; char *pin = NULL; int r, ok = 1; dev = open_dev(path); if ((r = fido_dev_enable_entattest(dev, NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) { if ((pin = get_pin(path)) == NULL) goto out; r = fido_dev_enable_entattest(dev, pin); freezero(pin, PINBUF_LEN); pin = NULL; } if (r != FIDO_OK) { warnx("fido_dev_enable_entattest: %s (0x%x)", fido_strerr(r), r); goto out; } ok = 0; out: fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } int config_always_uv(char *path, int toggle) { fido_dev_t *dev; char *pin = NULL; int v, r, ok = 1; dev = open_dev(path); if (get_devopt(dev, "alwaysUv", &v) < 0) { warnx("%s: getdevopt", __func__); goto out; } if (v == -1) { warnx("%s: option not found", __func__); goto out; } if (v == toggle) { ok = 0; goto out; } if ((r = fido_dev_toggle_always_uv(dev, NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) { if ((pin = get_pin(path)) == NULL) goto out; r = fido_dev_toggle_always_uv(dev, pin); freezero(pin, PINBUF_LEN); pin = NULL; } if (r != FIDO_OK) { warnx("fido_dev_toggle_always_uv: %s (0x%x)", fido_strerr(r), r); goto out; } ok = 0; out: fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } int config_pin_minlen(char *path, const char *pinlen) { fido_dev_t *dev; char *pin = NULL; int len, r, ok = 1; dev = open_dev(path); if ((len = base10(pinlen)) < 0 || len > 63) { warnx("%s: len > 63", __func__); goto out; } if ((r = fido_dev_set_pin_minlen(dev, (size_t)len, NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) { if ((pin = get_pin(path)) == NULL) goto out; r = fido_dev_set_pin_minlen(dev, (size_t)len, pin); freezero(pin, PINBUF_LEN); pin = NULL; } if (r != FIDO_OK) { warnx("fido_dev_set_pin_minlen: %s (0x%x)", fido_strerr(r), r); goto out; } ok = 0; out: fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } int config_force_pin_change(char *path) { fido_dev_t *dev; char *pin = NULL; int r, ok = 1; dev = open_dev(path); if ((r = fido_dev_force_pin_change(dev, NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) { if ((pin = get_pin(path)) == NULL) goto out; r = fido_dev_force_pin_change(dev, pin); freezero(pin, PINBUF_LEN); pin = NULL; } if (r != FIDO_OK) { warnx("fido_dev_force_pin_change: %s (0x%x)", fido_strerr(r), r); goto out; } ok = 0; out: fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } + +int +config_pin_minlen_rpid(char *path, const char *rpids) +{ + fido_dev_t *dev; + char *otmp, *tmp, *cp; + char *pin = NULL, **rpid = NULL; + int r, ok = 1; + size_t n; + + if ((tmp = strdup(rpids)) == NULL) + err(1, "strdup"); + otmp = tmp; + for (n = 0; (cp = strsep(&tmp, ",")) != NULL; n++) { + if (n == SIZE_MAX || (rpid = recallocarray(rpid, n, n + 1, + sizeof(*rpid))) == NULL) + err(1, "recallocarray"); + if ((rpid[n] = strdup(cp)) == NULL) + err(1, "strdup"); + if (*rpid[n] == '\0') + errx(1, "empty rpid"); + } + free(otmp); + if (rpid == NULL || n == 0) + errx(1, "could not parse rp_id"); + dev = open_dev(path); + if ((r = fido_dev_set_pin_minlen_rpid(dev, (const char * const *)rpid, + n, NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) { + if ((pin = get_pin(path)) == NULL) + goto out; + r = fido_dev_set_pin_minlen_rpid(dev, (const char * const *)rpid, + n, pin); + freezero(pin, PINBUF_LEN); + pin = NULL; + } + if (r != FIDO_OK) { + warnx("fido_dev_set_pin_minlen_rpid: %s (0x%x)", + fido_strerr(r), r); + goto out; + } + + ok = 0; +out: + fido_dev_close(dev); + fido_dev_free(&dev); + + exit(ok); +} diff --git a/contrib/libfido2/tools/extern.h b/contrib/libfido2/tools/extern.h index 207c35894f8b..8b25dadd45ac 100644 --- a/contrib/libfido2/tools/extern.h +++ b/contrib/libfido2/tools/extern.h @@ -1,99 +1,100 @@ /* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #ifndef _EXTERN_H_ #define _EXTERN_H_ #include #include #include #include #include struct blob { unsigned char *ptr; size_t len; }; -#define TOKEN_OPT "CDGILPRSVabcdefi:k:l:n:p:ru" +#define TOKEN_OPT "CDGILPRSVabcdefi:k:l:m:n:p:ru" #define FLAG_DEBUG 0x01 #define FLAG_QUIET 0x02 #define FLAG_RK 0x04 #define FLAG_UV 0x08 #define FLAG_U2F 0x10 #define FLAG_HMAC 0x20 #define FLAG_UP 0x40 #define FLAG_LARGEBLOB 0x80 #define PINBUF_LEN 256 EC_KEY *read_ec_pubkey(const char *); fido_dev_t *open_dev(const char *); FILE *open_read(const char *); FILE *open_write(const char *); char *get_pin(const char *); const char *plural(size_t); const char *cose_string(int); const char *prot_string(int); int assert_get(int, char **); int assert_verify(int, char **); int base64_decode(const char *, void **, size_t *); int base64_encode(const void *, size_t, char **); int base64_read(FILE *, struct blob *); int bio_delete(const char *, const char *); int bio_enroll(const char *); void bio_info(fido_dev_t *); int bio_list(const char *); int bio_set_name(const char *, const char *, const char *); int blob_clean(const char *); int blob_list(const char *); int blob_delete(const char *, const char *, const char *, const char *); int blob_get(const char *, const char *, const char *, const char *, const char *); int blob_set(const char *, const char *, const char *, const char *, const char *); int config_always_uv(char *, int); int config_entattest(char *); int config_force_pin_change(char *); int config_pin_minlen(char *, const char *); +int config_pin_minlen_rpid(char *, const char *); int cose_type(const char *, int *); int cred_make(int, char **); int cred_verify(int, char **); int credman_delete_rk(const char *, const char *); int credman_update_rk(const char *, const char *, const char *, const char *, const char *); int credman_get_metadata(fido_dev_t *, const char *); int credman_list_rk(const char *, const char *); int credman_list_rp(const char *); int credman_print_rk(fido_dev_t *, const char *, const char *, const char *); int get_devopt(fido_dev_t *, const char *, int *); int pin_change(char *); int pin_set(char *); int should_retry_with_pin(const fido_dev_t *, int); int string_read(FILE *, char **); int token_config(int, char **, char *); int token_delete(int, char **, char *); int token_get(int, char **, char *); int token_info(int, char **, char *); int token_list(int, char **, char *); int token_reset(char *); int token_set(int, char **, char *); int write_ec_pubkey(FILE *, const void *, size_t); int write_rsa_pubkey(FILE *, const void *, size_t); int read_file(const char *, u_char **, size_t *); int write_file(const char *, const u_char *, size_t); RSA *read_rsa_pubkey(const char *); EVP_PKEY *read_eddsa_pubkey(const char *); int write_eddsa_pubkey(FILE *, const void *, size_t); void print_cred(FILE *, int, const fido_cred_t *); void usage(void); void xxd(const void *, size_t); int base10(const char *); #endif /* _EXTERN_H_ */ diff --git a/contrib/libfido2/tools/fido2-token.c b/contrib/libfido2/tools/fido2-token.c index c1539b8bc08e..e6d9f9f96381 100644 --- a/contrib/libfido2/tools/fido2-token.c +++ b/contrib/libfido2/tools/fido2-token.c @@ -1,107 +1,109 @@ /* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" static int action; void usage(void) { fprintf(stderr, "usage: fido2-token -C [-d] device\n" " fido2-token -Db [-k key_path] [-i cred_id -n rp_id] device\n" " fido2-token -Dei template_id device\n" " fido2-token -Du device\n" " fido2-token -Gb [-k key_path] [-i cred_id -n rp_id] blob_path device\n" " fido2-token -I [-cd] [-k rp_id -i cred_id] device\n" " fido2-token -L [-bder] [-k rp_id] [device]\n" " fido2-token -R [-d] device\n" " fido2-token -S [-adefu] [-l pin_length] [-i template_id -n template_name] device\n" " fido2-token -Sb [-k key_path] [-i cred_id -n rp_id] blob_path device\n" " fido2-token -Sc -i cred_id -k user_id -n name -p display_name device\n" +" fido2-token -Sm rp_id device\n" " fido2-token -V\n" ); exit(1); } static void setaction(int ch) { if (action) usage(); action = ch; } int main(int argc, char **argv) { int ch; int flags = 0; char *device; while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) { switch (ch) { case 'a': case 'b': case 'c': case 'e': case 'f': case 'i': case 'k': case 'l': + case 'm': case 'n': case 'p': case 'r': case 'u': break; /* ignore */ case 'd': flags = FIDO_DEBUG; break; default: setaction(ch); break; } } if (argc - optind < 1) device = NULL; else device = argv[argc - 1]; fido_init(flags); switch (action) { case 'C': return (pin_change(device)); case 'D': return (token_delete(argc, argv, device)); case 'G': return (token_get(argc, argv, device)); case 'I': return (token_info(argc, argv, device)); case 'L': return (token_list(argc, argv, device)); case 'R': return (token_reset(device)); case 'S': return (token_set(argc, argv, device)); case 'V': fprintf(stderr, "%d.%d.%d\n", _FIDO_MAJOR, _FIDO_MINOR, _FIDO_PATCH); exit(0); } usage(); /* NOTREACHED */ } diff --git a/contrib/libfido2/tools/token.c b/contrib/libfido2/tools/token.c index 4dcc2fea6dbd..3d165623fdbf 100644 --- a/contrib/libfido2/tools/token.c +++ b/contrib/libfido2/tools/token.c @@ -1,576 +1,582 @@ /* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" static void format_flags(char *ret, size_t retlen, uint8_t flags) { memset(ret, 0, retlen); if (flags & FIDO_CAP_WINK) { if (strlcat(ret, "wink,", retlen) >= retlen) goto toolong; } else { if (strlcat(ret, "nowink,", retlen) >= retlen) goto toolong; } if (flags & FIDO_CAP_CBOR) { if (strlcat(ret, " cbor,", retlen) >= retlen) goto toolong; } else { if (strlcat(ret, " nocbor,", retlen) >= retlen) goto toolong; } if (flags & FIDO_CAP_NMSG) { if (strlcat(ret, " nomsg", retlen) >= retlen) goto toolong; } else { if (strlcat(ret, " msg", retlen) >= retlen) goto toolong; } return; toolong: strlcpy(ret, "toolong", retlen); } static void print_attr(const fido_dev_t *dev) { char flags_txt[128]; printf("proto: 0x%02x\n", fido_dev_protocol(dev)); printf("major: 0x%02x\n", fido_dev_major(dev)); printf("minor: 0x%02x\n", fido_dev_minor(dev)); printf("build: 0x%02x\n", fido_dev_build(dev)); format_flags(flags_txt, sizeof(flags_txt), fido_dev_flags(dev)); printf("caps: 0x%02x (%s)\n", fido_dev_flags(dev), flags_txt); } static void print_str_array(const char *label, char * const *sa, size_t len) { if (len == 0) return; printf("%s strings: ", label); for (size_t i = 0; i < len; i++) printf("%s%s", i > 0 ? ", " : "", sa[i]); printf("\n"); } static void print_opt_array(const char *label, char * const *name, const bool *value, size_t len) { if (len == 0) return; printf("%s: ", label); for (size_t i = 0; i < len; i++) printf("%s%s%s", i > 0 ? ", " : "", value[i] ? "" : "no", name[i]); printf("\n"); } static void print_algorithms(const fido_cbor_info_t *ci) { const char *cose, *type; size_t len; if ((len = fido_cbor_info_algorithm_count(ci)) == 0) return; printf("algorithms: "); for (size_t i = 0; i < len; i++) { cose = type = "unknown"; switch (fido_cbor_info_algorithm_cose(ci, i)) { case COSE_EDDSA: cose = "eddsa"; break; case COSE_ES256: cose = "es256"; break; case COSE_RS256: cose = "rs256"; break; } if (fido_cbor_info_algorithm_type(ci, i) != NULL) type = fido_cbor_info_algorithm_type(ci, i); printf("%s%s (%s)", i > 0 ? ", " : "", cose, type); } printf("\n"); } static void print_aaguid(const unsigned char *buf, size_t buflen) { printf("aaguid: "); while (buflen--) printf("%02x", *buf++); printf("\n"); } static void print_maxmsgsiz(uint64_t maxmsgsiz) { printf("maxmsgsiz: %d\n", (int)maxmsgsiz); } static void print_maxcredcntlst(uint64_t maxcredcntlst) { printf("maxcredcntlst: %d\n", (int)maxcredcntlst); } static void print_maxcredidlen(uint64_t maxcredidlen) { printf("maxcredlen: %d\n", (int)maxcredidlen); } static void print_fwversion(uint64_t fwversion) { printf("fwversion: 0x%x\n", (int)fwversion); } static void print_byte_array(const char *label, const uint8_t *ba, size_t len) { if (len == 0) return; printf("%s: ", label); for (size_t i = 0; i < len; i++) printf("%s%u", i > 0 ? ", " : "", (unsigned)ba[i]); printf("\n"); } int token_info(int argc, char **argv, char *path) { char *cred_id = NULL; char *rp_id = NULL; fido_cbor_info_t *ci = NULL; fido_dev_t *dev = NULL; int ch; int credman = 0; int r; int retrycnt; optind = 1; while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) { switch (ch) { case 'c': credman = 1; break; case 'i': cred_id = optarg; break; case 'k': rp_id = optarg; break; default: break; /* ignore */ } } if (path == NULL || (credman && (cred_id != NULL || rp_id != NULL))) usage(); dev = open_dev(path); if (credman) return (credman_get_metadata(dev, path)); if (cred_id && rp_id) return (credman_print_rk(dev, path, rp_id, cred_id)); if (cred_id || rp_id) usage(); print_attr(dev); if (fido_dev_is_fido2(dev) == false) goto end; if ((ci = fido_cbor_info_new()) == NULL) errx(1, "fido_cbor_info_new"); if ((r = fido_dev_get_cbor_info(dev, ci)) != FIDO_OK) errx(1, "fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r); /* print supported protocol versions */ print_str_array("version", fido_cbor_info_versions_ptr(ci), fido_cbor_info_versions_len(ci)); /* print supported extensions */ print_str_array("extension", fido_cbor_info_extensions_ptr(ci), fido_cbor_info_extensions_len(ci)); /* print supported transports */ print_str_array("transport", fido_cbor_info_transports_ptr(ci), fido_cbor_info_transports_len(ci)); /* print supported algorithms */ print_algorithms(ci); /* print aaguid */ print_aaguid(fido_cbor_info_aaguid_ptr(ci), fido_cbor_info_aaguid_len(ci)); /* print supported options */ print_opt_array("options", fido_cbor_info_options_name_ptr(ci), fido_cbor_info_options_value_ptr(ci), fido_cbor_info_options_len(ci)); /* print maximum message size */ print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci)); /* print maximum number of credentials allowed in credential lists */ print_maxcredcntlst(fido_cbor_info_maxcredcntlst(ci)); /* print maximum length of a credential ID */ print_maxcredidlen(fido_cbor_info_maxcredidlen(ci)); /* print firmware version */ print_fwversion(fido_cbor_info_fwversion(ci)); /* print supported pin protocols */ print_byte_array("pin protocols", fido_cbor_info_protocols_ptr(ci), fido_cbor_info_protocols_len(ci)); if (fido_dev_get_retry_count(dev, &retrycnt) != FIDO_OK) printf("pin retries: undefined\n"); else printf("pin retries: %d\n", retrycnt); if (fido_dev_get_uv_retry_count(dev, &retrycnt) != FIDO_OK) printf("uv retries: undefined\n"); else printf("uv retries: %d\n", retrycnt); bio_info(dev); fido_cbor_info_free(&ci); end: fido_dev_close(dev); fido_dev_free(&dev); exit(0); } int token_reset(char *path) { fido_dev_t *dev = NULL; int r; if (path == NULL) usage(); dev = open_dev(path); if ((r = fido_dev_reset(dev)) != FIDO_OK) errx(1, "fido_dev_reset: %s", fido_strerr(r)); fido_dev_close(dev); fido_dev_free(&dev); exit(0); } int token_get(int argc, char **argv, char *path) { char *id = NULL; char *key = NULL; char *name = NULL; int blob = 0; int ch; optind = 1; while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) { switch (ch) { case 'b': blob = 1; break; case 'i': id = optarg; break; case 'k': key = optarg; break; case 'n': name = optarg; break; default: break; /* ignore */ } } argc -= optind; argv += optind; if (blob == 0 || argc != 2) usage(); return blob_get(path, key, name, id, argv[0]); } int token_set(int argc, char **argv, char *path) { char *id = NULL; char *key = NULL; char *len = NULL; char *display_name = NULL; char *name = NULL; + char *rpid = NULL; int blob = 0; int cred = 0; int ch; int enroll = 0; int ea = 0; int uv = 0; bool force = false; optind = 1; while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) { switch (ch) { case 'a': ea = 1; break; case 'b': blob = 1; break; case 'c': cred = 1; break; case 'e': enroll = 1; break; case 'f': force = true; break; case 'i': id = optarg; break; case 'k': key = optarg; break; case 'l': len = optarg; break; case 'p': display_name = optarg; break; + case 'm': + rpid = optarg; + break; case 'n': name = optarg; break; case 'u': uv = 1; break; default: break; /* ignore */ } } argc -= optind; argv += optind; if (path == NULL) usage(); if (blob) { if (argc != 2) usage(); return (blob_set(path, key, name, id, argv[0])); } if (cred) { if (!id || !key) usage(); if (!name && !display_name) usage(); return (credman_update_rk(path, key, id, name, display_name)); } if (enroll) { if (ea || uv) usage(); if (id && name) return (bio_set_name(path, id, name)); if (!id && !name) return (bio_enroll(path)); usage(); } if (ea) { if (uv) usage(); return (config_entattest(path)); } if (len) return (config_pin_minlen(path, len)); + if (rpid) + return (config_pin_minlen_rpid(path, rpid)); if (force) return (config_force_pin_change(path)); if (uv) return (config_always_uv(path, 1)); return (pin_set(path)); } int token_list(int argc, char **argv, char *path) { fido_dev_info_t *devlist; size_t ndevs; const char *rp_id = NULL; int blobs = 0; int enrolls = 0; int keys = 0; int rplist = 0; int ch; int r; optind = 1; while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) { switch (ch) { case 'b': blobs = 1; break; case 'e': enrolls = 1; break; case 'k': keys = 1; rp_id = optarg; break; case 'r': rplist = 1; break; default: break; /* ignore */ } } if (blobs || enrolls || keys || rplist) { if (path == NULL) usage(); if (blobs) return (blob_list(path)); if (enrolls) return (bio_list(path)); if (keys) return (credman_list_rk(path, rp_id)); if (rplist) return (credman_list_rp(path)); /* NOTREACHED */ } if ((devlist = fido_dev_info_new(64)) == NULL) errx(1, "fido_dev_info_new"); if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK) errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r); for (size_t i = 0; i < ndevs; i++) { const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i); printf("%s: vendor=0x%04x, product=0x%04x (%s %s)\n", fido_dev_info_path(di), (uint16_t)fido_dev_info_vendor(di), (uint16_t)fido_dev_info_product(di), fido_dev_info_manufacturer_string(di), fido_dev_info_product_string(di)); } fido_dev_info_free(&devlist, ndevs); exit(0); } int token_delete(int argc, char **argv, char *path) { char *id = NULL; char *key = NULL; char *name = NULL; int blob = 0; int ch; int enroll = 0; int uv = 0; optind = 1; while ((ch = getopt(argc, argv, TOKEN_OPT)) != -1) { switch (ch) { case 'b': blob = 1; break; case 'e': enroll = 1; break; case 'i': id = optarg; break; case 'k': key = optarg; break; case 'n': name = optarg; break; case 'u': uv = 1; break; default: break; /* ignore */ } } if (path == NULL) usage(); if (blob) return (blob_delete(path, key, name, id)); if (id) { if (uv) usage(); if (enroll == 0) return (credman_delete_rk(path, id)); return (bio_delete(path, id)); } if (uv == 0) usage(); return (config_always_uv(path, 0)); } diff --git a/contrib/libfido2/windows/build.ps1 b/contrib/libfido2/windows/build.ps1 index 55aac9d96bc5..87d0c31e5311 100644 --- a/contrib/libfido2/windows/build.ps1 +++ b/contrib/libfido2/windows/build.ps1 @@ -1,272 +1,240 @@ +# Copyright (c) 2021 Yubico AB. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + param( [string]$CMakePath = "C:\Program Files\CMake\bin\cmake.exe", [string]$GitPath = "C:\Program Files\Git\bin\git.exe", [string]$SevenZPath = "C:\Program Files\7-Zip\7z.exe", [string]$GPGPath = "C:\Program Files (x86)\GnuPG\bin\gpg.exe", [string]$WinSDK = "", + [string]$Config = "Release", + [string]$Arch = "x64", + [string]$Type = "dynamic", [string]$Fido2Flags = "" ) -$ErrorActionPreference = "Continue" - +$ErrorActionPreference = "Stop" [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -# LibreSSL coordinates. -New-Variable -Name 'LIBRESSL_URL' ` - -Value 'https://fastly.cdn.openbsd.org/pub/OpenBSD/LibreSSL' -Option Constant -New-Variable -Name 'LIBRESSL' -Value 'libressl-3.2.5' -Option Constant +. "$PSScriptRoot\const.ps1" -# libcbor coordinates. -New-Variable -Name 'LIBCBOR' -Value 'libcbor-0.8.0' -Option Constant -New-Variable -Name 'LIBCBOR_BRANCH' -Value 'v0.8.0' -Option Constant -New-Variable -Name 'LIBCBOR_GIT' -Value 'https://github.com/pjk/libcbor' ` - -Option Constant +Function ExitOnError() { + if ($LastExitCode -ne 0) { + throw "A command exited with status $LastExitCode" + } +} -# zlib coordinates. -New-Variable -Name 'ZLIB' -Value 'zlib-1.2.11' -Option Constant -New-Variable -Name 'ZLIB_BRANCH' -Value 'v1.2.11' -Option Constant -New-Variable -Name 'ZLIB_GIT' -Value 'https://github.com/madler/zlib' ` - -Option Constant +Function GitClone(${REPO}, ${BRANCH}, ${DIR}) { + Write-Host "Cloning ${REPO}..." + & $Git -c advice.detachedHead=false clone --quiet --depth=1 ` + --branch "${BRANCH}" "${REPO}" "${DIR}" + Write-Host "${REPO}'s ${BRANCH} HEAD is:" + & $Git -C "${DIR}" show -s HEAD +} -# Work directories. -New-Variable -Name 'BUILD' -Value "$PSScriptRoot\..\build" -Option Constant -New-Variable -Name 'OUTPUT' -Value "$PSScriptRoot\..\output" -Option Constant +# Find Git. +$Git = $(Get-Command git -ErrorAction Ignore | ` + Select-Object -ExpandProperty Source) +if ([string]::IsNullOrEmpty($Git)) { + $Git = $GitPath +} +if (-Not (Test-Path $Git)) { + throw "Unable to find Git at $Git" +} # Find CMake. -$CMake = $(Get-Command cmake -ErrorAction Ignore | Select-Object -ExpandProperty Source) -if([string]::IsNullOrEmpty($CMake)) { +$CMake = $(Get-Command cmake -ErrorAction Ignore | ` + Select-Object -ExpandProperty Source) +if ([string]::IsNullOrEmpty($CMake)) { $CMake = $CMakePath } - -# Find Git. -$Git = $(Get-Command git -ErrorAction Ignore | Select-Object -ExpandProperty Source) -if([string]::IsNullOrEmpty($Git)) { - $Git = $GitPath +if (-Not (Test-Path $CMake)) { + throw "Unable to find CMake at $CMake" } # Find 7z. -$SevenZ = $(Get-Command 7z -ErrorAction Ignore | Select-Object -ExpandProperty Source) -if([string]::IsNullOrEmpty($SevenZ)) { +$SevenZ = $(Get-Command 7z -ErrorAction Ignore | ` + Select-Object -ExpandProperty Source) +if ([string]::IsNullOrEmpty($SevenZ)) { $SevenZ = $SevenZPath } +if (-Not (Test-Path $SevenZ)) { + throw "Unable to find 7z at $SevenZ" +} # Find GPG. -$GPG = $(Get-Command gpg -ErrorAction Ignore | Select-Object -ExpandProperty Source) -if([string]::IsNullOrEmpty($GPG)) { +$GPG = $(Get-Command gpg -ErrorAction Ignore | ` + Select-Object -ExpandProperty Source) +if ([string]::IsNullOrEmpty($GPG)) { $GPG = $GPGPath } +if (-Not (Test-Path $GPG)) { + throw "Unable to find GPG at $GPG" +} # Override CMAKE_SYSTEM_VERSION if $WinSDK is set. -if(-Not ([string]::IsNullOrEmpty($WinSDK))) { +if (-Not ([string]::IsNullOrEmpty($WinSDK))) { $CMAKE_SYSTEM_VERSION = "-DCMAKE_SYSTEM_VERSION='$WinSDK'" } else { $CMAKE_SYSTEM_VERSION = '' } -if(-Not (Test-Path $CMake)) { - throw "Unable to find CMake at $CMake" -} - -if(-Not (Test-Path $Git)) { - throw "Unable to find Git at $Git" -} - -if(-Not (Test-Path $SevenZ)) { - throw "Unable to find 7z at $SevenZ" -} - -if(-Not (Test-Path $GPG)) { - throw "Unable to find GPG at $GPG" -} - +Write-Host "WinSDK: $WinSDK" +Write-Host "Config: $Config" +Write-Host "Arch: $Arch" +Write-Host "Type: $Type" Write-Host "Git: $Git" Write-Host "CMake: $CMake" Write-Host "7z: $SevenZ" Write-Host "GPG: $GPG" -New-Item -Type Directory ${BUILD} -New-Item -Type Directory ${BUILD}\32 -New-Item -Type Directory ${BUILD}\32\dynamic -New-Item -Type Directory ${BUILD}\32\static -New-Item -Type Directory ${BUILD}\64 -New-Item -Type Directory ${BUILD}\64\dynamic -New-Item -Type Directory ${BUILD}\64\static -New-Item -Type Directory ${OUTPUT} -New-Item -Type Directory ${OUTPUT}\pkg\Win64\Release\v142\dynamic -New-Item -Type Directory ${OUTPUT}\pkg\Win32\Release\v142\dynamic -New-Item -Type Directory ${OUTPUT}\pkg\Win64\Release\v142\static -New-Item -Type Directory ${OUTPUT}\pkg\Win32\Release\v142\static +# Create build directories. +New-Item -Type Directory "${BUILD}" -Force +New-Item -Type Directory "${BUILD}\${Arch}" -Force +New-Item -Type Directory "${BUILD}\${Arch}\${Type}" -Force +New-Item -Type Directory "${STAGE}\${LIBRESSL}" -Force +New-Item -Type Directory "${STAGE}\${LIBCBOR}" -Force +New-Item -Type Directory "${STAGE}\${ZLIB}" -Force -Push-Location ${BUILD} +# Create output directories. +New-Item -Type Directory "${OUTPUT}" -Force +New-Item -Type Directory "${OUTPUT}\${Arch}" -Force +New-Item -Type Directory "${OUTPUT}\${Arch}\${Type}" -force +# Fetch and verify dependencies. +Push-Location ${BUILD} try { - if (Test-Path .\${LIBRESSL}) { - Remove-Item .\${LIBRESSL} -Recurse -ErrorAction Stop - } - - if(-Not (Test-Path .\${LIBRESSL}.tar.gz -PathType leaf)) { - Invoke-WebRequest ${LIBRESSL_URL}/${LIBRESSL}.tar.gz ` - -OutFile .\${LIBRESSL}.tar.gz - } - if(-Not (Test-Path .\${LIBRESSL}.tar.gz.asc -PathType leaf)) { - Invoke-WebRequest ${LIBRESSL_URL}/${LIBRESSL}.tar.gz.asc ` - -OutFile .\${LIBRESSL}.tar.gz.asc - } - - Copy-Item "$PSScriptRoot\libressl.gpg" -Destination "${BUILD}" - & $GPG --list-keys - & $GPG -v --no-default-keyring --keyring ./libressl.gpg ` - --verify .\${LIBRESSL}.tar.gz.asc .\${LIBRESSL}.tar.gz - if ($LastExitCode -ne 0) { - throw "GPG signature verification failed" + if (-Not (Test-Path .\${LIBRESSL})) { + if (-Not (Test-Path .\${LIBRESSL}.tar.gz -PathType leaf)) { + Invoke-WebRequest ${LIBRESSL_URL}/${LIBRESSL}.tar.gz ` + -OutFile .\${LIBRESSL}.tar.gz + } + if (-Not (Test-Path .\${LIBRESSL}.tar.gz.asc -PathType leaf)) { + Invoke-WebRequest ${LIBRESSL_URL}/${LIBRESSL}.tar.gz.asc ` + -OutFile .\${LIBRESSL}.tar.gz.asc + } + + Copy-Item "$PSScriptRoot\libressl.gpg" -Destination "${BUILD}" + & $GPG --list-keys + & $GPG --quiet --no-default-keyring --keyring ./libressl.gpg ` + --verify .\${LIBRESSL}.tar.gz.asc .\${LIBRESSL}.tar.gz + if ($LastExitCode -ne 0) { + throw "GPG signature verification failed" + } + & $SevenZ e .\${LIBRESSL}.tar.gz + & $SevenZ x .\${LIBRESSL}.tar + Remove-Item -Force .\${LIBRESSL}.tar } - - & $SevenZ e .\${LIBRESSL}.tar.gz - & $SevenZ x .\${LIBRESSL}.tar - Remove-Item -Force .\${LIBRESSL}.tar - - if(-Not (Test-Path .\${LIBCBOR})) { - Write-Host "Cloning ${LIBCBOR}..." - & $Git clone --branch ${LIBCBOR_BRANCH} ${LIBCBOR_GIT} ` - .\${LIBCBOR} + if (-Not (Test-Path .\${LIBCBOR})) { + GitClone "${LIBCBOR_GIT}" "${LIBCBOR_BRANCH}" ".\${LIBCBOR}" } - - if(-Not (Test-Path .\${ZLIB})) { - Write-Host "Cloning ${ZLIB}..." - & $Git clone --branch ${ZLIB_BRANCH} ${ZLIB_GIT} ` - .\${ZLIB} + if (-Not (Test-Path .\${ZLIB})) { + GitClone "${ZLIB_GIT}" "${ZLIB_BRANCH}" ".\${ZLIB}" } } catch { throw "Failed to fetch and verify dependencies" } finally { Pop-Location } -Function Build(${OUTPUT}, ${GENERATOR}, ${ARCH}, ${SHARED}, ${FLAGS}) { - if (-Not (Test-Path .\${LIBRESSL})) { - New-Item -Type Directory .\${LIBRESSL} -ErrorAction Stop - } - - Push-Location .\${LIBRESSL} - & $CMake ..\..\..\${LIBRESSL} -G "${GENERATOR}" -A "${ARCH}" ` - -DBUILD_SHARED_LIBS="${SHARED}" -DLIBRESSL_TESTS=OFF ` - -DCMAKE_C_FLAGS_RELEASE="${FLAGS} /Zi /guard:cf /sdl" ` - -DCMAKE_INSTALL_PREFIX="${OUTPUT}" "${CMAKE_SYSTEM_VERSION}" - & $CMake --build . --config Release --verbose - & $CMake --build . --config Release --target install --verbose +# Build LibreSSL. +Push-Location ${STAGE}\${LIBRESSL} +try { + & $CMake ..\..\..\${LIBRESSL} -A "${Arch}" ` + -DBUILD_SHARED_LIBS="${SHARED}" -DLIBRESSL_TESTS=OFF ` + -DCMAKE_C_FLAGS_DEBUG="${CFLAGS_DEBUG}" ` + -DCMAKE_C_FLAGS_RELEASE="${CFLAGS_RELEASE}" ` + -DCMAKE_INSTALL_PREFIX="${PREFIX}" "${CMAKE_SYSTEM_VERSION}"; ` + ExitOnError + & $CMake --build . --config ${Config} --verbose; ExitOnError + & $CMake --build . --config ${Config} --target install --verbose; ` + ExitOnError +} catch { + throw "Failed to build LibreSSL" +} finally { Pop-Location +} - if (-Not (Test-Path .\${LIBCBOR})) { - New-Item -Type Directory .\${LIBCBOR} -ErrorAction Stop - } - - Push-Location .\${LIBCBOR} - & $CMake ..\..\..\${LIBCBOR} -G "${GENERATOR}" -A "${ARCH}" ` - -DBUILD_SHARED_LIBS="${SHARED}" ` - -DCMAKE_C_FLAGS_RELEASE="${FLAGS} /Zi /guard:cf /sdl" ` - -DCMAKE_INSTALL_PREFIX="${OUTPUT}" "${CMAKE_SYSTEM_VERSION}" - & $CMake --build . --config Release --verbose - & $CMake --build . --config Release --target install --verbose +# Build libcbor. +Push-Location ${STAGE}\${LIBCBOR} +try { + & $CMake ..\..\..\${LIBCBOR} -A "${Arch}" ` + -DWITH_EXAMPLES=OFF ` + -DBUILD_SHARED_LIBS="${SHARED}" ` + -DCMAKE_C_FLAGS_DEBUG="${CFLAGS_DEBUG}" ` + -DCMAKE_C_FLAGS_RELEASE="${CFLAGS_RELEASE}" ` + -DCMAKE_INSTALL_PREFIX="${PREFIX}" "${CMAKE_SYSTEM_VERSION}"; ` + ExitOnError + & $CMake --build . --config ${Config} --verbose; ExitOnError + & $CMake --build . --config ${Config} --target install --verbose; ` + ExitOnError +} catch { + throw "Failed to build libcbor" +} finally { Pop-Location +} - if(-Not (Test-Path .\${ZLIB})) { - New-Item -Type Directory .\${ZLIB} -ErrorAction Stop +# Build zlib. +Push-Location ${STAGE}\${ZLIB} +try { + & $CMake ..\..\..\${ZLIB} -A "${Arch}" ` + -DBUILD_SHARED_LIBS="${SHARED}" ` + -DCMAKE_C_FLAGS_DEBUG="${CFLAGS_DEBUG}" ` + -DCMAKE_C_FLAGS_RELEASE="${CFLAGS_RELEASE}" ` + -DCMAKE_INSTALL_PREFIX="${PREFIX}" "${CMAKE_SYSTEM_VERSION}"; ` + ExitOnError + & $CMake --build . --config ${Config} --verbose; ExitOnError + & $CMake --build . --config ${Config} --target install --verbose; ` + ExitOnError + # Patch up zlib's resulting names when built with --config Debug. + if ("${Config}" -eq "Debug") { + if ("${Type}" -eq "Dynamic") { + Copy-Item "${PREFIX}/lib/zlibd.lib" ` + -Destination "${PREFIX}/lib/zlib.lib" -Force + Copy-Item "${PREFIX}/bin/zlibd1.dll" ` + -Destination "${PREFIX}/bin/zlib1.dll" -Force + } else { + Copy-Item "${PREFIX}/lib/zlibstaticd.lib" ` + -Destination "${PREFIX}/lib/zlib.lib" -Force + } } - - Push-Location .\${ZLIB} - & $CMake ..\..\..\${ZLIB} -G "${GENERATOR}" -A "${ARCH}" ` - -DBUILD_SHARED_LIBS="${SHARED}" ` - -DCMAKE_C_FLAGS_RELEASE="${FLAGS} /Zi /guard:cf /sdl" ` - -DCMAKE_INSTALL_PREFIX="${OUTPUT}" "${CMAKE_SYSTEM_VERSION}" - & $CMake --build . --config Release --verbose - & $CMake --build . --config Release --target install --verbose +} catch { + throw "Failed to build zlib" +} finally { Pop-Location +} - & $CMake ..\..\.. -G "${GENERATOR}" -A "${ARCH}" ` - -DBUILD_SHARED_LIBS="${SHARED}" ` - -DCBOR_INCLUDE_DIRS="${OUTPUT}\include" ` - -DCBOR_LIBRARY_DIRS="${OUTPUT}\lib" ` - -DZLIB_INCLUDE_DIRS="${OUTPUT}\include" ` - -DZLIB_LIBRARY_DIRS="${OUTPUT}\lib" ` - -DCRYPTO_INCLUDE_DIRS="${OUTPUT}\include" ` - -DCRYPTO_LIBRARY_DIRS="${OUTPUT}\lib" ` - -DCMAKE_C_FLAGS_RELEASE="${FLAGS} /Zi /guard:cf /sdl ${Fido2Flags}" ` - -DCMAKE_INSTALL_PREFIX="${OUTPUT}" "${CMAKE_SYSTEM_VERSION}" - & $CMake --build . --config Release --verbose - & $CMake --build . --config Release --target install --verbose +# Build libfido2. +Push-Location ${STAGE} +try { + & $CMake ..\..\.. -A "${Arch}" ` + -DCMAKE_BUILD_TYPE="${Config}" ` + -DBUILD_SHARED_LIBS="${SHARED}" ` + -DCBOR_INCLUDE_DIRS="${PREFIX}\include" ` + -DCBOR_LIBRARY_DIRS="${PREFIX}\lib" ` + -DCBOR_BIN_DIRS="${PREFIX}\bin" ` + -DZLIB_INCLUDE_DIRS="${PREFIX}\include" ` + -DZLIB_LIBRARY_DIRS="${PREFIX}\lib" ` + -DZLIB_BIN_DIRS="${PREFIX}\bin" ` + -DCRYPTO_INCLUDE_DIRS="${PREFIX}\include" ` + -DCRYPTO_LIBRARY_DIRS="${PREFIX}\lib" ` + -DCRYPTO_BIN_DIRS="${PREFIX}\bin" ` + -DCMAKE_C_FLAGS_DEBUG="${CFLAGS_DEBUG} ${Fido2Flags}" ` + -DCMAKE_C_FLAGS_RELEASE="${CFLAGS_RELEASE} ${Fido2Flags}" ` + -DCMAKE_INSTALL_PREFIX="${PREFIX}" "${CMAKE_SYSTEM_VERSION}"; ` + ExitOnError + & $CMake --build . --config ${Config} --verbose; ExitOnError + & $CMake --build . --config ${Config} --target install --verbose; ` + ExitOnError + # Copy DLLs. if ("${SHARED}" -eq "ON") { - "cbor.dll", "crypto-46.dll", "zlib1.dll" | %{ Copy-Item "${OUTPUT}\bin\$_" ` - -Destination "examples\Release" } + "cbor.dll", "crypto-46.dll", "zlib1.dll" | ` + %{ Copy-Item "${PREFIX}\bin\$_" ` + -Destination "examples\${Config}" } } +} catch { + throw "Failed to build libfido2" +} finally { + Pop-Location } - -Function Package-Headers() { - Copy-Item "${OUTPUT}\64\dynamic\include" -Destination "${OUTPUT}\pkg" ` - -Recurse -ErrorAction Stop -} - -Function Package-Dynamic(${SRC}, ${DEST}) { - Copy-Item "${SRC}\bin\cbor.dll" "${DEST}" -ErrorAction Stop - Copy-Item "${SRC}\lib\cbor.lib" "${DEST}" -ErrorAction Stop - Copy-Item "${SRC}\bin\zlib1.dll" "${DEST}" -ErrorAction Stop - Copy-Item "${SRC}\lib\zlib.lib" "${DEST}" -ErrorAction Stop - Copy-Item "${SRC}\bin\crypto-46.dll" "${DEST}" -ErrorAction Stop - Copy-Item "${SRC}\lib\crypto-46.lib" "${DEST}" -ErrorAction Stop - Copy-Item "${SRC}\bin\fido2.dll" "${DEST}" -ErrorAction Stop - Copy-Item "${SRC}\lib\fido2.lib" "${DEST}" -ErrorAction Stop -} - -Function Package-Static(${SRC}, ${DEST}) { - Copy-Item "${SRC}/lib/cbor.lib" "${DEST}" -ErrorAction Stop - Copy-Item "${SRC}/lib/zlib.lib" "${DEST}" -ErrorAction Stop - Copy-Item "${SRC}/lib/crypto-46.lib" "${DEST}" -ErrorAction Stop - Copy-Item "${SRC}/lib/fido2_static.lib" "${DEST}/fido2.lib" ` - -ErrorAction Stop -} - -Function Package-PDBs(${SRC}, ${DEST}) { - Copy-Item "${SRC}\${LIBRESSL}\crypto\crypto.dir\Release\vc142.pdb" ` - "${DEST}\crypto-46.pdb" -ErrorAction Stop - Copy-Item "${SRC}\${LIBCBOR}\src\cbor.dir\Release\vc142.pdb" ` - "${DEST}\cbor.pdb" -ErrorAction Stop - Copy-Item "${SRC}\${ZLIB}\zlib.dir\Release\vc142.pdb" ` - "${DEST}\zlib.pdb" -ErrorAction Stop - Copy-Item "${SRC}\src\fido2_shared.dir\Release\vc142.pdb" ` - "${DEST}\fido2.pdb" -ErrorAction Stop -} - -Function Package-Tools(${SRC}, ${DEST}) { - Copy-Item "${SRC}\tools\Release\fido2-assert.exe" ` - "${DEST}\fido2-assert.exe" -ErrorAction stop - Copy-Item "${SRC}\tools\Release\fido2-cred.exe" ` - "${DEST}\fido2-cred.exe" -ErrorAction stop - Copy-Item "${SRC}\tools\Release\fido2-token.exe" ` - "${DEST}\fido2-token.exe" -ErrorAction stop -} - -Push-Location ${BUILD}\64\dynamic -Build ${OUTPUT}\64\dynamic "Visual Studio 16 2019" "x64" "ON" "/MD" -Pop-Location -Push-Location ${BUILD}\32\dynamic -Build ${OUTPUT}\32\dynamic "Visual Studio 16 2019" "Win32" "ON" "/MD" -Pop-Location - -Push-Location ${BUILD}\64\static -Build ${OUTPUT}\64\static "Visual Studio 16 2019" "x64" "OFF" "/MT" -Pop-Location -Push-Location ${BUILD}\32\static -Build ${OUTPUT}\32\static "Visual Studio 16 2019" "Win32" "OFF" "/MT" -Pop-Location - -Package-Headers - -Package-Dynamic ${OUTPUT}\64\dynamic ${OUTPUT}\pkg\Win64\Release\v142\dynamic -Package-PDBs ${BUILD}\64\dynamic ${OUTPUT}\pkg\Win64\Release\v142\dynamic -Package-Tools ${BUILD}\64\dynamic ${OUTPUT}\pkg\Win64\Release\v142\dynamic - -Package-Dynamic ${OUTPUT}\32\dynamic ${OUTPUT}\pkg\Win32\Release\v142\dynamic -Package-PDBs ${BUILD}\32\dynamic ${OUTPUT}\pkg\Win32\Release\v142\dynamic -Package-Tools ${BUILD}\32\dynamic ${OUTPUT}\pkg\Win32\Release\v142\dynamic - -Package-Static ${OUTPUT}\64\static ${OUTPUT}\pkg\Win64\Release\v142\static -Package-Static ${OUTPUT}\32\static ${OUTPUT}\pkg\Win32\Release\v142\static diff --git a/contrib/libfido2/windows/const.ps1 b/contrib/libfido2/windows/const.ps1 new file mode 100644 index 000000000000..6d2a8189d362 --- /dev/null +++ b/contrib/libfido2/windows/const.ps1 @@ -0,0 +1,42 @@ +# Copyright (c) 2021 Yubico AB. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +# LibreSSL coordinates. +New-Variable -Name 'LIBRESSL_URL' ` + -Value 'https://fastly.cdn.openbsd.org/pub/OpenBSD/LibreSSL' ` + -Option Constant +New-Variable -Name 'LIBRESSL' -Value 'libressl-3.3.4' -Option Constant + +# libcbor coordinates. +New-Variable -Name 'LIBCBOR' -Value 'libcbor-0.8.0' -Option Constant +New-Variable -Name 'LIBCBOR_BRANCH' -Value 'v0.8.0' -Option Constant +New-Variable -Name 'LIBCBOR_GIT' -Value 'https://github.com/pjk/libcbor' ` + -Option Constant + +# zlib coordinates. +New-Variable -Name 'ZLIB' -Value 'zlib-1.2.11' -Option Constant +New-Variable -Name 'ZLIB_BRANCH' -Value 'v1.2.11' -Option Constant +New-Variable -Name 'ZLIB_GIT' -Value 'https://github.com/madler/zlib' ` + -Option Constant + +# Work directories. +New-Variable -Name 'BUILD' -Value "$PSScriptRoot\..\build" -Option Constant +New-Variable -Name 'OUTPUT' -Value "$PSScriptRoot\..\output" -Option Constant + +# Prefixes. +New-Variable -Name 'STAGE' -Value "${BUILD}\${Arch}\${Type}" -Option Constant +New-Variable -Name 'PREFIX' -Value "${OUTPUT}\${Arch}\${Type}" -Option Constant + +# Build flags. +if ("${Type}" -eq "dynamic") { + New-Variable -Name 'RUNTIME' -Value '/MD' -Option Constant + New-Variable -Name 'SHARED' -Value 'ON' -Option Constant +} else { + New-Variable -Name 'RUNTIME' -Value '/MT' -Option Constant + New-Variable -Name 'SHARED' -Value 'OFF' -Option Constant +} +New-Variable -Name 'CFLAGS_DEBUG' -Value "${RUNTIME}d /Zi /guard:cf /sdl" ` + -Option Constant +New-Variable -Name 'CFLAGS_RELEASE' -Value "${RUNTIME} /Zi /guard:cf /sdl" ` + -Option Constant diff --git a/contrib/libfido2/windows/release.ps1 b/contrib/libfido2/windows/release.ps1 new file mode 100644 index 000000000000..32e88e256274 --- /dev/null +++ b/contrib/libfido2/windows/release.ps1 @@ -0,0 +1,84 @@ +# Copyright (c) 2021 Yubico AB. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +$ErrorActionPreference = "Stop" +$Architectures = @('x64', 'Win32', 'ARM64', 'ARM') +$InstallPrefixes = @('Win64', 'Win32', 'ARM64', 'ARM') +$Types = @('dynamic', 'static') +$Config = 'Release' +$LibCrypto = '46' +$SDK = '142' + +. "$PSScriptRoot\const.ps1" + +foreach ($Arch in $Architectures) { + foreach ($Type in $Types) { + ./build.ps1 -Arch ${Arch} -Type ${Type} -Config ${Config} + } +} + +foreach ($InstallPrefix in $InstallPrefixes) { + foreach ($Type in $Types) { + New-Item -Type Directory ` + "${OUTPUT}/pkg/${InstallPrefix}/${Config}/v${SDK}/${Type}" + } +} + +Function Package-Headers() { + Copy-Item "${OUTPUT}\x64\dynamic\include" -Destination "${OUTPUT}\pkg" ` + -Recurse -ErrorAction Stop +} + +Function Package-Dynamic(${SRC}, ${DEST}) { + Copy-Item "${SRC}\bin\cbor.dll" "${DEST}" + Copy-Item "${SRC}\lib\cbor.lib" "${DEST}" + Copy-Item "${SRC}\bin\zlib1.dll" "${DEST}" + Copy-Item "${SRC}\lib\zlib.lib" "${DEST}" + Copy-Item "${SRC}\bin\crypto-${LibCrypto}.dll" "${DEST}" + Copy-Item "${SRC}\lib\crypto-${LibCrypto}.lib" "${DEST}" + Copy-Item "${SRC}\bin\fido2.dll" "${DEST}" + Copy-Item "${SRC}\lib\fido2.lib" "${DEST}" +} + +Function Package-Static(${SRC}, ${DEST}) { + Copy-Item "${SRC}/lib/cbor.lib" "${DEST}" + Copy-Item "${SRC}/lib/zlib.lib" "${DEST}" + Copy-Item "${SRC}/lib/crypto-${LibCrypto}.lib" "${DEST}" + Copy-Item "${SRC}/lib/fido2_static.lib" "${DEST}/fido2.lib" +} + +Function Package-PDBs(${SRC}, ${DEST}) { + Copy-Item "${SRC}\${LIBRESSL}\crypto\crypto.dir\${Config}\vc${SDK}.pdb" ` + "${DEST}\crypto-${LibCrypto}.pdb" + Copy-Item "${SRC}\${LIBCBOR}\src\cbor.dir\${Config}\vc${SDK}.pdb" ` + "${DEST}\cbor.pdb" + Copy-Item "${SRC}\${ZLIB}\zlib.dir\${Config}\vc${SDK}.pdb" ` + "${DEST}\zlib.pdb" + Copy-Item "${SRC}\src\fido2_shared.dir\${Config}\vc${SDK}.pdb" ` + "${DEST}\fido2.pdb" +} + +Function Package-Tools(${SRC}, ${DEST}) { + Copy-Item "${SRC}\tools\${Config}\fido2-assert.exe" ` + "${DEST}\fido2-assert.exe" + Copy-Item "${SRC}\tools\${Config}\fido2-cred.exe" ` + "${DEST}\fido2-cred.exe" + Copy-Item "${SRC}\tools\${Config}\fido2-token.exe" ` + "${DEST}\fido2-token.exe" +} + +Package-Headers + +for ($i = 0; $i -lt $Architectures.Length; $i++) { + $Arch = $Architectures[$i] + $InstallPrefix = $InstallPrefixes[$i] + Package-Dynamic "${OUTPUT}\${Arch}\dynamic" ` + "${OUTPUT}\pkg\${InstallPrefix}\${Config}\v${SDK}\dynamic" + Package-PDBs "${BUILD}\${Arch}\dynamic" ` + "${OUTPUT}\pkg\${InstallPrefix}\${Config}\v${SDK}\dynamic" + Package-Tools "${BUILD}\${Arch}\dynamic" ` + "${OUTPUT}\pkg\${InstallPrefix}\${Config}\v${SDK}\dynamic" + Package-Static "${OUTPUT}\${Arch}\static" ` + "${OUTPUT}\pkg\${InstallPrefix}\${Config}\v${SDK}\static" +} diff --git a/lib/libfido2/Makefile b/lib/libfido2/Makefile index edf737b9dafc..9a0e4a57bd9a 100644 --- a/lib/libfido2/Makefile +++ b/lib/libfido2/Makefile @@ -1,73 +1,77 @@ PACKAGE=ssh LIB= fido2 PRIVATELIB= DIST= ${SRCTOP}/contrib/libfido2 .PATH: ${DIST}/src ${DIST} SRCS+= aes256.c SRCS+= assert.c SRCS+= authkey.c SRCS+= bio.c SRCS+= blob.c SRCS+= buf.c SRCS+= cbor.c SRCS+= compress.c SRCS+= config.c SRCS+= cred.c SRCS+= credman.c SRCS+= dev.c SRCS+= ecdh.c SRCS+= eddsa.c SRCS+= err.c SRCS+= es256.c SRCS+= hid_freebsd.c SRCS+= hid_unix.c SRCS+= hid.c SRCS+= info.c SRCS+= io.c SRCS+= iso7816.c SRCS+= largeblob.c SRCS+= log.c SRCS+= pin.c SRCS+= random.c SRCS+= reset.c +SRCS+= rs1.c SRCS+= rs256.c +SRCS+= time.c +SRCS+= tpm.c +SRCS+= types.c SRCS+= u2f.c SRCS+= openbsd-compat/freezero.c SRCS+= openbsd-compat/recallocarray.c CFLAGS+= -I ${DIST}/src -I${SRCTOP}/contrib/libcbor/src -I${.CURDIR}/../libcbor CFLAGS+= -D_FIDO_INTERNAL CFLAGS+= -DHAVE_ARC4RANDOM_BUF CFLAGS+= -DHAVE_CLOCK_GETTIME CFLAGS+= -DHAVE_DEV_URANDOM CFLAGS+= -DHAVE_ERR_H CFLAGS+= -DHAVE_EXPLICIT_BZERO CFLAGS+= -DHAVE_GETLINE CFLAGS+= -DHAVE_GETOPT CFLAGS+= -DHAVE_GETPAGESIZE CFLAGS+= -DHAVE_GETRANDOM CFLAGS+= -DHAVE_OPENSSLV_H CFLAGS+= -DHAVE_READPASSPHRASE CFLAGS+= -DHAVE_SIGNAL_H CFLAGS+= -DHAVE_STRLCAT CFLAGS+= -DHAVE_STRLCPY CFLAGS+= -DHAVE_STRSEP CFLAGS+= -DHAVE_SYSCONF CFLAGS+= -DHAVE_SYS_RANDOM_H CFLAGS+= -DHAVE_TIMESPECSUB CFLAGS+= -DHAVE_TIMINGSAFE_BCMP CFLAGS+= -DHAVE_UNISTD_H CFLAGS+= -DTLS=__thread CFLAGS+= -D_FIDO_MAJOR=1 CFLAGS+= -D_FIDO_MINOR=9 CFLAGS+= -D_FIDO_PATCH=0 LIBADD= crypto z WARNS=2 MAN= .include