diff --git a/contrib/libfido2/CMakeLists.txt b/contrib/libfido2/CMakeLists.txt index 11a51ac5a645..6fa341a01cc6 100644 --- a/contrib/libfido2/CMakeLists.txt +++ b/contrib/libfido2/CMakeLists.txt @@ -1,428 +1,498 @@ -# Copyright (c) 2018-2021 Yubico AB. All rights reserved. +# Copyright (c) 2018-2022 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. +# SPDX-License-Identifier: BSD-2-Clause # 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 "10") +set(FIDO_MINOR "13") set(FIDO_PATCH "0") set(FIDO_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}.${FIDO_PATCH}) +option(BUILD_TESTS "Build the regress tests" ON) 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_SHARED_LIBS "Build a shared library" ON) +option(BUILD_STATIC_LIBS "Build a 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_PCSC "Enable experimental PCSC support" OFF) option(USE_WINHELLO "Abstract Windows Hello as a FIDO device" ON) option(NFC_LINUX "Enable NFC support on Linux" ON) add_definitions(-D_FIDO_MAJOR=${FIDO_MAJOR}) add_definitions(-D_FIDO_MINOR=${FIDO_MINOR}) add_definitions(-D_FIDO_PATCH=${FIDO_PATCH}) +if(BUILD_SHARED_LIBS) + set(_FIDO2_LIBRARY fido2_shared) +elseif(BUILD_STATIC_LIBS) + set(_FIDO2_LIBRARY fido2) +else() + message(FATAL_ERROR "Nothing to build (BUILD_*_LIBS=OFF)") +endif() + if(CYGWIN OR MSYS OR MINGW) set(WIN32 1) 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") + elseif((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR MINGW OR CYGWIN) set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_GNU_SOURCE") set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_DEFAULT_SOURCE") elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD") set(FIDO_CFLAGS "${FIDO_CFLAGS} -D__BSD_VISIBLE=1") elseif(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_NETBSD_SOURCE") 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("-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_symbol_exists(arc4random_buf stdlib.h HAVE_ARC4RANDOM_BUF) +check_symbol_exists(asprintf stdio.h HAVE_ASPRINTF) 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(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_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_ASPRINTF 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_SIGNAL_H HAVE_STRLCAT HAVE_STRLCPY HAVE_STRSEP HAVE_SYSCONF HAVE_SYS_RANDOM_H HAVE_TIMESPECSUB HAVE_TIMINGSAFE_BCMP HAVE_UNISTD_H ) foreach(v ${CHECK_VARIABLES}) if (${v}) add_definitions(-D${v}) endif() endforeach() -if(HAVE_EXPLICIT_BZERO AND NOT LIBFUZZER) +if(HAVE_EXPLICIT_BZERO AND NOT FUZZ) add_definitions(-DHAVE_EXPLICIT_BZERO) endif() if(UNIX) add_definitions(-DHAVE_DEV_URANDOM) endif() + if(MSVC) if((NOT CBOR_INCLUDE_DIRS) OR (NOT CBOR_LIBRARY_DIRS) OR - (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)) + (NOT CRYPTO_INCLUDE_DIRS) OR (NOT CRYPTO_LIBRARY_DIRS) OR + (NOT ZLIB_INCLUDE_DIRS) OR (NOT ZLIB_LIBRARY_DIRS)) message(FATAL_ERROR "please define " - "{CBOR,CRYPTO,ZLIB}_{INCLUDE,LIBRARY,BIN}_DIRS when " + "{CBOR,CRYPTO,ZLIB}_{INCLUDE,LIBRARY}_DIRS when " "building under msvc") endif() - set(CBOR_LIBRARIES cbor) - set(ZLIB_LIBRARIES zlib) - set(CRYPTO_LIBRARIES crypto-47) + if(BUILD_TESTS AND BUILD_SHARED_LIBS AND + ((NOT CBOR_BIN_DIRS) OR (NOT ZLIB_BIN_DIRS) OR (NOT CRYPTO_BIN_DIRS))) + message(FATAL_ERROR "please define {CBOR,CRYPTO,ZLIB}_BIN_DIRS " + "when building tests") + endif() + if(NOT CBOR_LIBRARIES) + set(CBOR_LIBRARIES cbor) + endif() + if(NOT ZLIB_LIBRARIES) + set(ZLIB_LIBRARIES zlib1) + endif() + if(NOT CRYPTO_LIBRARIES) + set(CRYPTO_LIBRARIES crypto) + endif() + 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; "C4201" # nonstandard extension used: nameless 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} /Od /Z7 /guard:cf /sdl /RTCcsu") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi /guard:cf /sdl") if(USE_WINHELLO) add_definitions(-DUSE_WINHELLO) endif() set(NFC_LINUX OFF) 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(NOT CBOR_LIBRARIES) + set(CBOR_LIBRARIES "cbor") + endif() + if(NOT CRYPTO_LIBRARIES) + set(CRYPTO_LIBRARIES "crypto") + endif() 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() else() set(NFC_LINUX OFF) 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(FUZZ) + set(USE_PCSC ON) + add_definitions(-DFIDO_FUZZ) + endif() + + # If building with PCSC, look for pcsc-lite. + if(USE_PCSC AND NOT (APPLE OR CYGWIN OR MSYS OR MINGW)) + pkg_search_module(PCSC libpcsclite REQUIRED) + set(PCSC_LIBRARIES pcsclite) + endif() + if(USE_HIDAPI) add_definitions(-DUSE_HIDAPI) pkg_search_module(HIDAPI hidapi${HIDAPI_SUFFIX} REQUIRED) set(HIDAPI_LIBRARIES hidapi${HIDAPI_SUFFIX}) endif() if(NFC_LINUX) - add_definitions(-DNFC_LINUX) + add_definitions(-DUSE_NFC) endif() if(WIN32) if(USE_WINHELLO) add_definitions(-DUSE_WINHELLO) endif() else() set(USE_WINHELLO OFF) 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(-Wimplicit-fallthrough) add_compile_options(-pedantic) add_compile_options(-pedantic-errors) + set(EXTRA_CFLAGS "-Wconversion -Wsign-conversion") + if(WIN32) add_compile_options(-Wno-type-limits) add_compile_options(-Wno-cast-function-type) endif() + 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") + if(NOT FUZZ) + set(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wframe-larger-than=2047") 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}) +if(USE_PCSC) + add_definitions(-DUSE_PCSC) +endif() + # 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(${PROJECT_SOURCE_DIR}/src) include_directories(${CBOR_INCLUDE_DIRS}) include_directories(${CRYPTO_INCLUDE_DIRS}) include_directories(${HIDAPI_INCLUDE_DIRS}) +include_directories(${PCSC_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(${PCSC_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}") +if(BUILD_TESTS) + message(STATUS "CBOR_BIN_DIRS: ${CBOR_BIN_DIRS}") +endif() 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_CROSSCOMPILING: ${CMAKE_CROSSCOMPILING}") +message(STATUS "CMAKE_GENERATOR_PLATFORM: ${CMAKE_GENERATOR_PLATFORM}") +message(STATUS "CMAKE_HOST_SYSTEM_NAME: ${CMAKE_HOST_SYSTEM_NAME}") +message(STATUS "CMAKE_HOST_SYSTEM_PROCESSOR: ${CMAKE_HOST_SYSTEM_PROCESSOR}") 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_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") 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}") +if(BUILD_TESTS) + message(STATUS "CRYPTO_BIN_DIRS: ${CRYPTO_BIN_DIRS}") +endif() message(STATUS "CRYPTO_VERSION: ${CRYPTO_VERSION}") message(STATUS "FIDO_VERSION: ${FIDO_VERSION}") message(STATUS "FUZZ: ${FUZZ}") +if(FUZZ) + message(STATUS "FUZZ_LDFLAGS: ${FUZZ_LDFLAGS}") +endif() message(STATUS "ZLIB_INCLUDE_DIRS: ${ZLIB_INCLUDE_DIRS}") message(STATUS "ZLIB_LIBRARIES: ${ZLIB_LIBRARIES}") message(STATUS "ZLIB_LIBRARY_DIRS: ${ZLIB_LIBRARY_DIRS}") +if(BUILD_TESTS) + message(STATUS "ZLIB_BIN_DIRS: ${ZLIB_BIN_DIRS}") +endif() 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 "PCSC_INCLUDE_DIRS: ${PCSC_INCLUDE_DIRS}") +message(STATUS "PCSC_LIBRARIES: ${PCSC_LIBRARIES}") +message(STATUS "PCSC_LIBRARY_DIRS: ${PCSC_LIBRARY_DIRS}") +message(STATUS "PCSC_VERSION: ${PCSC_VERSION}") 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_PCSC: ${USE_PCSC}") message(STATUS "USE_WINHELLO: ${USE_WINHELLO}") message(STATUS "NFC_LINUX: ${NFC_LINUX}") -subdirs(src) +if(BUILD_TESTS) + enable_testing() +endif() + +add_subdirectory(src) + +if(BUILD_TESTS) + add_subdirectory(regress) +endif() if(BUILD_EXAMPLES) - subdirs(examples) + add_subdirectory(examples) endif() if(BUILD_TOOLS) - subdirs(tools) + add_subdirectory(tools) endif() if(BUILD_MANPAGES) - subdirs(man) + add_subdirectory(man) endif() if(NOT WIN32) - if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT FUZZ) - enable_testing() - subdirs(regress) - endif() if(FUZZ) - subdirs(fuzz) + add_subdirectory(fuzz) endif() if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - subdirs(udev) + add_subdirectory(udev) endif() endif() diff --git a/contrib/libfido2/LICENSE b/contrib/libfido2/LICENSE index 75a03f87e3af..ad0e13358930 100644 --- a/contrib/libfido2/LICENSE +++ b/contrib/libfido2/LICENSE @@ -1,24 +1,26 @@ -Copyright (c) 2018-2022 Yubico AB. All rights reserved. +Copyright (c) 2018-2023 Yubico AB. 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +SPDX-License-Identifier: BSD-2-Clause diff --git a/contrib/libfido2/NEWS b/contrib/libfido2/NEWS index a48b685156c1..bf648aabfd92 100644 --- a/contrib/libfido2/NEWS +++ b/contrib/libfido2/NEWS @@ -1,215 +1,256 @@ +* Version 1.13.0 (2023-02-20) + ** Support for linking against OpenSSL on Windows; gh#668. + ** New API calls: + - fido_assert_empty_allow_list; + - fido_cred_empty_exclude_list. + ** fido2-token: fix issue when listing large blobs. + ** Improved support for different fuzzing engines. + +* Version 1.12.0 (2022-09-22) + ** Support for COSE_ES384. + ** Support for hidraw(4) on FreeBSD; gh#597. + ** Improved support for FIDO 2.1 authenticators. + ** New API calls: + - es384_pk_free; + - es384_pk_from_EC_KEY; + - es384_pk_from_EVP_PKEY; + - es384_pk_from_ptr; + - es384_pk_new; + - es384_pk_to_EVP_PKEY; + - fido_cbor_info_certs_len; + - fido_cbor_info_certs_name_ptr; + - fido_cbor_info_certs_value_ptr; + - fido_cbor_info_maxrpid_minpinlen; + - fido_cbor_info_minpinlen; + - fido_cbor_info_new_pin_required; + - fido_cbor_info_rk_remaining; + - fido_cbor_info_uv_attempts; + - fido_cbor_info_uv_modality. + ** Documentation and reliability fixes. + +* Version 1.11.0 (2022-05-03) + ** Experimental PCSC support; enable with -DUSE_PCSC. + ** Improved OpenSSL 3.0 compatibility. + ** Use RFC1951 raw deflate to compress CTAP 2.1 largeBlobs. + ** winhello: advertise "uv" instead of "clientPin". + ** winhello: support hmac-secret in fido_dev_get_assert(). + ** New API calls: + - fido_cbor_info_maxlargeblob. + ** Documentation and reliability fixes. + ** Separate build and regress targets. + * Version 1.10.0 (2022-01-17) ** hid_osx: handle devices with paths > 511 bytes; gh#462. ** bio: fix CTAP2 canonical CBOR encoding in fido_bio_dev_enroll_*(); gh#480. ** winhello: fallback to GetTopWindow() if GetForegroundWindow() fails. ** winhello: fallback to hid_win.c if webauthn.dll isn't available. ** New API calls: - fido_dev_info_set; - fido_dev_io_handle; - fido_dev_new_with_info; - fido_dev_open_with_info. ** Cygwin and NetBSD build fixes. ** Documentation and reliability fixes. ** Support for TPM 2.0 attestation of COSE_ES256 credentials. * 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 114cc5eed762..44d559894dac 100644 --- a/contrib/libfido2/README.adoc +++ b/contrib/libfido2/README.adoc @@ -1,96 +1,144 @@ == 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 +communicate with a FIDO device over USB or NFC, and to verify attestation and assertion signatures. *libfido2* supports the FIDO U2F (CTAP 1) and FIDO2 (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] +=== Releases + +The current release of *libfido2* is 1.13.0. Signed release tarballs are +available at Yubico's +https://developers.yubico.com/libfido2/Releases[release page]. + +=== Dependencies + +*libfido2* depends on https://github.com/pjk/libcbor[libcbor], +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. + === Installation -==== Releases +==== Fedora 35 and 34 -The current release of *libfido2* is 1.10.0. Please consult Yubico's -https://developers.yubico.com/libfido2/Releases[release page] for source -and binary releases. + $ sudo dnf install libfido2 libfido2-devel fido2-tools -==== Ubuntu 20.04 (Focal) +==== Ubuntu 22.04 (Jammy) and 20.04 (Focal) - $ sudo apt install libfido2-1 - $ sudo apt install libfido2-dev - $ sudo apt install libfido2-doc + $ sudo apt install libfido2-1 libfido2-dev libfido2-doc fido2-tools 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 + $ sudo apt install libfido2-1 libfido2-dev libfido2-doc fido2-tools + +On Linux, you may need to add a udev rule to be able to access the FIDO +device. 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" +---- ==== macOS $ brew install libfido2 -Or from source, on UNIX-like systems: +==== Windows + +Please consult Yubico's +https://developers.yubico.com/libfido2/Releases[release page] for ARM, ARM64, +Win32, and Win64 artefacts. + +=== Building from source + +On UNIX-like systems: $ 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] 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" ----- +be installed, or the PKG_CONFIG_PATH environment variable set. For complete, +OS-specific build instructions, please refer to the `.actions/` +(Linux, macOS, BSD) and `windows/` directories. + +=== Build-time Customisation + +*libfido2* supports a number of CMake options. Some of the options require +additional dependencies. Options that are disabled by default are not +officially supported. + +[%autowidth.stretch] +|=== +|*Option* |*Description* |*Default* +| BUILD_EXAMPLES | Build example programs | ON +| BUILD_MANPAGES | Build man pages | ON +| BUILD_SHARED_LIBS | Build a shared library | ON +| BUILD_STATIC_LIBS | Build a static library | ON +| BUILD_TOOLS | Build auxiliary tools | ON +| FUZZ | Enable fuzzing instrumentation | OFF +| NFC_LINUX | Enable netlink NFC support on Linux | ON +| USE_HIDAPI | Use hidapi as the HID backend | OFF +| USE_PCSC | Enable experimental PCSC support | OFF +| USE_WINHELLO | Abstract Windows Hello as a FIDO device | ON +|=== + +The USE_HIDAPI option requires https://github.com/libusb/hidapi[hidapi]. The +USE_PCSC option requires https://github.com/LudovicRousseau/PCSC[pcsc-lite] on +Linux. + +=== Development + +Please use https://github.com/Yubico/libfido2/discussions[GitHub Discussions] +to ask questions and suggest features, and +https://github.com/Yubico/libfido2/pulls[GitHub pull-requests] for code +contributions. + +=== Reporting bugs + +Please use https://github.com/Yubico/libfido2/issues[GitHub Issues] to report +bugs. To report security issues, please contact security@yubico.com. A PGP +public key can be found at +https://www.yubico.com/support/security-advisories/issue-rating-system/. diff --git a/contrib/libfido2/examples/CMakeLists.txt b/contrib/libfido2/examples/CMakeLists.txt index ad3d44faad6b..f013df4e71ec 100644 --- a/contrib/libfido2/examples/CMakeLists.txt +++ b/contrib/libfido2/examples/CMakeLists.txt @@ -1,69 +1,59 @@ # 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. +# SPDX-License-Identifier: BSD-2-Clause list(APPEND COMPAT_SOURCES ../openbsd-compat/clock_gettime.c ../openbsd-compat/getopt_long.c ../openbsd-compat/strlcat.c ../openbsd-compat/strlcpy.c ) if(WIN32 AND BUILD_SHARED_LIBS AND NOT CYGWIN AND NOT MSYS) list(APPEND COMPAT_SOURCES ../openbsd-compat/posix_win.c) endif() -# set the library to link against -if(BUILD_STATIC_LIBS) - # drop -rdynamic - set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") - set(_FIDO2_LIBRARY fido2) -elseif(BUILD_SHARED_LIBS) - set(_FIDO2_LIBRARY fido2_shared) -else() - set(_FIDO2_LIBRARY ${CRYPTO_LIBRARIES} fido2) -endif() - # enable -Wconversion -Wsign-conversion if(NOT MSVC) set_source_files_properties(assert.c cred.c info.c manifest.c reset.c retries.c setpin.c util.c PROPERTIES COMPILE_FLAGS "-Wconversion -Wsign-conversion") endif() # manifest add_executable(manifest manifest.c ${COMPAT_SOURCES}) target_link_libraries(manifest ${_FIDO2_LIBRARY}) # info add_executable(info info.c ${COMPAT_SOURCES}) target_link_libraries(info ${_FIDO2_LIBRARY}) # reset add_executable(reset reset.c util.c ${COMPAT_SOURCES}) target_link_libraries(reset ${_FIDO2_LIBRARY}) # cred add_executable(cred cred.c util.c ${COMPAT_SOURCES}) target_link_libraries(cred ${_FIDO2_LIBRARY}) # assert add_executable(assert assert.c util.c ${COMPAT_SOURCES}) target_link_libraries(assert ${_FIDO2_LIBRARY}) # setpin add_executable(setpin setpin.c ${COMPAT_SOURCES}) target_link_libraries(setpin ${_FIDO2_LIBRARY}) # retries add_executable(retries retries.c ${COMPAT_SOURCES}) target_link_libraries(retries ${_FIDO2_LIBRARY}) # select add_executable(select select.c ${COMPAT_SOURCES}) target_link_libraries(select ${_FIDO2_LIBRARY}) if(MINGW) # needed for nanosleep() in mingw target_link_libraries(select winpthread) endif() diff --git a/contrib/libfido2/examples/README.adoc b/contrib/libfido2/examples/README.adoc index 44ee52743a0d..d44218c2cf87 100644 --- a/contrib/libfido2/examples/README.adoc +++ b/contrib/libfido2/examples/README.adoc @@ -1,98 +1,99 @@ = Examples === Definitions The following definitions are used in the description below: - The file system path or subsystem-specific identification string of a FIDO device. - , [oldpin] Strings passed directly in the executed command's argument vector. - The file system path of a file containing a FIDO credential ID in binary representation. - - The file system path of a file containing a NIST P-256 public key in - PEM format. + The file system path of a file containing a public key in PEM format. - A credential's associated CTAP 2.1 "largeBlob" symmetric key. === Description The following examples are provided: - manifest Prints a list of configured FIDO devices. - info Prints information about . - reset Performs a factory reset on . - setpin [oldpin] Configures as the new PIN of . If [oldpin] is provided, the device's PIN is changed from [oldpin] to . -- cred [-t ecdsa|rsa|eddsa] [-k pubkey] [-ei cred_id] [-P pin] [-T seconds] - [-b blobkey] [-hruv] +- cred [-t es256|es384|rs256|eddsa] [-k pubkey] [-ei cred_id] [-P pin] + [-T seconds] [-b blobkey] [-hruv] Creates a new credential on and verify that the credential was signed by the authenticator. The device's attestation certificate is not verified. If option -k is specified, the credential's public key is stored in . If option -i is specified, the credential ID is stored in . The -e option may be used to add to the list of excluded credentials. If option -h is specified, the hmac-secret FIDO2 extension is enabled on the generated credential. If option -r is specified, the generated credential will involve a resident key. User verification may be requested through the -v option. If option -u is specified, the credential is generated using U2F (CTAP1) instead of FIDO2 (CTAP2) commands. The -T option may be used to enforce a timeout of . If the option -b is specified, the credential's "largeBlob" key is stored in . -- assert [-t ecdsa|rsa|eddsa] [-a cred_id] [-h hmac_secret] [-s hmac_salt] - [-P pin] [-T seconds] [-b blobkey] [-puv] +- assert [-t es256|es384|rs256|eddsa] [-a cred_id] [-h hmac_secret] [-P pin] + [-s hmac_salt] [-T seconds] [-b blobkey] [-puv] Asks for a FIDO2 assertion corresponding to [cred_id], which may be omitted for resident keys. The obtained assertion is verified using . The -p option requests that the user - be present. User verification may be requested through the -v - option. If option -u is specified, the assertion is generated using + be present and checks whether the user presence bit was signed by the + authenticator. The -v option requests user verification and checks + whether the user verification bit was signed by the authenticator. + If option -u is specified, the assertion is generated using U2F (CTAP1) instead of FIDO2 (CTAP2) commands. If option -s is specified, a FIDO2 hmac-secret is requested from the authenticator, and the contents of are used as the salt. If option -h is specified, the resulting hmac-secret is stored in . The -T option may be used to enforce a timeout of . If the option -b specified, the credential's "largeBlob" key is stored in . - retries Get the number of PIN attempts left on before lockout. - select Enumerates available FIDO devices and, if more than one is present, simultaneously requests touch on all of them, printing information about the device touched. Debugging is possible through the use of the FIDO_DEBUG environment variable. If set, libfido2 will produce a log of its transactions with the authenticator. Additionally, an example of a WebAuthn client using libfido2 is available at https://github.com/martelletto/fido2-webauthn-client. diff --git a/contrib/libfido2/examples/assert.c b/contrib/libfido2/examples/assert.c index 8b0dbd9f6eb2..32ba97b2fca3 100644 --- a/contrib/libfido2/examples/assert.c +++ b/contrib/libfido2/examples/assert.c @@ -1,328 +1,349 @@ /* - * Copyright (c) 2018-2021 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #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 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"); + fprintf(stderr, "usage: assert [-t es256|es384|rs256|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; + es384_pk_t *es384_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_ES384: + if ((ec = read_ec_pubkey(key)) == NULL) + errx(1, "read_ec_pubkey"); + + if ((es384_pk = es384_pk_new()) == NULL) + errx(1, "es384_pk_new"); + + if (es384_pk_from_EC_KEY(es384_pk, ec) != FIDO_OK) + errx(1, "es384_pk_from_EC_KEY"); + + pk = es384_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(assert, cd, sizeof(cd)); if (r != FIDO_OK) 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); + es384_pk_free(&es384_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 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': if (base10(optarg, &ms) < 0) errx(1, "base10: %s", optarg); if (ms <= 0 || ms > 30) errx(1, "-T: %s must be in (0,30]", optarg); ms *= 1000; /* seconds to milliseconds */ break; 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) + if (strcmp(optarg, "es256") == 0) type = COSE_ES256; - else if (strcmp(optarg, "rsa") == 0) + else if (strcmp(optarg, "es384") == 0) + type = COSE_ES384; + else if (strcmp(optarg, "rs256") == 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(assert, cd, sizeof(cd)); if (r != FIDO_OK) 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); /* 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); 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 4a9d8bf4b25a..576900d97786 100644 --- a/contrib/libfido2/examples/cred.c +++ b/contrib/libfido2/examples/cred.c @@ -1,300 +1,311 @@ /* - * Copyright (c) 2018-2021 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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 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] " + fprintf(stderr, "usage: cred [-t es256|es384|rs256|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 *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 */ r = fido_cred_set_clientdata(cred, cd, sizeof(cd)); if (r != FIDO_OK) 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; } /* attestation statement */ r = fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len); if (r != FIDO_OK) 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), + if (write_es256_pubkey(key_out, + fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)) < 0) - errx(1, "write_ec_pubkey"); + errx(1, "write_es256_pubkey"); + } else if (type == COSE_ES384) { + if (write_es384_pubkey(key_out, + fido_cred_pubkey_ptr(cred), + fido_cred_pubkey_len(cred)) < 0) + errx(1, "write_es384_pubkey"); } else if (type == COSE_RS256) { - if (write_rsa_pubkey(key_out, fido_cred_pubkey_ptr(cred), + if (write_rs256_pubkey(key_out, + fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)) < 0) - errx(1, "write_rsa_pubkey"); + errx(1, "write_rs256_pubkey"); } else if (type == COSE_EDDSA) { - if (write_eddsa_pubkey(key_out, fido_cred_pubkey_ptr(cred), + 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); } 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; unsigned char *body = NULL; long long ms = 0; size_t len; int type = COSE_ES256; int ext = 0; int ch; int r; 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': if (base10(optarg, &ms) < 0) errx(1, "base10: %s", optarg); if (ms <= 0 || ms > 30) errx(1, "-T: %s must be in (0,30]", optarg); ms *= 1000; /* seconds to milliseconds */ break; 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) + if (strcmp(optarg, "es256") == 0) type = COSE_ES256; - else if (strcmp(optarg, "rsa") == 0) + else if (strcmp(optarg, "es384") == 0) + type = COSE_ES384; + else if (strcmp(optarg, "rs256") == 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 != 1) usage(); 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 */ r = fido_cred_set_clientdata(cred, cd, sizeof(cd)); if (r != FIDO_OK) 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); /* 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); 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_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 5633b23d2003..5cffd7fbf882 100644 --- a/contrib/libfido2/examples/extern.h +++ b/contrib/libfido2/examples/extern.h @@ -1,25 +1,27 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #ifndef _EXTERN_H_ #define _EXTERN_H_ #include #include #include /* 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_es256_pubkey(const char *, const void *, size_t); +int write_es384_pubkey(const char *, const void *, size_t); +int write_rs256_pubkey(const char *, const void *, size_t); int write_eddsa_pubkey(const char *, const void *, size_t); #endif /* _EXTERN_H_ */ diff --git a/contrib/libfido2/examples/info.c b/contrib/libfido2/examples/info.c index 72b786a8bd83..a10a50cffb37 100644 --- a/contrib/libfido2/examples/info.c +++ b/contrib/libfido2/examples/info.c @@ -1,293 +1,382 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" /* * Pretty-print a device's capabilities flags and return the result. */ 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); } /* * Print a FIDO device's attributes on stdout. */ 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); } /* * Auxiliary function to print an array of strings on stdout. */ 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"); } /* * Auxiliary function to print (char *, bool) pairs on stdout. */ 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"); } +/* + * Auxiliary function to print (char *, uint64_t) pairs on stdout. + */ +static void +print_cert_array(const char *label, char * const *name, const uint64_t *value, + size_t len) +{ + if (len == 0) + return; + + printf("%s: ", label); + + for (size_t i = 0; i < len; i++) + printf("%s%s %llu", i > 0 ? ", " : "", name[i], + (unsigned long long)value[i]); + + printf("\n"); +} + /* * Auxiliary function to print a list of supported COSE algorithms on stdout. */ 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_ES384: + cose = "es384"; + break; case COSE_RS256: cose = "rs256"; break; + case COSE_EDDSA: + cose = "eddsa"; + 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"); } /* * Auxiliary function to print an authenticator's AAGUID on stdout. */ static void print_aaguid(const unsigned char *buf, size_t buflen) { printf("aaguid: "); while (buflen--) printf("%02x", *buf++); printf("\n"); } /* * Auxiliary function to print an authenticator's maximum message size on * stdout. */ static void print_maxmsgsiz(uint64_t maxmsgsiz) { printf("maxmsgsiz: %d\n", (int)maxmsgsiz); } /* * Auxiliary function to print an authenticator's maximum number of credentials * in a credential list on stdout. */ static void print_maxcredcntlst(uint64_t maxcredcntlst) { printf("maxcredcntlst: %d\n", (int)maxcredcntlst); } /* * Auxiliary function to print an authenticator's maximum credential ID length * on stdout. */ static void print_maxcredidlen(uint64_t maxcredidlen) { printf("maxcredlen: %d\n", (int)maxcredidlen); } +/* + * Auxiliary function to print the maximum size of an authenticator's + * serialized largeBlob array. + */ +static void +print_maxlargeblob(uint64_t maxlargeblob) +{ + printf("maxlargeblob: %d\n", (int)maxlargeblob); +} + +/* + * Auxiliary function to print the authenticator's estimated number of + * remaining resident credentials. + */ +static void +print_rk_remaining(int64_t rk_remaining) +{ + printf("remaining rk(s): "); + + if (rk_remaining == -1) + printf("undefined\n"); + else + printf("%d\n", (int)rk_remaining); +} + +/* + * Auxiliary function to print the minimum pin length observed by the + * authenticator. + */ +static void +print_minpinlen(uint64_t minpinlen) +{ + printf("minpinlen: %d\n", (int)minpinlen); +} + +/* + * Auxiliary function to print the authenticator's preferred (platform) + * UV attempts. + */ +static void +print_uv_attempts(uint64_t uv_attempts) +{ + printf("platform uv attempt(s): %d\n", (int)uv_attempts); +} + /* * Auxiliary function to print an authenticator's firmware version on stdout. */ static void print_fwversion(uint64_t fwversion) { printf("fwversion: 0x%x\n", (int)fwversion); } /* * Auxiliary function to print an array of bytes on stdout. */ 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"); } static void getinfo(const char *path) { fido_dev_t *dev; fido_cbor_info_t *ci; int r; fido_init(0); if ((dev = fido_dev_new()) == NULL) errx(1, "fido_dev_new"); if ((r = fido_dev_open(dev, path)) != FIDO_OK) errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); 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 certifications */ + print_cert_array("certifications", fido_cbor_info_certs_name_ptr(ci), + fido_cbor_info_certs_value_ptr(ci), + fido_cbor_info_certs_len(ci)); + + /* print firmware version */ + print_fwversion(fido_cbor_info_fwversion(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 maximum length of largeBlob array */ + print_maxlargeblob(fido_cbor_info_maxlargeblob(ci)); + + /* print number of remaining resident credentials */ + print_rk_remaining(fido_cbor_info_rk_remaining(ci)); + + /* print minimum pin length */ + print_minpinlen(fido_cbor_info_minpinlen(ci)); /* print supported pin protocols */ print_byte_array("pin protocols", fido_cbor_info_protocols_ptr(ci), fido_cbor_info_protocols_len(ci)); + /* print whether a new pin is required */ + printf("pin change required: %s\n", + fido_cbor_info_new_pin_required(ci) ? "true" : "false"); + + /* print platform uv attempts */ + print_uv_attempts(fido_cbor_info_uv_attempts(ci)); + fido_cbor_info_free(&ci); end: if ((r = fido_dev_close(dev)) != FIDO_OK) errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r); fido_dev_free(&dev); } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "usage: info \n"); exit(EXIT_FAILURE); } getinfo(argv[1]); exit(0); } diff --git a/contrib/libfido2/examples/manifest.c b/contrib/libfido2/examples/manifest.c index d38166a9fea9..c2b3bf19137b 100644 --- a/contrib/libfido2/examples/manifest.c +++ b/contrib/libfido2/examples/manifest.c @@ -1,41 +1,42 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include "../openbsd-compat/openbsd-compat.h" int main(void) { fido_dev_info_t *devlist; size_t ndevs; int r; fido_init(0); if ((devlist = fido_dev_info_new(64)) == NULL) errx(1, "fido_dev_info_new"); if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK) errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r); 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); } diff --git a/contrib/libfido2/examples/reset.c b/contrib/libfido2/examples/reset.c index b429d05f0fe4..767a162b6f63 100644 --- a/contrib/libfido2/examples/reset.c +++ b/contrib/libfido2/examples/reset.c @@ -1,48 +1,49 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ /* * 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); if ((r = fido_dev_reset(dev)) != FIDO_OK) { 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/retries.c b/contrib/libfido2/examples/retries.c index b96118b1e154..a0610fe13903 100644 --- a/contrib/libfido2/examples/retries.c +++ b/contrib/libfido2/examples/retries.c @@ -1,48 +1,49 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ /* * Get an authenticator's number of PIN attempts left. */ #include #include #include #include "../openbsd-compat/openbsd-compat.h" int main(int argc, char **argv) { fido_dev_t *dev; int n; int r; if (argc != 2) { fprintf(stderr, "usage: retries \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_open: %s (0x%x)", fido_strerr(r), r); if ((r = fido_dev_get_retry_count(dev, &n)) != FIDO_OK) - errx(1, "fido_get_retries: %s (0x%x)", fido_strerr(r), r); + errx(1, "fido_dev_get_retry_count: %s (0x%x)", fido_strerr(r), r); if ((r = fido_dev_close(dev)) != FIDO_OK) errx(1, "fido_close: %s (0x%x)", fido_strerr(r), r); fido_dev_free(&dev); printf("%d\n", n); exit(0); } diff --git a/contrib/libfido2/examples/select.c b/contrib/libfido2/examples/select.c index 6ede9b490a95..008eb2e99b8f 100644 --- a/contrib/libfido2/examples/select.c +++ b/contrib/libfido2/examples/select.c @@ -1,214 +1,215 @@ /* - * Copyright (c) 2020 Yubico AB. All rights reserved. + * Copyright (c) 2020-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #define FIDO_POLL_MS 50 #if defined(_MSC_VER) static int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) { if (rmtp != NULL) { errno = EINVAL; return (-1); } - Sleep(rqtp->tv_nsec / 1000000); + Sleep((DWORD)(rqtp->tv_sec * 1000) + (DWORD)(rqtp->tv_nsec / 1000000)); return (0); } #endif static fido_dev_t * open_dev(const fido_dev_info_t *di) { fido_dev_t *dev; int r; if ((dev = fido_dev_new()) == NULL) { warnx("%s: fido_dev_new", __func__); return (NULL); } if ((r = fido_dev_open(dev, fido_dev_info_path(di))) != FIDO_OK) { warnx("%s: fido_dev_open %s: %s", __func__, fido_dev_info_path(di), fido_strerr(r)); fido_dev_free(&dev); return (NULL); } printf("%s (0x%04x:0x%04x) is %s\n", fido_dev_info_path(di), fido_dev_info_vendor(di), fido_dev_info_product(di), fido_dev_is_fido2(dev) ? "fido2" : "u2f"); return (dev); } static int select_dev(const fido_dev_info_t *devlist, size_t ndevs, fido_dev_t **dev, size_t *idx, int secs) { const fido_dev_info_t *di; fido_dev_t **devtab; struct timespec ts_start; struct timespec ts_now; struct timespec ts_delta; struct timespec ts_pause; size_t nopen = 0; int touched; int r; long ms_remain; *dev = NULL; *idx = 0; printf("%u authenticator(s) detected\n", (unsigned)ndevs); if (ndevs == 0) return (0); /* nothing to do */ if ((devtab = calloc(ndevs, sizeof(*devtab))) == NULL) { warn("%s: calloc", __func__); return (-1); } for (size_t i = 0; i < ndevs; i++) { di = fido_dev_info_ptr(devlist, i); if ((devtab[i] = open_dev(di)) != NULL) { *idx = i; nopen++; } } printf("%u authenticator(s) opened\n", (unsigned)nopen); if (nopen < 2) { if (nopen == 1) *dev = devtab[*idx]; /* single candidate */ r = 0; goto out; } for (size_t i = 0; i < ndevs; i++) { di = fido_dev_info_ptr(devlist, i); if (devtab[i] == NULL) continue; /* failed to open */ if ((r = fido_dev_get_touch_begin(devtab[i])) != FIDO_OK) { warnx("%s: fido_dev_get_touch_begin %s: %s", __func__, fido_dev_info_path(di), fido_strerr(r)); r = -1; goto out; } } if (clock_gettime(CLOCK_MONOTONIC, &ts_start) != 0) { warn("%s: clock_gettime", __func__); r = -1; goto out; } ts_pause.tv_sec = 0; ts_pause.tv_nsec = 200000000; /* 200ms */ do { nanosleep(&ts_pause, NULL); for (size_t i = 0; i < ndevs; i++) { di = fido_dev_info_ptr(devlist, i); if (devtab[i] == NULL) { /* failed to open or discarded */ continue; } if ((r = fido_dev_get_touch_status(devtab[i], &touched, FIDO_POLL_MS)) != FIDO_OK) { warnx("%s: fido_dev_get_touch_status %s: %s", __func__, fido_dev_info_path(di), fido_strerr(r)); fido_dev_close(devtab[i]); fido_dev_free(&devtab[i]); continue; /* discard */ } if (touched) { *dev = devtab[i]; *idx = i; r = 0; goto out; } } if (clock_gettime(CLOCK_MONOTONIC, &ts_now) != 0) { warn("%s: clock_gettime", __func__); r = -1; goto out; } timespecsub(&ts_now, &ts_start, &ts_delta); ms_remain = (secs * 1000) - ((long)ts_delta.tv_sec * 1000) + ((long)ts_delta.tv_nsec / 1000000); } while (ms_remain > FIDO_POLL_MS); printf("timeout after %d seconds\n", secs); r = -1; out: if (r != 0) { *dev = NULL; *idx = 0; } for (size_t i = 0; i < ndevs; i++) { if (devtab[i] && devtab[i] != *dev) { fido_dev_cancel(devtab[i]); fido_dev_close(devtab[i]); fido_dev_free(&devtab[i]); } } free(devtab); return (r); } int main(void) { const fido_dev_info_t *di; fido_dev_info_t *devlist; fido_dev_t *dev; size_t idx; size_t ndevs; int r; fido_init(0); if ((devlist = fido_dev_info_new(64)) == NULL) errx(1, "fido_dev_info_new"); if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK) errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r); if (select_dev(devlist, ndevs, &dev, &idx, 15) != 0) errx(1, "select_dev"); if (dev == NULL) errx(1, "no authenticator found"); di = fido_dev_info_ptr(devlist, idx); printf("%s: %s by %s (PIN %sset)\n", fido_dev_info_path(di), fido_dev_info_product_string(di), fido_dev_info_manufacturer_string(di), fido_dev_has_pin(dev) ? "" : "un"); fido_dev_close(dev); fido_dev_free(&dev); fido_dev_info_free(&devlist, ndevs); exit(0); } diff --git a/contrib/libfido2/examples/setpin.c b/contrib/libfido2/examples/setpin.c index 4b9e792769d9..72e08e4b9088 100644 --- a/contrib/libfido2/examples/setpin.c +++ b/contrib/libfido2/examples/setpin.c @@ -1,54 +1,55 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ /* * Configure a PIN on a given authenticator. */ #include #include #include #include "../openbsd-compat/openbsd-compat.h" static void setpin(const char *path, const char *pin, const char *oldpin) { fido_dev_t *dev; int r; fido_init(0); if ((dev = fido_dev_new()) == NULL) errx(1, "fido_dev_new"); if ((r = fido_dev_open(dev, path)) != FIDO_OK) errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r); if ((r = fido_dev_set_pin(dev, pin, oldpin)) != FIDO_OK) - errx(1, "fido_setpin: %s (0x%x)", fido_strerr(r), r); + errx(1, "fido_dev_set_pin: %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); } int main(int argc, char **argv) { if (argc < 3 || argc > 4) { fprintf(stderr, "usage: setpin [oldpin] \n"); exit(EXIT_FAILURE); } if (argc == 3) setpin(argv[2], argv[1], NULL); else setpin(argv[3], argv[1], argv[2]); exit(0); } diff --git a/contrib/libfido2/examples/util.c b/contrib/libfido2/examples/util.c index 8b360af21c7a..0c0c77a94001 100644 --- a/contrib/libfido2/examples/util.c +++ b/contrib/libfido2/examples/util.c @@ -1,385 +1,444 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #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" 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) +write_es256_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); } +int +write_es384_pubkey(const char *path, const void *ptr, size_t len) +{ + FILE *fp = NULL; + EVP_PKEY *pkey = NULL; + es384_pk_t *pk = NULL; + int fd = -1; + int ok = -1; + + if ((pk = es384_pk_new()) == NULL) { + warnx("es384_pk_new"); + goto fail; + } + + if (es384_pk_from_ptr(pk, ptr, len) != FIDO_OK) { + warnx("es384_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 = es384_pk_to_EVP_PKEY(pk)) == NULL) { + warnx("es384_pk_to_EVP_PKEY"); + goto fail; + } + + if (PEM_write_PUBKEY(fp, pkey) == 0) { + warnx("PEM_write_PUBKEY"); + goto fail; + } + + ok = 0; +fail: + es384_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) +write_rs256_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/CMakeLists.txt b/contrib/libfido2/fuzz/CMakeLists.txt index b1eebd55481b..cc30baae88f2 100644 --- a/contrib/libfido2/fuzz/CMakeLists.txt +++ b/contrib/libfido2/fuzz/CMakeLists.txt @@ -1,63 +1,82 @@ -# Copyright (c) 2019 Yubico AB. All rights reserved. +# Copyright (c) 2019-2023 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. +# SPDX-License-Identifier: BSD-2-Clause list(APPEND COMPAT_SOURCES ../openbsd-compat/strlcpy.c ../openbsd-compat/strlcat.c ) list(APPEND COMMON_SOURCES libfuzzer.c mutator_aux.c ) -set(FUZZ_LDFLAGS "-fsanitize=fuzzer") +# XXX: OSS-Fuzz require linking using CXX +set(FUZZ_LINKER_LANGUAGE "C" CACHE STRING "Linker language for fuzz harnesses") +mark_as_advanced(FUZZ_LINKER_LANGUAGE) +enable_language(${FUZZ_LINKER_LANGUAGE}) # fuzz_cred add_executable(fuzz_cred fuzz_cred.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) -target_compile_options(fuzz_cred PRIVATE ${FUZZ_LDFLAGS}) -set_target_properties(fuzz_cred PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) +set_target_properties(fuzz_cred PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) target_link_libraries(fuzz_cred fido2_shared) # fuzz_assert add_executable(fuzz_assert fuzz_assert.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) -target_compile_options(fuzz_assert PRIVATE ${FUZZ_LDFLAGS}) -set_target_properties(fuzz_assert PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) +set_target_properties(fuzz_assert PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) target_link_libraries(fuzz_assert fido2_shared) # fuzz_mgmt add_executable(fuzz_mgmt fuzz_mgmt.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) -target_compile_options(fuzz_mgmt PRIVATE ${FUZZ_LDFLAGS}) -set_target_properties(fuzz_mgmt PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) +set_target_properties(fuzz_mgmt PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) target_link_libraries(fuzz_mgmt fido2_shared) # fuzz_credman add_executable(fuzz_credman fuzz_credman.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) -target_compile_options(fuzz_credman PRIVATE ${FUZZ_LDFLAGS}) -set_target_properties(fuzz_credman PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) +set_target_properties(fuzz_credman PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) target_link_libraries(fuzz_credman fido2_shared) # fuzz_bio add_executable(fuzz_bio fuzz_bio.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) -target_compile_options(fuzz_bio PRIVATE ${FUZZ_LDFLAGS}) -set_target_properties(fuzz_bio PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) +set_target_properties(fuzz_bio PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) target_link_libraries(fuzz_bio fido2_shared) # fuzz_hid add_executable(fuzz_hid fuzz_hid.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) -target_compile_options(fuzz_hid PRIVATE ${FUZZ_LDFLAGS}) -set_target_properties(fuzz_hid PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) +set_target_properties(fuzz_hid PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) target_link_libraries(fuzz_hid fido2_shared) # fuzz_netlink add_executable(fuzz_netlink fuzz_netlink.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) -target_compile_options(fuzz_netlink PRIVATE ${FUZZ_LDFLAGS}) -set_target_properties(fuzz_netlink PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) +set_target_properties(fuzz_netlink PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) target_link_libraries(fuzz_netlink fido2_shared) # fuzz_largeblob add_executable(fuzz_largeblob fuzz_largeblob.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) -target_compile_options(fuzz_largeblob PRIVATE ${FUZZ_LDFLAGS}) -set_target_properties(fuzz_largeblob PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS}) +set_target_properties(fuzz_largeblob PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) target_link_libraries(fuzz_largeblob fido2_shared) + +# fuzz_pcsc +add_executable(fuzz_pcsc fuzz_pcsc.c ${COMMON_SOURCES} ${COMPAT_SOURCES}) +set_target_properties(fuzz_pcsc PROPERTIES + LINK_FLAGS ${FUZZ_LDFLAGS} + LINKER_LANGUAGE ${FUZZ_LINKER_LANGUAGE}) +target_link_libraries(fuzz_pcsc fido2_shared) diff --git a/contrib/libfido2/fuzz/Dockerfile b/contrib/libfido2/fuzz/Dockerfile index aefe1980ada4..9cda37589b44 100644 --- a/contrib/libfido2/fuzz/Dockerfile +++ b/contrib/libfido2/fuzz/Dockerfile @@ -1,12 +1,16 @@ -# Copyright (c) 2019-2021 Yubico AB. All rights reserved. +# Copyright (c) 2019-2023 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. +# SPDX-License-Identifier: BSD-2-Clause -FROM ubuntu:focal -ENV DEBIAN_FRONTEND=noninteractive -RUN apt-get update -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.9.0 https://github.com/PJK/libcbor -RUN git clone https://github.com/yubico/libfido2 -RUN CC=clang-12 CXX=clang++-12 /libfido2/fuzz/build-coverage /libcbor /libfido2 +FROM alpine:latest +ENV CC=clang +ENV CXX=clang++ +RUN apk -q update +RUN apk add build-base clang clang-analyzer cmake compiler-rt coreutils +RUN apk add eudev-dev git linux-headers llvm openssl-dev pcsc-lite-dev +RUN apk add sudo tar zlib-dev +RUN git clone --branch v0.10.1 --depth=1 https://github.com/PJK/libcbor +RUN git clone --depth=1 https://github.com/yubico/libfido2 +WORKDIR /libfido2 +RUN ./fuzz/build-coverage /libcbor /libfido2 diff --git a/contrib/libfido2/fuzz/Makefile b/contrib/libfido2/fuzz/Makefile index ce3fee73c69c..0e6756f0ada1 100644 --- a/contrib/libfido2/fuzz/Makefile +++ b/contrib/libfido2/fuzz/Makefile @@ -1,81 +1,90 @@ -# Copyright (c) 2019-2021 Yubico AB. All rights reserved. +# Copyright (c) 2019-2023 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. +# SPDX-License-Identifier: BSD-2-Clause -IMAGE := libfido2-coverage:1.10.0 +IMAGE := libfido2-coverage:1.13.1 RUNNER := libfido2-runner -PROFDATA := llvm-profdata-12 -COV := llvm-cov-12 +PROFDATA := llvm-profdata +COV := llvm-cov TARGETS := fuzz_assert fuzz_bio fuzz_cred fuzz_credman fuzz_hid \ - fuzz_largeblob fuzz_netlink fuzz_mgmt + fuzz_largeblob fuzz_netlink fuzz_mgmt fuzz_pcsc 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 + 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 $@' + 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=/$< \ - --show-branch-summary=false -output-dir=/report \ - /libfido2/build/src/libfido2.so' + -ignore-filename-regex=pcsclite.h --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 \ - --show-branch-summary=false /libfido2/build/src/libfido2.so \ - -instr-profile=/$< > $@ + -ignore-filename-regex=pcsclite.h --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 --show-branch-summary=false -instr-profile=/$< \ + -ignore-filename-regex=pcsclite.h -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} +fetch-oss-fuzz: ${CORPORA} + find ${TARGETS} -type f -size +8192c -print0 | xargs -0 rm + +fetch-franz: + ssh franz tar -C corpus -cf- . | tar -xf- + +corpus.tgz: tar zcf $@ ${TARGETS} .PHONY: build run sync corpus ${TARGETS} ${CORPORA} .PHONY: report.tgz summary.txt functions.txt +.PHONY: fetch-oss-fuzz fetch-franz corpus.tgz diff --git a/contrib/libfido2/fuzz/README b/contrib/libfido2/fuzz/README index 28fc7f8f51b2..427625c6e714 100644 --- a/contrib/libfido2/fuzz/README +++ b/contrib/libfido2/fuzz/README @@ -1,33 +1,43 @@ libfido2 can be fuzzed using AFL or libFuzzer, with or without ASAN/MSAN/UBSAN. AFL is more convenient when fuzzing the path from the authenticator to libfido2 in an existing application. To do so, use preload-snoop.c with a real authenticator to obtain an initial corpus, rebuild libfido2 with -DFUZZ=ON, and use preload-fuzz.c to read device data from stdin. libFuzzer is better suited for bespoke fuzzers; see fuzz_cred.c, fuzz_credman.c, fuzz_assert.c, fuzz_hid.c, and fuzz_mgmt.c for examples. To build these -harnesses, use -DFUZZ=ON -DLIBFUZZER=ON. +harnesses, use -DCMAKE_C_FLAGS=-fsanitize=fuzzer-no-link +-DFUZZ_LDFLAGS=-fsanitize=fuzzer -DFUZZ=ON. + +If -DFUZZ=ON is enabled, symbols listed in wrapped.sym are wrapped in the +resulting shared object. The wrapper functions simulate failure according to a +deterministic RNG and probabilities defined in wrap.c. Harnesses wishing to +use this functionality should call prng_init() with a seed obtained from the +corpus. To mutate only the seed part of a libFuzzer harness's corpora, +use '-reduce_inputs=0 --fido-mutate=seed'. To run under ASAN/MSAN/UBSAN, libfido2 needs to be linked against flavours of libcbor and OpenSSL built with the respective sanitiser. In order to keep memory utilisation at a manageable level, you can either enforce limits at the OS level (e.g. cgroups on Linux), or patch libcbor with the diff below. +N.B., the patch below is relative to libcbor 0.10.1. diff --git src/cbor/internal/memory_utils.c src/cbor/internal/memory_utils.c -index aa049a2..e294b38 100644 +index bbea63c..3f7c9af 100644 --- src/cbor/internal/memory_utils.c +++ src/cbor/internal/memory_utils.c -@@ -28,7 +28,10 @@ bool _cbor_safe_to_multiply(size_t a, size_t b) { +@@ -41,7 +41,11 @@ size_t _cbor_safe_signaling_add(size_t a, size_t b) { void* _cbor_alloc_multiple(size_t item_size, size_t item_count) { if (_cbor_safe_to_multiply(item_size, item_count)) { -- return _CBOR_MALLOC(item_size * item_count); +- return _cbor_malloc(item_size * item_count); + if (item_count > 1000) { + return NULL; -+ } else -+ return _CBOR_MALLOC(item_size * item_count); ++ } else { ++ return _cbor_malloc(item_size * item_count); ++ } } else { return NULL; } diff --git a/contrib/libfido2/fuzz/build-coverage b/contrib/libfido2/fuzz/build-coverage index e0e90da02b5d..6cc5041a1db2 100755 --- a/contrib/libfido2/fuzz/build-coverage +++ b/contrib/libfido2/fuzz/build-coverage @@ -1,31 +1,34 @@ #!/bin/sh -eux # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. +# SPDX-License-Identifier: BSD-2-Clause LIBCBOR="$1" LIBFIDO2="$2" CC="${CC:-clang}" CXX="${CXX:-clang++}" PKG_CONFIG_PATH="${PKG_CONFIG_PATH:-${LIBCBOR}/install/lib/pkgconfig}" export CC PKG_CONFIG_PATH # Clean up. rm -rf "${LIBCBOR}/build" "${LIBCBOR}/install" "${LIBFIDO2}/build" # Patch, build, and install libcbor. (cd "${LIBCBOR}" && patch -N -l -s -p0 < "${LIBFIDO2}/fuzz/README") || true mkdir "${LIBCBOR}/build" "${LIBCBOR}/install" (cd "${LIBCBOR}/build" && cmake -DBUILD_SHARED_LIBS=ON \ -DCMAKE_INSTALL_PREFIX="${LIBCBOR}/install" ..) make -C "${LIBCBOR}/build" VERBOSE=1 all install # Build libfido2. mkdir -p "${LIBFIDO2}/build" export CFLAGS="-fprofile-instr-generate -fcoverage-mapping" +export CFLAGS="${CFLAGS} -fsanitize=fuzzer-no-link" export LDFLAGS="${CFLAGS}" -(cd "${LIBFIDO2}/build" && cmake -DFUZZ=ON -DLIBFUZZER=ON \ - -DCMAKE_BUILD_TYPE=Debug ..) +export FUZZ_LDFLAGS="${LDFLAGS} -fsanitize=fuzzer" +(cd "${LIBFIDO2}/build" && cmake -DFUZZ=ON -DFUZZ_LDFLAGS="${FUZZ_LDFLAGS}" \ + -DCMAKE_BUILD_TYPE=Debug ..) make -C "${LIBFIDO2}/build" diff --git a/contrib/libfido2/fuzz/clock.c b/contrib/libfido2/fuzz/clock.c index 23803c2ee3e5..bd758ea1a497 100644 --- a/contrib/libfido2/fuzz/clock.c +++ b/contrib/libfido2/fuzz/clock.c @@ -1,79 +1,80 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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 95744eba634b..fc4bfc5ada4b 100644 --- a/contrib/libfido2/fuzz/dummy.h +++ b/contrib/libfido2/fuzz/dummy.h @@ -1,179 +1,182 @@ /* - * Copyright (c) 2020 Yubico AB. All rights reserved. + * Copyright (c) 2020-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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 char dummy_pcsc_list[] = "reader1\0reader2\0reader3\0\0"; +const char dummy_pcsc_path[] = "pcsc://slot7"; 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 cac142ae970e..f0fb840dd686 100644 --- a/contrib/libfido2/fuzz/export.gnu +++ b/contrib/libfido2/fuzz/export.gnu @@ -1,255 +1,283 @@ { 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; + es384_pk_free; + es384_pk_from_EC_KEY; + es384_pk_from_EVP_PKEY; + es384_pk_from_ptr; + es384_pk_new; + es384_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_certs_len; + fido_cbor_info_certs_name_ptr; + fido_cbor_info_certs_value_ptr; fido_cbor_info_extensions_len; fido_cbor_info_extensions_ptr; fido_cbor_info_free; - fido_cbor_info_maxmsgsiz; + fido_cbor_info_fwversion; fido_cbor_info_maxcredbloblen; fido_cbor_info_maxcredcntlst; fido_cbor_info_maxcredidlen; - fido_cbor_info_fwversion; + fido_cbor_info_maxlargeblob; + fido_cbor_info_maxmsgsiz; + fido_cbor_info_maxrpid_minpinlen; + fido_cbor_info_minpinlen; fido_cbor_info_new; + fido_cbor_info_new_pin_required; 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_rk_remaining; fido_cbor_info_transports_len; fido_cbor_info_transports_ptr; + fido_cbor_info_uv_attempts; + fido_cbor_info_uv_modality; 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_set; 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_pcsc; 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_pcsc_close; + fido_pcsc_manifest; + fido_pcsc_open; + fido_pcsc_read; + fido_pcsc_rx; + fido_pcsc_tx; + fido_pcsc_write; 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; + prng_up; fuzz_clock_reset; + fuzz_save_corpus; set_netlink_io_functions; + set_pcsc_parameters; + set_pcsc_io_functions; set_udev_parameters; uniform_random; local: *; }; diff --git a/contrib/libfido2/fuzz/functions.txt b/contrib/libfido2/fuzz/functions.txt index 946682d07d00..da7f058d6c00 100644 --- a/contrib/libfido2/fuzz/functions.txt +++ b/contrib/libfido2/fuzz/functions.txt @@ -1,871 +1,949 @@ 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_cbc_enc 4 0 100.00% 4 0 100.00% +aes256_cbc_dec 4 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% 42 7 83.33% +aes256.c:aes256_cbc_fips 26 1 96.15% 42 4 90.48% 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% +aes256.c:aes256_gcm 52 1 98.08% 60 4 93.33% -------------------------------------------------------------------------------------------------------- -TOTAL 115 4 96.52% 157 14 91.08% +TOTAL 118 3 97.46% 157 11 92.99% File '/libfido2/src/assert.c': Name Regions Miss Cover Lines Miss Cover ----------------------------------------------------------------------------------------------------------------- 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_get_signed_hash 20 1 95.00% 34 3 91.18% +fido_assert_verify 50 4 92.00% 70 7 90.00% 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_options 8 8 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% 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% 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:fido_dev_get_assert_rx 27 0 100.00% 36 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:fido_get_next_assert_rx 23 2 91.30% 29 5 82.76% assert.c:decrypt_hmac_secrets 9 0 100.00% 15 0 100.00% +assert.c:get_es256_hash 16 0 100.00% 17 0 100.00% +assert.c:get_es384_hash 16 0 100.00% 17 0 100.00% +assert.c:get_eddsa_hash 6 0 100.00% 9 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 563 40 92.90% 694 40 94.24% +TOTAL 605 43 92.89% 745 46 93.83% 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% 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:fido_dev_authkey_rx 14 0 100.00% 21 0 100.00% authkey.c:parse_authkey 8 0 100.00% 10 0 100.00% ----------------------------------------------------------------------------------------------------------------- -TOTAL 44 0 100.00% 59 0 100.00% +TOTAL 52 0 100.00% 66 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_get_template_array 5 2 60.00% 6 1 83.33% fido_bio_dev_set_template_name 7 0 100.00% 6 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_begin 25 2 92.00% 31 1 96.77% +fido_bio_dev_enroll_continue 5 2 60.00% 6 1 83.33% 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% 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% 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% 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_rx_template_array 19 0 100.00% 24 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_rx_enroll_begin 23 0 100.00% 31 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_rx_enroll_continue 19 0 100.00% 25 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_rx_info 19 0 100.00% 24 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% 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% 6 0 100.00% ----------------------------------------------------------------------------------------------------------------- -TOTAL 419 20 95.23% 559 21 96.24% +TOTAL 451 20 95.57% 587 24 95.91% 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% 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% 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% 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% 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% 18 0 100.00% cbor_string_copy 14 0 100.00% 18 0 100.00% 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_auth 21 1 95.24% 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_change_pin_auth 32 1 96.88% 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_pubkey 26 1 96.15% 36 2 94.44% 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 1 90.00% 9 2 77.78% +cbor_decode_bool 10 0 100.00% 11 0 100.00% +cbor_build_uint 10 1 90.00% 9 1 88.89% cbor_array_append 17 0 100.00% 21 0 100.00% -cbor_array_drop 18 2 88.89% 17 3 82.35% +cbor_array_drop 18 0 100.00% 17 0 100.00% 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 0 100.00% 38 0 100.00% +cbor.c:get_cose_alg 46 1 97.83% 45 3 93.33% 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_cred_extension 41 1 97.56% 45 3 93.33% 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_attstmt_entry 56 0 100.00% 51 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 23 97.80% 1237 46 96.28% +TOTAL 1070 13 98.79% 1258 31 97.54% 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% 22 3 86.36% +fido_uncompress 6 0 100.00% 5 0 100.00% +compress.c:rfc1951_deflate 33 4 87.88% 47 6 87.23% +compress.c:rfc1950_inflate 27 2 92.59% 22 4 81.82% +compress.c:rfc1951_inflate 38 8 78.95% 45 14 68.89% ------------------------------------------------------------------------------------------------------------------ -TOTAL 34 4 88.24% 28 3 89.29% +TOTAL 105 14 86.67% 122 24 80.33% File '/libfido2/src/config.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------------------------------- 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_tx 41 0 100.00% 49 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% +TOTAL 112 0 100.00% 152 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% 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_verify 59 2 96.61% 75 4 94.67% +fido_cred_verify_self 60 6 90.00% 87 11 87.36% fido_cred_new 1 0 100.00% 3 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_options 8 8 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_set_blob 13 0 100.00% 8 0 100.00% +fido_cred_set_fmt 20 4 80.00% 12 2 83.33% +fido_cred_set_type 23 2 91.30% 9 1 88.89% 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_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_pubkey_ptr 11 0 100.00% 21 0 100.00% +fido_cred_pubkey_len 11 0 100.00% 21 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% 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:get_signed_hash_u2f 27 0 100.00% 27 0 100.00% +cred.c:verify_attstmt 25 2 92.00% 43 6 86.05% 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% +TOTAL 651 38 94.16% 849 43 94.94% File '/libfido2/src/credman.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------------------------------- 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% 8 0 100.00% +fido_credman_rk_free 6 1 83.33% 8 1 87.50% fido_credman_rk_count 1 0 100.00% 3 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% 7 0 100.00% +fido_credman_metadata_free 6 1 83.33% 7 1 85.71% 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% 8 0 100.00% +fido_credman_rp_free 6 1 83.33% 8 1 87.50% fido_credman_rp_count 1 0 100.00% 3 0 100.00% 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_rx_metadata 19 0 100.00% 24 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_rx_rk 27 0 100.00% 35 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_rx_next_rk 23 2 91.30% 29 5 82.76% 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_rx_rp 27 0 100.00% 35 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_rx_next_rp 23 2 91.30% 29 5 82.76% 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% +TOTAL 422 10 97.63% 557 20 96.41% File '/libfido2/src/dev.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------------------------------- -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_info_manifest 2 0 100.00% 11 0 100.00% fido_dev_open_with_info 5 5 0.00% 6 6 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_open 13 4 69.23% 16 6 62.50% +fido_dev_close 9 2 77.78% 8 1 87.50% 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% 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_dev_io_handle 1 1 0.00% 3 3 0.00% 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% 7 0 100.00% fido_dev_maxmsgsize 1 0 100.00% 3 0 100.00% 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:run_manifest 10 0 100.00% 13 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:fido_dev_open_tx 56 11 80.36% 56 20 64.29% dev.c:set_random_report_len 11 0 100.00% 6 0 100.00% 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% 7 0 100.00% -dev.c:fido_dev_set_option_flags 29 0 100.00% 18 0 100.00% +dev.c:fido_dev_set_option_flags 31 0 100.00% 20 0 100.00% dev.c:fido_dev_set_protocol_flags 11 0 100.00% 17 0 100.00% ------------------------------------------------------------------------------------------------------------------- -TOTAL 421 79 81.24% 491 105 78.62% +TOTAL 332 65 80.42% 378 80 78.84% File '/libfido2/src/ecdh.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------------------------------- 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% 9 0 100.00% eddsa_pk_new 1 0 100.00% 3 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_from_ptr 10 0 100.00% 12 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_pk_from_EVP_PKEY 18 2 88.89% 12 1 91.67% 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% +TOTAL 88 5 94.32% 114 9 92.11% 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% 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% 7 0 100.00% es256_pk_new 1 0 100.00% 3 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_from_ptr 15 0 100.00% 17 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_sk_create 39 0 100.00% 40 0 100.00% +es256_pk_to_EVP_PKEY 42 0 100.00% 53 0 100.00% +es256_pk_from_EC_KEY 42 2 95.24% 47 4 91.49% +es256_pk_from_EVP_PKEY 8 2 75.00% 7 1 85.71% +es256_sk_to_EVP_PKEY 28 0 100.00% 39 0 100.00% +es256_derive_pk 25 0 100.00% 29 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% +TOTAL 315 7 97.78% 372 12 96.77% + +File '/libfido2/src/es384.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +es384_pk_decode 8 0 100.00% 9 0 100.00% +es384_pk_new 1 0 100.00% 3 0 100.00% +es384_pk_free 6 0 100.00% 7 0 100.00% +es384_pk_from_ptr 15 0 100.00% 17 0 100.00% +es384_pk_to_EVP_PKEY 42 0 100.00% 53 0 100.00% +es384_pk_from_EC_KEY 42 2 95.24% 47 4 91.49% +es384_pk_from_EVP_PKEY 8 2 75.00% 7 1 85.71% +es384_verify_sig 12 2 83.33% 19 5 73.68% +es384_pk_verify_sig 7 1 85.71% 13 2 84.62% +es384.c:decode_pubkey_point 9 0 100.00% 13 0 100.00% +es384.c:decode_coord 8 1 87.50% 10 3 70.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 158 8 94.94% 198 15 92.42% File '/libfido2/src/extern.h': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------------------------------- +File '/libfido2/src/fallthrough.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% 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% 9 0 100.00% fido_dev_info_ptr 1 0 100.00% 3 0 100.00% fido_dev_info_set 26 2 92.31% 30 3 90.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% 12 0 100.00% hid.c:get_key_val 6 0 100.00% 18 0 100.00% hid.c:fido_dev_info_reset 1 0 100.00% 6 0 100.00% ------------------------------------------------------------------------------------------------------------------- TOTAL 87 2 97.70% 145 3 97.93% File '/libfido2/src/hid_linux.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------------------------------- -fido_hid_manifest 35 4 88.57% 41 1 97.56% -fido_hid_open 27 27 0.00% 40 40 0.00% +fido_hid_manifest 35 4 88.57% 41 2 95.12% +fido_hid_open 33 33 0.00% 51 51 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:is_fido 15 1 93.33% 16 1 93.75% 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% 17 3 82.35% ------------------------------------------------------------------------------------------------------------------- -TOTAL 173 68 60.69% 250 104 58.40% +TOTAL 184 73 60.33% 263 115 56.27% File '/libfido2/src/hid_unix.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------------------------------- fido_hid_unix_open 18 11 38.89% 22 14 36.36% -fido_hid_unix_wait 10 9 10.00% 21 10 52.38% +fido_hid_unix_wait 11 10 9.09% 21 12 42.86% ------------------------------------------------------------------------------------------------------------------- -TOTAL 28 20 28.57% 43 24 44.19% +TOTAL 29 21 27.59% 43 26 39.53% File '/libfido2/src/info.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------------------------------- 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_new 4 0 100.00% 7 0 100.00% +fido_cbor_info_reset 1 0 100.00% 10 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_maxlargeblob 1 0 100.00% 3 0 100.00% fido_cbor_info_fwversion 1 0 100.00% 3 0 100.00% +fido_cbor_info_minpinlen 1 0 100.00% 3 0 100.00% +fido_cbor_info_maxrpid_minpinlen 1 0 100.00% 3 0 100.00% +fido_cbor_info_uv_attempts 1 0 100.00% 3 0 100.00% +fido_cbor_info_uv_modality 1 0 100.00% 3 0 100.00% +fido_cbor_info_rk_remaining 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% 5 0 100.00% fido_cbor_info_algorithm_cose 4 0 100.00% 5 0 100.00% +fido_cbor_info_new_pin_required 1 0 100.00% 3 0 100.00% +fido_cbor_info_certs_name_ptr 1 0 100.00% 3 0 100.00% +fido_cbor_info_certs_value_ptr 1 0 100.00% 3 0 100.00% +fido_cbor_info_certs_len 1 0 100.00% 3 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:fido_dev_get_cbor_info_rx 14 0 100.00% 21 0 100.00% +info.c:parse_reply_element 32 0 100.00% 59 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_option 7 0 100.00% 15 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% +info.c:decode_certs 11 0 100.00% 15 0 100.00% +info.c:decode_cert 7 0 100.00% 15 0 100.00% ------------------------------------------------------------------------------------------------------------------- -TOTAL 184 0 100.00% 316 0 100.00% +TOTAL 232 0 100.00% 409 0 100.00% File '/libfido2/src/io.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------------------------------- -fido_tx 13 0 100.00% 11 0 100.00% +fido_tx 14 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% +fido_rx_cbor_status 16 0 100.00% 19 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:tx_preamble 17 1 94.12% 20 1 95.00% +io.c:tx_frame 16 1 93.75% 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 40 2 95.00% 52 2 96.15% 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% +TOTAL 193 7 96.37% 230 12 94.78% File '/libfido2/src/iso7816.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------------------------------- 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_add 6 1 83.33% 8 1 87.50% 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% 38 0 100.00% +TOTAL 18 1 94.44% 38 1 97.37% File '/libfido2/src/largeblob.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------------------------------- fido_dev_largeblob_get 26 2 92.31% 38 4 89.47% fido_dev_largeblob_set 27 0 100.00% 36 0 100.00% 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:get_chunklen 10 1 90.00% 9 1 88.89% 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:largeblob_get_rx 26 0 100.00% 30 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_do_decode 27 3 88.89% 30 7 76.67% 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% 21 0 100.00% largeblob.c:largeblob_new 1 0 100.00% 3 0 100.00% 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_get_nonce 8 0 100.00% 16 0 100.00% 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 19 96.30% 684 43 93.71% +TOTAL 525 18 96.57% 693 43 93.80% 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% 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_log_debug 6 1 83.33% 8 1 87.50% +fido_log_xxd 16 1 93.75% 24 1 95.83% +fido_log_error 8 2 75.00% 11 2 81.82% 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% 9 0 100.00% ------------------------------------------------------------------------------------------------------------------- -TOTAL 39 5 87.18% 63 4 93.65% +TOTAL 39 5 87.18% 63 7 88.89% File '/libfido2/src/netlink.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------------------------------- -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_power_nfc 18 0 100.00% 24 0 100.00% +fido_nl_get_nfc_target 17 0 100.00% 31 0 100.00% +fido_nl_free 10 2 80.00% 9 2 77.78% 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% 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% 17 0 100.00% +netlink.c:nlmsg_setattr 15 1 93.33% 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% 17 9 47.06% +netlink.c:nlmsg_rx 11 2 81.82% 17 6 64.71% 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% 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% 21 0 100.00% -netlink.c:nl_nfc_poll 18 1 94.44% 25 3 88.00% +netlink.c:nl_nfc_poll 18 0 100.00% 25 0 100.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% 7 0 100.00% -netlink.c:nl_dump_nfc_target 19 1 94.74% 31 3 90.32% +netlink.c:nl_dump_nfc_target 19 0 100.00% 31 0 100.00% 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:nl_get_nfc_family 23 0 100.00% 33 0 100.00% 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% 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% 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% 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% +TOTAL 329 8 97.57% 498 15 96.99% -File '/libfido2/src/nfc_linux.c': +File '/libfido2/src/nfc.c': Name Regions Miss Cover Lines Miss Cover ------------------------------------------------------------------------------------------------------------------- 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 5 85.71% 45 13 71.11% -fido_nfc_open 20 3 85.00% 23 5 78.26% +fido_nfc_rx 8 0 100.00% 13 0 100.00% +nfc_is_fido 13 1 92.31% 21 3 85.71% +fido_is_nfc 3 0 100.00% 3 0 100.00% +fido_dev_set_nfc 4 1 75.00% 18 3 83.33% +nfc.c:nfc_do_tx 20 0 100.00% 25 0 100.00% +nfc.c:tx_short_apdu 14 0 100.00% 32 0 100.00% +nfc.c:rx_init 25 0 100.00% 27 0 100.00% +nfc.c:rx_cbor 4 0 100.00% 6 0 100.00% +nfc.c:rx_msg 18 2 88.89% 23 6 73.91% +nfc.c:rx_apdu 14 1 92.86% 22 3 86.36% +nfc.c:tx_get_response 4 0 100.00% 11 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 155 5 96.77% 244 15 93.85% + +File '/libfido2/src/nfc_linux.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_nfc_manifest 35 7 80.00% 45 15 66.67% +fido_nfc_open 20 3 85.00% 23 4 82.61% 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% 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:copy_info 39 22 43.59% 44 16 63.64% +nfc_linux.c:get_usb_attr 1 1 0.00% 3 3 0.00% +nfc_linux.c:get_parent_attr 6 6 0.00% 9 9 0.00% +nfc_linux.c:sysnum_from_syspath 15 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% +TOTAL 172 77 55.23% 242 126 47.93% + +File '/libfido2/src/pcsc.c': +Name Regions Miss Cover Lines Miss Cover +------------------------------------------------------------------------------------------------------------------- +fido_pcsc_manifest 51 0 100.00% 55 0 100.00% +fido_pcsc_open 32 0 100.00% 43 0 100.00% +fido_pcsc_close 6 0 100.00% 9 0 100.00% +fido_pcsc_read 8 0 100.00% 16 0 100.00% +fido_pcsc_write 8 0 100.00% 22 0 100.00% +fido_pcsc_tx 1 0 100.00% 3 0 100.00% +fido_pcsc_rx 1 0 100.00% 3 0 100.00% +fido_is_pcsc 3 0 100.00% 3 0 100.00% +fido_dev_set_pcsc 4 1 75.00% 18 3 83.33% +pcsc.c:list_readers 24 0 100.00% 24 0 100.00% +pcsc.c:copy_info 30 0 100.00% 41 0 100.00% +pcsc.c:get_reader 25 0 100.00% 28 0 100.00% +pcsc.c:prepare_io_request 11 0 100.00% 17 0 100.00% +------------------------------------------------------------------------------------------------------------------- +TOTAL 204 1 99.51% 282 3 98.94% File '/libfido2/src/pin.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------------------------------------- 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% 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:uv_token_wait 14 2 85.71% 12 1 91.67% 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% 45 0 100.00% -pin.c:uv_token_rx 20 0 100.00% 30 0 100.00% +pin.c:uv_token_rx 27 0 100.00% 34 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:pad64 18 0 100.00% 20 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:fido_dev_get_pin_retry_count_rx 19 0 100.00% 24 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% 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:fido_dev_get_uv_retry_count_rx 19 0 100.00% 24 0 100.00% pin.c:parse_uv_retry_count 1 0 100.00% 3 0 100.00% --------------------------------------------------------------------------------------------------------------------- -TOTAL 403 3 99.26% 495 3 99.39% +TOTAL 426 3 99.30% 514 4 99.22% File '/libfido2/src/random.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------------------------------------- -fido_get_random 6 1 83.33% 6 1 83.33% +fido_get_random 6 0 100.00% 6 0 100.00% --------------------------------------------------------------------------------------------------------------------- -TOTAL 6 1 83.33% 6 1 83.33% +TOTAL 6 0 100.00% 6 0 100.00% File '/libfido2/src/reset.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------------------------------------- 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 0 100.00% 30 0 100.00% +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 0 100.00% 39 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% 9 0 100.00% rs256_pk_new 1 0 100.00% 3 0 100.00% 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_pk_from_ptr 10 0 100.00% 12 0 100.00% +rs256_pk_to_EVP_PKEY 35 0 100.00% 43 0 100.00% +rs256_pk_from_RSA 32 6 81.25% 26 9 65.38% +rs256_pk_from_EVP_PKEY 8 2 75.00% 7 1 85.71% 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% +TOTAL 149 10 93.29% 182 14 92.31% 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% +time.c:timespec_to_ms 16 2 87.50% 13 2 84.62% --------------------------------------------------------------------------------------------------------------------- -TOTAL 43 3 93.02% 43 1 97.67% +TOTAL 43 3 93.02% 43 2 95.35% + +File '/libfido2/src/touch.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +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% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 67 0 100.00% 79 0 100.00% File '/libfido2/src/tpm.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------------------------------------- fido_get_signed_hash_tpm 25 0 100.00% 39 0 100.00% -tpm.c:check_es256_pubarea 18 0 100.00% 30 0 100.00% +tpm.c:check_es256_pubarea 19 0 100.00% 30 0 100.00% tpm.c:bswap_es256_pubarea 1 0 100.00% 12 0 100.00% -tpm.c:check_rs256_pubarea 16 0 100.00% 28 0 100.00% +tpm.c:check_rs256_pubarea 17 0 100.00% 28 0 100.00% tpm.c:bswap_rs256_pubarea 1 0 100.00% 10 0 100.00% -tpm.c:check_sha1_certinfo 14 0 100.00% 38 0 100.00% +tpm.c:check_sha1_certinfo 15 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 100 0 100.00% 194 0 100.00% +TOTAL 103 0 100.00% 194 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_opt_array_free 4 0 100.00% 9 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_cert_array_free 4 0 100.00% 9 0 100.00% fido_str_array_pack 11 0 100.00% 14 0 100.00% --------------------------------------------------------------------------------------------------------------------- -TOTAL 25 0 100.00% 46 0 100.00% +TOTAL 29 0 100.00% 56 0 100.00% File '/libfido2/src/u2f.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------------------------------------- -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_register 76 0 100.00% 81 0 100.00% +u2f_authenticate 33 0 100.00% 37 0 100.00% +u2f_get_touch_begin 37 0 100.00% 45 0 100.00% +u2f_get_touch_status 26 0 100.00% 36 0 100.00% +u2f.c:key_lookup 51 0 100.00% 65 0 100.00% +u2f.c:send_dummy_register 37 0 100.00% 45 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:do_auth 56 0 100.00% 67 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% +TOTAL 572 4 99.30% 726 12 98.35% + +File '/libfido2/src/util.c': +Name Regions Miss Cover Lines Miss Cover +--------------------------------------------------------------------------------------------------------------------- +fido_to_uint64 14 1 92.86% 14 1 92.86% +--------------------------------------------------------------------------------------------------------------------- +TOTAL 14 1 92.86% 14 1 92.86% diff --git a/contrib/libfido2/fuzz/fuzz_assert.c b/contrib/libfido2/fuzz/fuzz_assert.c index 4331148b5e06..9f39f3d6ecb7 100644 --- a/contrib/libfido2/fuzz/fuzz_assert.c +++ b/contrib/libfido2/fuzz/fuzz_assert.c @@ -1,495 +1,532 @@ /* - * Copyright (c) 2019 Yubico AB. All rights reserved. + * Copyright (c) 2019-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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_alloc_len)) == 0 || cbor_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]; + uint8_t blob[MAXCORPUS]; 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); r = fido_assert_verify(assert, 0, type, pk); consume(&r, sizeof(r)); fido_assert_free(&assert); } /* * 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 es384_pk_from_EVP_PKEY(). + */ +static void +es384_convert(const es384_pk_t *k) +{ + EVP_PKEY *pkey = NULL; + es384_pk_t *pk = NULL; + int r; + + if ((pkey = es384_pk_to_EVP_PKEY(k)) == NULL || + (pk = es384_pk_new()) == NULL) + goto out; + + r = es384_pk_from_EVP_PKEY(pk, pkey); + consume(&r, sizeof(r)); +out: + es384_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; int r; if ((pkey = rs256_pk_to_EVP_PKEY(k)) == NULL || (pk = rs256_pk_new()) == NULL) goto out; r = rs256_pk_from_EVP_PKEY(pk, pkey); consume(&r, sizeof(r)); out: 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; 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; + es384_pk_t *es384_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; + case 2: + cose_alg = COSE_ES384; + + if ((es384_pk = es384_pk_new()) == NULL) + return; + + /* XXX reuse p->es256 as es384 */ + es384_pk_from_ptr(es384_pk, p->es256.body, p->es256.len); + pk = es384_pk; + + es384_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); + es384_pk_free(&es384_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 49a50932a543..0c6b12c4b7c3 100644 --- a/contrib/libfido2/fuzz/fuzz_bio.c +++ b/contrib/libfido2/fuzz/fuzz_bio.c @@ -1,441 +1,442 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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_alloc_len)) == 0 || cbor_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]; + uint8_t blob[MAXCORPUS]; 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 d7b630224054..497298f70290 100644 --- a/contrib/libfido2/fuzz/fuzz_cred.c +++ b/contrib/libfido2/fuzz/fuzz_cred.c @@ -1,478 +1,482 @@ /* - * Copyright (c) 2019-2021 Yubico AB. All rights reserved. + * Copyright (c) 2019-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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_alloc_len)) == 0 || cbor_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]; + uint8_t blob[MAXCORPUS]; 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 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); 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_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); 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; + case 2: + cose_alg = COSE_ES384; + 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_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 fb34f22f8147..ef2147581564 100644 --- a/contrib/libfido2/fuzz/fuzz_credman.c +++ b/contrib/libfido2/fuzz/fuzz_credman.c @@ -1,406 +1,407 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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_alloc_len)) == 0 || cbor_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]; + uint8_t blob[MAXCORPUS]; 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 eaf00dc92de8..daaadadf19bc 100644 --- a/contrib/libfido2/fuzz/fuzz_hid.c +++ b/contrib/libfido2/fuzz/fuzz_hid.c @@ -1,238 +1,239 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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) != 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[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[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(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[3] = pack_blob(&p->netlink_wiredata)) == NULL) goto fail; 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_alloc_len)) == 0 || cbor_len > len) { cbor_len = 0; goto fail; } memcpy(ptr, cbor, cbor_len); fail: 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]; + uint8_t blob[MAXCORPUS]; 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 = NULL, *devlist_set = NULL; int16_t vendor_id, product_id; fido_dev_io_t io; fido_dev_transport_t t; memset(&io, 0, sizeof(io)); memset(&t, 0, sizeof(t)); 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 || (devlist_set = fido_dev_info_new(1)) == 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)); fido_dev_info_set(devlist_set, 0, fido_dev_info_path(di), fido_dev_info_manufacturer_string(di), fido_dev_info_product_string(di), &io, &t); } out: fido_dev_info_free(&devlist, ndevs); fido_dev_info_free(&devlist_set, 1); } 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 3289ed46e2a7..6cdc0c0d57cb 100644 --- a/contrib/libfido2/fuzz/fuzz_largeblob.c +++ b/contrib/libfido2/fuzz/fuzz_largeblob.c @@ -1,271 +1,272 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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_alloc_len)) == 0 || cbor_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]; + uint8_t blob[MAXCORPUS]; 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 7c28979fb624..cbc313d1f793 100644 --- a/contrib/libfido2/fuzz/fuzz_mgmt.c +++ b/contrib/libfido2/fuzz/fuzz_mgmt.c @@ -1,508 +1,528 @@ /* - * Copyright (c) 2019 Yubico AB. All rights reserved. + * Copyright (c) 2019-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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_alloc_len)) == 0 || cbor_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]; + uint8_t blob[MAXCORPUS]; 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; + bool v; 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)); } + for (size_t i = 0; i < fido_cbor_info_certs_len(ci); i++) { + char * const *na = fido_cbor_info_certs_name_ptr(ci); + const uint64_t *va = fido_cbor_info_certs_value_ptr(ci); + consume(na[i], strlen(na[i])); + consume(&va[i], sizeof(va[i])); + } + 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_maxlargeblob(ci); + consume(&n, sizeof(n)); n = fido_cbor_info_fwversion(ci); consume(&n, sizeof(n)); + n = fido_cbor_info_minpinlen(ci); + consume(&n, sizeof(n)); + n = fido_cbor_info_maxrpid_minpinlen(ci); + consume(&n, sizeof(n)); + n = fido_cbor_info_uv_attempts(ci); + consume(&n, sizeof(n)); + n = fido_cbor_info_uv_modality(ci); + consume(&n, sizeof(n)); + n = (uint64_t)fido_cbor_info_rk_remaining(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)); + v = fido_cbor_info_new_pin_required(ci); + consume(&v, sizeof(v)); + 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 2447215a2471..4d28129c3567 100644 --- a/contrib/libfido2/fuzz/fuzz_netlink.c +++ b/contrib/libfido2/fuzz/fuzz_netlink.c @@ -1,163 +1,164 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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; }; 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_alloc_len)) == 0 || cbor_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]; + uint8_t blob[MAXCORPUS]; size_t blob_len; memset(&dummy, 0, sizeof(dummy)); 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/fuzz_pcsc.c b/contrib/libfido2/fuzz/fuzz_pcsc.c new file mode 100644 index 000000000000..cf6210b71be5 --- /dev/null +++ b/contrib/libfido2/fuzz/fuzz_pcsc.c @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2022 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. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#define _FIDO_INTERNAL + +#include +#include +#include +#include +#include +#include + +#include "mutator_aux.h" +#include "wiredata_fido2.h" +#include "dummy.h" + +#include "../src/extern.h" + +struct param { + int seed; + char path[MAXSTR]; + struct blob pcsc_list; + struct blob tx_apdu; + struct blob wiredata_init; + struct blob wiredata_msg; +}; + +static const uint8_t dummy_tx_apdu[] = { WIREDATA_CTAP_EXTENDED_APDU }; +static const uint8_t dummy_wiredata_init[] = { WIREDATA_CTAP_NFC_INIT }; +static const uint8_t dummy_wiredata_msg[] = { WIREDATA_CTAP_NFC_MSG }; + +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) != 6 || + (v = cbor_array_handle(item)) == NULL) + goto fail; + + if (unpack_int(v[0], &p->seed) < 0 || + unpack_string(v[1], p->path) < 0 || + unpack_blob(v[2], &p->pcsc_list) < 0 || + unpack_blob(v[3], &p->tx_apdu) < 0 || + unpack_blob(v[4], &p->wiredata_init) < 0 || + unpack_blob(v[5], &p->wiredata_msg) < 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[6], *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(6)) == NULL || + (argv[0] = pack_int(p->seed)) == NULL || + (argv[1] = pack_string(p->path)) == NULL || + (argv[2] = pack_blob(&p->pcsc_list)) == NULL || + (argv[3] = pack_blob(&p->tx_apdu)) == NULL || + (argv[4] = pack_blob(&p->wiredata_init)) == NULL || + (argv[5] = pack_blob(&p->wiredata_msg)) == NULL) + goto fail; + + for (size_t i = 0; i < 6; i++) + if (cbor_array_push(array, argv[i]) == false) + goto fail; + + if ((cbor_len = cbor_serialize_alloc(array, &cbor, + &cbor_alloc_len)) == 0 || cbor_len > len) { + cbor_len = 0; + goto fail; + } + + memcpy(ptr, cbor, cbor_len); +fail: + for (size_t i = 0; i < 6; 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[MAXCORPUS]; + size_t blob_len; + + memset(&dummy, 0, sizeof(dummy)); + + strlcpy(dummy.path, dummy_pcsc_path, sizeof(dummy.path)); + + dummy.pcsc_list.len = sizeof(dummy_pcsc_list); + memcpy(&dummy.pcsc_list.body, &dummy_pcsc_list, dummy.pcsc_list.len); + + dummy.tx_apdu.len = sizeof(dummy_tx_apdu); + memcpy(&dummy.tx_apdu.body, &dummy_tx_apdu, dummy.tx_apdu.len); + + dummy.wiredata_init.len = sizeof(dummy_wiredata_init); + memcpy(&dummy.wiredata_init.body, &dummy_wiredata_init, + dummy.wiredata_init.len); + + dummy.wiredata_msg.len = sizeof(dummy_wiredata_msg); + memcpy(&dummy.wiredata_msg.body, &dummy_wiredata_msg, + dummy.wiredata_msg.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 +test_manifest(void) +{ + size_t ndevs, nfound; + fido_dev_info_t *devlist = NULL; + int16_t vendor_id, product_id; + int r; + + r = fido_pcsc_manifest(NULL, 0, &nfound); + assert(r == FIDO_OK && nfound == 0); + r = fido_pcsc_manifest(NULL, 1, &nfound); + assert(r == FIDO_ERR_INVALID_ARGUMENT); + + ndevs = uniform_random(64); + if ((devlist = fido_dev_info_new(ndevs)) == NULL || + fido_pcsc_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); +} + +static void +test_tx(const char *path, const struct blob *apdu, uint8_t cmd, u_char *rx_buf, + size_t rx_len) +{ + fido_dev_t dev; + const u_char *tx_ptr = NULL; + size_t tx_len = 0; + int n; + + memset(&dev, 0, sizeof(dev)); + + if (fido_dev_set_pcsc(&dev) < 0) + return; + if ((dev.io_handle = fido_pcsc_open(path)) == NULL) + return; + + if (apdu) { + tx_ptr = apdu->body; + tx_len = apdu->len; + } + + fido_pcsc_tx(&dev, cmd, tx_ptr, tx_len); + + if ((n = fido_pcsc_rx(&dev, cmd, rx_buf, rx_len, -1)) >= 0) + consume(rx_buf, n); + + fido_pcsc_close(dev.io_handle); +} + +static void +test_misc(void) +{ + assert(fido_pcsc_open(NULL) == NULL); + assert(fido_pcsc_write(NULL, NULL, INT_MAX + 1LL) == -1); +} + +void +test(const struct param *p) +{ + u_char buf[512]; + + prng_init((unsigned int)p->seed); + fuzz_clock_reset(); + fido_init(FIDO_DEBUG); + fido_set_log_handler(consume_str); + + set_pcsc_parameters(&p->pcsc_list); + set_pcsc_io_functions(nfc_read, nfc_write, consume); + + set_wire_data(p->wiredata_init.body, p->wiredata_init.len); + test_manifest(); + + test_misc(); + + set_wire_data(p->wiredata_init.body, p->wiredata_init.len); + test_tx(p->path, NULL, CTAP_CMD_INIT, buf, uniform_random(20)); + + set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len); + test_tx(p->path, &p->tx_apdu, CTAP_CMD_MSG, buf, sizeof(buf)); + + set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len); + test_tx(p->path, &p->tx_apdu, CTAP_CMD_CBOR, buf, sizeof(buf)); + + set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len); + test_tx(p->path, &p->tx_apdu, CTAP_CMD_LOCK, buf, sizeof(buf)); +} + +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->path); + mutate_blob(&p->pcsc_list); + mutate_blob(&p->tx_apdu); + } + + if (flags & MUTATE_WIREDATA) { + mutate_blob(&p->wiredata_init); + mutate_blob(&p->wiredata_msg); + } +} diff --git a/contrib/libfido2/fuzz/libfuzzer.c b/contrib/libfido2/fuzz/libfuzzer.c index 09aec4ea2b68..073ebe655cf2 100644 --- a/contrib/libfido2/fuzz/libfuzzer.c +++ b/contrib/libfido2/fuzz/libfuzzer.c @@ -1,177 +1,230 @@ /* - * Copyright (c) 2019 Yubico AB. All rights reserved. + * Copyright (c) 2019-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ +#include + #include #include #include #include #include #include #include #include #include "mutator_aux.h" +extern int fuzz_save_corpus; + static bool debug; static unsigned int flags = MUTATE_ALL; static unsigned long long test_fail; static unsigned long long test_total; static unsigned long long mutate_fail; static unsigned long long mutate_total; int LLVMFuzzerInitialize(int *, char ***); int LLVMFuzzerTestOneInput(const uint8_t *, size_t); size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); static int save_seed(const char *opt) { const char *path; int fd = -1, status = 1; void *buf = NULL; - const size_t buflen = 4096; + const size_t buflen = MAXCORPUS; size_t n; struct param *p = NULL; if ((path = strchr(opt, '=')) == NULL || strlen(++path) == 0) { warnx("usage: --fido-save-seed="); goto fail; } if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644)) == -1) { warn("open %s", path); goto fail; } if ((buf = malloc(buflen)) == NULL) { warn("malloc"); goto fail; } n = pack_dummy(buf, buflen); if ((p = unpack(buf, n)) == NULL) { warnx("unpack"); goto fail; } if (write(fd, buf, n) != (ssize_t)n) { warn("write %s", path); goto fail; } status = 0; fail: if (fd != -1) close(fd); free(buf); free(p); return status; } +static int +save_corpus(const struct param *p) +{ + uint8_t blob[MAXCORPUS], dgst[SHA256_DIGEST_LENGTH]; + size_t blob_len; + char path[PATH_MAX]; + int r, fd; + + if ((blob_len = pack(blob, sizeof(blob), p)) == 0 || + blob_len > sizeof(blob)) { + warnx("pack"); + return -1; + } + + if (SHA256(blob, blob_len, dgst) != dgst) { + warnx("sha256"); + return -1; + } + + if ((r = snprintf(path, sizeof(path), "saved_corpus_%02x%02x%02x%02x" + "%02x%02x%02x%02x", dgst[0], dgst[1], dgst[2], dgst[3], dgst[4], + dgst[5], dgst[6], dgst[7])) < 0 || (size_t)r >= sizeof(path)) { + warnx("snprintf"); + return -1; + } + + if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644)) == -1) { + warn("open %s", path); + return -1; + } + + if (write(fd, blob, blob_len) != (ssize_t)blob_len) { + warn("write"); + r = -1; + } else { + warnx("wrote %s", path); + r = 0; + } + + close(fd); + + return r; +} + static void parse_mutate_flags(const char *opt, unsigned int *mutate_flags) { const char *f; if ((f = strchr(opt, '=')) == NULL || strlen(++f) == 0) errx(1, "usage: --fido-mutate="); if (strcmp(f, "seed") == 0) *mutate_flags |= MUTATE_SEED; else if (strcmp(f, "param") == 0) *mutate_flags |= MUTATE_PARAM; else if (strcmp(f, "wiredata") == 0) *mutate_flags |= MUTATE_WIREDATA; else errx(1, "--fido-mutate: unknown flag '%s'", f); } int LLVMFuzzerInitialize(int *argc, char ***argv) { unsigned int mutate_flags = 0; for (int i = 0; i < *argc; i++) if (strcmp((*argv)[i], "--fido-debug") == 0) { debug = 1; } else if (strncmp((*argv)[i], "--fido-save-seed=", 17) == 0) { exit(save_seed((*argv)[i])); } else if (strncmp((*argv)[i], "--fido-mutate=", 14) == 0) { parse_mutate_flags((*argv)[i], &mutate_flags); } if (mutate_flags) flags = mutate_flags; return 0; } int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { struct param *p; - if (size > 4096) + if (size > MAXCORPUS) return 0; if (++test_total % 100000 == 0 && debug) { double r = (double)test_fail/(double)test_total * 100.0; fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__, test_fail, test_total, r); } if ((p = unpack(data, size)) == NULL) test_fail++; else { + fuzz_save_corpus = 0; test(p); + if (fuzz_save_corpus && save_corpus(p) < 0) + fprintf(stderr, "%s: failed to save corpus\n", + __func__); free(p); } return 0; } size_t LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, unsigned int seed) NO_MSAN { struct param *p; - uint8_t blob[4096]; + uint8_t blob[MAXCORPUS]; size_t blob_len; memset(&p, 0, sizeof(p)); #ifdef WITH_MSAN __msan_unpoison(data, maxsize); #endif if (++mutate_total % 100000 == 0 && debug) { double r = (double)mutate_fail/(double)mutate_total * 100.0; fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__, mutate_fail, mutate_total, r); } if ((p = unpack(data, size)) == NULL) { mutate_fail++; return pack_dummy(data, maxsize); } mutate(p, seed, flags); if ((blob_len = pack(blob, sizeof(blob), p)) == 0 || blob_len > sizeof(blob) || blob_len > maxsize) { mutate_fail++; free(p); return 0; } free(p); memcpy(data, blob, blob_len); return blob_len; } diff --git a/contrib/libfido2/fuzz/mutator_aux.c b/contrib/libfido2/fuzz/mutator_aux.c index 92a67be78106..64c633f15f92 100644 --- a/contrib/libfido2/fuzz/mutator_aux.c +++ b/contrib/libfido2/fuzz/mutator_aux.c @@ -1,329 +1,332 @@ /* - * Copyright (c) 2019 Yubico AB. All rights reserved. + * Copyright (c) 2019-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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); +extern int prng_up; 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 (prng_up && uniform_random(400) < 1) { + errno = EIO; + return -1; + } + 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) { + if (prng_up && 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 +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); + assert(len > 0 && len <= 264); return buf_read(ptr, len, ms); } -static int +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_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 a9bebe232bae..5ad566140a8e 100644 --- a/contrib/libfido2/fuzz/mutator_aux.h +++ b/contrib/libfido2/fuzz/mutator_aux.h @@ -1,97 +1,111 @@ /* - * Copyright (c) 2019-2021 Yubico AB. All rights reserved. + * Copyright (c) 2019-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #ifndef _MUTATOR_AUX_H #define _MUTATOR_AUX_H +#include + #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/es384.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 3600 +#define MAXSTR 1024 +#define MAXBLOB 3600 +#define MAXCORPUS 8192 + +#define HID_DEV_HANDLE 0x68696421 +#define NFC_DEV_HANDLE 0x6e666321 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); +int nfc_read(void *, unsigned char *, size_t, int); +int nfc_write(void *, const unsigned char *, 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); +void set_pcsc_parameters(const struct blob *); +void set_pcsc_io_functions(int (*)(void *, u_char *, size_t, int), + int (*)(void *, const u_char *, size_t), void (*)(const void *, size_t)); + #endif /* !_MUTATOR_AUX_H */ diff --git a/contrib/libfido2/fuzz/pcsc.c b/contrib/libfido2/fuzz/pcsc.c new file mode 100644 index 000000000000..f6a3e9bdd773 --- /dev/null +++ b/contrib/libfido2/fuzz/pcsc.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2022 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. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include + +#include "mutator_aux.h" + +static const struct blob *reader_list; +static int (*xread)(void *, u_char *, size_t, int); +static int (*xwrite)(void *, const u_char *, size_t); +static void (*xconsume)(const void *, size_t); + +LONG __wrap_SCardEstablishContext(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT); +LONG __wrap_SCardListReaders(SCARDCONTEXT, LPCSTR, LPSTR, LPDWORD); +LONG __wrap_SCardReleaseContext(SCARDCONTEXT); +LONG __wrap_SCardConnect(SCARDCONTEXT, LPCSTR, DWORD, DWORD, LPSCARDHANDLE, + LPDWORD); +LONG __wrap_SCardDisconnect(SCARDHANDLE, DWORD); +LONG __wrap_SCardTransmit(SCARDHANDLE, const SCARD_IO_REQUEST *, LPCBYTE, + DWORD, SCARD_IO_REQUEST *, LPBYTE, LPDWORD); + +LONG +__wrap_SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, + LPCVOID pvReserved2, LPSCARDCONTEXT phContext) +{ + assert(dwScope == SCARD_SCOPE_SYSTEM); + assert(pvReserved1 == NULL); + assert(pvReserved2 == NULL); + + *phContext = 1; + + if (uniform_random(400) < 1) + return SCARD_E_NO_SERVICE; + if (uniform_random(400) < 1) + return SCARD_E_NO_SMARTCARD; + if (uniform_random(400) < 1) + return SCARD_E_NO_MEMORY; + if (uniform_random(400) < 1) + *phContext = 0; + + return SCARD_S_SUCCESS; +} + +LONG +__wrap_SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, + LPSTR mszReaders, LPDWORD pcchReaders) +{ + assert(hContext == 1); + assert(mszGroups == NULL); + assert(mszReaders != NULL); + assert(pcchReaders != 0); + + if (reader_list == NULL || uniform_random(400) < 1) + return SCARD_E_NO_READERS_AVAILABLE; + if (uniform_random(400) < 1) + return SCARD_E_NO_MEMORY; + + memcpy(mszReaders, reader_list->body, reader_list->len > *pcchReaders ? + *pcchReaders : reader_list->len); + *pcchReaders = (DWORD)reader_list->len; /* on purpose */ + + return SCARD_S_SUCCESS; +} + +LONG +__wrap_SCardReleaseContext(SCARDCONTEXT hContext) +{ + assert(hContext == 1); + + return SCARD_S_SUCCESS; +} + +LONG +__wrap_SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, + DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol) +{ + uint32_t r; + + assert(hContext == 1); + xconsume(szReader, strlen(szReader) + 1); + assert(dwShareMode == SCARD_SHARE_SHARED); + assert(dwPreferredProtocols == SCARD_PROTOCOL_ANY); + assert(phCard != NULL); + assert(pdwActiveProtocol != NULL); + + if ((r = uniform_random(400)) < 1) + return SCARD_E_UNEXPECTED; + + *phCard = 1; + *pdwActiveProtocol = (r & 1) ? SCARD_PROTOCOL_T0 : SCARD_PROTOCOL_T1; + + if (uniform_random(400) < 1) + *pdwActiveProtocol = SCARD_PROTOCOL_RAW; + + return SCARD_S_SUCCESS; +} + +LONG +__wrap_SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition) +{ + assert(hCard == 1); + assert(dwDisposition == SCARD_LEAVE_CARD); + + return SCARD_S_SUCCESS; +} + +extern void consume(const void *body, size_t len); + +LONG +__wrap_SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci, + LPCBYTE pbSendBuffer, DWORD cbSendLength, SCARD_IO_REQUEST *pioRecvPci, + LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength) +{ + void *ioh = (void *)NFC_DEV_HANDLE; + int n; + + assert(hCard == 1); + xconsume(pioSendPci, sizeof(*pioSendPci)); + xwrite(ioh, pbSendBuffer, cbSendLength); + assert(pioRecvPci == NULL); + + if (uniform_random(400) < 1 || + (n = xread(ioh, pbRecvBuffer, *pcbRecvLength, -1)) == -1) + return SCARD_E_UNEXPECTED; + *pcbRecvLength = (DWORD)n; + + return SCARD_S_SUCCESS; +} + +void +set_pcsc_parameters(const struct blob *reader_list_ptr) +{ + reader_list = reader_list_ptr; +} + +void +set_pcsc_io_functions(int (*read_f)(void *, u_char *, size_t, int), + int (*write_f)(void *, const u_char *, size_t), + void (*consume_f)(const void *, size_t)) +{ + xread = read_f; + xwrite = write_f; + xconsume = consume_f; +} diff --git a/contrib/libfido2/fuzz/preload-fuzz.c b/contrib/libfido2/fuzz/preload-fuzz.c index efcb8c632605..f18848dda34c 100644 --- a/contrib/libfido2/fuzz/preload-fuzz.c +++ b/contrib/libfido2/fuzz/preload-fuzz.c @@ -1,104 +1,105 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ /* * cc -fPIC -D_GNU_SOURCE -shared -o preload-fuzz.so preload-fuzz.c * LD_PRELOAD=$(realpath preload-fuzz.so) */ #include #include #include #include #include #include #include #include #include #include #include #include #define FUZZ_DEV_PREFIX "nodev" static int fd_fuzz = -1; static int (*open_f)(const char *, int, mode_t); static int (*close_f)(int); static ssize_t (*write_f)(int, const void *, size_t); int open(const char *path, int flags, ...) { va_list ap; mode_t mode; va_start(ap, flags); mode = va_arg(ap, mode_t); va_end(ap); if (open_f == NULL) { open_f = dlsym(RTLD_NEXT, "open"); if (open_f == NULL) { warnx("%s: dlsym", __func__); errno = EACCES; return (-1); } } if (strncmp(path, FUZZ_DEV_PREFIX, strlen(FUZZ_DEV_PREFIX)) != 0) return (open_f(path, flags, mode)); if (fd_fuzz != -1) { warnx("%s: fd_fuzz != -1", __func__); errno = EACCES; return (-1); } if ((fd_fuzz = dup(STDIN_FILENO)) < 0) { warn("%s: dup", __func__); errno = EACCES; return (-1); } return (fd_fuzz); } int close(int fd) { if (close_f == NULL) { close_f = dlsym(RTLD_NEXT, "close"); if (close_f == NULL) { warnx("%s: dlsym", __func__); errno = EACCES; return (-1); } } if (fd == fd_fuzz) fd_fuzz = -1; return (close_f(fd)); } ssize_t write(int fd, const void *buf, size_t nbytes) { if (write_f == NULL) { write_f = dlsym(RTLD_NEXT, "write"); if (write_f == NULL) { warnx("%s: dlsym", __func__); errno = EBADF; return (-1); } } if (fd != fd_fuzz) return (write_f(fd, buf, nbytes)); return (nbytes); } diff --git a/contrib/libfido2/fuzz/preload-snoop.c b/contrib/libfido2/fuzz/preload-snoop.c index 373acc560a60..34d57ade82f9 100644 --- a/contrib/libfido2/fuzz/preload-snoop.c +++ b/contrib/libfido2/fuzz/preload-snoop.c @@ -1,217 +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. + * SPDX-License-Identifier: BSD-2-Clause */ /* * cc -fPIC -D_GNU_SOURCE -shared -o preload-snoop.so preload-snoop.c * LD_PRELOAD=$(realpath preload-snoop.so) */ #include #include #include #include #include #include #include #include #include #include #include #include #define SNOOP_DEV_PREFIX "/dev/hidraw" struct fd_tuple { int snoop_in; int snoop_out; int real_dev; }; static struct fd_tuple *fd_tuple; static int (*open_f)(const char *, int, mode_t); static int (*close_f)(int); static ssize_t (*read_f)(int, void *, size_t); static ssize_t (*write_f)(int, const void *, size_t); static int get_fd(const char *hid_path, const char *suffix) { char *s = NULL; char path[PATH_MAX]; int fd; int r; if ((s = strdup(hid_path)) == NULL) { warnx("%s: strdup", __func__); return (-1); } for (size_t i = 0; i < strlen(s); i++) if (s[i] == '/') s[i] = '_'; if ((r = snprintf(path, sizeof(path), "%s-%s", s, suffix)) < 0 || (size_t)r >= sizeof(path)) { warnx("%s: snprintf", __func__); free(s); return (-1); } free(s); s = NULL; if ((fd = open_f(path, O_CREAT | O_WRONLY, 0644)) < 0) { warn("%s: open", __func__); return (-1); } return (fd); } int open(const char *path, int flags, ...) { va_list ap; mode_t mode; va_start(ap, flags); mode = va_arg(ap, mode_t); va_end(ap); if (open_f == NULL) { open_f = dlsym(RTLD_NEXT, "open"); if (open_f == NULL) { warnx("%s: dlsym", __func__); errno = EACCES; return (-1); } } if (strncmp(path, SNOOP_DEV_PREFIX, strlen(SNOOP_DEV_PREFIX)) != 0) return (open_f(path, flags, mode)); if (fd_tuple != NULL) { warnx("%s: fd_tuple != NULL", __func__); errno = EACCES; return (-1); } if ((fd_tuple = calloc(1, sizeof(*fd_tuple))) == NULL) { warn("%s: calloc", __func__); errno = ENOMEM; return (-1); } fd_tuple->snoop_in = -1; fd_tuple->snoop_out = -1; fd_tuple->real_dev = -1; if ((fd_tuple->snoop_in = get_fd(path, "in")) < 0 || (fd_tuple->snoop_out = get_fd(path, "out")) < 0 || (fd_tuple->real_dev = open_f(path, flags, mode)) < 0) { warn("%s: get_fd/open", __func__); goto fail; } return (fd_tuple->real_dev); fail: if (fd_tuple->snoop_in != -1) close(fd_tuple->snoop_in); if (fd_tuple->snoop_out != -1) close(fd_tuple->snoop_out); if (fd_tuple->real_dev != -1) close(fd_tuple->real_dev); free(fd_tuple); fd_tuple = NULL; errno = EACCES; return (-1); } int close(int fd) { if (close_f == NULL) { close_f = dlsym(RTLD_NEXT, "close"); if (close_f == NULL) { warnx("%s: dlsym", __func__); errno = EBADF; return (-1); } } if (fd_tuple == NULL || fd_tuple->real_dev != fd) return (close_f(fd)); close_f(fd_tuple->snoop_in); close_f(fd_tuple->snoop_out); close_f(fd_tuple->real_dev); free(fd_tuple); fd_tuple = NULL; return (0); } ssize_t read(int fd, void *buf, size_t nbytes) { ssize_t n; if (read_f == NULL) { read_f = dlsym(RTLD_NEXT, "read"); if (read_f == NULL) { warnx("%s: dlsym", __func__); errno = EBADF; return (-1); } } if (write_f == NULL) { write_f = dlsym(RTLD_NEXT, "write"); if (write_f == NULL) { warnx("%s: dlsym", __func__); errno = EBADF; return (-1); } } if (fd_tuple == NULL || fd_tuple->real_dev != fd) return (read_f(fd, buf, nbytes)); if ((n = read_f(fd, buf, nbytes)) < 0 || write_f(fd_tuple->snoop_in, buf, n) != n) return (-1); return (n); } ssize_t write(int fd, const void *buf, size_t nbytes) { ssize_t n; if (write_f == NULL) { write_f = dlsym(RTLD_NEXT, "write"); if (write_f == NULL) { warnx("%s: dlsym", __func__); errno = EBADF; return (-1); } } if (fd_tuple == NULL || fd_tuple->real_dev != fd) return (write_f(fd, buf, nbytes)); if ((n = write_f(fd, buf, nbytes)) < 0 || write_f(fd_tuple->snoop_out, buf, n) != n) return (-1); return (n); } diff --git a/contrib/libfido2/fuzz/report.tgz b/contrib/libfido2/fuzz/report.tgz index d78f4628de59..e984ee9dc765 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 05c000aa7757..0f79600f801d 100644 --- a/contrib/libfido2/fuzz/summary.txt +++ b/contrib/libfido2/fuzz/summary.txt @@ -1,57 +1,64 @@ Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -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/clock.c 24 1 95.83% 4 0 100.00% 35 1 97.14% +fuzz/pcsc.c 59 0 100.00% 8 0 100.00% 75 12 84.00% +fuzz/prng.c 31 0 100.00% 2 0 100.00% 35 1 97.14% +fuzz/udev.c 110 2 98.18% 17 0 100.00% 126 12 90.48% 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% +fuzz/wrap.c 23 0 100.00% 3 0 100.00% 29 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% 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/aes256.c 118 3 97.46% 8 0 100.00% 157 11 92.99% +src/assert.c 605 43 92.89% 59 3 94.92% 745 46 93.83% +src/authkey.c 52 0 100.00% 5 0 100.00% 66 0 100.00% +src/bio.c 451 20 95.57% 49 2 95.92% 587 24 95.91% 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 23 97.80% 54 0 100.00% 1237 46 96.28% -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 421 79 81.24% 45 7 84.44% 491 105 78.62% +src/cbor.c 1070 13 98.79% 55 0 100.00% 1258 31 97.54% +src/compress.c 105 14 86.67% 5 0 100.00% 122 24 80.33% +src/config.c 112 0 100.00% 11 0 100.00% 152 0 100.00% +src/cred.c 651 38 94.16% 69 2 97.10% 849 43 94.94% +src/credman.c 422 10 97.63% 40 0 100.00% 557 20 96.41% +src/dev.c 332 65 80.42% 41 6 85.37% 378 80 78.84% 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/eddsa.c 88 5 94.32% 10 0 100.00% 114 9 92.11% src/err.c 122 10 91.80% 1 0 100.00% 126 10 92.06% -src/es256.c 306 5 98.37% 19 0 100.00% 358 7 98.04% +src/es256.c 315 7 97.78% 19 0 100.00% 372 12 96.77% +src/es384.c 158 8 94.94% 11 0 100.00% 198 15 92.42% src/hid.c 87 2 97.70% 14 0 100.00% 145 3 97.93% -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 19 96.30% 30 0 100.00% 684 43 93.71% -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/hid_linux.c 184 73 60.33% 14 7 50.00% 263 115 56.27% +src/hid_unix.c 29 21 27.59% 2 0 100.00% 43 26 39.53% +src/info.c 232 0 100.00% 51 0 100.00% 409 0 100.00% +src/io.c 193 7 96.37% 13 0 100.00% 230 12 94.78% +src/iso7816.c 18 1 94.44% 5 0 100.00% 38 1 97.37% +src/largeblob.c 525 18 96.57% 30 0 100.00% 693 43 93.80% +src/log.c 39 5 87.18% 7 1 85.71% 63 7 88.89% +src/netlink.c 329 8 97.57% 40 0 100.00% 498 15 96.99% +src/nfc.c 155 5 96.77% 12 0 100.00% 244 15 93.85% +src/nfc_linux.c 172 77 55.23% 13 7 46.15% 242 126 47.93% +src/pcsc.c 204 1 99.51% 13 0 100.00% 282 3 98.94% +src/pin.c 426 3 99.30% 26 0 100.00% 514 4 99.22% +src/random.c 6 0 100.00% 1 0 100.00% 6 0 100.00% src/reset.c 24 0 100.00% 3 0 100.00% 23 0 100.00% -src/rs1.c 25 0 100.00% 3 0 100.00% 39 0 100.00% -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 100 0 100.00% 9 0 100.00% 194 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% +src/rs1.c 25 1 96.00% 3 0 100.00% 39 3 92.31% +src/rs256.c 149 10 93.29% 13 0 100.00% 182 14 92.31% +src/time.c 43 3 93.02% 3 0 100.00% 43 2 95.35% +src/touch.c 67 0 100.00% 2 0 100.00% 79 0 100.00% +src/tpm.c 103 0 100.00% 9 0 100.00% 194 0 100.00% +src/types.c 29 0 100.00% 7 0 100.00% 56 0 100.00% +src/u2f.c 572 4 99.30% 17 0 100.00% 726 12 98.35% +src/util.c 14 1 92.86% 1 0 100.00% 14 1 92.86% Files which contain no functions: +fuzz/mutator_aux.h 0 0 - 0 0 - 0 0 - 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/fallthrough.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 7861 476 93.94% 684 27 96.05% 10270 699 93.19% +TOTAL 8711 492 94.35% 737 28 96.20% 11320 771 93.19% diff --git a/contrib/libfido2/fuzz/udev.c b/contrib/libfido2/fuzz/udev.c index 3984d8f555ed..3194012ab97e 100644 --- a/contrib/libfido2/fuzz/udev.c +++ b/contrib/libfido2/fuzz/udev.c @@ -1,269 +1,270 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include "mutator_aux.h" struct udev { int magic; }; struct udev_enumerate { int magic; struct udev_list_entry *list_entry; }; struct udev_list_entry { int magic; }; struct udev_device { int magic; struct udev_device *parent; }; #define UDEV_MAGIC 0x584492cc #define UDEV_DEVICE_MAGIC 0x569180dd #define UDEV_LIST_ENTRY_MAGIC 0x497422ee #define UDEV_ENUM_MAGIC 0x583570ff #define ASSERT_TYPE(x, m) assert((x) != NULL && (x)->magic == (m)) #define ASSERT_UDEV(x) ASSERT_TYPE((x), UDEV_MAGIC) #define ASSERT_UDEV_ENUM(x) ASSERT_TYPE((x), UDEV_ENUM_MAGIC) #define ASSERT_UDEV_LIST_ENTRY(x) ASSERT_TYPE((x), UDEV_LIST_ENTRY_MAGIC) #define ASSERT_UDEV_DEVICE(x) ASSERT_TYPE((x), UDEV_DEVICE_MAGIC) static const char *uevent; static const struct blob *report_descriptor; struct udev *__wrap_udev_new(void); struct udev_device *__wrap_udev_device_get_parent_with_subsystem_devtype( struct udev_device *, const char *, const char *); struct udev_device *__wrap_udev_device_new_from_syspath(struct udev *, const char *); struct udev_enumerate *__wrap_udev_enumerate_new(struct udev *); struct udev_list_entry *__wrap_udev_enumerate_get_list_entry( struct udev_enumerate *); struct udev_list_entry *__wrap_udev_list_entry_get_next( struct udev_list_entry *); const char *__wrap_udev_device_get_sysattr_value(struct udev_device *, const char *); const char *__wrap_udev_list_entry_get_name(struct udev_list_entry *); const char *__wrap_udev_device_get_devnode(struct udev_device *); const char *__wrap_udev_device_get_sysnum(struct udev_device *); int __wrap_udev_enumerate_add_match_subsystem(struct udev_enumerate *, const char *); int __wrap_udev_enumerate_scan_devices(struct udev_enumerate *); int __wrap_ioctl(int, unsigned long , ...); void __wrap_udev_device_unref(struct udev_device *); void __wrap_udev_enumerate_unref(struct udev_enumerate *); void __wrap_udev_unref(struct udev *); void set_udev_parameters(const char *, const struct blob *); struct udev_device * __wrap_udev_device_get_parent_with_subsystem_devtype(struct udev_device *child, const char *subsystem, const char *devtype) { ASSERT_UDEV_DEVICE(child); fido_log_debug("%s", subsystem); /* XXX consume */ fido_log_debug("%s", devtype); /* XXX consume */ if (child->parent != NULL) return child->parent; if ((child->parent = calloc(1, sizeof(*child->parent))) == NULL) return NULL; child->parent->magic = UDEV_DEVICE_MAGIC; return child->parent; } const char * __wrap_udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) { ASSERT_UDEV_DEVICE(udev_device); if (uniform_random(400) < 1) return NULL; if (!strcmp(sysattr, "manufacturer") || !strcmp(sysattr, "product")) return "product info"; /* XXX randomise? */ else if (!strcmp(sysattr, "uevent")) return uevent; return NULL; } const char * __wrap_udev_list_entry_get_name(struct udev_list_entry *entry) { ASSERT_UDEV_LIST_ENTRY(entry); return uniform_random(400) < 1 ? NULL : "name"; /* XXX randomise? */ } struct udev_device * __wrap_udev_device_new_from_syspath(struct udev *udev, const char *syspath) { struct udev_device *udev_device; ASSERT_UDEV(udev); fido_log_debug("%s", syspath); if ((udev_device = calloc(1, sizeof(*udev_device))) == NULL) return NULL; udev_device->magic = UDEV_DEVICE_MAGIC; return udev_device; } const char * __wrap_udev_device_get_devnode(struct udev_device *udev_device) { ASSERT_UDEV_DEVICE(udev_device); return uniform_random(400) < 1 ? NULL : "/dev/zero"; } const char * __wrap_udev_device_get_sysnum(struct udev_device *udev_device) { ASSERT_UDEV_DEVICE(udev_device); return uniform_random(400) < 1 ? NULL : "101010"; /* XXX randomise? */ } void __wrap_udev_device_unref(struct udev_device *udev_device) { ASSERT_UDEV_DEVICE(udev_device); if (udev_device->parent) { ASSERT_UDEV_DEVICE(udev_device->parent); free(udev_device->parent); } free(udev_device); } struct udev * __wrap_udev_new(void) { struct udev *udev; if ((udev = calloc(1, sizeof(*udev))) == NULL) return NULL; udev->magic = UDEV_MAGIC; return udev; } struct udev_enumerate * __wrap_udev_enumerate_new(struct udev *udev) { struct udev_enumerate *udev_enum; ASSERT_UDEV(udev); if ((udev_enum = calloc(1, sizeof(*udev_enum))) == NULL) return NULL; udev_enum->magic = UDEV_ENUM_MAGIC; return udev_enum; } int __wrap_udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enum, const char *subsystem) { ASSERT_UDEV_ENUM(udev_enum); fido_log_debug("%s:", subsystem); return uniform_random(400) < 1 ? -EINVAL : 0; } int __wrap_udev_enumerate_scan_devices(struct udev_enumerate *udev_enum) { ASSERT_UDEV_ENUM(udev_enum); return uniform_random(400) < 1 ? -EINVAL : 0; } struct udev_list_entry * __wrap_udev_enumerate_get_list_entry(struct udev_enumerate *udev_enum) { ASSERT_UDEV_ENUM(udev_enum); if ((udev_enum->list_entry = calloc(1, sizeof(*udev_enum->list_entry))) == NULL) return NULL; udev_enum->list_entry->magic = UDEV_LIST_ENTRY_MAGIC; return udev_enum->list_entry; } struct udev_list_entry * __wrap_udev_list_entry_get_next(struct udev_list_entry *udev_list_entry) { ASSERT_UDEV_LIST_ENTRY(udev_list_entry); return uniform_random(400) < 1 ? NULL : udev_list_entry; } void __wrap_udev_enumerate_unref(struct udev_enumerate *udev_enum) { ASSERT_UDEV_ENUM(udev_enum); if (udev_enum->list_entry) ASSERT_UDEV_LIST_ENTRY(udev_enum->list_entry); free(udev_enum->list_entry); free(udev_enum); } void __wrap_udev_unref(struct udev *udev) { ASSERT_UDEV(udev); free(udev); } int __wrap_ioctl(int fd, unsigned long request, ...) { va_list ap; struct hidraw_report_descriptor *hrd; (void)fd; if (uniform_random(400) < 1) { errno = EINVAL; return -1; } va_start(ap, request); - switch (request) { + switch (IOCTL_REQ(request)) { case IOCTL_REQ(HIDIOCGRDESCSIZE): *va_arg(ap, int *) = (int)report_descriptor->len; break; case IOCTL_REQ(HIDIOCGRDESC): hrd = va_arg(ap, struct hidraw_report_descriptor *); assert(hrd->size == report_descriptor->len); memcpy(hrd->value, report_descriptor->body, hrd->size); break; default: warnx("%s: unknown request 0x%lx", __func__, request); abort(); } va_end(ap); return 0; } void set_udev_parameters(const char *uevent_ptr, const struct blob *report_descriptor_ptr) { uevent = uevent_ptr; report_descriptor = report_descriptor_ptr; } diff --git a/contrib/libfido2/fuzz/wiredata_fido2.h b/contrib/libfido2/fuzz/wiredata_fido2.h index da905516f92a..6c66c545b235 100644 --- a/contrib/libfido2/fuzz/wiredata_fido2.h +++ b/contrib/libfido2/fuzz/wiredata_fido2.h @@ -1,633 +1,708 @@ /* - * Copyright (c) 2020 Yubico AB. All rights reserved. + * Copyright (c) 2020-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #ifndef _WIREDATA_FIDO2_H #define _WIREDATA_FIDO2_H #define WIREDATA_CTAP_INIT \ 0xff, 0xff, 0xff, 0xff, 0x86, 0x00, 0x11, 0x80, \ 0x43, 0x56, 0x40, 0xb1, 0x4e, 0xd9, 0x2d, 0x00, \ 0x22, 0x00, 0x02, 0x02, 0x05, 0x02, 0x01, 0x05, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define WIREDATA_CTAP_KEEPALIVE \ 0x00, 0x22, 0x00, 0x02, 0xbb, 0x00, 0x01, 0x02, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define WIREDATA_CTAP_CBOR_INFO \ 0x00, 0x22, 0x00, 0x02, 0x90, 0x00, 0xb9, 0x00, \ 0xa9, 0x01, 0x83, 0x66, 0x55, 0x32, 0x46, 0x5f, \ 0x56, 0x32, 0x68, 0x46, 0x49, 0x44, 0x4f, 0x5f, \ 0x32, 0x5f, 0x30, 0x6c, 0x46, 0x49, 0x44, 0x4f, \ 0x5f, 0x32, 0x5f, 0x31, 0x5f, 0x50, 0x52, 0x45, \ 0x02, 0x82, 0x6b, 0x63, 0x72, 0x65, 0x64, 0x50, \ 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x6b, 0x68, \ 0x6d, 0x61, 0x63, 0x2d, 0x73, 0x65, 0x63, 0x72, \ 0x00, 0x22, 0x00, 0x02, 0x00, 0x65, 0x74, 0x03, \ 0x50, 0x19, 0x56, 0xe5, 0xbd, 0xa3, 0x74, 0x45, \ 0xf1, 0xa8, 0x14, 0x35, 0x64, 0x03, 0xfd, 0xbc, \ 0x18, 0x04, 0xa5, 0x62, 0x72, 0x6b, 0xf5, 0x62, \ 0x75, 0x70, 0xf5, 0x64, 0x70, 0x6c, 0x61, 0x74, \ 0xf4, 0x69, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, \ 0x50, 0x69, 0x6e, 0xf4, 0x75, 0x63, 0x72, 0x65, \ 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x4d, \ 0x00, 0x22, 0x00, 0x02, 0x01, 0x67, 0x6d, 0x74, \ 0x50, 0x72, 0x65, 0x76, 0x69, 0x65, 0x77, 0xf5, \ 0x05, 0x19, 0x04, 0xb0, 0x06, 0x81, 0x01, 0x07, \ 0x08, 0x08, 0x18, 0x80, 0x0a, 0x82, 0xa2, 0x63, \ 0x61, 0x6c, 0x67, 0x26, 0x64, 0x74, 0x79, 0x70, \ 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, \ 0x2d, 0x6b, 0x65, 0x79, 0xa2, 0x63, 0x61, 0x6c, \ 0x67, 0x27, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, \ 0x00, 0x22, 0x00, 0x02, 0x02, 0x70, 0x75, 0x62, \ 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define WIREDATA_CTAP_CBOR_AUTHKEY \ 0x00, 0x22, 0x00, 0x02, 0x90, 0x00, 0x51, 0x00, \ 0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, \ 0x20, 0x01, 0x21, 0x58, 0x20, 0x2a, 0xb8, 0x2d, \ 0x36, 0x69, 0xab, 0x30, 0x9d, 0xe3, 0x5e, 0x9b, \ 0xfb, 0x94, 0xfc, 0x1d, 0x92, 0x95, 0xaf, 0x01, \ 0x47, 0xfe, 0x4b, 0x87, 0xe5, 0xcf, 0x3f, 0x05, \ 0x0b, 0x39, 0xda, 0x17, 0x49, 0x22, 0x58, 0x20, \ 0x15, 0x1b, 0xbe, 0x08, 0x78, 0x60, 0x4d, 0x3c, \ 0x00, 0x22, 0x00, 0x02, 0x00, 0x3f, 0xf1, 0x60, \ 0xa6, 0xd8, 0xf8, 0xed, 0xce, 0x4a, 0x30, 0x5d, \ 0x1a, 0xaf, 0x80, 0xc4, 0x0a, 0xd2, 0x6f, 0x77, \ 0x38, 0x12, 0x97, 0xaa, 0xbd, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define WIREDATA_CTAP_CBOR_PINTOKEN \ 0x00, 0x22, 0x00, 0x02, 0x90, 0x00, 0x14, 0x00, \ 0xa1, 0x02, 0x50, 0xee, 0x40, 0x4c, 0x85, 0xd7, \ 0xa1, 0x2f, 0x56, 0xc4, 0x4e, 0xc5, 0x93, 0x41, \ 0xd0, 0x3b, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define WIREDATA_CTAP_CBOR_STATUS \ 0x00, 0x22, 0x00, 0x02, 0x90, 0x00, 0x01, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define WIREDATA_CTAP_CBOR_RETRIES \ 0x00, 0x22, 0x00, 0x02, 0x90, 0x00, 0x04, 0x00, \ 0xa1, 0x03, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define WIREDATA_CTAP_CBOR_ASSERT \ 0x00, 0x22, 0x00, 0x02, 0x90, 0x00, 0xcb, 0x00, \ 0xa3, 0x01, 0xa2, 0x62, 0x69, 0x64, 0x58, 0x40, \ 0x4a, 0x4c, 0x9e, 0xcc, 0x81, 0x7d, 0x42, 0x03, \ 0x2b, 0x41, 0xd1, 0x38, 0xd3, 0x49, 0xb4, 0xfc, \ 0xfb, 0xe4, 0x4e, 0xe4, 0xff, 0x76, 0x34, 0x16, \ 0x68, 0x06, 0x9d, 0xa6, 0x01, 0x32, 0xb9, 0xff, \ 0xc2, 0x35, 0x0d, 0x89, 0x43, 0x66, 0x12, 0xf8, \ 0x8e, 0x5b, 0xde, 0xf4, 0xcc, 0xec, 0x9d, 0x03, \ 0x00, 0x92, 0x00, 0x0e, 0x00, 0x85, 0xc2, 0xf5, \ 0xe6, 0x8e, 0xeb, 0x3f, 0x3a, 0xec, 0xc3, 0x1d, \ 0x04, 0x6e, 0xf3, 0x5b, 0x88, 0x64, 0x74, 0x79, \ 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, \ 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x02, 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, \ 0x00, 0x92, 0x00, 0x0e, 0x01, 0x99, 0x5c, 0xf3, \ 0xba, 0x83, 0x1d, 0x97, 0x63, 0x04, 0x00, 0x00, \ 0x00, 0x09, 0x03, 0x58, 0x47, 0x30, 0x45, 0x02, \ 0x21, 0x00, 0xcf, 0x3f, 0x36, 0x0e, 0x1f, 0x6f, \ 0xd6, 0xa0, 0x9d, 0x13, 0xcf, 0x55, 0xf7, 0x49, \ 0x8f, 0xc8, 0xc9, 0x03, 0x12, 0x76, 0x41, 0x75, \ 0x7b, 0xb5, 0x0a, 0x90, 0xa5, 0x82, 0x26, 0xf1, \ 0x6b, 0x80, 0x02, 0x20, 0x34, 0x9b, 0x7a, 0x82, \ 0x00, 0x92, 0x00, 0x0e, 0x02, 0xd3, 0xe1, 0x79, \ 0x49, 0x55, 0x41, 0x9f, 0xa4, 0x06, 0x06, 0xbd, \ 0xc8, 0xb9, 0x2b, 0x5f, 0xe1, 0xa7, 0x99, 0x1c, \ 0xa1, 0xfc, 0x7e, 0x3e, 0xd5, 0x85, 0x2e, 0x11, \ 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define WIREDATA_CTAP_CBOR_CRED \ 0x00, 0x91, 0x00, 0x03, 0x90, 0x03, 0xe1, 0x00, \ 0xa3, 0x01, 0x66, 0x70, 0x61, 0x63, 0x6b, 0x65, \ 0x64, 0x02, 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, 0x45, 0x00, 0x00, 0x00, \ 0x00, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, \ 0x00, 0x91, 0x00, 0x03, 0x00, 0x15, 0x80, 0x06, \ 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x00, 0x40, \ 0xed, 0x88, 0x48, 0xa1, 0xdb, 0x56, 0x4d, 0x0f, \ 0x0d, 0xc8, 0x8f, 0x0f, 0xe9, 0x16, 0xb1, 0x78, \ 0xa9, 0x40, 0x98, 0x71, 0xa0, 0xb3, 0xf2, 0xcf, \ 0x05, 0x73, 0x6c, 0x12, 0xbf, 0x00, 0x96, 0xf3, \ 0x7b, 0x93, 0xba, 0x49, 0xee, 0x23, 0xb4, 0x78, \ 0x2e, 0xfb, 0xce, 0x27, 0xa8, 0xc2, 0x26, 0x78, \ 0x00, 0x91, 0x00, 0x03, 0x01, 0xcc, 0x95, 0x2d, \ 0x40, 0xdb, 0xd1, 0x40, 0x3d, 0x2b, 0xa3, 0x31, \ 0xa0, 0x75, 0x82, 0x63, 0xf0, 0xa5, 0x01, 0x02, \ 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x9d, \ 0x95, 0xa1, 0xb5, 0xd6, 0x11, 0xbf, 0xe2, 0x28, \ 0xa0, 0x7f, 0xca, 0x1e, 0xd9, 0x09, 0x0f, 0x0d, \ 0xe7, 0x8e, 0x29, 0xe8, 0x2e, 0x11, 0xdb, 0x55, \ 0x62, 0x13, 0xd7, 0x26, 0xc2, 0x7e, 0x2b, 0x22, \ 0x00, 0x91, 0x00, 0x03, 0x02, 0x58, 0x20, 0xbe, \ 0x74, 0x2a, 0xac, 0xde, 0x11, 0x40, 0x76, 0x31, \ 0x0b, 0xed, 0x55, 0xde, 0xf3, 0x03, 0xe4, 0x1c, \ 0xac, 0x42, 0x63, 0x8f, 0xe8, 0x30, 0x63, 0xb7, \ 0x07, 0x4e, 0x5d, 0xfb, 0x17, 0x5e, 0x9b, 0x03, \ 0xa3, 0x63, 0x61, 0x6c, 0x67, 0x26, 0x63, 0x73, \ 0x69, 0x67, 0x58, 0x48, 0x30, 0x46, 0x02, 0x21, \ 0x00, 0xfb, 0xd1, 0x26, 0x76, 0x34, 0x74, 0xac, \ 0x00, 0x91, 0x00, 0x03, 0x03, 0xf6, 0xd8, 0x5c, \ 0x5d, 0xbc, 0xda, 0xe0, 0x43, 0xe0, 0xa5, 0x42, \ 0x9f, 0xc7, 0xe2, 0x18, 0x3e, 0xe2, 0x2c, 0x94, \ 0x78, 0xbf, 0x9c, 0xeb, 0x3e, 0x9d, 0x02, 0x21, \ 0x00, 0xab, 0x21, 0x1b, 0xc4, 0x30, 0x69, 0xee, \ 0x7f, 0x09, 0xe6, 0x6b, 0x99, 0x98, 0x34, 0x07, \ 0x7b, 0x9a, 0x58, 0xb2, 0xe8, 0x77, 0xe0, 0xba, \ 0x7d, 0xab, 0x65, 0xf8, 0xba, 0x2a, 0xcb, 0x9a, \ 0x00, 0x91, 0x00, 0x03, 0x04, 0x41, 0x63, 0x78, \ 0x35, 0x63, 0x81, 0x59, 0x02, 0xb3, 0x30, 0x82, \ 0x02, 0xaf, 0x30, 0x82, 0x01, 0x97, 0xa0, 0x03, \ 0x02, 0x01, 0x02, 0x02, 0x04, 0x48, 0x5b, 0x3d, \ 0xb6, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, \ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, \ 0x30, 0x21, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, \ 0x55, 0x04, 0x03, 0x0c, 0x16, 0x59, 0x75, 0x62, \ 0x00, 0x91, 0x00, 0x03, 0x05, 0x69, 0x63, 0x6f, \ 0x20, 0x46, 0x49, 0x44, 0x4f, 0x20, 0x50, 0x72, \ 0x65, 0x76, 0x69, 0x65, 0x77, 0x20, 0x43, 0x41, \ 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x34, \ 0x31, 0x32, 0x31, 0x30, 0x35, 0x37, 0x31, 0x30, \ 0x5a, 0x17, 0x0d, 0x31, 0x38, 0x31, 0x32, 0x33, \ 0x31, 0x31, 0x30, 0x35, 0x37, 0x31, 0x30, 0x5a, \ 0x30, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, \ 0x00, 0x91, 0x00, 0x03, 0x06, 0x55, 0x04, 0x06, \ 0x13, 0x02, 0x53, 0x45, 0x31, 0x12, 0x30, 0x10, \ 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x59, \ 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x41, 0x42, \ 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, \ 0x0b, 0x0c, 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, \ 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, \ 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, \ 0x00, 0x91, 0x00, 0x03, 0x07, 0x74, 0x69, 0x6f, \ 0x6e, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, \ 0x04, 0x03, 0x0c, 0x1f, 0x59, 0x75, 0x62, 0x69, \ 0x63, 0x6f, 0x20, 0x55, 0x32, 0x46, 0x20, 0x45, \ 0x45, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, \ 0x20, 0x31, 0x32, 0x31, 0x33, 0x39, 0x33, 0x39, \ 0x31, 0x32, 0x36, 0x30, 0x59, 0x30, 0x13, 0x06, \ 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, \ 0x00, 0x91, 0x00, 0x03, 0x08, 0x06, 0x08, 0x2a, \ 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, \ 0x42, 0x00, 0x04, 0xfb, 0x2c, 0xdd, 0x30, 0x43, \ 0x28, 0xc5, 0x72, 0x4a, 0x50, 0xcc, 0xe6, 0xf6, \ 0x0b, 0xad, 0x7d, 0x27, 0xa9, 0x1b, 0x59, 0xe1, \ 0xe6, 0x6f, 0x29, 0x7b, 0x89, 0xc9, 0xd4, 0x3d, \ 0xc2, 0xb2, 0xc7, 0x78, 0x89, 0xb4, 0xf0, 0xff, \ 0x9d, 0x02, 0x28, 0xcb, 0x94, 0x6d, 0xfc, 0xe0, \ 0x00, 0x91, 0x00, 0x03, 0x09, 0x1b, 0x19, 0x58, \ 0x9b, 0x67, 0x80, 0x4a, 0xac, 0x97, 0x7f, 0x28, \ 0x18, 0x9c, 0xcd, 0xb3, 0x25, 0x74, 0xca, 0x28, \ 0xa3, 0x6c, 0x30, 0x6a, 0x30, 0x22, 0x06, 0x09, \ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xc4, 0x0a, \ 0x02, 0x04, 0x15, 0x31, 0x2e, 0x33, 0x2e, 0x36, \ 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, \ 0x31, 0x34, 0x38, 0x32, 0x2e, 0x31, 0x2e, 0x36, \ 0x00, 0x91, 0x00, 0x03, 0x0a, 0x30, 0x13, 0x06, \ 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0xe5, \ 0x1c, 0x02, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, \ 0x04, 0x30, 0x30, 0x21, 0x06, 0x0b, 0x2b, 0x06, \ 0x01, 0x04, 0x01, 0x82, 0xe5, 0x1c, 0x01, 0x01, \ 0x04, 0x04, 0x12, 0x04, 0x10, 0xf8, 0xa0, 0x11, \ 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, \ 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x30, 0x0c, 0x06, \ 0x00, 0x91, 0x00, 0x03, 0x0b, 0x03, 0x55, 0x1d, \ 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, \ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, \ 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, \ 0x82, 0x01, 0x01, 0x00, 0x32, 0xf3, 0xe4, 0xbd, \ 0x58, 0xd7, 0x42, 0x2b, 0xaf, 0x49, 0x99, 0x86, \ 0x08, 0x1f, 0x0d, 0xa9, 0x3b, 0xc6, 0xaa, 0x1c, \ 0x72, 0x11, 0xf9, 0x28, 0x53, 0xeb, 0xf3, 0xeb, \ 0x00, 0x91, 0x00, 0x03, 0x0c, 0x73, 0xda, 0x69, \ 0x3b, 0x06, 0xde, 0x31, 0x33, 0x8e, 0x5d, 0x02, \ 0xec, 0xf6, 0x76, 0xe9, 0x5c, 0x42, 0xbe, 0xa5, \ 0x8f, 0x25, 0xd3, 0x37, 0x3f, 0x77, 0xbb, 0x2a, \ 0x9d, 0x7c, 0xb2, 0x3e, 0x11, 0x8c, 0x41, 0xd4, \ 0x9a, 0x4c, 0x9a, 0xd8, 0xf3, 0xe2, 0xa4, 0xec, \ 0x01, 0x77, 0x7a, 0x74, 0xa8, 0xc4, 0x12, 0x43, \ 0xc3, 0x1e, 0xce, 0x20, 0x8f, 0x2d, 0x0f, 0x6e, \ 0x00, 0x91, 0x00, 0x03, 0x0d, 0xbc, 0x61, 0x9b, \ 0xe1, 0x84, 0xa1, 0x72, 0xf6, 0xa9, 0xac, 0xcb, \ 0xf8, 0x73, 0x6d, 0x5b, 0xe2, 0x98, 0xb3, 0x6b, \ 0xec, 0xe7, 0x1e, 0x77, 0x8d, 0x0a, 0x69, 0xaa, \ 0xf9, 0x94, 0xb8, 0x63, 0x6d, 0xe8, 0xfa, 0xf6, \ 0x2f, 0xd3, 0xce, 0x7f, 0x04, 0x4c, 0x32, 0x2c, \ 0xf7, 0x26, 0x3e, 0x34, 0x99, 0xe6, 0xa5, 0xb2, \ 0xb0, 0x2a, 0xbb, 0xad, 0x5b, 0xd9, 0xec, 0xe5, \ 0x00, 0x91, 0x00, 0x03, 0x0e, 0xb0, 0x71, 0x4d, \ 0x73, 0xbb, 0x94, 0x61, 0x49, 0x9c, 0x94, 0x2a, \ 0x5f, 0x1d, 0xcc, 0xaf, 0x65, 0x03, 0x3b, 0x39, \ 0x39, 0xd4, 0x47, 0xd9, 0xfc, 0xc4, 0x7b, 0x0b, \ 0x16, 0xd8, 0xe9, 0x01, 0xfc, 0xec, 0x3f, 0x8c, \ 0x1b, 0xc0, 0xc6, 0xac, 0x0b, 0x5d, 0x74, 0xc7, \ 0xbb, 0x03, 0x05, 0x69, 0x17, 0xe9, 0x98, 0x1a, \ 0x19, 0xb9, 0x09, 0x5c, 0xa1, 0xf4, 0xab, 0x9f, \ 0x00, 0x91, 0x00, 0x03, 0x0f, 0x02, 0x7c, 0x28, \ 0x0f, 0x8a, 0xf9, 0xed, 0x1d, 0x29, 0x3c, 0xf6, \ 0xcc, 0x2f, 0x04, 0x6d, 0x9a, 0xd6, 0x62, 0xb4, \ 0xa9, 0x6e, 0xb1, 0xca, 0xca, 0xac, 0x5e, 0x05, \ 0x3e, 0x83, 0x91, 0x47, 0x7c, 0x1f, 0x8b, 0x60, \ 0x01, 0xde, 0x65, 0x3a, 0xbf, 0xf2, 0xaa, 0xbb, \ 0x55, 0x98, 0x86, 0x91, 0x7e, 0xad, 0x3b, 0x36, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define WIREDATA_CTAP_CBOR_CREDMAN_META \ 0x00, 0x12, 0x00, 0x04, 0x90, 0x00, 0x07, 0x00, \ 0xa2, 0x01, 0x00, 0x02, 0x18, 0x19, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define WIREDATA_CTAP_CBOR_CREDMAN_RPLIST \ 0x00, 0x15, 0x00, 0x02, 0x90, 0x00, 0x37, 0x00, \ 0xa3, 0x03, 0xa1, 0x62, 0x69, 0x64, 0x6a, 0x79, \ 0x75, 0x62, 0x69, 0x63, 0x6f, 0x2e, 0x63, 0x6f, \ 0x6d, 0x04, 0x58, 0x20, 0x37, 0x82, 0x09, 0xb7, \ 0x2d, 0xef, 0xcb, 0xa9, 0x1d, 0xcb, 0xf8, 0x54, \ 0xed, 0xb4, 0xda, 0xa6, 0x48, 0x82, 0x8a, 0x2c, \ 0xbd, 0x18, 0x0a, 0xfc, 0x77, 0xa7, 0x44, 0x34, \ 0x65, 0x5a, 0x1c, 0x7d, 0x05, 0x03, 0x00, 0x00, \ 0x00, 0x15, 0x00, 0x02, 0x90, 0x00, 0x36, 0x00, \ 0xa2, 0x03, 0xa1, 0x62, 0x69, 0x64, 0x6b, 0x79, \ 0x75, 0x62, 0x69, 0x6b, 0x65, 0x79, 0x2e, 0x6f, \ 0x72, 0x67, 0x04, 0x58, 0x20, 0x12, 0x6b, 0xba, \ 0x6a, 0x2d, 0x7a, 0x81, 0x84, 0x25, 0x7b, 0x74, \ 0xdd, 0x1d, 0xdd, 0x46, 0xb6, 0x2a, 0x8c, 0xa2, \ 0xa7, 0x83, 0xfe, 0xdb, 0x5b, 0x19, 0x48, 0x73, \ 0x55, 0xb7, 0xe3, 0x46, 0x09, 0x00, 0x00, 0x00, \ 0x00, 0x15, 0x00, 0x02, 0x90, 0x00, 0x37, 0x00, \ 0xa2, 0x03, 0xa1, 0x62, 0x69, 0x64, 0x6c, 0x77, \ 0x65, 0x62, 0x61, 0x75, 0x74, 0x68, 0x6e, 0x2e, \ 0x64, 0x65, 0x76, 0x04, 0x58, 0x20, 0xd6, 0x32, \ 0x7d, 0x8c, 0x6a, 0x5d, 0xe6, 0xae, 0x0e, 0x33, \ 0xd0, 0xa3, 0x31, 0xfb, 0x67, 0x77, 0xb9, 0x4e, \ 0xf4, 0x73, 0x19, 0xfe, 0x7e, 0xfd, 0xfa, 0x82, \ 0x70, 0x8e, 0x1f, 0xbb, 0xa2, 0x55, 0x00, 0x00 #define WIREDATA_CTAP_CBOR_CREDMAN_RKLIST \ 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xc5, 0x00, \ 0xa5, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, \ 0xe4, 0xe1, 0x06, 0x31, 0xde, 0x00, 0x0f, 0x4f, \ 0x12, 0x6e, 0xc9, 0x68, 0x2d, 0x43, 0x3f, 0xf1, \ 0x02, 0x2c, 0x6e, 0xe6, 0x96, 0x10, 0xbf, 0x73, \ 0x35, 0xc9, 0x20, 0x27, 0x06, 0xba, 0x39, 0x09, \ 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, \ 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, \ 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, \ 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, \ 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, \ 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0x19, \ 0xf7, 0x78, 0x0c, 0xa0, 0xbc, 0xb9, 0xa6, 0xd5, \ 0x1e, 0xd7, 0x87, 0xfb, 0x6c, 0x80, 0x03, 0x64, \ 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, \ 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, \ 0x00, 0x15, 0x00, 0x04, 0x01, 0xa5, 0x01, 0x02, \ 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x81, \ 0x6c, 0xdd, 0x8c, 0x8f, 0x8c, 0xc8, 0x43, 0xa7, \ 0xbb, 0x79, 0x51, 0x09, 0xb1, 0xdf, 0xbe, 0xc4, \ 0xa5, 0x54, 0x16, 0x9e, 0x58, 0x56, 0xb3, 0x0b, \ 0x34, 0x4f, 0xa5, 0x6c, 0x05, 0xa2, 0x21, 0x22, \ 0x58, 0x20, 0xcd, 0xc2, 0x0c, 0x99, 0x83, 0x5a, \ 0x61, 0x73, 0xd8, 0xe0, 0x74, 0x23, 0x46, 0x64, \ 0x00, 0x15, 0x00, 0x04, 0x02, 0x39, 0x4c, 0xb0, \ 0xf4, 0x6c, 0x0a, 0x37, 0x72, 0xaa, 0xa8, 0xea, \ 0x58, 0xd3, 0xd4, 0xe0, 0x51, 0xb2, 0x28, 0x09, \ 0x05, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xa0, 0x00, \ 0xa4, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, \ 0x56, 0xa1, 0x3c, 0x06, 0x2b, 0xad, 0xa2, 0x21, \ 0x7d, 0xcd, 0x91, 0x08, 0x47, 0xa8, 0x8a, 0x06, \ 0x06, 0xf6, 0x66, 0x91, 0xf6, 0xeb, 0x89, 0xe4, \ 0xdf, 0x26, 0xbc, 0x46, 0x59, 0xc3, 0x7d, 0xc0, \ 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, \ 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, \ 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, \ 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, \ 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, \ 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0xd8, \ 0x27, 0x4b, 0x25, 0xed, 0x19, 0xef, 0x11, 0xaf, \ 0xa6, 0x89, 0x7b, 0x84, 0x50, 0xe7, 0x62, 0x64, \ 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, \ 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, \ 0x00, 0x15, 0x00, 0x04, 0x01, 0xa4, 0x01, 0x01, \ 0x03, 0x27, 0x20, 0x06, 0x21, 0x58, 0x20, 0x8d, \ 0xfe, 0x45, 0xd5, 0x7d, 0xb6, 0x17, 0xab, 0x86, \ 0x2d, 0x32, 0xf6, 0x85, 0xf0, 0x92, 0x76, 0xb7, \ 0xce, 0x73, 0xca, 0x4e, 0x0e, 0xfd, 0xd5, 0xdb, \ 0x2a, 0x1d, 0x55, 0x90, 0x96, 0x52, 0xc2, 0x0a, \ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xa0, 0x00, \ 0xa4, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, \ 0x04, 0x0e, 0x0f, 0xa0, 0xcd, 0x60, 0x35, 0x9a, \ 0xba, 0x47, 0x0c, 0x10, 0xb6, 0x82, 0x6e, 0x2f, \ 0x66, 0xb9, 0xa7, 0xcf, 0xd8, 0x47, 0xb4, 0x3d, \ 0xfd, 0x77, 0x1a, 0x38, 0x22, 0xa1, 0xda, 0xa5, \ 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, \ 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, \ 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, \ 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, \ 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, \ 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0x00, \ 0x5d, 0xdf, 0xef, 0xe2, 0xf3, 0x06, 0xb2, 0xa5, \ 0x46, 0x4d, 0x98, 0xbc, 0x14, 0x65, 0xc1, 0x64, \ 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, \ 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, \ 0x00, 0x15, 0x00, 0x04, 0x01, 0xa4, 0x01, 0x01, \ 0x03, 0x27, 0x20, 0x06, 0x21, 0x58, 0x20, 0x72, \ 0x79, 0x14, 0x69, 0xdf, 0xcb, 0x64, 0x75, 0xee, \ 0xd4, 0x45, 0x94, 0xbc, 0x48, 0x4d, 0x2a, 0x9f, \ 0xc9, 0xf4, 0xb5, 0x1b, 0x05, 0xa6, 0x5b, 0x54, \ 0x9a, 0xac, 0x6c, 0x2e, 0xc6, 0x90, 0x62, 0x0a, \ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xc3, 0x00, \ 0xa4, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, \ 0xce, 0x32, 0xd8, 0x79, 0xdd, 0x86, 0xa2, 0x42, \ 0x7c, 0xc3, 0xe1, 0x95, 0x12, 0x93, 0x1a, 0x03, \ 0xe6, 0x70, 0xb8, 0xff, 0xcd, 0xa5, 0xdf, 0x15, \ 0xfc, 0x88, 0x2a, 0xf5, 0x44, 0xf1, 0x33, 0x9c, \ 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, \ 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, \ 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, \ 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, \ 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, \ 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0x0a, \ 0x26, 0x5b, 0x7e, 0x1a, 0x2a, 0xba, 0x70, 0x5f, \ 0x18, 0x26, 0x14, 0xb2, 0x71, 0xca, 0x98, 0x64, \ 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, \ 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, \ 0x00, 0x15, 0x00, 0x04, 0x01, 0xa5, 0x01, 0x02, \ 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0x8b, \ 0x48, 0xf0, 0x69, 0xfb, 0x22, 0xfb, 0xf3, 0x86, \ 0x57, 0x7c, 0xdd, 0x82, 0x2c, 0x1c, 0x0c, 0xdc, \ 0x27, 0xe2, 0x6a, 0x4c, 0x1a, 0x10, 0x04, 0x27, \ 0x51, 0x3e, 0x2a, 0x9d, 0x3a, 0xb6, 0xb5, 0x22, \ 0x58, 0x20, 0x70, 0xfe, 0x91, 0x67, 0x64, 0x53, \ 0x63, 0x83, 0x72, 0x31, 0xe9, 0xe5, 0x20, 0xb7, \ 0x00, 0x15, 0x00, 0x04, 0x02, 0xee, 0xc9, 0xfb, \ 0x63, 0xd7, 0xe4, 0x76, 0x39, 0x80, 0x82, 0x74, \ 0xb8, 0xfa, 0x67, 0xf5, 0x1b, 0x8f, 0xe0, 0x0a, \ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x15, 0x00, 0x04, 0x90, 0x00, 0xc3, 0x00, \ 0xa4, 0x06, 0xa3, 0x62, 0x69, 0x64, 0x58, 0x20, \ 0xf9, 0xa3, 0x67, 0xbf, 0x5e, 0x80, 0x95, 0xdb, \ 0x4c, 0xc5, 0x8f, 0x65, 0x36, 0xc5, 0xaf, 0xdd, \ 0x90, 0x2e, 0x62, 0x68, 0x67, 0x9c, 0xa2, 0x26, \ 0x2f, 0x2a, 0xf9, 0x3a, 0xda, 0x15, 0xf2, 0x27, \ 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x62, 0x6f, \ 0x62, 0x20, 0x62, 0x61, 0x6e, 0x61, 0x6e, 0x61, \ 0x00, 0x15, 0x00, 0x04, 0x00, 0x6b, 0x64, 0x69, \ 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, \ 0x65, 0x67, 0x62, 0x62, 0x61, 0x6e, 0x61, 0x6e, \ 0x61, 0x07, 0xa2, 0x62, 0x69, 0x64, 0x50, 0xfb, \ 0xa6, 0xbe, 0xc1, 0x01, 0xf6, 0x7a, 0x81, 0xf9, \ 0xcd, 0x6d, 0x20, 0x41, 0x7a, 0x1c, 0x40, 0x64, \ 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, \ 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x08, \ 0x00, 0x15, 0x00, 0x04, 0x01, 0xa5, 0x01, 0x02, \ 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xda, \ 0x2b, 0x53, 0xc3, 0xbe, 0x48, 0xf8, 0xab, 0xbd, \ 0x06, 0x28, 0x46, 0xfa, 0x35, 0xab, 0xf9, 0xc5, \ 0x2e, 0xfd, 0x3c, 0x38, 0x88, 0xb3, 0xe1, 0xa7, \ 0xc5, 0xc6, 0xed, 0x72, 0x54, 0x37, 0x93, 0x22, \ 0x58, 0x20, 0x12, 0x82, 0x32, 0x2d, 0xab, 0xbc, \ 0x64, 0xb3, 0xed, 0xcc, 0xd5, 0x22, 0xec, 0x79, \ 0x00, 0x15, 0x00, 0x04, 0x02, 0x4b, 0xe2, 0x4d, \ 0x0c, 0x4b, 0x8d, 0x31, 0x4c, 0xb4, 0x0f, 0xd4, \ 0xa9, 0xbe, 0x0c, 0xab, 0x9e, 0x0a, 0xc9, 0x0a, \ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define WIREDATA_CTAP_CBOR_BIO_INFO \ 0x00, 0x10, 0x00, 0x04, 0x90, 0x00, 0x06, 0x00, \ 0xa2, 0x02, 0x01, 0x03, 0x04, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define WIREDATA_CTAP_CBOR_BIO_ENROLL \ 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x0a, 0x00, 0x05, 0x90, 0x00, 0x0a, 0x00, \ 0xa3, 0x04, 0x42, 0x68, 0x96, 0x05, 0x00, 0x06, \ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x0a, 0x00, 0x05, 0x90, 0x00, 0x06, 0x00, \ 0xa2, 0x05, 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x0a, 0x00, 0x05, 0xbb, 0x00, 0x01, 0x02, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x0a, 0x00, 0x05, 0x90, 0x00, 0x06, 0x00, \ 0xa2, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define WIREDATA_CTAP_CBOR_BIO_ENUM \ 0x00, 0x10, 0x00, 0x0f, 0x90, 0x00, 0x2e, 0x00, \ 0xa1, 0x07, 0x83, 0xa2, 0x01, 0x42, 0xce, 0xa3, \ 0x02, 0x67, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, \ 0x31, 0xa2, 0x01, 0x42, 0xbf, 0x5e, 0x02, 0x67, \ 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x32, 0xa2, \ 0x01, 0x42, 0x5e, 0xd2, 0x02, 0x67, 0x66, 0x69, \ 0x6e, 0x67, 0x65, 0x72, 0x33, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY \ 0x89, 0xc9, 0x8d, 0x28, 0x90, 0x01, 0xe6, 0x00, \ 0xa1, 0x01, 0x59, 0x01, 0xe0, 0x81, 0xa3, 0x01, \ 0x59, 0x01, 0xb8, 0xb3, 0x26, 0x24, 0x99, 0xde, \ 0x06, 0x3f, 0xca, 0xde, 0x98, 0x8d, 0x9d, 0xc5, \ 0x3f, 0x26, 0x6c, 0xc7, 0x40, 0x93, 0xc4, 0x88, \ 0x06, 0x51, 0x4f, 0xb9, 0x61, 0xf2, 0xc9, 0x8d, \ 0xbc, 0xce, 0x79, 0x08, 0xec, 0x90, 0xc5, 0x5b, \ 0xe5, 0x0a, 0x72, 0x08, 0x7b, 0xe1, 0xf9, 0x16, \ 0x89, 0xc9, 0x8d, 0x28, 0x00, 0x06, 0x8b, 0x76, \ 0x32, 0xa0, 0xae, 0x55, 0xb2, 0x39, 0x71, 0xce, \ 0x34, 0x4b, 0x6e, 0x6b, 0x89, 0xa6, 0x5e, 0x69, \ 0x07, 0xac, 0xf6, 0x01, 0x3c, 0xba, 0x45, 0x7a, \ 0x75, 0x25, 0x3a, 0xbd, 0x95, 0x22, 0x9d, 0xc3, \ 0xe4, 0x42, 0x31, 0x5c, 0xb5, 0xf4, 0x64, 0x6a, \ 0x56, 0x1d, 0xab, 0xc7, 0x6e, 0x96, 0x75, 0xe7, \ 0xb3, 0x22, 0x0b, 0x82, 0xac, 0x57, 0x78, 0xdf, \ 0x89, 0xc9, 0x8d, 0x28, 0x01, 0x57, 0x06, 0xc5, \ 0x4b, 0x61, 0x0b, 0x4d, 0xa1, 0x66, 0xa0, 0x89, \ 0xad, 0x19, 0x8f, 0xd8, 0x96, 0x55, 0x22, 0x5f, \ 0xca, 0x2e, 0xc1, 0xd7, 0xbd, 0xa1, 0x83, 0x66, \ 0x4d, 0x85, 0xcb, 0x01, 0x60, 0x3f, 0xf7, 0xf7, \ 0xa3, 0x7a, 0xfa, 0x99, 0xa0, 0x1e, 0x25, 0x90, \ 0xd0, 0xd0, 0x3b, 0x54, 0x90, 0x77, 0x94, 0xa6, \ 0x88, 0xea, 0xc3, 0x6b, 0xa0, 0x59, 0x5e, 0x69, \ 0x89, 0xc9, 0x8d, 0x28, 0x02, 0x78, 0x0b, 0x2b, \ 0xab, 0x5b, 0x04, 0x2f, 0x78, 0x15, 0x86, 0x2b, \ 0x0f, 0x63, 0xb2, 0xd7, 0xc9, 0xe9, 0xac, 0x0e, \ 0xbc, 0x17, 0xe4, 0x19, 0x88, 0xe0, 0xe6, 0x13, \ 0xf8, 0x15, 0x08, 0xa7, 0xe1, 0x6e, 0x71, 0x5c, \ 0xef, 0x3e, 0xc1, 0x0f, 0x74, 0xdb, 0xdc, 0x52, \ 0x9c, 0xfc, 0xe9, 0xa9, 0xf3, 0x0d, 0x52, 0xbc, \ 0x0c, 0xe8, 0xba, 0xd1, 0x76, 0x46, 0x87, 0xb5, \ 0x89, 0xc9, 0x8d, 0x28, 0x03, 0x30, 0xe6, 0x9d, \ 0xa1, 0x2b, 0xa5, 0x9e, 0x3b, 0x86, 0xb3, 0x5f, \ 0xe3, 0x81, 0xa6, 0x76, 0x32, 0x9d, 0xf9, 0xc5, \ 0x07, 0x93, 0xb3, 0xdf, 0x64, 0xe2, 0x78, 0x9c, \ 0x00, 0xc7, 0x86, 0x79, 0xd6, 0x67, 0xa2, 0xfb, \ 0xf2, 0x8d, 0xea, 0xe9, 0xc8, 0xfc, 0x43, 0xd2, \ 0x0f, 0x2f, 0x7d, 0x9d, 0xd3, 0x8f, 0x9c, 0xdd, \ 0xa2, 0x9f, 0x42, 0x76, 0x40, 0xcc, 0x4a, 0xd0, \ 0x89, 0xc9, 0x8d, 0x28, 0x04, 0xb4, 0x87, 0x18, \ 0x06, 0xc3, 0xc7, 0x89, 0x98, 0x72, 0xcc, 0x1a, \ 0xd1, 0xd8, 0x78, 0xb9, 0x75, 0x0b, 0x92, 0xe3, \ 0xcc, 0xed, 0x38, 0x39, 0x4b, 0xa9, 0xcf, 0x30, \ 0xd6, 0xb5, 0xa1, 0x3f, 0xfa, 0x4f, 0x29, 0x99, \ 0xa9, 0x03, 0x77, 0xf6, 0x53, 0xfa, 0xd8, 0x32, \ 0xce, 0xf4, 0xf6, 0x0a, 0x3c, 0xe8, 0x9c, 0x3d, \ 0xaa, 0xe0, 0x7b, 0x2c, 0xa5, 0x28, 0xe1, 0xdd, \ 0x89, 0xc9, 0x8d, 0x28, 0x05, 0x51, 0xbf, 0xe1, \ 0xd4, 0xf5, 0x5e, 0x38, 0x2c, 0xec, 0xab, 0xdd, \ 0xb8, 0x5c, 0x13, 0x43, 0x62, 0xc2, 0xb6, 0x02, \ 0x18, 0xce, 0x9a, 0x62, 0x67, 0x6a, 0xeb, 0x99, \ 0xf6, 0x2f, 0xf1, 0xf1, 0xec, 0x3e, 0x74, 0xfa, \ 0xf8, 0x16, 0x43, 0xea, 0x1e, 0xef, 0x5d, 0x37, \ 0x6c, 0x13, 0xf9, 0x7f, 0x65, 0x09, 0xab, 0x60, \ 0x38, 0xda, 0x0f, 0xe7, 0xfa, 0x9e, 0x17, 0x10, \ 0x89, 0xc9, 0x8d, 0x28, 0x06, 0xdc, 0x4c, 0x4d, \ 0xae, 0x5c, 0xb4, 0x0d, 0x6b, 0x05, 0x6d, 0x25, \ 0x3f, 0x78, 0x5d, 0xf3, 0x34, 0x33, 0xa4, 0x89, \ 0x34, 0x0e, 0x88, 0x66, 0x40, 0x57, 0x6b, 0x34, \ 0x83, 0xfd, 0x39, 0xe7, 0xfb, 0x84, 0x09, 0xb3, \ 0x16, 0x8f, 0x80, 0xdf, 0x1b, 0xe0, 0x02, 0x4c, \ 0xde, 0x31, 0x2a, 0x32, 0x58, 0x5b, 0xa3, 0x23, \ 0x8e, 0x2a, 0xa6, 0xaf, 0x03, 0x19, 0x02, 0x7a, \ 0x89, 0xc9, 0x8d, 0x28, 0x07, 0xf8, 0xbf, 0xa6, \ 0xad, 0xf9, 0xd1, 0xdc, 0xbd, 0x6e, 0xb3, 0xc1, \ 0xfb, 0x65, 0xd8, 0x5f, 0x2e, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +#define WIREDATA_CTAP_NFC_INIT \ + 0x55, 0x32, 0x46, 0x5f, 0x56, 0x32, 0x90, 0x00 + +#define WIREDATA_CTAP_NFC_MSG \ + 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00 + +#define WIREDATA_CTAP_EXTENDED_APDU \ + 0x00, 0xa4, 0x04, 0x00, 0x00, 0x02, 0x00, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, \ + 0x00 + #endif /* _WIREDATA_FIDO2_H */ diff --git a/contrib/libfido2/fuzz/wiredata_u2f.h b/contrib/libfido2/fuzz/wiredata_u2f.h index afe418fe9d96..3be22d34b6c2 100644 --- a/contrib/libfido2/fuzz/wiredata_u2f.h +++ b/contrib/libfido2/fuzz/wiredata_u2f.h @@ -1,152 +1,153 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #ifndef _WIREDATA_U2F_H #define _WIREDATA_U2F_H #define WIREDATA_CTAP_U2F_6985 \ 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x02, 0x69, \ 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define WIREDATA_CTAP_U2F_AUTH \ 0x00, 0x00, 0x99, 0x01, 0x83, 0x00, 0x4e, 0x01, \ 0x00, 0x00, 0x00, 0x2c, 0x30, 0x45, 0x02, 0x20, \ 0x1c, 0xf5, 0x7c, 0xf6, 0xde, 0xbe, 0xe9, 0x86, \ 0xee, 0x97, 0xb7, 0x64, 0xa3, 0x4e, 0x7a, 0x70, \ 0x85, 0xd0, 0x66, 0xf9, 0xf0, 0xcd, 0x04, 0x5d, \ 0x97, 0xf2, 0x3c, 0x22, 0xe3, 0x0e, 0x61, 0xc8, \ 0x02, 0x21, 0x00, 0x97, 0xef, 0xae, 0x36, 0xe6, \ 0x17, 0x9f, 0x5e, 0x2d, 0xd7, 0x8c, 0x34, 0xa7, \ 0x00, 0x00, 0x99, 0x01, 0x00, 0xa1, 0xe9, 0xfb, \ 0x8f, 0x86, 0x8c, 0xe3, 0x1e, 0xde, 0x3f, 0x4e, \ 0x1b, 0xe1, 0x2f, 0x8f, 0x2f, 0xca, 0x42, 0x26, \ 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #define WIREDATA_CTAP_U2F_REGISTER \ 0x00, 0x00, 0x99, 0x01, 0x83, 0x03, 0x1e, 0x05, \ 0x04, 0x9f, 0xa0, 0xf9, 0x0d, 0x4c, 0xf4, 0xae, \ 0x96, 0x3c, 0xb7, 0x46, 0xb7, 0x5c, 0x9d, 0x8b, \ 0x48, 0x19, 0xdf, 0xc4, 0xad, 0xea, 0xb2, 0x70, \ 0x58, 0x72, 0xd9, 0xce, 0x75, 0xf5, 0xe6, 0x8e, \ 0x0f, 0x9c, 0x0e, 0x2e, 0x62, 0x3e, 0x91, 0xd3, \ 0x7b, 0x97, 0x46, 0x60, 0xb9, 0x57, 0x13, 0x97, \ 0x26, 0xae, 0x0f, 0xb3, 0x8f, 0x2e, 0x9b, 0x3f, \ 0x00, 0x00, 0x99, 0x01, 0x00, 0xa5, 0x55, 0xec, \ 0x8c, 0x25, 0x7c, 0x65, 0xb7, 0x09, 0x40, 0x48, \ 0xae, 0xa8, 0xcb, 0xa1, 0x91, 0xac, 0x40, 0x24, \ 0xf2, 0x34, 0x6e, 0x3a, 0x8f, 0xa5, 0xb7, 0x48, \ 0x54, 0x6e, 0xfb, 0xf4, 0x37, 0x88, 0x69, 0x79, \ 0x6f, 0x12, 0xc1, 0x32, 0xdf, 0x15, 0x5d, 0x6e, \ 0x82, 0x54, 0xc0, 0x6e, 0x56, 0x4f, 0x3a, 0x9c, \ 0xc3, 0x96, 0x7a, 0xde, 0xa5, 0xfe, 0xec, 0xd1, \ 0x00, 0x00, 0x99, 0x01, 0x01, 0x5a, 0x21, 0x85, \ 0x0e, 0x25, 0x7b, 0x8d, 0x6e, 0x1d, 0x32, 0x29, \ 0xdb, 0x21, 0xb0, 0xa3, 0x30, 0x82, 0x02, 0x4f, \ 0x30, 0x82, 0x01, 0x37, 0xa0, 0x03, 0x02, 0x01, \ 0x02, 0x02, 0x04, 0x2a, 0xd9, 0x6a, 0xf3, 0x30, \ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, \ 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x2e, \ 0x31, 0x2c, 0x30, 0x2a, 0x06, 0x03, 0x55, 0x04, \ 0x00, 0x00, 0x99, 0x01, 0x02, 0x03, 0x13, 0x23, \ 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, \ 0x32, 0x46, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, \ 0x43, 0x41, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, \ 0x6c, 0x20, 0x34, 0x35, 0x37, 0x32, 0x30, 0x30, \ 0x36, 0x33, 0x31, 0x30, 0x20, 0x17, 0x0d, 0x31, \ 0x34, 0x30, 0x38, 0x30, 0x31, 0x30, 0x30, 0x30, \ 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x30, \ 0x00, 0x00, 0x99, 0x01, 0x03, 0x35, 0x30, 0x30, \ 0x39, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, \ 0x30, 0x5a, 0x30, 0x31, 0x31, 0x2f, 0x30, 0x2d, \ 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x26, 0x59, \ 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x55, 0x32, \ 0x46, 0x20, 0x45, 0x45, 0x20, 0x53, 0x65, 0x72, \ 0x69, 0x61, 0x6c, 0x20, 0x32, 0x33, 0x39, 0x32, \ 0x35, 0x37, 0x33, 0x34, 0x35, 0x31, 0x36, 0x35, \ 0x00, 0x00, 0x99, 0x01, 0x04, 0x35, 0x30, 0x33, \ 0x38, 0x37, 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, 0x2f, 0xe1, 0xa2, \ 0x3e, 0xbf, 0xa5, 0x5b, 0x3e, 0x46, 0x1d, 0x59, \ 0xa4, 0x35, 0x22, 0xd7, 0x97, 0x48, 0x98, 0x1c, \ 0xba, 0x6d, 0x28, 0x9a, 0x98, 0xf1, 0xbd, 0x7d, \ 0x00, 0x00, 0x99, 0x01, 0x05, 0xff, 0x65, 0x66, \ 0x80, 0xdb, 0xbb, 0xed, 0xbc, 0x2b, 0xae, 0x60, \ 0x7e, 0x6e, 0xf7, 0x72, 0xf5, 0x76, 0xb0, 0x4d, \ 0x54, 0xc4, 0xe5, 0xf3, 0x2f, 0x59, 0x6f, 0x26, \ 0xe6, 0x11, 0x15, 0xc7, 0x27, 0x2c, 0xf6, 0xca, \ 0x75, 0x94, 0xa3, 0x3b, 0x30, 0x39, 0x30, 0x22, \ 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, \ 0xc4, 0x0a, 0x02, 0x04, 0x15, 0x31, 0x2e, 0x33, \ 0x00, 0x00, 0x99, 0x01, 0x06, 0x2e, 0x36, 0x2e, \ 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e, 0x34, 0x31, \ 0x34, 0x38, 0x32, 0x2e, 0x31, 0x2e, 0x32, 0x30, \ 0x13, 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, \ 0x82, 0xe5, 0x1c, 0x02, 0x01, 0x01, 0x04, 0x04, \ 0x03, 0x02, 0x04, 0x30, 0x30, 0x0d, 0x06, 0x09, \ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, \ 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, \ 0x00, 0x00, 0x99, 0x01, 0x07, 0x85, 0x6a, 0xfa, \ 0x8b, 0xcf, 0x4f, 0x3f, 0x62, 0x5f, 0x29, 0x1b, \ 0xc1, 0x15, 0x8e, 0x3c, 0x7e, 0xbd, 0x25, 0x52, \ 0xbc, 0xf7, 0x57, 0x07, 0x53, 0xf5, 0x12, 0x1d, \ 0xa6, 0xa5, 0x4d, 0x24, 0xcc, 0xcf, 0xae, 0x27, \ 0xce, 0xd6, 0xab, 0x31, 0x12, 0x8c, 0x29, 0x7e, \ 0x5b, 0x5b, 0x89, 0x05, 0xdd, 0xa0, 0x20, 0x17, \ 0x93, 0x1f, 0x1f, 0x5f, 0x59, 0x25, 0x93, 0x59, \ 0x00, 0x00, 0x99, 0x01, 0x08, 0x51, 0xfc, 0x00, \ 0x4b, 0xcb, 0xe2, 0x0a, 0xdd, 0x7d, 0x8d, 0x05, \ 0x2f, 0x95, 0x43, 0xb3, 0x49, 0x6c, 0x15, 0xb8, \ 0x31, 0x0e, 0x10, 0xcb, 0xd9, 0xbb, 0x05, 0x38, \ 0x27, 0x4f, 0x58, 0x3e, 0xad, 0x1f, 0x45, 0x12, \ 0x88, 0xc3, 0xea, 0x76, 0xd0, 0x70, 0xad, 0x44, \ 0xe5, 0x3a, 0xfe, 0xa8, 0xf2, 0x2d, 0x1f, 0x73, \ 0x62, 0x5f, 0xf2, 0xd5, 0x89, 0xfe, 0x30, 0xdf, \ 0x00, 0x00, 0x99, 0x01, 0x09, 0x26, 0x62, 0xcb, \ 0x7c, 0xbb, 0x7c, 0x99, 0x61, 0x80, 0xad, 0xcf, \ 0xa9, 0x8a, 0x4d, 0x01, 0x2c, 0xf3, 0x13, 0x46, \ 0xcd, 0x11, 0x74, 0x6a, 0x58, 0x48, 0xe8, 0xbe, \ 0xed, 0xf3, 0xe3, 0x0c, 0xcb, 0xd9, 0xc1, 0xdd, \ 0x22, 0x16, 0x71, 0xb2, 0x83, 0x88, 0x61, 0xf6, \ 0x5a, 0x45, 0x36, 0x23, 0xb5, 0x18, 0xd5, 0x56, \ 0x7f, 0xa8, 0xf0, 0xa3, 0xce, 0x10, 0x5d, 0xf4, \ 0x00, 0x00, 0x99, 0x01, 0x0a, 0xf1, 0x39, 0x53, \ 0xe1, 0x14, 0xea, 0x59, 0xe0, 0xa7, 0xf2, 0xfe, \ 0x66, 0x88, 0x67, 0x43, 0x2e, 0x52, 0xfd, 0x6a, \ 0x2f, 0x64, 0xf7, 0x3c, 0x48, 0xcd, 0x9b, 0x38, \ 0xf2, 0xdf, 0xba, 0x2c, 0x7a, 0x4b, 0x3b, 0x11, \ 0x28, 0xdf, 0x26, 0xd6, 0x6a, 0x24, 0xf8, 0x95, \ 0xdd, 0xa0, 0xb6, 0x11, 0x80, 0xf4, 0x14, 0x4f, \ 0x6b, 0x70, 0x75, 0xc3, 0x18, 0xa4, 0x9a, 0xe0, \ 0x00, 0x00, 0x99, 0x01, 0x0b, 0x8b, 0x58, 0xd3, \ 0x6a, 0xdb, 0x1e, 0x30, 0x53, 0x67, 0x2b, 0x17, \ 0xc5, 0xa1, 0x9f, 0x7f, 0x0a, 0x22, 0xf1, 0x0e, \ 0x94, 0x30, 0x44, 0x02, 0x20, 0x07, 0x5c, 0x4f, \ 0xd2, 0x83, 0xb6, 0x9f, 0x0a, 0x4a, 0x4d, 0x4b, \ 0x08, 0x35, 0xeb, 0xc0, 0x7e, 0x4a, 0x14, 0x2e, \ 0xc7, 0x8c, 0xd6, 0x64, 0x2f, 0xd3, 0x1e, 0xcc, \ 0xb5, 0xe8, 0x42, 0xea, 0xf6, 0x02, 0x20, 0x6b, \ 0x00, 0x00, 0x99, 0x01, 0x0c, 0x5a, 0xba, 0x4a, \ 0xc8, 0xd7, 0x89, 0xcc, 0x77, 0xe6, 0xb9, 0xa3, \ 0x34, 0xea, 0x06, 0x85, 0x72, 0xc6, 0x28, 0xa8, \ 0x7a, 0xaa, 0x19, 0x88, 0x34, 0xbb, 0xdc, 0x64, \ 0x90, 0x0a, 0xdb, 0x39, 0x90, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 #endif /* !_WIREDATA_U2F_H */ diff --git a/contrib/libfido2/fuzz/wrap.c b/contrib/libfido2/fuzz/wrap.c index 8d7be6bb6247..6f40ea1d079e 100644 --- a/contrib/libfido2/fuzz/wrap.c +++ b/contrib/libfido2/fuzz/wrap.c @@ -1,637 +1,700 @@ /* - * Copyright (c) 2019-2021 Yubico AB. All rights reserved. + * Copyright (c) 2019-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include +#include #include #include #include #include #include #include #include #include #include +#include #include "mutator_aux.h" extern int prng_up; +int fuzz_save_corpus; + /* * Build wrappers around functions of interest, and have them fail - * in a pseudo-random manner. + * in a pseudo-random manner. A uniform probability of 0.25% (1/400) + * allows for a depth of log(0.5)/log(399/400) > 276 operations + * before simulated errors become statistically more likely. */ #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(ssize_t, + getrandom, + (void *buf, size_t buflen, unsigned int flags), + -1, + (buf, buflen, flags), + 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_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(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, int *ms), -1, (d, cmd, buf, count, ms), 1 ) WRAP(int, bind, (int sockfd, const struct sockaddr *addr, socklen_t addrlen), -1, (sockfd, addr, addrlen), 1 ) + +WRAP(int, + deflateInit2_, + (z_streamp strm, int level, int method, int windowBits, int memLevel, + int strategy, const char *version, int stream_size), + Z_STREAM_ERROR, + (strm, level, method, windowBits, memLevel, strategy, version, + stream_size), + 1 +) + +int __wrap_deflate(z_streamp, int); +int __real_deflate(z_streamp, int); + +int +__wrap_deflate(z_streamp strm, int flush) +{ + if (prng_up && uniform_random(400) < 1) { + return Z_BUF_ERROR; + } + /* should never happen, but we check for it */ + if (prng_up && uniform_random(400) < 1) { + strm->avail_out = UINT_MAX; + return Z_STREAM_END; + } + + return __real_deflate(strm, flush); +} + +int __wrap_asprintf(char **, const char *, ...); + +int +__wrap_asprintf(char **strp, const char *fmt, ...) +{ + va_list ap; + int r; + + if (prng_up && uniform_random(400) < 1) { + *strp = (void *)0xdeadbeef; + return -1; + } + + va_start(ap, fmt); + r = vasprintf(strp, fmt, ap); + va_end(ap); + + return r; +} diff --git a/contrib/libfido2/fuzz/wrapped.sym b/contrib/libfido2/fuzz/wrapped.sym index 0e9d34627f86..219a0d8b8f46 100644 --- a/contrib/libfido2/fuzz/wrapped.sym +++ b/contrib/libfido2/fuzz/wrapped.sym @@ -1,92 +1,102 @@ +asprintf 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 +deflate +deflateInit2_ 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_CipherInit EVP_DigestFinal_ex EVP_DigestInit_ex EVP_DigestUpdate EVP_DigestVerifyInit 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 +getrandom HMAC HMAC_CTX_new HMAC_Final HMAC_Init_ex HMAC_Update ioctl malloc realloc RSA_new RSA_pkey_ctx_ctrl RSA_set0_key +SCardConnect +SCardDisconnect +SCardEstablishContext +SCardListReaders +SCardReleaseContext +SCardTransmit SHA1 SHA256 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 5ce2fc7b83ed..a47767fb6d4b 100644 --- a/contrib/libfido2/man/CMakeLists.txt +++ b/contrib/libfido2/man/CMakeLists.txt @@ -1,391 +1,410 @@ -# Copyright (c) 2018 Yubico AB. All rights reserved. +# Copyright (c) 2018-2022 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. +# SPDX-License-Identifier: BSD-2-Clause 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 + es384_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_EVP_PKEY 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 + es384_pk_new es384_pk_free + es384_pk_new es384_pk_from_EC_KEY + es384_pk_new es384_pk_from_EVP_PKEY + es384_pk_new es384_pk_from_ptr + es384_pk_new es384_pk_to_EVP_PKEY + fido_assert_allow_cred fido_assert_empty_allow_list 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_authdata_raw 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_certs_len + fido_cbor_info_new fido_cbor_info_certs_name_ptr + fido_cbor_info_new fido_cbor_info_certs_value_ptr fido_cbor_info_new fido_cbor_info_extensions_len fido_cbor_info_new fido_cbor_info_extensions_ptr fido_cbor_info_new fido_cbor_info_free - fido_cbor_info_new fido_cbor_info_maxmsgsiz + fido_cbor_info_new fido_cbor_info_fwversion 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_maxlargeblob + fido_cbor_info_new fido_cbor_info_maxmsgsiz + fido_cbor_info_new fido_cbor_info_maxrpid_minpinlen + fido_cbor_info_new fido_cbor_info_minpinlen + fido_cbor_info_new fido_cbor_info_new_pin_required 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_rk_remaining 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_uv_attempts + fido_cbor_info_new fido_cbor_info_uv_modality 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_exclude fido_cred_empty_exclude_list 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_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_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_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_cred_verify fido_cred_verify_self 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_set 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_has_pin fido_dev_open fido_dev_has_uv 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_new_with_info fido_dev_open fido_dev_open_with_info 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_permissions fido_dev_open fido_dev_supports_pin fido_dev_open fido_dev_supports_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_io_handle fido_dev_set_io_functions fido_dev_set_sigmask fido_dev_set_io_functions fido_dev_set_timeout fido_dev_set_io_functions fido_dev_set_transport_functions 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 fido_init fido_set_log_handler 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} . + COMMAND cp -f ${PROJECT_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}) + 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}) + string(REGEX REPLACE "\\.[13]$" "" g ${f}) add_custom_command(OUTPUT ${g}.partial - COMMAND cat ${CMAKE_SOURCE_DIR}/man/dyc.css > ${g}.partial + COMMAND cat ${PROJECT_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 + install(FILES ${PROJECT_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 + string(REGEX REPLACE "\\.[13]$" "" f ${f}) + install(FILES ${PROJECT_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 + install(FILES ${PROJECT_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 + install(FILES ${PROJECT_BINARY_DIR}/man/${f}.gz DESTINATION "${CMAKE_INSTALL_MANDIR}/man1") elseif(${f} MATCHES ".3$") - install(FILES ${CMAKE_BINARY_DIR}/man/${f}.gz + install(FILES ${PROJECT_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 + install(FILES ${PROJECT_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} + install(FILES ${PROJECT_BINARY_DIR}/man/${f} DESTINATION "${CMAKE_INSTALL_MANDIR}/man1") elseif(${f} MATCHES ".3$") - install(FILES ${CMAKE_BINARY_DIR}/man/${f} + install(FILES ${PROJECT_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 + install(FILES ${PROJECT_BINARY_DIR}/man/${DST}.3 DESTINATION "${CMAKE_INSTALL_MANDIR}/man3") endforeach() endif() diff --git a/contrib/libfido2/man/check.sh b/contrib/libfido2/man/check.sh index 951afeb88e0b..d969a7afb666 100755 --- a/contrib/libfido2/man/check.sh +++ b/contrib/libfido2/man/check.sh @@ -1,42 +1,43 @@ #!/bin/sh -u # Copyright (c) 2022 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. +# SPDX-License-Identifier: BSD-2-Clause T=$(mktemp -d) || exit 1 find . -maxdepth 1 -type f -name '*.3' -print0 > "$T/files" xargs -0 awk '/^.Sh NAME/,/^.Nd/' < "$T/files" | \ awk '/^.Nm/ { print $2 }' | sort -u > "$T/Nm" xargs -0 awk '/^.Fn/ { print $2 }' < "$T/files" | sort -u > "$T/Fn" (cd "$T" && diff -u Nm Fn) cut -c2- ../src/export.llvm | sort > "$T/exports" (cd "$T" && diff -u Nm exports) awk '/^list\(APPEND MAN_SOURCES/,/^\)/' CMakeLists.txt | \ awk '/.3$/ { print $1 }' | sort > "$T/listed_sources" xargs -0 -n1 basename < "$T/files" | sort > "$T/actual_sources" (cd "$T" && diff -u listed_sources actual_sources) awk '/^list\(APPEND MAN_ALIAS/,/^\)/' CMakeLists.txt | \ sed '1d;$d' | awk '{ print $1, $2 }' | sort > "$T/listed_aliases" xargs -0 grep -o "^.Fn [A-Za-z0-9_]* \"" < "$T/files" | \ cut -c3- | sed 's/\.3:\.Fn//;s/ "//' | awk '$1 != $2' | \ sort > "$T/actual_aliases" (cd "$T" && diff -u listed_aliases actual_aliases) xargs -0 grep -hB1 "^.Fn [A-Za-z0-9_]* \"" < "$T/files" | \ sed -E 's/^.F[tn] //;s/\*[^"\*]+"/\*"/g;s/ [^" \*]+"/"/g;/^--$/d' | \ paste -d " " - - | sed 's/\* /\*/' | sort > "$T/documented_prototypes" while read -r f; do awk "/\/\*/ { next } /$f\(/,/;/" ../src/fido.h ../src/fido/*.h | \ sed -E 's/^[ ]+//;s/[ ]+/ /' | tr '\n' ' ' | \ sed 's/(/ "/;s/, /" "/g;s/);/"/;s/ $/\n/' done < "$T/exports" | sort > "$T/actual_prototypes" (cd "$T" && diff -u documented_prototypes actual_prototypes) (cd "$T" && rm files Nm Fn exports listed_sources actual_sources \ listed_aliases actual_aliases documented_prototypes actual_prototypes) rmdir -- "$T" diff --git a/contrib/libfido2/man/eddsa_pk_new.3 b/contrib/libfido2/man/eddsa_pk_new.3 index 998def484790..428d724a45ee 100644 --- a/contrib/libfido2/man/eddsa_pk_new.3 +++ b/contrib/libfido2/man/eddsa_pk_new.3 @@ -1,122 +1,146 @@ -.\" 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. +.\" Copyright (c) 2019-2022 Yubico AB. All rights reserved. .\" -.Dd $Mdocdate: May 15 2019 $ +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd $Mdocdate: July 15 2022 $ .Dt EDDSA_PK_NEW 3 .Os .Sh NAME .Nm eddsa_pk_new , .Nm eddsa_pk_free , .Nm eddsa_pk_from_EVP_PKEY , .Nm eddsa_pk_from_ptr , .Nm eddsa_pk_to_EVP_PKEY .Nd FIDO2 COSE EDDSA API .Sh SYNOPSIS .In openssl/evp.h .In fido/eddsa.h .Ft eddsa_pk_t * .Fn eddsa_pk_new "void" .Ft void .Fn eddsa_pk_free "eddsa_pk_t **pkp" .Ft int .Fn eddsa_pk_from_EVP_PKEY "eddsa_pk_t *pk" "const EVP_PKEY *pkey" .Ft int .Fn eddsa_pk_from_ptr "eddsa_pk_t *pk" "const void *ptr" "size_t len" .Ft EVP_PKEY * .Fn eddsa_pk_to_EVP_PKEY "const eddsa_pk_t *pk" .Sh DESCRIPTION EDDSA is the name given in the CBOR Object Signing and Encryption (COSE) RFC to EDDSA over Curve25519 with SHA-512. The COSE EDDSA API of .Em libfido2 is an auxiliary API with routines to convert between the different EDDSA public key types used in .Em libfido2 and .Em OpenSSL . .Pp In .Em libfido2 , EDDSA public keys are abstracted by the .Vt eddsa_pk_t type. .Pp The .Fn eddsa_pk_new function returns a pointer to a newly allocated, empty .Vt eddsa_pk_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn eddsa_pk_free function releases the memory backing .Fa *pkp , where .Fa *pkp must have been previously allocated by .Fn eddsa_pk_new . On return, .Fa *pkp is set to NULL. Either .Fa pkp or .Fa *pkp may be NULL, in which case .Fn eddsa_pk_free is a NOP. .Pp The .Fn eddsa_pk_from_EVP_PKEY function fills .Fa pk with the contents of .Fa pkey . No references to .Fa pkey are kept. .Pp The .Fn eddsa_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 eddsa_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 eddsa_pk_to_EVP_PKEY returns NULL. .Sh RETURN VALUES The .Fn eddsa_pk_from_EVP_PKEY and .Fn eddsa_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 es256_pk_new 3 , +.Xr es384_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/es256_pk_new.3 b/contrib/libfido2/man/es256_pk_new.3 index 5e184340a575..7d6be4d6223c 100644 --- a/contrib/libfido2/man/es256_pk_new.3 +++ b/contrib/libfido2/man/es256_pk_new.3 @@ -1,140 +1,164 @@ -.\" 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. +.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved. .\" -.Dd $Mdocdate: May 24 2018 $ +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd $Mdocdate: July 15 2022 $ .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_PKEY , .Nm es256_pk_from_ptr , .Nm es256_pk_to_EVP_PKEY .Nd FIDO2 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_PKEY 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_EVP_PKEY , 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 es384_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/es384_pk_new.3 b/contrib/libfido2/man/es384_pk_new.3 new file mode 100644 index 000000000000..e865913b7807 --- /dev/null +++ b/contrib/libfido2/man/es384_pk_new.3 @@ -0,0 +1,164 @@ +.\" Copyright (c) 2022 Yubico AB. 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd $Mdocdate: July 15 2022 $ +.Dt ES384_PK_NEW 3 +.Os +.Sh NAME +.Nm es384_pk_new , +.Nm es384_pk_free , +.Nm es384_pk_from_EC_KEY , +.Nm es384_pk_from_EVP_PKEY , +.Nm es384_pk_from_ptr , +.Nm es384_pk_to_EVP_PKEY +.Nd FIDO2 COSE ES384 API +.Sh SYNOPSIS +.In openssl/ec.h +.In fido/es384.h +.Ft es384_pk_t * +.Fn es384_pk_new "void" +.Ft void +.Fn es384_pk_free "es384_pk_t **pkp" +.Ft int +.Fn es384_pk_from_EC_KEY "es384_pk_t *pk" "const EC_KEY *ec" +.Ft int +.Fn es384_pk_from_EVP_PKEY "es384_pk_t *pk" "const EVP_PKEY *pkey" +.Ft int +.Fn es384_pk_from_ptr "es384_pk_t *pk" "const void *ptr" "size_t len" +.Ft EVP_PKEY * +.Fn es384_pk_to_EVP_PKEY "const es384_pk_t *pk" +.Sh DESCRIPTION +ES384 is the name given in the CBOR Object Signing and Encryption +(COSE) RFC to ECDSA over P-384 with SHA-384. +The COSE ES384 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 , +ES384 public keys are abstracted by the +.Vt es384_pk_t +type. +.Pp +The +.Fn es384_pk_new +function returns a pointer to a newly allocated, empty +.Vt es384_pk_t +type. +If memory cannot be allocated, NULL is returned. +.Pp +The +.Fn es384_pk_free +function releases the memory backing +.Fa *pkp , +where +.Fa *pkp +must have been previously allocated by +.Fn es384_pk_new . +On return, +.Fa *pkp +is set to NULL. +Either +.Fa pkp +or +.Fa *pkp +may be NULL, in which case +.Fn es384_pk_free +is a NOP. +.Pp +The +.Fn es384_pk_from_EC_KEY +function fills +.Fa pk +with the contents of +.Fa ec . +No references to +.Fa ec +are kept. +.Pp +The +.Fn es384_pk_from_EVP_PKEY +function fills +.Fa pk +with the contents of +.Fa pkey . +No references to +.Fa pkey +are kept. +.Pp +The +.Fn es384_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 es384_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 es384_pk_to_EVP_PKEY +returns NULL. +.Sh RETURN VALUES +The +.Fn es384_pk_from_EC_KEY , +.Fn es384_pk_from_EVP_PKEY , +and +.Fn es384_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 , +.Xr rs256_pk_new 3 diff --git a/contrib/libfido2/man/fido2-assert.1 b/contrib/libfido2/man/fido2-assert.1 index ee8135c18483..0ee6e0942ba2 100644 --- a/contrib/libfido2/man/fido2-assert.1 +++ b/contrib/libfido2/man/fido2-assert.1 @@ -1,256 +1,279 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .Dd $Mdocdate: November 5 2019 $ .Dt FIDO2-ASSERT 1 .Os .Sh NAME .Nm fido2-assert .Nd get/verify a FIDO2 assertion .Sh SYNOPSIS .Nm .Fl G .Op Fl bdhpruv .Op Fl t Ar option .Op Fl i Ar input_file .Op Fl o Ar output_file .Ar device .Nm .Fl V .Op Fl dhpv .Op Fl i Ar input_file .Ar key_file .Op Ar type .Sh DESCRIPTION .Nm gets or verifies a FIDO2 assertion. .Pp The input of .Nm is defined by the parameters of the assertion to be obtained/verified. See the .Sx INPUT FORMAT section for details. .Pp The output of .Nm is defined by the result of the selected operation. See the .Sx OUTPUT FORMAT section for details. .Pp If an assertion is successfully obtained or verified, .Nm exits 0. Otherwise, .Nm exits 1. .Pp The options are as follows: .Bl -tag -width Ds .It Fl G Tells .Nm to obtain a new assertion from .Ar device . .It Fl V Tells .Nm to verify an assertion using the PEM-encoded public key in .Ar key_file of type .Ar type , where .Ar type may be .Em es256 (denoting ECDSA over NIST P-256 with SHA-256), .Em rs256 (denoting 2048-bit RSA with PKCS#1.5 padding and SHA-256), or .Em eddsa (denoting EDDSA over Curve25519 with SHA-512). If .Ar type is not specified, .Em es256 is assumed. .It Fl b Request the credential's .Dq largeBlobKey , a 32-byte symmetric key associated with the asserted credential. .It Fl h If obtaining an assertion, enable the FIDO2 hmac-secret extension. If verifying an assertion, check whether the extension data bit was signed by the authenticator. .It Fl d Causes .Nm to emit debugging output on .Em stderr . .It Fl i Ar input_file Tells .Nm to read the parameters of the assertion from .Ar input_file instead of .Em stdin . .It Fl o Ar output_file Tells .Nm to write output on .Ar output_file instead of .Em stdout . .It Fl p If obtaining an assertion, request user presence. If verifying an assertion, check whether the user presence bit was signed by the authenticator. .It Fl r Obtain an assertion using a resident credential. If .Fl r is specified, .Nm will not expect a credential id in its input, and may output multiple assertions. Resident credentials are called .Dq discoverable credentials in CTAP 2.1. .It Fl t Ar option Toggles a key/value .Ar option , where .Ar option is a string of the form .Dq key=value . The options supported at present are: .Bl -tag -width Ds .It Cm up Ns = Ns Ar true|false Asks the authenticator for user presence to be enabled or disabled. .It Cm uv Ns = Ns Ar true|false Asks the authenticator for user verification to be enabled or disabled. .It Cm pin Ns = Ns Ar true|false Tells .Nm whether to prompt for a PIN and request user verification. .El .Pp The .Fl t option may be specified multiple times. .It Fl u Obtain an assertion using U2F. By default, .Nm will use FIDO2 if supported by the authenticator, and fallback to U2F otherwise. .It Fl v If obtaining an assertion, prompt the user for a PIN and request user verification from the authenticator. If verifying an assertion, check whether the user verification bit was signed by the authenticator. .El .Pp If a .Em tty is available, .Nm will use it to obtain the PIN. Otherwise, .Em stdin is used. .Sh INPUT FORMAT The input of .Nm consists of base64 blobs and UTF-8 strings separated by newline characters ('\\n'). .Pp When obtaining an assertion, .Nm expects its input to consist of: .Pp .Bl -enum -offset indent -compact .It client data hash (base64 blob); .It relying party id (UTF-8 string); .It credential id, if credential not resident (base64 blob); .It hmac salt, if the FIDO2 hmac-secret extension is enabled (base64 blob); .El .Pp When verifying an assertion, .Nm expects its input to consist of: .Pp .Bl -enum -offset indent -compact .It client data hash (base64 blob); .It relying party id (UTF-8 string); .It authenticator data (base64 blob); .It assertion signature (base64 blob); .El .Pp UTF-8 strings passed to .Nm must not contain embedded newline or NUL characters. .Sh OUTPUT FORMAT The output of .Nm consists of base64 blobs and UTF-8 strings separated by newline characters ('\\n'). .Pp For each generated assertion, .Nm outputs: .Pp .Bl -enum -offset indent -compact .It client data hash (base64 blob); .It relying party id (UTF-8 string); .It authenticator data (base64 blob); .It assertion signature (base64 blob); .It user id, if credential resident (base64 blob); .It hmac secret, if the FIDO2 hmac-secret extension is enabled (base64 blob); .It the credential's associated 32-byte symmetric key .Pq Dq largeBlobKey , if requested (base64 blob). .El .Pp When verifying an assertion, .Nm produces no output. .Sh EXAMPLES Assuming .Pa cred contains a .Em es256 credential created according to the steps outlined in .Xr fido2-cred 1 , obtain an assertion from an authenticator at .Pa /dev/hidraw5 and verify it: .Pp .Dl $ echo assertion challenge | openssl sha256 -binary | base64 > assert_param .Dl $ echo relying party >> assert_param .Dl $ head -1 cred >> assert_param .Dl $ tail -n +2 cred > pubkey .Dl $ fido2-assert -G -i assert_param /dev/hidraw5 | fido2-assert -V pubkey es256 .Sh SEE ALSO .Xr fido2-cred 1 , .Xr fido2-token 1 diff --git a/contrib/libfido2/man/fido2-cred.1 b/contrib/libfido2/man/fido2-cred.1 index 0b10e74a0507..bd82499acac4 100644 --- a/contrib/libfido2/man/fido2-cred.1 +++ b/contrib/libfido2/man/fido2-cred.1 @@ -1,267 +1,290 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .Dd $Mdocdate: November 5 2019 $ .Dt FIDO2-CRED 1 .Os .Sh NAME .Nm fido2-cred .Nd make/verify a FIDO2 credential .Sh SYNOPSIS .Nm .Fl M .Op Fl bdhqruv .Op Fl c Ar cred_protect .Op Fl i Ar input_file .Op Fl o Ar output_file .Ar device .Op Ar type .Nm .Fl V .Op Fl dhv .Op Fl c Ar cred_protect .Op Fl i Ar input_file .Op Fl o Ar output_file .Op Ar type .Sh DESCRIPTION .Nm makes or verifies a FIDO2 credential. .Pp A credential .Ar type may be .Em es256 (denoting ECDSA over NIST P-256 with SHA-256), .Em rs256 (denoting 2048-bit RSA with PKCS#1.5 padding and SHA-256), or .Em eddsa (denoting EDDSA over Curve25519 with SHA-512). If .Ar type is not specified, .Em es256 is assumed. .Pp When making a credential, the authenticator may require the user to authenticate with a PIN. If the .Fl q option is not specified, .Nm will prompt the user for the PIN. If a .Em tty is available, .Nm will use it to obtain the PIN. Otherwise, .Em stdin is used. .Pp The input of .Nm is defined by the parameters of the credential to be made/verified. See the .Sx INPUT FORMAT section for details. .Pp The output of .Nm is defined by the result of the selected operation. See the .Sx OUTPUT FORMAT section for details. .Pp If a credential is successfully created or verified, .Nm exits 0. Otherwise, .Nm exits 1. .Pp The options are as follows: .Bl -tag -width Ds .It Fl M Tells .Nm to make a new credential on .Ar device . .It Fl V Tells .Nm to verify a credential. .It Fl b Request the credential's .Dq largeBlobKey , a 32-byte symmetric key associated with the generated credential. .It Fl c Ar cred_protect If making a credential, set the credential's protection level to .Ar cred_protect , where .Ar cred_protect is the credential's protection level in decimal notation. Please refer to .In fido/param.h for the set of possible values. If verifying a credential, check whether the credential's protection level was signed by the authenticator as .Ar cred_protect . .It Fl d Causes .Nm to emit debugging output on .Em stderr . .It Fl h If making a credential, enable the FIDO2 hmac-secret extension. If verifying a credential, check whether the extension data bit was signed by the authenticator. .It Fl i Ar input_file Tells .Nm to read the parameters of the credential from .Ar input_file instead of .Em stdin . .It Fl o Ar output_file Tells .Nm to write output on .Ar output_file instead of .Em stdout . .It Fl q Tells .Nm to be quiet. If a PIN is required and .Fl q is specified, .Nm will fail. .It Fl r Create a resident credential. Resident credentials are called .Dq discoverable credentials in CTAP 2.1. .It Fl u Create a U2F credential. By default, .Nm will use FIDO2 if supported by the authenticator, and fallback to U2F otherwise. .It Fl v If making a credential, request user verification. If verifying a credential, check whether the user verification bit was signed by the authenticator. .El .Sh INPUT FORMAT The input of .Nm consists of base64 blobs and UTF-8 strings separated by newline characters ('\\n'). .Pp When making a credential, .Nm expects its input to consist of: .Pp .Bl -enum -offset indent -compact .It client data hash (base64 blob); .It relying party id (UTF-8 string); .It user name (UTF-8 string); .It user id (base64 blob). .El .Pp When verifying a credential, .Nm expects its input to consist of: .Pp .Bl -enum -offset indent -compact .It client data hash (base64 blob); .It relying party id (UTF-8 string); .It credential format (UTF-8 string); .It authenticator data (base64 blob); .It credential id (base64 blob); .It attestation signature (base64 blob); .It attestation certificate (optional, base64 blob). .El .Pp UTF-8 strings passed to .Nm must not contain embedded newline or NUL characters. .Sh OUTPUT FORMAT The output of .Nm consists of base64 blobs, UTF-8 strings, and PEM-encoded public keys separated by newline characters ('\\n'). .Pp Upon the successful generation of a credential, .Nm outputs: .Pp .Bl -enum -offset indent -compact .It client data hash (base64 blob); .It relying party id (UTF-8 string); .It credential format (UTF-8 string); .It authenticator data (base64 blob); .It credential id (base64 blob); .It attestation signature (base64 blob); .It attestation certificate, if present (base64 blob). .It the credential's associated 32-byte symmetric key .Pq Dq largeBlobKey , if present (base64 blob). .El .Pp Upon the successful verification of a credential, .Nm outputs: .Pp .Bl -enum -offset indent -compact .It credential id (base64 blob); .It PEM-encoded credential key. .El .Sh EXAMPLES Create a new .Em es256 credential on .Pa /dev/hidraw5 , verify it, and save the id and the public key of the credential in .Em cred : .Pp .Dl $ echo credential challenge | openssl sha256 -binary | base64 > cred_param .Dl $ echo relying party >> cred_param .Dl $ echo user name >> cred_param .Dl $ dd if=/dev/urandom bs=1 count=32 | base64 >> cred_param .Dl $ fido2-cred -M -i cred_param /dev/hidraw5 | fido2-cred -V -o cred .Sh SEE ALSO .Xr fido2-assert 1 , .Xr fido2-token 1 .Sh CAVEATS Please note that .Nm handles Basic Attestation and Self Attestation transparently. In the case of Basic Attestation, the validity of the authenticator's attestation certificate is .Em not verified. diff --git a/contrib/libfido2/man/fido2-token.1 b/contrib/libfido2/man/fido2-token.1 index 1aa2feb86859..65a228cb1a31 100644 --- a/contrib/libfido2/man/fido2-token.1 +++ b/contrib/libfido2/man/fido2-token.1 @@ -1,400 +1,421 @@ -.\" 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. +.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved. .\" -.Dd $Mdocdate: September 13 2019 $ +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd $Mdocdate: April 11 2022 $ .Dt FIDO2-TOKEN 1 .Os .Sh NAME .Nm fido2-token .Nd find and manage a FIDO2 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 FIDO2 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. +holds the blob's base64-encoded 32-byte AES-256 GCM 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 CTAP 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 CTAP 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. +holds the blob's base64-encoded 32-byte AES-256 GCM 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 CTAP 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 CTAP 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 CTAP 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 CTAP 2.1 +Sets a CTAP 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. +holds the blob's base64-encoded 32-byte AES-256 GCM encryption key. +The blob is read from +.Fa blob_path . 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 CTAP 2.1 +Sets a CTAP 2.1 .Dq largeBlob associated with .Ar rp_id on .Ar device . +The blob is read from +.Fa blob_path . 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 CTAP 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 CTAP 2.1. .Pp Whether the CTAP 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_assert_allow_cred.3 b/contrib/libfido2/man/fido_assert_allow_cred.3 index 7fd730c3f63c..652013734295 100644 --- a/contrib/libfido2/man/fido_assert_allow_cred.3 +++ b/contrib/libfido2/man/fido_assert_allow_cred.3 @@ -1,47 +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. +.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved. .\" -.Dd $Mdocdate: May 23 2018 $ +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd $Mdocdate: December 1 2022 $ .Dt FIDO_ASSERT_ALLOW_CRED 3 .Os .Sh NAME -.Nm fido_assert_allow_cred -.Nd allow a credential in a FIDO2 assertion +.Nm fido_assert_allow_cred , +.Nm fido_assert_empty_allow_list +.Nd manage allow lists in a FIDO2 assertion .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_assert_allow_cred "fido_assert_t *assert" "const unsigned char *ptr" "size_t len" +.Ft int +.Fn fido_assert_empty_allow_list "fido_assert_t *assert" .Sh DESCRIPTION The .Fn fido_assert_allow_cred function adds .Fa ptr to the list of credentials allowed in .Fa assert , where .Fa ptr points to a credential ID of .Fa len bytes. A copy of .Fa ptr is made, and no references to the passed pointer are kept. If .Fn fido_assert_allow_cred fails, the existing list of allowed credentials is preserved. .Pp For the format of a FIDO2 credential ID, please refer to the Web Authentication (webauthn) standard. +.Pp +The +.Fn fido_assert_empty_allow_list +function empties the list of credentials allowed in +.Fa assert . .Sh RETURN VALUES The error codes returned by .Fn fido_assert_allow_cred +and +.Fn fido_assert_empty_allow_list are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. .Sh SEE ALSO .Xr fido_assert_new 3 , .Xr fido_assert_set_authdata 3 , .Xr fido_dev_get_assert 3 diff --git a/contrib/libfido2/man/fido_assert_new.3 b/contrib/libfido2/man/fido_assert_new.3 index a1a3c101ba33..192625e32630 100644 --- a/contrib/libfido2/man/fido_assert_new.3 +++ b/contrib/libfido2/man/fido_assert_new.3 @@ -1,256 +1,285 @@ -.\" 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. +.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved. .\" -.Dd $Mdocdate: October 22 2019 $ +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd $Mdocdate: April 27 2022 $ .Dt FIDO_ASSERT_NEW 3 .Os .Sh NAME .Nm fido_assert_new , .Nm fido_assert_free , .Nm fido_assert_count , .Nm fido_assert_rp_id , .Nm fido_assert_user_display_name , .Nm fido_assert_user_icon , .Nm fido_assert_user_name , .Nm fido_assert_authdata_ptr , .Nm fido_assert_blob_ptr , .Nm fido_assert_clientdata_hash_ptr , .Nm fido_assert_hmac_secret_ptr , .Nm fido_assert_largeblob_key_ptr , .Nm fido_assert_user_id_ptr , .Nm fido_assert_sig_ptr , .Nm fido_assert_id_ptr , .Nm fido_assert_authdata_len , .Nm fido_assert_blob_len , .Nm fido_assert_clientdata_hash_len , .Nm fido_assert_hmac_secret_len , .Nm fido_assert_largeblob_key_len , .Nm fido_assert_user_id_len , .Nm fido_assert_sig_len , .Nm fido_assert_id_len , .Nm fido_assert_sigcount , .Nm fido_assert_flags .Nd FIDO2 assertion API .Sh SYNOPSIS .In fido.h .Ft fido_assert_t * .Fn fido_assert_new "void" .Ft void .Fn fido_assert_free "fido_assert_t **assert_p" .Ft size_t .Fn fido_assert_count "const fido_assert_t *assert" .Ft const char * .Fn fido_assert_rp_id "const fido_assert_t *assert" .Ft const char * .Fn fido_assert_user_display_name "const fido_assert_t *assert" "size_t idx" .Ft const char * .Fn fido_assert_user_icon "const fido_assert_t *assert" "size_t idx" .Ft const char * .Fn fido_assert_user_name "const fido_assert_t *assert" "size_t idx" .Ft const unsigned char * .Fn fido_assert_authdata_ptr "const fido_assert_t *assert" "size_t idx" .Ft const unsigned char * .Fn fido_assert_clientdata_hash_ptr "const fido_assert_t *assert" .Ft const unsigned char * .Fn fido_assert_blob_ptr "const fido_assert_t *assert" "size_t idx" .Ft const unsigned char * .Fn fido_assert_hmac_secret_ptr "const fido_assert_t *assert" "size_t idx" .Ft const unsigned char * .Fn fido_assert_largeblob_key_ptr "const fido_assert_t *assert" "size_t idx" .Ft const unsigned char * .Fn fido_assert_user_id_ptr "const fido_assert_t *assert" "size_t idx" .Ft const unsigned char * .Fn fido_assert_sig_ptr "const fido_assert_t *assert" "size_t idx" .Ft const unsigned char * .Fn fido_assert_id_ptr "const fido_assert_t *assert" "size_t idx" .Ft size_t .Fn fido_assert_authdata_len "const fido_assert_t *assert" "size_t idx" .Ft size_t .Fn fido_assert_clientdata_hash_len "const fido_assert_t *assert" .Ft size_t .Fn fido_assert_blob_len "const fido_assert_t *assert" "size_t idx" .Ft size_t .Fn fido_assert_hmac_secret_len "const fido_assert_t *assert" "size_t idx" .Ft size_t .Fn fido_assert_largeblob_key_len "const fido_assert_t *assert" "size_t idx" .Ft size_t .Fn fido_assert_user_id_len "const fido_assert_t *assert" "size_t idx" .Ft size_t .Fn fido_assert_sig_len "const fido_assert_t *assert" "size_t idx" .Ft size_t .Fn fido_assert_id_len "const fido_assert_t *assert" "size_t idx" .Ft uint32_t .Fn fido_assert_sigcount "const fido_assert_t *assert" "size_t idx" .Ft uint8_t .Fn fido_assert_flags "const fido_assert_t *assert" "size_t idx" .Sh DESCRIPTION A FIDO2 assertion is a collection of statements, each statement a map between a challenge, a credential, a signature, and ancillary attributes. In .Em libfido2 , a FIDO2 assertion is abstracted by the .Vt fido_assert_t type. The functions described in this page allow a .Vt fido_assert_t type to be allocated, deallocated, and inspected. For other operations on .Vt fido_assert_t , please refer to .Xr fido_assert_set_authdata 3 , .Xr fido_assert_allow_cred 3 , .Xr fido_assert_verify 3 , and .Xr fido_dev_get_assert 3 . .Pp The .Fn fido_assert_new function returns a pointer to a newly allocated, empty .Vt fido_assert_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_assert_free function releases the memory backing .Fa *assert_p , where .Fa *assert_p must have been previously allocated by .Fn fido_assert_new . On return, .Fa *assert_p is set to NULL. Either .Fa assert_p or .Fa *assert_p may be NULL, in which case .Fn fido_assert_free is a NOP. .Pp The .Fn fido_assert_count function returns the number of statements in .Fa assert . .Pp The .Fn fido_assert_rp_id function returns a pointer to a NUL-terminated string holding the relying party ID of .Fa assert . .Pp The .Fn fido_assert_user_display_name , .Fn fido_assert_user_icon , and .Fn fido_assert_user_name , functions return pointers to the user display name, icon, and name attributes of statement .Fa idx in .Fa assert . If not NULL, the values returned by these functions point to NUL-terminated UTF-8 strings. +The user display name, icon, and name attributes will typically +only be returned by the authenticator if user verification was +performed by the authenticator and multiple resident/discoverable +credentials were involved in the assertion. .Pp The .Fn fido_assert_authdata_ptr , .Fn fido_assert_clientdata_hash_ptr , .Fn fido_assert_id_ptr , .Fn fido_assert_user_id_ptr , .Fn fido_assert_sig_ptr , .Fn fido_assert_sigcount , and .Fn fido_assert_flags functions return pointers to the CBOR-encoded authenticator data, client data hash, credential ID, user ID, signature, signature count, and authenticator data flags of statement .Fa idx in .Fa assert . .Pp The .Fn fido_assert_hmac_secret_ptr function returns a pointer to the hmac-secret attribute of statement .Fa idx in .Fa assert . The HMAC Secret Extension .Pq hmac-secret is a CTAP 2.0 extension. +Note that the resulting hmac-secret varies according to whether +user verification was performed by the authenticator. .Pp The .Fn fido_assert_blob_ptr and .Fn fido_assert_largeblob_key_ptr functions return pointers to the .Dq credBlob and .Dq largeBlobKey attributes of statement .Fa idx in .Fa assert . Credential Blob .Pq credBlob and Large Blob Key .Pq largeBlobKey are CTAP 2.1 extensions. .Pp The .Fn fido_assert_authdata_len , .Fn fido_assert_clientdata_hash_len , .Fn fido_assert_id_len , .Fn fido_assert_user_id_len , .Fn fido_assert_sig_len , .Fn fido_assert_hmac_secret_len , .Fn fido_assert_blob_len , and .Fn fido_assert_largeblob_key_len functions return the length of a given attribute. .Pp Please note that the first statement in .Fa assert has an .Fa idx (index) value of 0. .Pp The authenticator data and signature parts of an assertion statement are typically passed to a FIDO2 server for verification. .Sh RETURN VALUES The authenticator data returned by .Fn fido_assert_authdata_ptr is a CBOR-encoded byte string, as obtained from the authenticator. .Pp The .Fn fido_assert_rp_id , .Fn fido_assert_user_display_name , .Fn fido_assert_user_icon , .Fn fido_assert_user_name , .Fn fido_assert_authdata_ptr , .Fn fido_assert_clientdata_hash_ptr , .Fn fido_assert_id_ptr , .Fn fido_assert_user_id_ptr , .Fn fido_assert_sig_ptr , .Fn fido_assert_hmac_secret_ptr , .Fn fido_assert_blob_ptr , and .Fn fido_assert_largeblob_key_ptr functions may return NULL if the respective field in .Fa assert is not set. If not NULL, returned pointers are guaranteed to exist until any API function that takes .Fa assert without the .Em const qualifier is invoked. .Sh SEE ALSO .Xr fido_assert_allow_cred 3 , .Xr fido_assert_set_authdata 3 , .Xr fido_assert_verify 3 , .Xr fido_dev_get_assert 3 , .Xr fido_dev_largeblob_get 3 diff --git a/contrib/libfido2/man/fido_assert_set_authdata.3 b/contrib/libfido2/man/fido_assert_set_authdata.3 index 51cdcc97c292..f3a307fd05b8 100644 --- a/contrib/libfido2/man/fido_assert_set_authdata.3 +++ b/contrib/libfido2/man/fido_assert_set_authdata.3 @@ -1,236 +1,261 @@ -.\" 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. +.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved. .\" -.Dd $Mdocdate: May 23 2018 $ +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd $Mdocdate: April 27 2022 $ .Dt FIDO_ASSERT_SET_AUTHDATA 3 .Os .Sh NAME .Nm fido_assert_set_authdata , .Nm fido_assert_set_authdata_raw , .Nm fido_assert_set_clientdata , .Nm fido_assert_set_clientdata_hash , .Nm fido_assert_set_count , .Nm fido_assert_set_extensions , .Nm fido_assert_set_hmac_salt , .Nm fido_assert_set_hmac_secret , .Nm fido_assert_set_up , .Nm fido_assert_set_uv , .Nm fido_assert_set_rp , .Nm fido_assert_set_sig .Nd set parameters of a FIDO2 assertion .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_assert_set_authdata "fido_assert_t *assert" "size_t idx" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_assert_set_authdata_raw "fido_assert_t *assert" "size_t idx" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_assert_set_clientdata "fido_assert_t *assert" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_assert_set_clientdata_hash "fido_assert_t *assert" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_assert_set_count "fido_assert_t *assert" "size_t n" .Ft int .Fn fido_assert_set_extensions "fido_assert_t *assert" "int flags" .Ft int .Fn fido_assert_set_hmac_salt "fido_assert_t *assert" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_assert_set_hmac_secret "fido_assert_t *assert" "size_t idx" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_assert_set_up "fido_assert_t *assert" "fido_opt_t up" .Ft int .Fn fido_assert_set_uv "fido_assert_t *assert" "fido_opt_t uv" .Ft int .Fn fido_assert_set_rp "fido_assert_t *assert" "const char *id" .Ft int .Fn fido_assert_set_sig "fido_assert_t *assert" "size_t idx" "const unsigned char *ptr" "size_t len" .Sh DESCRIPTION The .Nm set of functions define the various parameters of a FIDO2 assertion, allowing a .Fa fido_assert_t type to be prepared for a subsequent call to .Xr fido_dev_get_assert 3 or .Xr fido_assert_verify 3 . For the complete specification of a FIDO2 assertion and the format of its constituent parts, please refer to the Web Authentication (webauthn) standard. .Pp The .Fn fido_assert_set_count function sets the number of assertion statements in .Fa assert to .Fa n . .Pp The .Fn fido_assert_set_authdata and .Fn fido_assert_set_sig functions set the authenticator data and signature parts of the statement with index .Fa idx of .Fa assert 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. Please note that the first assertion statement of .Fa assert has an .Fa idx of .Em 0 . The authenticator data passed to .Fn fido_assert_set_authdata must be a CBOR-encoded byte string, as obtained from .Fn fido_assert_authdata_ptr . Alternatively, a raw binary blob may be passed to .Fn fido_assert_set_authdata_raw . .Pp The .Fn fido_assert_set_clientdata_hash function sets the client data hash of .Fa assert 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 .Fn fido_assert_set_clientdata function allows an application to set the client data hash of .Fa assert by specifying the assertion'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_assert_set_clientdata instead of .Fn fido_assert_set_clientdata_hash . .Pp The .Fn fido_assert_set_rp function sets the relying party .Fa id of .Fa assert , where .Fa id is a NUL-terminated UTF-8 string. The content of .Fa id is copied, and no references to the passed pointer are kept. .Pp The .Fn fido_assert_set_extensions function sets the extensions of .Fa assert to the bitmask .Fa flags . At the moment, only the .Dv FIDO_EXT_CRED_BLOB , .Dv FIDO_EXT_HMAC_SECRET , and .Dv FIDO_EXT_LARGEBLOB_KEY extensions are supported. If .Fa flags is zero, the extensions of .Fa assert are cleared. .Pp The .Fn fido_assert_set_hmac_salt and .Fn fido_assert_set_hmac_secret functions set the hmac-salt and hmac-secret parts of .Fa assert 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. The HMAC Secret .Pq hmac-secret Extension is a CTAP 2.0 extension. +Note that the resulting hmac-secret varies according to whether +user verification was performed by the authenticator. The .Fn fido_assert_set_hmac_secret function is normally only useful when writing tests. .Pp The .Fn fido_assert_set_up and .Fn fido_assert_set_uv functions set the .Fa up (user presence) and .Fa uv (user verification) attributes of .Fa assert . Both are .Dv FIDO_OPT_OMIT by default, allowing the authenticator to use its default settings. .Pp Use of the .Nm set of functions may happen in two distinct situations: when asking a FIDO2 device to produce a series of assertion statements, prior to .Xr fido_dev_get_assert 3 (i.e, in the context of a FIDO2 client), or when verifying assertion statements using .Xr fido_assert_verify 3 (i.e, in the context of a FIDO2 server). .Pp For a complete description of the generation of a FIDO2 assertion and its verification, please refer to the FIDO2 specification. An example of how to use the .Nm set of functions can be found in the .Pa examples/assert.c file shipped with .Em libfido2 . .Sh RETURN VALUES The .Nm functions return .Dv FIDO_OK on success. The error codes returned by the .Nm set of functions are defined in .In fido/err.h . .Sh SEE ALSO .Xr fido_assert_allow_cred 3 , .Xr fido_assert_verify 3 , .Xr fido_dev_get_assert 3 diff --git a/contrib/libfido2/man/fido_assert_verify.3 b/contrib/libfido2/man/fido_assert_verify.3 index 8c0823703434..1b79448b6c32 100644 --- a/contrib/libfido2/man/fido_assert_verify.3 +++ b/contrib/libfido2/man/fido_assert_verify.3 @@ -1,79 +1,104 @@ -.\" 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. +.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved. .\" -.Dd $Mdocdate: May 24 2018 $ +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd $Mdocdate: July 15 2022 $ .Dt FIDO_ASSERT_VERIFY 3 .Os .Sh NAME .Nm fido_assert_verify .Nd verifies the signature of a FIDO2 assertion statement .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_assert_verify "const fido_assert_t *assert" "size_t idx" "int cose_alg" "const void *pk" .Sh DESCRIPTION The .Fn fido_assert_verify function verifies whether the signature contained in statement index .Fa idx of .Fa assert matches the parameters of the assertion. Before using .Fn fido_assert_verify in a sensitive context, the reader is strongly encouraged to make herself familiar with the FIDO2 assertion statement process as defined in the Web Authentication (webauthn) standard. .Pp A brief description follows: .Pp The .Fn fido_assert_verify function verifies whether the client data hash, relying party ID, user presence and user verification attributes of .Fa assert have been attested by the holder of the private counterpart of the public key .Fa pk of COSE type .Fa cose_alg , where .Fa cose_alg is .Dv COSE_ES256 , +.Dv COSE_ES384 , .Dv COSE_RS256 , or .Dv COSE_EDDSA , and .Fa pk points to a .Vt es256_pk_t , +.Vt es384_pk_t , .Vt rs256_pk_t , or .Vt eddsa_pk_t type accordingly. .Pp Please note that the first statement in .Fa assert has an .Fa idx of 0. .Sh RETURN VALUES The error codes returned by .Fn fido_assert_verify are defined in .In fido/err.h . If statement .Fa idx of .Fa assert passes verification with .Fa pk , then .Dv FIDO_OK is returned. .Sh SEE ALSO .Xr fido_assert_new 3 , .Xr fido_assert_set_authdata 3 diff --git a/contrib/libfido2/man/fido_bio_dev_get_info.3 b/contrib/libfido2/man/fido_bio_dev_get_info.3 index 7f1696fc12a4..b8fc1043c231 100644 --- a/contrib/libfido2/man/fido_bio_dev_get_info.3 +++ b/contrib/libfido2/man/fido_bio_dev_get_info.3 @@ -1,122 +1,145 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .Dd $Mdocdate: September 13 2019 $ .Dt FIDO_BIO_DEV_GET_INFO 3 .Os .Sh NAME .Nm fido_bio_dev_get_info , .Nm fido_bio_dev_enroll_begin , .Nm fido_bio_dev_enroll_continue , .Nm fido_bio_dev_enroll_cancel , .Nm fido_bio_dev_enroll_remove , .Nm fido_bio_dev_get_template_array , .Nm fido_bio_dev_set_template_name .Nd FIDO2 biometric authenticator API .Sh SYNOPSIS .In fido.h .In fido/bio.h .Ft int .Fn fido_bio_dev_get_info "fido_dev_t *dev" "fido_bio_info_t *info" .Ft int .Fn fido_bio_dev_enroll_begin "fido_dev_t *dev" "fido_bio_template_t *template" "fido_bio_enroll_t *enroll" "uint32_t timeout_ms" "const char *pin" .Ft int .Fn fido_bio_dev_enroll_continue "fido_dev_t *dev" "const fido_bio_template_t *template" "fido_bio_enroll_t *enroll" "uint32_t timeout_ms" .Ft int .Fn fido_bio_dev_enroll_cancel "fido_dev_t *dev" .Ft int .Fn fido_bio_dev_enroll_remove "fido_dev_t *dev" "const fido_bio_template_t *template" "const char *pin" .Ft int .Fn fido_bio_dev_get_template_array "fido_dev_t *dev" "fido_bio_template_array_t *template_array" "const char *pin" .Ft int .Fn fido_bio_dev_set_template_name "fido_dev_t *dev" "const fido_bio_template_t *template" "const char *pin" .Sh DESCRIPTION The functions described in this page allow biometric templates on a FIDO2 authenticator to be listed, created, removed, and customised. Please note that not all FIDO2 authenticators support biometric enrollment. For a description of the types involved, please refer to .Xr fido_bio_info_new 3 , .Xr fido_bio_enroll_new 3 , and .Xr fido_bio_template 3 . .Pp The .Fn fido_bio_dev_get_info function populates .Fa info with sensor information from .Fa dev . .Pp The .Fn fido_bio_dev_enroll_begin function initiates a biometric enrollment on .Fa dev , instructing the authenticator to wait .Fa timeout_ms milliseconds. On success, .Fa template and .Fa enroll will be populated with the newly created template's information and enrollment status, respectively. .Pp The .Fn fido_bio_dev_enroll_continue function continues an ongoing enrollment on .Fa dev , instructing the authenticator to wait .Fa timeout_ms milliseconds. On success, .Fa enroll will be updated to reflect the status of the biometric enrollment. .Pp The .Fn fido_bio_dev_enroll_cancel function cancels an ongoing enrollment on .Fa dev . .Pp The .Fn fido_bio_dev_enroll_remove function removes .Fa template from .Fa dev . .Pp The .Fn fido_bio_dev_get_template_array function populates .Fa template_array with the templates currently enrolled on .Fa dev . .Pp The .Fn fido_bio_dev_set_template_name function sets the friendly name of .Fa template on .Fa dev . .Sh RETURN VALUES The error codes returned by .Fn fido_bio_dev_get_info , .Fn fido_bio_dev_enroll_begin , .Fn fido_bio_dev_enroll_continue , .Fn fido_bio_dev_enroll_cancel , .Fn fido_bio_dev_enroll_remove , .Fn fido_bio_dev_get_template_array , and .Fn fido_bio_dev_set_template_name are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. .Sh SEE ALSO .Xr fido_bio_enroll_new 3 , .Xr fido_bio_info_new 3 , .Xr fido_bio_template 3 diff --git a/contrib/libfido2/man/fido_bio_enroll_new.3 b/contrib/libfido2/man/fido_bio_enroll_new.3 index 37b842e644fd..536ba9af9f91 100644 --- a/contrib/libfido2/man/fido_bio_enroll_new.3 +++ b/contrib/libfido2/man/fido_bio_enroll_new.3 @@ -1,95 +1,118 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .Dd $Mdocdate: September 13 2019 $ .Dt FIDO_BIO_ENROLL_NEW 3 .Os .Sh NAME .Nm fido_bio_enroll_new , .Nm fido_bio_enroll_free , .Nm fido_bio_enroll_last_status , .Nm fido_bio_enroll_remaining_samples .Nd FIDO2 biometric enrollment API .Sh SYNOPSIS .In fido.h .In fido/bio.h .Bd -literal #define FIDO_BIO_ENROLL_FP_GOOD 0x00 #define FIDO_BIO_ENROLL_FP_TOO_HIGH 0x01 #define FIDO_BIO_ENROLL_FP_TOO_LOW 0x02 #define FIDO_BIO_ENROLL_FP_TOO_LEFT 0x03 #define FIDO_BIO_ENROLL_FP_TOO_RIGHT 0x04 #define FIDO_BIO_ENROLL_FP_TOO_FAST 0x05 #define FIDO_BIO_ENROLL_FP_TOO_SLOW 0x06 #define FIDO_BIO_ENROLL_FP_POOR_QUALITY 0x07 #define FIDO_BIO_ENROLL_FP_TOO_SKEWED 0x08 #define FIDO_BIO_ENROLL_FP_TOO_SHORT 0x09 #define FIDO_BIO_ENROLL_FP_MERGE_FAILURE 0x0a #define FIDO_BIO_ENROLL_FP_EXISTS 0x0b #define FIDO_BIO_ENROLL_FP_DATABASE_FULL 0x0c #define FIDO_BIO_ENROLL_NO_USER_ACTIVITY 0x0d #define FIDO_BIO_ENROLL_NO_USER_PRESENCE_TRANSITION 0x0e .Ed .Ft fido_bio_enroll_t * .Fn fido_bio_enroll_new "void" .Ft void .Fn fido_bio_enroll_free "fido_bio_enroll_t **enroll_p" .Ft uint8_t .Fn fido_bio_enroll_last_status "const fido_bio_enroll_t *enroll" .Ft uint8_t .Fn fido_bio_enroll_remaining_samples "const fido_bio_enroll_t *enroll" .Sh DESCRIPTION Ongoing FIDO2 biometric enrollments are abstracted in .Em libfido2 by the .Vt fido_bio_enroll_t type. .Pp The functions described in this page allow a .Vt fido_bio_enroll_t type to be allocated, deallocated, and inspected. For device operations on .Vt fido_bio_enroll_t , please refer to .Xr fido_bio_dev_get_info 3 . .Pp The .Fn fido_bio_enroll_new function returns a pointer to a newly allocated, empty .Vt fido_bio_enroll_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_bio_enroll_free function releases the memory backing .Fa *enroll_p , where .Fa *enroll_p must have been previously allocated by .Fn fido_bio_enroll_new . On return, .Fa *enroll_p is set to NULL. Either .Fa enroll_p or .Fa *enroll_p may be NULL, in which case .Fn fido_bio_enroll_free is a NOP. .Pp The .Fn fido_bio_enroll_last_status function returns the enrollment status of .Fa enroll . .Pp The .Fn fido_bio_enroll_remaining_samples function returns the number of samples left for .Fa enroll to complete. .Sh SEE ALSO .Xr fido_bio_dev_get_info 3 , .Xr fido_bio_template 3 diff --git a/contrib/libfido2/man/fido_bio_info_new.3 b/contrib/libfido2/man/fido_bio_info_new.3 index a7435fd615e7..41343068b162 100644 --- a/contrib/libfido2/man/fido_bio_info_new.3 +++ b/contrib/libfido2/man/fido_bio_info_new.3 @@ -1,81 +1,104 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .Dd $Mdocdate: September 13 2019 $ .Dt FIDO_BIO_INFO_NEW 3 .Os .Sh NAME .Nm fido_bio_info_new , .Nm fido_bio_info_free , .Nm fido_bio_info_type , .Nm fido_bio_info_max_samples .Nd FIDO2 biometric sensor information API .Sh SYNOPSIS .In fido.h .In fido/bio.h .Ft fido_bio_info_t * .Fn fido_bio_info_new "void" .Ft void .Fn fido_bio_info_free "fido_bio_info_t **info_p" .Ft uint8_t .Fn fido_bio_info_type "const fido_bio_info_t *info" .Ft uint8_t .Fn fido_bio_info_max_samples "const fido_bio_info_t *info" .Sh DESCRIPTION Biometric sensor metadata is abstracted in .Em libfido2 by the .Vt fido_bio_info_t type. .Pp The functions described in this page allow a .Vt fido_bio_info_t type to be allocated, deallocated, and inspected. For device operations on .Vt fido_bio_info_t , please refer to .Xr fido_bio_dev_get_info 3 . .Pp The .Fn fido_bio_info_new function returns a pointer to a newly allocated, empty .Vt fido_bio_info_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_bio_info_free function releases the memory backing .Fa *info_p , where .Fa *info_p must have been previously allocated by .Fn fido_bio_info_new . On return, .Fa *info_p is set to NULL. Either .Fa info_p or .Fa *info_p may be NULL, in which case .Fn fido_bio_info_free is a NOP. .Pp The .Fn fido_bio_info_type function returns the fingerprint sensor type, which is .Dv 1 for touch sensors, and .Dv 2 for swipe sensors. .Pp The .Fn fido_bio_info_max_samples function returns the maximum number of successful samples required for enrollment. .Sh SEE ALSO .Xr fido_bio_dev_get_info 3 , .Xr fido_bio_enroll_new 3 , .Xr fido_bio_template 3 diff --git a/contrib/libfido2/man/fido_bio_template.3 b/contrib/libfido2/man/fido_bio_template.3 index 232f3ead2ab3..a8ff8bc38dc6 100644 --- a/contrib/libfido2/man/fido_bio_template.3 +++ b/contrib/libfido2/man/fido_bio_template.3 @@ -1,179 +1,202 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .Dd $Mdocdate: September 13 2019 $ .Dt FIDO_BIO_TEMPLATE 3 .Os .Sh NAME .Nm fido_bio_template , .Nm fido_bio_template_array_count , .Nm fido_bio_template_array_free , .Nm fido_bio_template_array_new , .Nm fido_bio_template_free , .Nm fido_bio_template_id_len , .Nm fido_bio_template_id_ptr , .Nm fido_bio_template_name , .Nm fido_bio_template_new , .Nm fido_bio_template_set_id , .Nm fido_bio_template_set_name .Nd FIDO2 biometric template API .Sh SYNOPSIS .In fido.h .In fido/bio.h .Ft fido_bio_template_t * .Fn fido_bio_template_new "void" .Ft void .Fn fido_bio_template_free "fido_bio_template_t **template_p" .Ft const char * .Fn fido_bio_template_name "const fido_bio_template_t *template" .Ft const unsigned char * .Fn fido_bio_template_id_ptr "const fido_bio_template_t *template" .Ft size_t .Fn fido_bio_template_id_len "const fido_bio_template_t *template" .Ft int .Fn fido_bio_template_set_id "fido_bio_template_t *template" "const unsigned char *ptr" "size_t len" .Ft int .Fn fido_bio_template_set_name "fido_bio_template_t *template" "const char *name" .Ft fido_bio_template_array_t * .Fn fido_bio_template_array_new "void" .Ft void .Fn fido_bio_template_array_free "fido_bio_template_array_t **array_p" .Ft size_t .Fn fido_bio_template_array_count "const fido_bio_template_array_t *array" .Ft const fido_bio_template_t * .Fn fido_bio_template "const fido_bio_template_array_t *array" "size_t idx" .Sh DESCRIPTION Existing FIDO2 biometric enrollments are abstracted in .Em libfido2 by the .Vt fido_bio_template_t and .Vt fido_bio_template_array_t types. .Pp The functions described in this page allow a .Vt fido_bio_template_t type to be allocated, deallocated, changed, and inspected, and a .Vt fido_bio_template_array_t type to be allocated, deallocated, and inspected. For device operations on .Vt fido_bio_template_t and .Vt fido_bio_template_array_t , please refer to .Xr fido_bio_dev_get_info 3 . .Pp The .Fn fido_bio_template_new function returns a pointer to a newly allocated, empty .Vt fido_bio_template_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_bio_template_free function releases the memory backing .Fa *template_p , where .Fa *template_p must have been previously allocated by .Fn fido_bio_template_new . On return, .Fa *template_p is set to NULL. Either .Fa template_p or .Fa *template_p may be NULL, in which case .Fn fido_bio_template_free is a NOP. .Pp The .Fn fido_bio_template_name function returns a pointer to a NUL-terminated string containing the friendly name of .Fa template , or NULL if .Fa template does not have a friendly name set. .Pp The .Fn fido_bio_template_id_ptr function returns a pointer to the template id of .Fa template , or NULL if .Fa template does not have an id. The corresponding length can be obtained by .Fn fido_bio_template_id_len . .Pp The .Fn fido_bio_template_set_name function sets the friendly name of .Fa template to .Fa name . If .Fa name is NULL, the friendly name of .Fa template is unset. .Pp The .Fn fido_bio_template_array_new function returns a pointer to a newly allocated, empty .Vt fido_bio_template_array_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_bio_template_array_free function releases the memory backing .Fa *array_p , where .Fa *array_p must have been previously allocated by .Fn fido_bio_template_array_new . On return, .Fa *array_p is set to NULL. Either .Fa array_p or .Fa *array_p may be NULL, in which case .Fn fido_bio_template_array_free is a NOP. .Pp The .Fn fido_bio_template_array_count function returns the number of templates in .Fa array . .Pp The .Fn fido_bio_template function returns a pointer to the template at index .Fa idx in .Fa array . Please note that the first template in .Fa array has an .Fa idx (index) value of 0. .Sh RETURN VALUES The error codes returned by .Fn fido_bio_template_set_id and .Fn fido_bio_template_set_name are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. .Sh SEE ALSO .Xr fido_bio_dev_get_info 3 , .Xr fido_bio_enroll_new 3 diff --git a/contrib/libfido2/man/fido_cbor_info_new.3 b/contrib/libfido2/man/fido_cbor_info_new.3 index 86f2a887f99a..a8168c05c916 100644 --- a/contrib/libfido2/man/fido_cbor_info_new.3 +++ b/contrib/libfido2/man/fido_cbor_info_new.3 @@ -1,232 +1,389 @@ -.\" 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. +.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved. .\" -.Dd $Mdocdate: May 24 2018 $ +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd $Mdocdate: April 22 2022 $ .Dt FIDO_CBOR_INFO_NEW 3 .Os .Sh NAME .Nm fido_cbor_info_new , .Nm fido_cbor_info_free , .Nm fido_dev_get_cbor_info , .Nm fido_cbor_info_aaguid_ptr , .Nm fido_cbor_info_extensions_ptr , .Nm fido_cbor_info_protocols_ptr , .Nm fido_cbor_info_transports_ptr , .Nm fido_cbor_info_versions_ptr , .Nm fido_cbor_info_options_name_ptr , .Nm fido_cbor_info_options_value_ptr , .Nm fido_cbor_info_algorithm_type , .Nm fido_cbor_info_algorithm_cose , .Nm fido_cbor_info_algorithm_count , +.Nm fido_cbor_info_certs_name_ptr , +.Nm fido_cbor_info_certs_value_ptr , +.Nm fido_cbor_info_certs_len , .Nm fido_cbor_info_aaguid_len , .Nm fido_cbor_info_extensions_len , .Nm fido_cbor_info_protocols_len , .Nm fido_cbor_info_transports_len , .Nm fido_cbor_info_versions_len , .Nm fido_cbor_info_options_len , .Nm fido_cbor_info_maxmsgsiz , .Nm fido_cbor_info_maxcredbloblen , .Nm fido_cbor_info_maxcredcntlst , .Nm fido_cbor_info_maxcredidlen , -.Nm fido_cbor_info_fwversion +.Nm fido_cbor_info_maxlargeblob , +.Nm fido_cbor_info_maxrpid_minpinlen , +.Nm fido_cbor_info_minpinlen , +.Nm fido_cbor_info_fwversion , +.Nm fido_cbor_info_uv_attempts , +.Nm fido_cbor_info_uv_modality , +.Nm fido_cbor_info_rk_remaining , +.Nm fido_cbor_info_new_pin_required .Nd FIDO2 CBOR Info API .Sh SYNOPSIS .In fido.h .Ft fido_cbor_info_t * .Fn fido_cbor_info_new "void" .Ft void .Fn fido_cbor_info_free "fido_cbor_info_t **ci_p" .Ft int .Fn fido_dev_get_cbor_info "fido_dev_t *dev" "fido_cbor_info_t *ci" .Ft const unsigned char * .Fn fido_cbor_info_aaguid_ptr "const fido_cbor_info_t *ci" .Ft char ** .Fn fido_cbor_info_extensions_ptr "const fido_cbor_info_t *ci" .Ft const uint8_t * .Fn fido_cbor_info_protocols_ptr "const fido_cbor_info_t *ci" .Ft char ** .Fn fido_cbor_info_transports_ptr "const fido_cbor_info_t *ci" .Ft char ** .Fn fido_cbor_info_versions_ptr "const fido_cbor_info_t *ci" .Ft char ** .Fn fido_cbor_info_options_name_ptr "const fido_cbor_info_t *ci" .Ft const bool * .Fn fido_cbor_info_options_value_ptr "const fido_cbor_info_t *ci" .Ft const char * .Fn fido_cbor_info_algorithm_type "const fido_cbor_info_t *ci" "size_t idx" .Ft int .Fn fido_cbor_info_algorithm_cose "const fido_cbor_info_t *ci" "size_t idx" .Ft size_t .Fn fido_cbor_info_algorithm_count "const fido_cbor_info_t *ci" +.Ft char ** +.Fn fido_cbor_info_certs_name_ptr "const fido_cbor_info_t *ci" +.Ft const uint64_t * +.Fn fido_cbor_info_certs_value_ptr "const fido_cbor_info_t *ci" +.Ft size_t +.Fn fido_cbor_info_certs_len "const fido_cbor_info_t *ci" .Ft size_t .Fn fido_cbor_info_aaguid_len "const fido_cbor_info_t *ci" .Ft size_t .Fn fido_cbor_info_extensions_len "const fido_cbor_info_t *ci" .Ft size_t .Fn fido_cbor_info_protocols_len "const fido_cbor_info_t *ci" .Ft size_t .Fn fido_cbor_info_transports_len "const fido_cbor_info_t *ci" .Ft size_t .Fn fido_cbor_info_versions_len "const fido_cbor_info_t *ci" .Ft size_t .Fn fido_cbor_info_options_len "const fido_cbor_info_t *ci" .Ft uint64_t .Fn fido_cbor_info_maxmsgsiz "const fido_cbor_info_t *ci" .Ft uint64_t .Fn fido_cbor_info_maxcredbloblen "const fido_cbor_info_t *ci" .Ft uint64_t .Fn fido_cbor_info_maxcredcntlst "const fido_cbor_info_t *ci" .Ft uint64_t .Fn fido_cbor_info_maxcredidlen "const fido_cbor_info_t *ci" .Ft uint64_t +.Fn fido_cbor_info_maxlargeblob "const fido_cbor_info_t *ci" +.Ft uint64_t +.Fn fido_cbor_info_maxrpid_minpinlen "const fido_cbor_info_t *ci" +.Ft uint64_t +.Fn fido_cbor_info_minpinlen "const fido_cbor_info_t *ci" +.Ft uint64_t .Fn fido_cbor_info_fwversion "const fido_cbor_info_t *ci" +.Ft uint64_t +.Fn fido_cbor_info_uv_attempts "const fido_cbor_info_t *ci" +.Ft uint64_t +.Fn fido_cbor_info_uv_modality "const fido_cbor_info_t *ci" +.Ft int64_t +.Fn fido_cbor_info_rk_remaining "const fido_cbor_info_t *ci" +.Ft bool +.Fn fido_cbor_info_new_pin_required "const fido_cbor_info_t *ci" .Sh DESCRIPTION The .Fn fido_cbor_info_new function returns a pointer to a newly allocated, empty .Vt fido_cbor_info_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_cbor_info_free function releases the memory backing .Fa *ci_p , where .Fa *ci_p must have been previously allocated by .Fn fido_cbor_info_new . On return, .Fa *ci_p is set to NULL. Either .Fa ci_p or .Fa *ci_p may be NULL, in which case .Fn fido_cbor_info_free is a NOP. .Pp The .Fn fido_dev_get_cbor_info function transmits a .Dv CTAP_CBOR_GETINFO command to .Fa dev and fills .Fa ci with attributes retrieved from the command's response. The .Fn fido_dev_get_cbor_info function may block. .Pp The .Fn fido_cbor_info_aaguid_ptr , .Fn fido_cbor_info_extensions_ptr , .Fn fido_cbor_info_protocols_ptr , .Fn fido_cbor_info_transports_ptr , and .Fn fido_cbor_info_versions_ptr functions return pointers to the authenticator attestation GUID, supported extensions, PIN protocol, transports, and CTAP version strings of .Fa ci . The corresponding length of a given attribute can be obtained by .Fn fido_cbor_info_aaguid_len , .Fn fido_cbor_info_extensions_len , .Fn fido_cbor_info_protocols_len , .Fn fido_cbor_info_transports_len , or .Fn fido_cbor_info_versions_len . .Pp The .Fn fido_cbor_info_options_name_ptr and .Fn fido_cbor_info_options_value_ptr functions return pointers to the array of option names and their respective values in .Fa ci . The length of the options array is returned by .Fn fido_cbor_info_options_len . .Pp The .Fn fido_cbor_info_algorithm_count function returns the number of supported algorithms in .Fa ci . The .Fn fido_cbor_info_algorithm_cose function returns the COSE identifier of algorithm .Fa idx in .Fa ci , or 0 if the COSE identifier is unknown or unset. The .Fn fido_cbor_info_algorithm_type function returns the type of algorithm .Fa idx in .Fa ci , or NULL if the type is unset. Please note that the first algorithm in .Fa ci has an .Fa idx (index) value of 0. .Pp The +.Fn fido_cbor_info_certs_name_ptr +and +.Fn fido_cbor_info_certs_value_ptr +functions return pointers to the array of certification names and their +respective values +in +.Fa ci . +The length of the certifications array is returned by +.Fn fido_cbor_info_certs_len . +.Pp +The .Fn fido_cbor_info_maxmsgsiz function returns the maximum message size attribute of .Fa ci . .Pp The .Fn fido_cbor_info_maxcredbloblen function returns the maximum .Dq credBlob length in bytes supported by the authenticator as reported in .Fa ci . .Pp The .Fn fido_cbor_info_maxcredcntlst function returns the maximum supported number of credentials in a single credential ID list as reported in .Fa ci . .Pp The .Fn fido_cbor_info_maxcredidlen function returns the maximum supported length of a credential ID as reported in .Fa ci . .Pp The +.Fn fido_cbor_info_maxrpid_minpinlen +function returns the maximum number of RP IDs that may be passed to +.Xr fido_dev_set_pin_minlen_rpid 3 , +as reported in +.Fa ci . +The minimum PIN length attribute is a CTAP 2.1 addition. +If the attribute is not advertised by the authenticator, the +.Fn fido_cbor_info_maxrpid_minpinlen +function returns zero. +.Pp +The +.Fn fido_cbor_info_maxlargeblob +function returns the maximum length in bytes of an authenticator's +serialized largeBlob array as reported in +.Fa ci . +.Pp +The +.Fn fido_cbor_info_minpinlen +function returns the minimum PIN length enforced by the +authenticator as reported in +.Fa ci . +The minimum PIN length attribute is a CTAP 2.1 addition. +If the attribute is not advertised by the authenticator, the +.Fn fido_cbor_info_minpinlen +function returns zero. +.Pp +The .Fn fido_cbor_info_fwversion function returns the firmware version attribute of .Fa ci . .Pp +The +.Fn fido_cbor_info_uv_attempts +function returns the number of UV attempts that the platform may +attempt before falling back to PIN authentication. +If 1, then all +.Xr fido_dev_get_uv_retry_count 3 +retries are handled internally by the authenticator and the +platform may only attempt non-PIN UV once. +The UV attempts attribute is a CTAP 2.1 addition. +If the attribute is not advertised by the authenticator, +the +.Fn fido_cbor_info_uv_attempts +function returns zero. +.Pp +The +.Fn fido_cbor_info_uv_modality +function returns a bitmask representing different UV modes +supported by the authenticator, as defined in the FIDO Registry of +Predefined Values and reported in +.Fa ci . +See the +.Em FIDO_UV_MODE_* +definitions in +.In fido/param.h +for the set of values defined by libfido2 and a brief description +of each. +The UV modality attribute is a CTAP 2.1 addition. +If the attribute is not advertised by the authenticator, the +.Fn fido_cbor_info_uv_modality +function returns zero. +.Pp +The +.Fn fido_cbor_info_rk_remaining +function returns the estimated number of additional +resident/discoverable credentials that can be stored on the +authenticator as reported in +.Fa ci . +The estimated number of remaining resident credentials is a +CTAP 2.1 addition. +If the attribute is not advertised by the authenticator, the +.Fn fido_cbor_info_rk_remaining +function returns -1. +.Pp +The +.Fn fido_cbor_info_new_pin_required +function returns whether a new PIN is required by the authenticator +as reported in +.Fa ci . +If +.Fn fido_cbor_info_new_pin_required +returns true, operations requiring PIN authentication will fail +until a new PIN is set on the authenticator. +The +.Xr fido_dev_set_pin 3 +function can be used to set a new PIN. +.Pp A complete example of how to use these functions can be found in the .Pa example/info.c file shipped with .Em libfido2 . .Sh RETURN VALUES The .Fn fido_cbor_info_aaguid_ptr , .Fn fido_cbor_info_extensions_ptr , .Fn fido_cbor_info_protocols_ptr , .Fn fido_cbor_info_transports_ptr , .Fn fido_cbor_info_versions_ptr , .Fn fido_cbor_info_options_name_ptr , and .Fn fido_cbor_info_options_value_ptr functions return NULL if the respective field in .Fa ci is absent. If not NULL, returned pointers are guaranteed to exist until any API function that takes .Fa ci without the .Em const qualifier is invoked. .Sh SEE ALSO -.Xr fido_dev_open 3 +.Xr fido_dev_get_uv_retry_count 3 , +.Xr fido_dev_open 3 , +.Xr fido_dev_set_pin 3 , +.Xr fido_dev_set_pin_minlen_rpid 3 +.Rs +.%D 2021-05-25 +.%O Review Draft, Version 2.2 +.%Q FIDO Alliance +.%R FIDO Registry of Predefined Values +.%U https://fidoalliance.org/specs/common-specs/fido-registry-v2.2-rd-20210525.html +.Re diff --git a/contrib/libfido2/man/fido_cred_exclude.3 b/contrib/libfido2/man/fido_cred_exclude.3 index 2aa87f28976f..d5e840d56e11 100644 --- a/contrib/libfido2/man/fido_cred_exclude.3 +++ b/contrib/libfido2/man/fido_cred_exclude.3 @@ -1,60 +1,93 @@ -.\" 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. +.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved. .\" -.Dd $Mdocdate: May 23 2018 $ +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd $Mdocdate: December 2 2022 $ .Dt FIDO_CRED_EXCLUDE 3 .Os .Sh NAME -.Nm fido_cred_exclude -.Nd appends a credential ID to a credential's list of excluded credentials +.Nm fido_cred_exclude , +.Nm fido_cred_empty_exclude_list +.Nd manage exclude lists in a FIDO2 credential .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_cred_exclude "fido_cred_t *cred" "const unsigned char *ptr" "size_t len" +.Ft int +.Fn fido_cred_empty_exclude_list "fido_cred_t *cred" .Sh DESCRIPTION The .Fn fido_cred_exclude function adds .Fa ptr to the list of credentials excluded by .Fa cred , where .Fa ptr points to a credential ID of .Fa len bytes. A copy of .Fa ptr is made, and no references to the passed pointer are kept. If .Fn fido_cred_exclude fails, the existing list of excluded credentials is preserved. .Pp If .Nm returns success and .Fa cred is later passed to .Xr fido_dev_make_cred 3 on a device that contains the credential denoted by .Fa ptr , then .Xr fido_dev_make_cred 3 will fail. .Pp For the format of a FIDO2 credential ID, please refer to the Web Authentication (webauthn) standard. +.Pp +The +.Fn fido_cred_empty_exclude_list +function empties the list of credentials excluded by +.Fa cred . .Sh RETURN VALUES The error codes returned by .Fn fido_cred_exclude +and +.Fn fido_cred_empty_exclude_list are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. .Sh SEE ALSO .Xr fido_cred_new 3 , .Xr fido_cred_set_authdata 3 , .Xr fido_dev_make_cred 3 diff --git a/contrib/libfido2/man/fido_cred_new.3 b/contrib/libfido2/man/fido_cred_new.3 index ee7ac96a6b0b..4f8b1be7bc45 100644 --- a/contrib/libfido2/man/fido_cred_new.3 +++ b/contrib/libfido2/man/fido_cred_new.3 @@ -1,293 +1,316 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .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 FIDO2 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 "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 FIDO2 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 If the CTAP 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 CTAP 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 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 +the attestation statement format identifier 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_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, 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_attstmt_len . .Pp The authenticator data, x509 certificate, and signature parts of a credential are typically passed to a FIDO2 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 921a682f8f91..e4538325b291 100644 --- a/contrib/libfido2/man/fido_cred_set_authdata.3 +++ b/contrib/libfido2/man/fido_cred_set_authdata.3 @@ -1,354 +1,382 @@ -.\" 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. +.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved. .\" -.Dd $Mdocdate: May 23 2018 $ +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd $Mdocdate: July 15 2022 $ .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 FIDO2 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 FIDO2 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 FIDO2 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 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 . 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 CTAP 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 enables the CTAP 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 +function sets the attestation statement format identifier 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 , +.Pq the format used in U2F , +.Vt "tpm" +.Pq the format used by TPM-based authenticators , 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 +Note that not all authenticators support FIDO2 and therefore may only be able to generate -.Vt "packed" . +.Vt fido-u2f +attestation statements. .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_ES384 , .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. +Note that not all authenticators support COSE_RS256, COSE_ES384, or +COSE_EDDSA. .Pp Use of the .Nm set of functions may happen in two distinct situations: when generating a new credential on a FIDO2 device, prior to .Xr fido_dev_make_cred 3 (i.e, in the context of a FIDO2 client), or when validating a generated credential using .Xr fido_cred_verify 3 (i.e, in the context of a FIDO2 server). .Pp For a complete description of the generation of a FIDO2 credential and its verification, please refer to the FIDO2 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 696dec293e4d..9548870204c7 100644 --- a/contrib/libfido2/man/fido_cred_verify.3 +++ b/contrib/libfido2/man/fido_cred_verify.3 @@ -1,91 +1,114 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .Dd $Mdocdate: May 23 2018 $ .Dt FIDO_CRED_VERIFY 3 .Os .Sh NAME .Nm fido_cred_verify , .Nm fido_cred_verify_self .Nd verify the attestation signature of a FIDO2 credential .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_cred_verify "const fido_cred_t *cred" .Ft int .Fn fido_cred_verify_self "const fido_cred_t *cred" .Sh DESCRIPTION The .Fn fido_cred_verify and .Fn fido_cred_verify_self functions verify whether the attestation signature contained in .Fa cred matches the attributes of the credential. Before using .Fn fido_cred_verify or .Fn fido_cred_verify_self in a sensitive context, the reader is strongly encouraged to make herself familiar with the FIDO2 credential attestation process as defined in the Web Authentication (webauthn) standard. .Pp The .Fn fido_cred_verify function verifies whether the client data hash, relying party ID, 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 fido-u2f , and .Em tpm . The attestation type implemented by .Fn fido_cred_verify is .Em Basic Attestation . .Pp The .Fn fido_cred_verify_self function verifies whether the client data hash, relying party ID, 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 credential's private key. .Pp The attestation statement formats supported by .Fn fido_cred_verify_self are .Em packed and .Em fido-u2f . The attestation type implemented by .Fn fido_cred_verify_self is .Em Self Attestation . .Pp Other attestation formats and types are not supported. .Sh RETURN VALUES The error codes returned by .Fn fido_cred_verify and .Fn fido_cred_verify_self are defined in .In fido/err.h . 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_credman_metadata_new.3 b/contrib/libfido2/man/fido_credman_metadata_new.3 index cd6722e24aa8..122020bd68b1 100644 --- a/contrib/libfido2/man/fido_credman_metadata_new.3 +++ b/contrib/libfido2/man/fido_credman_metadata_new.3 @@ -1,326 +1,349 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .Dd $Mdocdate: June 28 2019 $ .Dt FIDO_CREDMAN_METADATA_NEW 3 .Os .Sh NAME .Nm fido_credman_metadata_new , .Nm fido_credman_rk_new , .Nm fido_credman_rp_new , .Nm fido_credman_metadata_free , .Nm fido_credman_rk_free , .Nm fido_credman_rp_free , .Nm fido_credman_rk_existing , .Nm fido_credman_rk_remaining , .Nm fido_credman_rk , .Nm fido_credman_rk_count , .Nm fido_credman_rp_id , .Nm fido_credman_rp_name , .Nm fido_credman_rp_count , .Nm fido_credman_rp_id_hash_ptr , .Nm fido_credman_rp_id_hash_len , .Nm fido_credman_get_dev_metadata , .Nm fido_credman_get_dev_rk , .Nm fido_credman_set_dev_rk , .Nm fido_credman_del_dev_rk , .Nm fido_credman_get_dev_rp .Nd FIDO2 credential management API .Sh SYNOPSIS .In fido.h .In fido/credman.h .Ft fido_credman_metadata_t * .Fn fido_credman_metadata_new "void" .Ft fido_credman_rk_t * .Fn fido_credman_rk_new "void" .Ft fido_credman_rp_t * .Fn fido_credman_rp_new "void" .Ft void .Fn fido_credman_metadata_free "fido_credman_metadata_t **metadata_p" .Ft void .Fn fido_credman_rk_free "fido_credman_rk_t **rk_p" .Ft void .Fn fido_credman_rp_free "fido_credman_rp_t **rp_p" .Ft uint64_t .Fn fido_credman_rk_existing "const fido_credman_metadata_t *metadata" .Ft uint64_t .Fn fido_credman_rk_remaining "const fido_credman_metadata_t *metadata" .Ft const fido_cred_t * .Fn fido_credman_rk "const fido_credman_rk_t *rk" "size_t idx" .Ft size_t .Fn fido_credman_rk_count "const fido_credman_rk_t *rk" .Ft const char * .Fn fido_credman_rp_id "const fido_credman_rp_t *rp" "size_t idx" .Ft const char * .Fn fido_credman_rp_name "const fido_credman_rp_t *rp" "size_t idx" .Ft size_t .Fn fido_credman_rp_count "const fido_credman_rp_t *rp" .Ft const unsigned char * .Fn fido_credman_rp_id_hash_ptr "const fido_credman_rp_t *rp" "size_t idx" .Ft size_t .Fn fido_credman_rp_id_hash_len "const fido_credman_rp_t *" "size_t idx" .Ft int .Fn fido_credman_get_dev_metadata "fido_dev_t *dev" "fido_credman_metadata_t *metadata" "const char *pin" .Ft int .Fn fido_credman_get_dev_rk "fido_dev_t *dev" "const char *rp_id" "fido_credman_rk_t *rk" "const char *pin" .Ft int .Fn fido_credman_set_dev_rk "fido_dev_t *dev" "fido_cred_t *cred" "const char *pin" .Ft int .Fn fido_credman_del_dev_rk "fido_dev_t *dev" "const unsigned char *cred_id" "size_t cred_id_len" "const char *pin" .Ft int .Fn fido_credman_get_dev_rp "fido_dev_t *dev" "fido_credman_rp_t *rp" "const char *pin" .Sh DESCRIPTION The credential management API of .Em libfido2 allows resident credentials on a FIDO2 authenticator to be listed, inspected, modified, and removed. Please note that not all FIDO2 authenticators support credential management. To obtain information on what an authenticator supports, please refer to .Xr fido_cbor_info_new 3 . .Pp The .Vt fido_credman_metadata_t type abstracts credential management metadata. .Pp The .Fn fido_credman_metadata_new function returns a pointer to a newly allocated, empty .Vt fido_credman_metadata_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_credman_metadata_free function releases the memory backing .Fa *metadata_p , where .Fa *metadata_p must have been previously allocated by .Fn fido_credman_metadata_new . On return, .Fa *metadata_p is set to NULL. Either .Fa metadata_p or .Fa *metadata_p may be NULL, in which case .Fn fido_credman_metadata_free is a NOP. .Pp The .Fn fido_credman_get_dev_metadata function populates .Fa metadata with information retrieved from .Fa dev . A valid .Fa pin must be provided. .Pp The .Fn fido_credman_rk_existing function inspects .Fa metadata and returns the number of resident credentials on the authenticator. The .Fn fido_credman_rk_remaining function inspects .Fa metadata and returns the estimated number of resident credentials that can be created on the authenticator. .Pp The .Vt fido_credman_rk_t type abstracts the set of resident credentials belonging to a given relying party. .Pp The .Fn fido_credman_rk_new function returns a pointer to a newly allocated, empty .Vt fido_credman_rk_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_credman_rk_free function releases the memory backing .Fa *rk_p , where .Fa *rk_p must have been previously allocated by .Fn fido_credman_rk_new . On return, .Fa *rk_p is set to NULL. Either .Fa rk_p or .Fa *rk_p may be NULL, in which case .Fn fido_credman_rk_free is a NOP. .Pp The .Fn fido_credman_get_dev_rk function populates .Fa rk with the set of resident credentials belonging to .Fa rp_id in .Fa dev . A valid .Fa pin must be provided. .Pp The .Fn fido_credman_rk_count function returns the number of resident credentials in .Fa rk . The .Fn fido_credman_rk function returns a pointer to the credential at index .Fa idx in .Fa rk . Please note that the first credential in .Fa rk has an .Fa idx (index) value of 0. .Pp The .Fn fido_credman_set_dev_rk function updates the credential pointed to by .Fa cred in .Fa dev . The credential id and user id attributes of .Fa cred must be set. See .Xr fido_cred_set_id 3 and .Xr fido_cred_set_user 3 for details. Only a credential's user attributes (name, display name) may be updated at this time. .Pp The .Fn fido_credman_del_dev_rk function deletes the resident credential identified by .Fa cred_id from .Fa dev , where .Fa cred_id points to .Fa cred_id_len bytes. A valid .Fa pin must be provided. .Pp The .Vt fido_credman_rp_t type abstracts information about a relying party. .Pp The .Fn fido_credman_rp_new function returns a pointer to a newly allocated, empty .Vt fido_credman_rp_t type. If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_credman_rp_free function releases the memory backing .Fa *rp_p , where .Fa *rp_p must have been previously allocated by .Fn fido_credman_rp_new . On return, .Fa *rp_p is set to NULL. Either .Fa rp_p or .Fa *rp_p may be NULL, in which case .Fn fido_credman_rp_free is a NOP. .Pp The .Fn fido_credman_get_dev_rp function populates .Fa rp with information about relying parties with resident credentials in .Fa dev . A valid .Fa pin must be provided. .Pp The .Fn fido_credman_rp_count function returns the number of relying parties in .Fa rp . .Pp The .Fn fido_credman_rp_id and .Fn fido_credman_rp_name functions return pointers to the id and name of relying party .Fa idx in .Fa rp . If not NULL, the values returned by these functions point to NUL-terminated UTF-8 strings. Please note that the first relying party in .Fa rp has an .Fa idx (index) value of 0. .Pp The .Fn fido_credman_rp_id_hash_ptr function returns a pointer to the hashed id of relying party .Fa idx in .Fa rp . The corresponding length can be obtained by .Fn fido_credman_rp_id_hash_len . Please note that the first relying party in .Fa rp has an .Fa idx (index) value of 0. .Sh RETURN VALUES The .Fn fido_credman_get_dev_metadata , .Fn fido_credman_get_dev_rk , .Fn fido_credman_set_dev_rk , .Fn fido_credman_del_dev_rk , and .Fn fido_credman_get_dev_rp functions return .Dv FIDO_OK on success. On error, a different error code defined in .In fido/err.h is returned. Functions returning pointers are not guaranteed to succeed, and should have their return values checked for NULL. .Sh SEE ALSO .Xr fido_cbor_info_new 3 , .Xr fido_cred_new 3 , .Xr fido_dev_supports_credman 3 .Sh CAVEATS Resident credentials are called .Dq discoverable credentials in CTAP 2.1. diff --git a/contrib/libfido2/man/fido_dev_enable_entattest.3 b/contrib/libfido2/man/fido_dev_enable_entattest.3 index bfc1b2834e55..7617f22389e2 100644 --- a/contrib/libfido2/man/fido_dev_enable_entattest.3 +++ b/contrib/libfido2/man/fido_dev_enable_entattest.3 @@ -1,121 +1,149 @@ -.\" 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. +.\" Copyright (c) 2020-2022 Yubico AB. All rights reserved. .\" -.Dd $Mdocdate: September 22 2020 $ +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd $Mdocdate: March 30 2022 $ .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_rpid .Nd CTAP 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 CTAP 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 +function 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 CTAP 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. +The maximum value of +.Fa n +supported by the authenticator can be obtained using +.Xr fido_cbor_info_maxrpid_minpinlen 3 . .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_rpid are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. .Sh SEE ALSO +.Xr fido_cbor_info_maxrpid_minpinlen 3 , .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_get_assert.3 b/contrib/libfido2/man/fido_dev_get_assert.3 index bc67e441cca3..bb2fc43b8b24 100644 --- a/contrib/libfido2/man/fido_dev_get_assert.3 +++ b/contrib/libfido2/man/fido_dev_get_assert.3 @@ -1,76 +1,99 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .Dd $Mdocdate: May 24 2018 $ .Dt FIDO_DEV_GET_ASSERT 3 .Os .Sh NAME .Nm fido_dev_get_assert .Nd obtains an assertion from a FIDO2 device .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_dev_get_assert "fido_dev_t *dev" "fido_assert_t *assert" "const char *pin" .Sh DESCRIPTION The .Fn fido_dev_get_assert function asks the FIDO2 device represented by .Fa dev for an assertion according to the following parameters defined in .Fa assert : .Pp .Bl -dash -compact .It .Nm relying party ID ; .It .Nm client data hash ; .It .Nm list of allowed credential IDs ; .It .Nm user presence and user verification attributes . .El .Pp See .Xr fido_assert_set_authdata 3 for information on how these values are set. .Pp If a PIN is not needed to authenticate the request against .Fa dev , then .Fa pin may be NULL. Otherwise .Fa pin must point to a NUL-terminated UTF-8 string. .Pp After a successful call to .Fn fido_dev_get_assert , the .Xr fido_assert_count 3 , .Xr fido_assert_user_display_name 3 , .Xr fido_assert_user_icon 3 , .Xr fido_assert_user_name 3 , .Xr fido_assert_authdata_ptr 3 , .Xr fido_assert_user_id_ptr 3 , .Xr fido_assert_sig_ptr 3 , and .Xr fido_assert_sigcount 3 functions may be invoked on .Fa assert to retrieve the various attributes of the generated assertion. .Pp Please note that .Fn fido_dev_get_assert is synchronous and will block if necessary. .Sh RETURN VALUES The error codes returned by .Fn fido_dev_get_assert are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. .Sh SEE ALSO .Xr fido_assert_new 3 , .Xr fido_assert_set_authdata 3 diff --git a/contrib/libfido2/man/fido_dev_get_touch_begin.3 b/contrib/libfido2/man/fido_dev_get_touch_begin.3 index f3b8335cec12..f015eff2cb3c 100644 --- a/contrib/libfido2/man/fido_dev_get_touch_begin.3 +++ b/contrib/libfido2/man/fido_dev_get_touch_begin.3 @@ -1,73 +1,96 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .Dd $Mdocdate: August 5 2020 $ .Dt FIDO_DEV_GET_TOUCH_BEGIN 3 .Os .Sh NAME .Nm fido_dev_get_touch_begin , .Nm fido_dev_get_touch_status .Nd asynchronously wait for touch on a FIDO2 authenticator .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_dev_get_touch_begin "fido_dev_t *dev" .Ft int .Fn fido_dev_get_touch_status "fido_dev_t *dev" "int *touched" "int ms" .Sh DESCRIPTION The functions described in this page allow an application to asynchronously wait for touch on a FIDO2 authenticator. This is useful when multiple authenticators are present and the application needs to know which one to use. .Pp The .Fn fido_dev_get_touch_begin function initiates a touch request on .Fa dev . .Pp The .Fn fido_dev_get_touch_status function continues an ongoing touch request on .Fa dev , blocking up to .Fa ms milliseconds. On success, .Fa touched will be updated to reflect the touch request status. If .Fa touched is 1, the device was touched, and the touch request is terminated. If .Fa touched is 0, the application may call .Fn fido_dev_get_touch_status to continue the touch request, or .Fn fido_dev_cancel to terminate it. .Sh RETURN VALUES The error codes returned by .Fn fido_dev_get_touch_begin and .Fn fido_dev_get_touch_status are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. .Sh EXAMPLES Please refer to .Em examples/select.c in .Em libfido2's source tree. .Sh SEE ALSO .Xr fido_dev_cancel 3 .Sh CAVEATS The .Fn fido_dev_get_touch_status function will cause a command to be transmitted to U2F authenticators. These transmissions should not exceed a frequency of 5Hz. diff --git a/contrib/libfido2/man/fido_dev_info_manifest.3 b/contrib/libfido2/man/fido_dev_info_manifest.3 index 9539a0dda7c5..a70a3cb299ac 100644 --- a/contrib/libfido2/man/fido_dev_info_manifest.3 +++ b/contrib/libfido2/man/fido_dev_info_manifest.3 @@ -1,188 +1,211 @@ .\" 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 $ +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd $Mdocdate: March 30 2022 $ .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 , .Nm fido_dev_info_set .Nd FIDO2 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" .Ft int .Fn fido_dev_info_set "fido_dev_info_t *devlist" "size_t i" "const char *path" "const char *manufacturer" "const char *product" "const fido_dev_io_t *io" "const fido_dev_transport_t *transport" .Sh DESCRIPTION The .Fn fido_dev_info_manifest function fills .Fa devlist with up to .Fa ilen FIDO2 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 +function 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 . .Pp The .Fn fido_dev_info_set function initializes an entry in a device list allocated by .Fn fido_dev_info_new with the specified path, manufacturer, and product strings, and with the specified I/O handlers and, optionally, transport functions, as described in .Xr fido_dev_set_io_functions 3 . The .Fa io argument must be specified; the .Fa transport argument may be .Dv NULL . The path, I/O handlers, and transport functions will be used automatically by .Xr fido_dev_new_with_info 3 and .Xr fido_dev_open_with_info 3 . An application can use this, for example, to substitute mock FIDO2 devices in testing for the real ones that .Fn fido_dev_info_manifest would discover. .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 On success, the .Fn fido_dev_info_set function returns .Dv FIDO_OK . On error, a different error code defined in .In fido/err.h is returned. .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_largeblob_get.3 b/contrib/libfido2/man/fido_dev_largeblob_get.3 index c42208158c5e..12dd319485e1 100644 --- a/contrib/libfido2/man/fido_dev_largeblob_get.3 +++ b/contrib/libfido2/man/fido_dev_largeblob_get.3 @@ -1,194 +1,216 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .Dd $Mdocdate: October 26 2020 $ .Dt FIDO_LARGEBLOB_GET 3 .Os .Sh NAME .Nm fido_dev_largeblob_get , .Nm fido_dev_largeblob_set , .Nm fido_dev_largeblob_remove , .Nm fido_dev_largeblob_get_array , .Nm fido_dev_largeblob_set_array .Nd FIDO2 large blob API .Sh SYNOPSIS .In fido.h .Ft int .Fn 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" .Ft int .Fn 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" .Ft int .Fn fido_dev_largeblob_remove "fido_dev_t *dev" "const unsigned char *key_ptr" "size_t key_len" "const char *pin" .Ft int .Fn fido_dev_largeblob_get_array "fido_dev_t *dev" "unsigned char **cbor_ptr" "size_t *cbor_len" .Ft int .Fn fido_dev_largeblob_set_array "fido_dev_t *dev" "const unsigned char *cbor_ptr" "size_t cbor_len" "const char *pin" .Sh DESCRIPTION The .Dq largeBlobs API of .Em libfido2 allows binary blobs residing on a CTAP 2.1 authenticator to be read, written, and inspected. .Dq largeBlobs is a CTAP 2.1 extension. .Pp .Dq largeBlobs are stored as elements of a CBOR array. Confidentiality is ensured by encrypting each element with a distinct, credential-bound 256-bit AES-GCM key. The array is otherwise shared between different credentials and FIDO2 relying parties. .Pp Retrieval of a credential's encryption key is possible during enrollment with .Xr fido_cred_set_extensions 3 and .Xr fido_cred_largeblob_key_ptr 3 , during assertion with .Xr fido_assert_set_extensions 3 and .Xr fido_assert_largeblob_key_ptr 3 , or, in the case of a resident credential, via .Em libfido2's credential management API. .Pp The .Dq largeBlobs CBOR array is opaque to the authenticator. Management of the array is left at the discretion of FIDO2 clients. For further details on CTAP 2.1's .Dq largeBlobs extension, please refer to the CTAP 2.1 spec. .Pp The .Fn fido_dev_largeblob_get function retrieves the authenticator's .Dq largeBlobs CBOR array and, on success, returns the first blob .Pq iterating from array index zero -that can be -decrypted by +that can be decrypted by .Fa key_ptr , where .Fa key_ptr points to .Fa key_len bytes. On success, .Fn fido_dev_largeblob_get sets .Fa blob_ptr to the body of the decrypted blob, and .Fa blob_len to the length of the decrypted blob in bytes. It is the caller's responsibility to free .Fa blob_ptr . .Pp The .Fn fido_dev_largeblob_set function uses .Fa key_ptr to encrypt .Fa blob_ptr and inserts the result in the authenticator's .Dq largeBlobs CBOR array. Insertion happens at the end of the array if no existing element can be decrypted by .Fa key_ptr , or at the position of the first element .Pq iterating from array index zero that can be decrypted by .Fa key_ptr . .Fa key_len holds the length of .Fa key_ptr in bytes, and .Fa blob_len the length of .Fa blob_ptr in bytes. A .Fa pin or equivalent user-verification gesture is required. .Pp The .Fn fido_dev_largeblob_remove function retrieves the authenticator's .Dq largeBlobs CBOR array and, on success, drops the first blob .Pq iterating from array index zero that can be decrypted by .Fa key_ptr , where .Fa key_ptr points to .Fa key_len bytes. A .Fa pin or equivalent user-verification gesture is required. .Pp The .Fn fido_dev_largeblob_get_array function retrieves the authenticator's .Dq largeBlobs CBOR array and, on success, sets .Fa cbor_ptr to the body of the CBOR array, and .Fa cbor_len to its corresponding length in bytes. It is the caller's responsibility to free .Fa cbor_ptr . .Pp Finally, the .Fn fido_dev_largeblob_set_array function sets the authenticator's .Dq largeBlobs CBOR array to the data pointed to by .Fa cbor_ptr , where .Fa cbor_ptr points to .Fa cbor_len bytes. A .Fa pin or equivalent user-verification gesture is required. .Sh RETURN VALUES The functions .Fn fido_dev_largeblob_set , .Fn fido_dev_largeblob_get , .Fn fido_dev_largeblob_remove , .Fn fido_dev_largeblob_get_array , and .Fn fido_dev_largeblob_set_array return .Dv FIDO_OK on success. On error, an error code defined in .In fido/err.h is returned. .Sh SEE ALSO .Xr fido_assert_largeblob_key_len 3 , .Xr fido_assert_largeblob_key_ptr 3 , .Xr fido_assert_set_extensions 3 , .Xr fido_cred_largeblob_key_len 3 , .Xr fido_cred_largeblob_key_ptr 3 , .Xr fido_cred_set_extensions 3 , -.Xr fido_credman_dev_get_rk 3 , -.Xr fido_credman_dev_get_rp 3 , +.Xr fido_credman_get_dev_rk 3 , +.Xr fido_credman_get_dev_rp 3 , .Xr fido_dev_get_assert 3 , .Xr fido_dev_make_cred 3 .Sh CAVEATS The .Dq largeBlobs extension is not meant to be used to store sensitive data. When retrieved, a credential's .Dq largeBlobs encryption key is transmitted in the clear, and an authenticator's .Dq largeBlobs CBOR array can be read without user interaction or verification. diff --git a/contrib/libfido2/man/fido_dev_make_cred.3 b/contrib/libfido2/man/fido_dev_make_cred.3 index 60b77fb9c010..b13f9a14bc85 100644 --- a/contrib/libfido2/man/fido_dev_make_cred.3 +++ b/contrib/libfido2/man/fido_dev_make_cred.3 @@ -1,77 +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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .Dd $Mdocdate: May 23 2018 $ .Dt FIDO_DEV_MAKE_CRED 3 .Os .Sh NAME .Nm fido_dev_make_cred .Nd generates a new credential on a FIDO2 device .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_dev_make_cred "fido_dev_t *dev" "fido_cred_t *cred" "const char *pin" .Sh DESCRIPTION The .Fn fido_dev_make_cred function asks the FIDO2 device represented by .Fa dev to generate a new credential according to the following parameters defined in .Fa cred : .Pp .Bl -dash -compact .It .Nm type ; .It .Nm client data hash ; .It .Nm relying party ; .It .Nm user attributes ; .It .Nm list of excluded credential IDs ; .It .Nm resident/discoverable key and user verification attributes . .El .Pp See .Xr fido_cred_set_authdata 3 for information on how these values are set. .Pp If a PIN is not needed to authenticate the request against .Fa dev , then .Fa pin may be NULL. Otherwise .Fa pin must point to a NUL-terminated UTF-8 string. .Pp After a successful call to .Fn fido_dev_make_cred , the .Xr fido_cred_authdata_ptr 3 , .Xr fido_cred_pubkey_ptr 3 , .Xr fido_cred_x5c_ptr 3 , and .Xr fido_cred_sig_ptr 3 functions may be invoked on .Fa cred to retrieve the various parts of the generated credential. .Pp Please note that .Fn fido_dev_make_cred is synchronous and will block if necessary. .Sh RETURN VALUES The error codes returned by .Fn fido_dev_make_cred are defined in .In fido/err.h . On success, .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_open.3 b/contrib/libfido2/man/fido_dev_open.3 index cdb148fe8b16..f839e26787b4 100644 --- a/contrib/libfido2/man/fido_dev_open.3 +++ b/contrib/libfido2/man/fido_dev_open.3 @@ -1,293 +1,316 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .Dd $Mdocdate: May 25 2018 $ .Dt FIDO_DEV_OPEN 3 .Os .Sh NAME .Nm fido_dev_open , .Nm fido_dev_open_with_info , .Nm fido_dev_close , .Nm fido_dev_cancel , .Nm fido_dev_new , .Nm fido_dev_new_with_info , .Nm fido_dev_free , .Nm fido_dev_force_fido2 , .Nm fido_dev_force_u2f , .Nm fido_dev_is_fido2 , .Nm fido_dev_is_winhello , .Nm fido_dev_supports_credman , .Nm fido_dev_supports_cred_prot , .Nm fido_dev_supports_permissions , .Nm fido_dev_supports_pin , .Nm fido_dev_supports_uv , .Nm fido_dev_has_pin , .Nm fido_dev_has_uv , .Nm fido_dev_protocol , .Nm fido_dev_build , .Nm fido_dev_flags , .Nm fido_dev_major , .Nm fido_dev_minor .Nd FIDO2 device open/close and related functions .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_dev_open "fido_dev_t *dev" "const char *path" .Ft int .Fn fido_dev_open_with_info "fido_dev_t *dev" .Ft int .Fn fido_dev_close "fido_dev_t *dev" .Ft int .Fn fido_dev_cancel "fido_dev_t *dev" .Ft fido_dev_t * .Fn fido_dev_new "void" .Ft fido_dev_t * .Fn fido_dev_new_with_info "const fido_dev_info_t *" .Ft void .Fn fido_dev_free "fido_dev_t **dev_p" .Ft void .Fn fido_dev_force_fido2 "fido_dev_t *dev" .Ft void .Fn fido_dev_force_u2f "fido_dev_t *dev" .Ft bool .Fn fido_dev_is_fido2 "const fido_dev_t *dev" .Ft bool .Fn fido_dev_is_winhello "const fido_dev_t *dev" .Ft bool .Fn fido_dev_supports_credman "const fido_dev_t *dev" .Ft bool .Fn fido_dev_supports_cred_prot "const fido_dev_t *dev" .Ft bool .Fn fido_dev_supports_permissions "const fido_dev_t *dev" .Ft bool .Fn fido_dev_supports_pin "const fido_dev_t *dev" .Ft bool .Fn fido_dev_supports_uv "const fido_dev_t *dev" .Ft bool .Fn fido_dev_has_pin "const fido_dev_t *dev" .Ft bool .Fn fido_dev_has_uv "const fido_dev_t *dev" .Ft uint8_t .Fn fido_dev_protocol "const fido_dev_t *dev" .Ft uint8_t .Fn fido_dev_build "const fido_dev_t *dev" .Ft uint8_t .Fn fido_dev_flags "const fido_dev_t *dev" .Ft uint8_t .Fn fido_dev_major "const fido_dev_t *dev" .Ft uint8_t .Fn fido_dev_minor "const fido_dev_t *dev" .Sh DESCRIPTION The .Fn fido_dev_open function opens the device pointed to by .Fa path , where .Fa dev is a freshly allocated or otherwise closed .Vt fido_dev_t . If .Fa dev claims to be FIDO2, .Em libfido2 will attempt to speak FIDO2 to .Fa dev . If that fails, .Em libfido2 will fallback to U2F unless the .Dv FIDO_DISABLE_U2F_FALLBACK flag was set in .Xr fido_init 3 . .Pp The .Fn fido_dev_open_with_info function opens .Fa dev as previously allocated using .Fn fido_dev_new_with_info . .Pp The .Fn fido_dev_close function closes the device represented by .Fa dev . If .Fa dev is already closed, .Fn fido_dev_close is a NOP. .Pp The .Fn fido_dev_cancel function cancels any pending requests on .Fa dev . .Pp The .Fn fido_dev_new function returns a pointer to a newly allocated, empty .Vt fido_dev_t . If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_dev_new_with_info function returns a pointer to a newly allocated .Vt fido_dev_t with .Vt fido_dev_info_t parameters, for use with .Xr fido_dev_info_manifest 3 and .Fn fido_dev_open_with_info . If memory cannot be allocated, NULL is returned. .Pp The .Fn fido_dev_free function releases the memory backing .Fa *dev_p , where .Fa *dev_p must have been previously allocated by .Fn fido_dev_new . On return, .Fa *dev_p is set to NULL. Either .Fa dev_p or .Fa *dev_p may be NULL, in which case .Fn fido_dev_free is a NOP. .Pp The .Fn fido_dev_force_fido2 function can be used to force CTAP2 communication with .Fa dev , where .Fa dev is an open device. .Pp The .Fn fido_dev_force_u2f function can be used to force CTAP1 (U2F) communication with .Fa dev , where .Fa dev is an open device. .Pp The .Fn fido_dev_is_fido2 function returns .Dv true if .Fa dev is a FIDO2 device. .Pp The .Fn fido_dev_is_winhello function returns .Dv true if .Fa dev is a Windows Hello device. .Pp The .Fn fido_dev_supports_credman function returns .Dv true if .Fa dev supports CTAP 2.1 Credential Management. .Pp The .Fn fido_dev_supports_cred_prot function returns .Dv true if .Fa dev supports CTAP 2.1 Credential Protection. .Pp The .Fn fido_dev_supports_permissions function returns .Dv true if .Fa dev supports CTAP 2.1 UV token permissions. .Pp The .Fn fido_dev_supports_pin function returns .Dv true if .Fa dev supports CTAP 2.0 Client PINs. .Pp The .Fn fido_dev_supports_uv function returns .Dv true if .Fa dev supports a built-in user verification method. .Pp The .Fn fido_dev_has_pin function returns .Dv true if .Fa dev has a CTAP 2.0 Client PIN set. .Pp The .Fn fido_dev_has_uv function returns .Dv true if .Fa dev supports built-in user verification and its user verification feature is configured. .Pp The .Fn fido_dev_protocol function returns the CTAPHID protocol version identifier of .Fa dev . .Pp The .Fn fido_dev_build function returns the CTAPHID build version number of .Fa dev . .Pp The .Fn fido_dev_flags function returns the CTAPHID capabilities flags of .Fa dev . .Pp The .Fn fido_dev_major function returns the CTAPHID major version number of .Fa dev . .Pp The .Fn fido_dev_minor function returns the CTAPHID minor version number of .Fa dev . .Pp For the format and meaning of the CTAPHID parameters returned by functions above, please refer to the FIDO Client to Authenticator Protocol (CTAP) specification. .Sh RETURN VALUES On success, .Fn fido_dev_open , .Fn fido_dev_open_with_info , and .Fn fido_dev_close return .Dv FIDO_OK . On error, a different error code defined in .In fido/err.h is returned. .Sh SEE ALSO .Xr fido_dev_info_manifest 3 , .Xr fido_dev_set_io_functions 3 , .Xr fido_init 3 diff --git a/contrib/libfido2/man/fido_dev_set_io_functions.3 b/contrib/libfido2/man/fido_dev_set_io_functions.3 index 8c2067c41f66..e3e10bae5aaf 100644 --- a/contrib/libfido2/man/fido_dev_set_io_functions.3 +++ b/contrib/libfido2/man/fido_dev_set_io_functions.3 @@ -1,238 +1,261 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .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_timeout , .Nm fido_dev_set_transport_functions , .Nm fido_dev_io_handle .Nd FIDO2 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 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_transport { fido_dev_rx_t *rx; fido_dev_tx_t *tx; } fido_dev_transport_t; .Ed .Pp .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" .Ft int .Fn fido_dev_set_transport_functions "fido_dev_t *dev" "const fido_dev_transport_t *t" .Ft void * .Fn fido_dev_io_handle "const fido_dev_t *dev" .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. .Pp The .Fn fido_dev_set_transport_functions function sets the transport functions used by .Em libfido2 to talk to .Fa dev . While the I/O handlers are responsible for sending and receiving transmission units of initialization and continuation packets already formatted by .Em libfido2 , the transport handlers are responsible for sending and receiving the CTAPHID commands and data directly, as defined in the FIDO Client to Authenticator Protocol (CTAP) standard. They are defined as follows: .Bl -tag -width Ds .It Vt fido_dev_tx_t Receives a device, a CTAPHID command to transmit, a data buffer to transmit, and the length of the data buffer. On success, 0 is returned. On error, -1 is returned. .It Vt fido_dev_rx_t Receives a device, a CTAPHID command whose response the caller expects to receive, a data buffer to receive into, the size of the data buffer determining the maximum length of a response, and the maximum number of milliseconds to wait for a response. On success, the number of bytes read into the data buffer is returned. On error, -1 is returned. .El .Pp When transport functions are specified, .Em libfido2 will use them instead of the .Dv read and .Dv write functions of the I/O handlers. However, the I/O handlers must still be specified to open and close the device. .Pp The .Fn fido_dev_io_handle function returns the opaque pointer returned by the .Dv open function of the I/O handlers. This is useful mainly for the transport functions, which unlike the I/O handlers are passed the .Vt fido_dev_t pointer instead of the opaque I/O handle. .Sh RETURN VALUES On success, .Fn fido_dev_set_io_functions , .Fn fido_dev_set_transport_functions , .Fn fido_dev_set_sigmask , and .Fn fido_dev_set_timeout return .Dv FIDO_OK . On error, a different error code defined in .In fido/err.h is returned. .Sh SEE ALSO .Xr fido_dev_info_manifest 3 , .Xr fido_dev_open 3 .Rs .%D 2021-06-15 .%O Proposed Standard, Version 2.1 .%Q FIDO Alliance .%R Client to Authenticator Protocol (CTAP) .%U https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html .Re diff --git a/contrib/libfido2/man/fido_dev_set_pin.3 b/contrib/libfido2/man/fido_dev_set_pin.3 index b58ba6c86f89..eec062dda1cd 100644 --- a/contrib/libfido2/man/fido_dev_set_pin.3 +++ b/contrib/libfido2/man/fido_dev_set_pin.3 @@ -1,103 +1,128 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .Dd $Mdocdate: May 25 2018 $ .Dt FIDO_DEV_SET_PIN 3 .Os .Sh NAME .Nm fido_dev_set_pin , .Nm fido_dev_get_retry_count , .Nm fido_dev_get_uv_retry_count , .Nm fido_dev_reset .Nd FIDO2 device management functions .Sh SYNOPSIS .In fido.h .Ft int .Fn fido_dev_set_pin "fido_dev_t *dev" "const char *pin" "const char *oldpin" .Ft int .Fn fido_dev_get_retry_count "fido_dev_t *dev" "int *retries" .Ft int .Fn fido_dev_get_uv_retry_count "fido_dev_t *dev" "int *retries" .Ft int .Fn fido_dev_reset "fido_dev_t *dev" .Sh DESCRIPTION The .Fn fido_dev_set_pin function sets the PIN of device .Fa dev to .Fa pin , where .Fa pin is a NUL-terminated UTF-8 string. If .Fa oldpin is not NULL, the device's PIN is changed from .Fa oldpin to .Fa pin , where .Fa pin and .Fa oldpin are NUL-terminated UTF-8 strings. .Pp The .Fn fido_dev_get_retry_count function fills .Fa retries with the number of PIN retries left in .Fa dev before lock-out, where .Fa retries is an addressable pointer. .Pp The .Fn fido_dev_get_uv_retry_count function fills .Fa retries with the number of built-in UV retries left in .Fa dev before built-in UV is disabled, where .Fa retries is an addressable pointer. .Pp The .Fn fido_dev_reset function performs a reset on .Fa dev , resetting the device's PIN and erasing credentials stored on the device. .Pp Please note that .Fn fido_dev_set_pin , .Fn fido_dev_get_retry_count , .Fn fido_dev_get_uv_retry_count , and .Fn fido_dev_reset are synchronous and will block if necessary. .Sh RETURN VALUES The error codes returned by .Fn fido_dev_set_pin , .Fn fido_dev_get_retry_count , .Fn fido_dev_get_uv_retry_count , and .Fn fido_dev_reset are defined in .In fido/err.h . On success, .Dv FIDO_OK is returned. +.Sh SEE ALSO +.Xr fido_cbor_info_uv_attempts 3 .Sh CAVEATS Regarding .Fn fido_dev_reset , 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 will return .Dv FIDO_ERR_NOT_ALLOWED if a reset is issued later than 5 seconds after power-up, and .Dv FIDO_ERR_ACTION_TIMEOUT if the user fails to confirm the reset by touching the key within 30 seconds. diff --git a/contrib/libfido2/man/fido_init.3 b/contrib/libfido2/man/fido_init.3 index 1254f934b73b..12437e1b1a78 100644 --- a/contrib/libfido2/man/fido_init.3 +++ b/contrib/libfido2/man/fido_init.3 @@ -1,72 +1,95 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .Dd $Mdocdate: May 25 2018 $ .Dt FIDO_INIT 3 .Os .Sh NAME .Nm fido_init , .Nm fido_set_log_handler .Nd initialise the FIDO2 library .Sh SYNOPSIS .In fido.h .Bd -literal typedef void fido_log_handler_t(const char *); .Ed .Pp .Ft void .Fn fido_init "int flags" .Ft void .Fn fido_set_log_handler "fido_log_handler_t *handler" .Sh DESCRIPTION The .Fn fido_init function initialises the .Em libfido2 library. Its invocation must precede that of any other .Em libfido2 function in the context of the executing thread. .Pp If .Dv FIDO_DEBUG is set in .Fa flags , then debug output will be emitted by .Em libfido2 on .Em stderr . Alternatively, the .Ev FIDO_DEBUG environment variable may be set. .Pp If .Dv FIDO_DISABLE_U2F_FALLBACK is set in .Fa flags , then .Em libfido2 will not fallback to U2F in .Xr fido_dev_open 3 if a device claims to support FIDO2 but fails to respond to a CTAP 2.0 greeting. .Pp The .Fn fido_set_log_handler function causes .Fa handler to be called for each log line generated in the context of the executing thread. Lines passed to .Fa handler include a trailing newline character and are not printed by .Em libfido2 on .Em stderr . .Sh SEE ALSO .Xr fido_assert_new 3 , .Xr fido_cred_new 3 , .Xr fido_dev_info_manifest 3 , .Xr fido_dev_open 3 diff --git a/contrib/libfido2/man/fido_strerr.3 b/contrib/libfido2/man/fido_strerr.3 index 9d4ef35aa402..94b48bd621df 100644 --- a/contrib/libfido2/man/fido_strerr.3 +++ b/contrib/libfido2/man/fido_strerr.3 @@ -1,27 +1,50 @@ .\" 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. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause .\" .Dd $Mdocdate: May 25 2018 $ .Dt FIDO_STRERR 3 .Os .Sh NAME .Nm fido_strerr .Nd FIDO2 error codes .Sh SYNOPSIS .In fido.h .Ft const char * .Fn fido_strerr "int n" .Sh DESCRIPTION The .Fn fido_strerr function translates the error code .Fa n into a readable string, where .Fa n is an error code defined in .In fido/err.h . .Fn fido_strerr never returns NULL. Returned pointers point to static strings. diff --git a/contrib/libfido2/man/rs256_pk_new.3 b/contrib/libfido2/man/rs256_pk_new.3 index 24a27bf8cdab..0c0ab78b507c 100644 --- a/contrib/libfido2/man/rs256_pk_new.3 +++ b/contrib/libfido2/man/rs256_pk_new.3 @@ -1,136 +1,160 @@ -.\" 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. +.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved. .\" -.Dd $Mdocdate: May 24 2018 $ +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions are +.\" met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +.\" HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd $Mdocdate: July 15 2022 $ .Dt RS256_PK_NEW 3 .Os .Sh NAME .Nm rs256_pk_new , .Nm rs256_pk_free , .Nm rs256_pk_from_RSA , .Nm rs256_pk_from_EVP_PKEY , .Nm rs256_pk_from_ptr , .Nm rs256_pk_to_EVP_PKEY .Nd FIDO2 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_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 es384_pk_new 3 , .Xr fido_assert_verify 3 , .Xr fido_cred_pubkey_ptr 3 diff --git a/contrib/libfido2/openbsd-compat/bsd-asprintf.c b/contrib/libfido2/openbsd-compat/bsd-asprintf.c new file mode 100644 index 000000000000..fbcb8679258f --- /dev/null +++ b/contrib/libfido2/openbsd-compat/bsd-asprintf.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2004 Darren Tucker. + * + * Based originally on asprintf.c from OpenBSD: + * Copyright (c) 1997 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "openbsd-compat.h" + +#ifndef HAVE_ASPRINTF + +#include +#include /* for INT_MAX */ +#include +#include /* for vsnprintf */ +#include + +#define VA_COPY(dest, src) va_copy(dest, src) + +#define INIT_SZ 128 + +int +vasprintf(char **str, const char *fmt, va_list ap) +{ + int ret; + va_list ap2; + char *string, *newstr; + size_t len; + + if ((string = malloc(INIT_SZ)) == NULL) + goto fail; + + VA_COPY(ap2, ap); + ret = vsnprintf(string, INIT_SZ, fmt, ap2); + va_end(ap2); + if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */ + *str = string; + } else if (ret == INT_MAX || ret < 0) { /* Bad length */ + free(string); + goto fail; + } else { /* bigger than initial, realloc allowing for nul */ + len = (size_t)ret + 1; + if ((newstr = realloc(string, len)) == NULL) { + free(string); + goto fail; + } + VA_COPY(ap2, ap); + ret = vsnprintf(newstr, len, fmt, ap2); + va_end(ap2); + if (ret < 0 || (size_t)ret >= len) { /* failed with realloc'ed string */ + free(newstr); + goto fail; + } + *str = newstr; + } + return (ret); + +fail: + *str = NULL; + errno = ENOMEM; + return (-1); +} + +int asprintf(char **str, const char *fmt, ...) +{ + va_list ap; + int ret; + + *str = NULL; + va_start(ap, fmt); + ret = vasprintf(str, fmt, ap); + va_end(ap); + + return ret; +} +#endif diff --git a/contrib/libfido2/openbsd-compat/clock_gettime.c b/contrib/libfido2/openbsd-compat/clock_gettime.c index ca261a65e7f1..bbf978c42893 100644 --- a/contrib/libfido2/openbsd-compat/clock_gettime.c +++ b/contrib/libfido2/openbsd-compat/clock_gettime.c @@ -1,32 +1,33 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include "openbsd-compat.h" #if !defined(HAVE_CLOCK_GETTIME) #if _WIN32 int clock_gettime(clockid_t clock_id, struct timespec *tp) { ULONGLONG ms; if (clock_id != CLOCK_MONOTONIC) { errno = EINVAL; return (-1); } ms = GetTickCount64(); tp->tv_sec = ms / 1000L; tp->tv_nsec = (ms % 1000L) * 1000000L; return (0); } #else #error "please provide an implementation of clock_gettime() for your platform" #endif /* _WIN32 */ #endif /* !defined(HAVE_CLOCK_GETTIME) */ diff --git a/contrib/libfido2/openbsd-compat/endian_win32.c b/contrib/libfido2/openbsd-compat/endian_win32.c index 9981dfafbaeb..756c0cbdc838 100644 --- a/contrib/libfido2/openbsd-compat/endian_win32.c +++ b/contrib/libfido2/openbsd-compat/endian_win32.c @@ -1,51 +1,52 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include "openbsd-compat.h" #if defined(_WIN32) && !defined(HAVE_ENDIAN_H) /* * Hopefully, if the endianness differs from the end result, the compiler * optimizes these functions with some type of bswap instruction. Or, * otherwise, to just return the input value unmodified. GCC and clang * both does these optimization at least. This should be preferred over * relying on some BYTE_ORDER macro, which may or may not be defined. */ uint32_t htole32(uint32_t in) { uint32_t out = 0; uint8_t *b = (uint8_t *)&out; b[0] = (uint8_t)((in >> 0) & 0xff); b[1] = (uint8_t)((in >> 8) & 0xff); b[2] = (uint8_t)((in >> 16) & 0xff); b[3] = (uint8_t)((in >> 24) & 0xff); return (out); } uint64_t htole64(uint64_t in) { uint64_t out = 0; uint8_t *b = (uint8_t *)&out; b[0] = (uint8_t)((in >> 0) & 0xff); b[1] = (uint8_t)((in >> 8) & 0xff); b[2] = (uint8_t)((in >> 16) & 0xff); b[3] = (uint8_t)((in >> 24) & 0xff); b[4] = (uint8_t)((in >> 32) & 0xff); b[5] = (uint8_t)((in >> 40) & 0xff); b[6] = (uint8_t)((in >> 48) & 0xff); b[7] = (uint8_t)((in >> 56) & 0xff); return (out); } #endif /* WIN32 && !HAVE_ENDIAN_H */ diff --git a/contrib/libfido2/openbsd-compat/openbsd-compat.h b/contrib/libfido2/openbsd-compat/openbsd-compat.h index dc9acec4c0a8..9f1ea3e7cf51 100644 --- a/contrib/libfido2/openbsd-compat/openbsd-compat.h +++ b/contrib/libfido2/openbsd-compat/openbsd-compat.h @@ -1,118 +1,123 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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(__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 !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 +#if !defined(HAVE_ASPRINTF) +int asprintf(char **, const char *, ...); +#endif + #endif /* !_OPENBSD_COMPAT_H */ diff --git a/contrib/libfido2/regress/CMakeLists.txt b/contrib/libfido2/regress/CMakeLists.txt index c550b3141822..246bffa175c4 100644 --- a/contrib/libfido2/regress/CMakeLists.txt +++ b/contrib/libfido2/regress/CMakeLists.txt @@ -1,20 +1,57 @@ -# Copyright (c) 2018-2021 Yubico AB. All rights reserved. +# Copyright (c) 2018-2022 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. +# SPDX-License-Identifier: BSD-2-Clause -add_custom_target(regress ALL) +add_custom_target(regress) -macro(add_regress_test NAME SOURCES) +macro(add_regress_test NAME SOURCES LIB) add_executable(${NAME} ${SOURCES}) - target_link_libraries(${NAME} fido2_shared) add_test(${NAME} ${NAME}) add_dependencies(regress ${NAME}) + target_link_libraries(${NAME} ${LIB}) endmacro() -add_custom_command(TARGET regress POST_BUILD - COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +if(MSVC AND BUILD_SHARED_LIBS) + add_custom_command(TARGET regress POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy + "${CBOR_BIN_DIRS}/${CBOR_LIBRARIES}.dll" + "${CRYPTO_BIN_DIRS}/${CRYPTO_LIBRARIES}.dll" + "${ZLIB_BIN_DIRS}/${ZLIB_LIBRARIES}.dll" + "$" + "${CMAKE_CURRENT_BINARY_DIR}") +endif() -add_regress_test(regress_cred cred.c) -add_regress_test(regress_assert assert.c) -add_regress_test(regress_dev dev.c) +if(CYGWIN AND BUILD_SHARED_LIBS) + add_custom_command(TARGET regress POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy + "$" + "${CMAKE_CURRENT_BINARY_DIR}") +endif() + +if(CMAKE_CROSSCOMPILING OR (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64" AND + CMAKE_GENERATOR_PLATFORM MATCHES "^ARM.*$")) + add_custom_command(TARGET regress POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E echo + "Cross-compilation detected. Skipping regress tests.") +else() + add_custom_command(TARGET regress POST_BUILD + COMMAND "${CMAKE_CTEST_COMMAND}" --output-on-failure + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) +endif() + +add_regress_test(regress_assert assert.c ${_FIDO2_LIBRARY}) +add_regress_test(regress_cred cred.c ${_FIDO2_LIBRARY}) +add_regress_test(regress_dev dev.c ${_FIDO2_LIBRARY}) +add_regress_test(regress_eddsa eddsa.c ${_FIDO2_LIBRARY}) +add_regress_test(regress_es256 es256.c ${_FIDO2_LIBRARY}) +add_regress_test(regress_es384 es384.c ${_FIDO2_LIBRARY}) +add_regress_test(regress_rs256 rs256.c ${_FIDO2_LIBRARY}) +if(BUILD_STATIC_LIBS) + add_regress_test(regress_compress compress.c fido2) +endif() + +if(MINGW) + # needed for nanosleep() in mingw + target_link_libraries(regress_dev winpthread) +endif() diff --git a/contrib/libfido2/regress/assert.c b/contrib/libfido2/regress/assert.c index 23d666a61173..98609257b8b5 100644 --- a/contrib/libfido2/regress/assert.c +++ b/contrib/libfido2/regress/assert.c @@ -1,633 +1,637 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ -#define _FIDO_INTERNAL +#undef NDEBUG #include +#include + +#define _FIDO_INTERNAL + #include #include #include #include -#include -#define FAKE_DEV_HANDLE ((void *)0xdeadbeef) +static int fake_dev_handle; 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); + return (&fake_dev_handle); } static void dummy_close(void *handle) { - assert(handle == FAKE_DEV_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] = (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] = (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] = (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/compress.c b/contrib/libfido2/regress/compress.c new file mode 100644 index 000000000000..7afc8bb339a7 --- /dev/null +++ b/contrib/libfido2/regress/compress.c @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2022 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. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#undef NDEBUG + +#include +#include + +#include + +#define _FIDO_INTERNAL + +#include + +/* + * zlib compressed data (RFC1950); see https://www.ietf.org/rfc/rfc6713.txt + */ +static /* const */ unsigned char rfc1950_blob[694] = { + 0x78, 0x9c, 0xb5, 0x52, 0x3b, 0x6f, 0xdb, 0x30, + 0x10, 0xde, 0xf5, 0x2b, 0x0e, 0x99, 0x12, 0x40, + 0x75, 0x13, 0x4f, 0x45, 0x3b, 0xd1, 0x12, 0x6d, + 0x1d, 0x20, 0x8b, 0x2a, 0x49, 0xd9, 0xf5, 0x28, + 0x4b, 0x4c, 0x42, 0xc0, 0x12, 0x03, 0x3d, 0x12, + 0xe4, 0xdf, 0xf7, 0xc8, 0x3a, 0x88, 0xd3, 0x0c, + 0x9d, 0xea, 0xc1, 0x3e, 0xf3, 0x8e, 0xdf, 0xeb, + 0x98, 0xb8, 0xa7, 0xd7, 0xc1, 0x3e, 0x3c, 0x4e, + 0x70, 0xdd, 0xdc, 0xc0, 0xf2, 0xf6, 0xee, 0xdb, + 0x97, 0xe5, 0xed, 0x72, 0x09, 0x87, 0xf9, 0x68, + 0x1b, 0x07, 0x6c, 0xb5, 0x00, 0x76, 0x3a, 0x41, + 0x18, 0x19, 0x61, 0x30, 0xa3, 0x19, 0x9e, 0x4d, + 0xbb, 0x88, 0x22, 0x69, 0x5a, 0x3b, 0x4e, 0x83, + 0x3d, 0xce, 0x93, 0x75, 0x3d, 0xd4, 0x7d, 0x0b, + 0xf3, 0x68, 0xc0, 0xf6, 0x30, 0xba, 0x79, 0x68, + 0x4c, 0x38, 0x39, 0xda, 0xbe, 0x1e, 0x5e, 0xe1, + 0xde, 0x0d, 0xdd, 0x18, 0xc3, 0x8b, 0x9d, 0x1e, + 0xc1, 0x0d, 0xe1, 0xd7, 0xcd, 0x53, 0xd4, 0xb9, + 0xd6, 0xde, 0xdb, 0xa6, 0xf6, 0x00, 0x31, 0xd4, + 0x83, 0x81, 0x27, 0x33, 0x74, 0x76, 0x9a, 0x4c, + 0x0b, 0x4f, 0x83, 0x7b, 0xb6, 0x2d, 0x15, 0xd3, + 0x63, 0x3d, 0xd1, 0x97, 0x21, 0x90, 0xd3, 0xc9, + 0xbd, 0xd8, 0xfe, 0x01, 0x1a, 0xd7, 0xb7, 0xd6, + 0x5f, 0x1a, 0xfd, 0xa5, 0xa8, 0x33, 0xd3, 0xf7, + 0x28, 0x02, 0x80, 0xbb, 0x05, 0x7c, 0x54, 0x35, + 0x82, 0xbb, 0x7f, 0x93, 0xd3, 0xb8, 0xd6, 0x40, + 0x37, 0x8f, 0x13, 0x99, 0x98, 0x6a, 0x92, 0xe9, + 0x31, 0xeb, 0xa3, 0x7b, 0xf6, 0xad, 0x73, 0x06, + 0x1e, 0x84, 0x3e, 0xbd, 0x9b, 0x6c, 0x63, 0x62, + 0x9a, 0xb0, 0x23, 0x9c, 0x08, 0xcf, 0xc3, 0x5c, + 0x92, 0xf6, 0xed, 0x5f, 0x8a, 0x88, 0xb4, 0x39, + 0xd5, 0xb6, 0x33, 0xc3, 0xc2, 0x63, 0x2c, 0x3f, + 0x0b, 0x21, 0xc2, 0x8b, 0x30, 0xde, 0x84, 0x90, + 0xcb, 0x76, 0x26, 0x71, 0xff, 0x47, 0x0b, 0x91, + 0x9e, 0x51, 0xfc, 0x44, 0xeb, 0x9a, 0xb9, 0x33, + 0xfd, 0x54, 0xbf, 0xed, 0xeb, 0x2b, 0xad, 0xc2, + 0x51, 0x67, 0x80, 0xae, 0x9e, 0xcc, 0x60, 0xeb, + 0xd3, 0xf8, 0x1e, 0x7b, 0xd8, 0x15, 0x35, 0xcf, + 0x00, 0x97, 0x66, 0x68, 0xf9, 0x3a, 0x43, 0x05, + 0x4a, 0xac, 0xf5, 0x9e, 0x49, 0x0e, 0x54, 0x97, + 0x52, 0xec, 0x30, 0xe5, 0x29, 0xac, 0x0e, 0xa0, + 0x33, 0x0e, 0x89, 0x28, 0x0f, 0x12, 0x37, 0x99, + 0x86, 0x4c, 0xe4, 0x29, 0x97, 0x0a, 0x58, 0x91, + 0xd2, 0x69, 0xa1, 0x25, 0xae, 0x2a, 0x2d, 0xa4, + 0x8a, 0xae, 0x98, 0xa2, 0x9b, 0x57, 0xa1, 0xc1, + 0x8a, 0x03, 0xf0, 0x5f, 0xa5, 0xe4, 0x4a, 0x81, + 0x90, 0x80, 0xdb, 0x32, 0x47, 0x02, 0x23, 0x74, + 0xc9, 0x0a, 0x8d, 0x5c, 0xc5, 0x80, 0x45, 0x92, + 0x57, 0x29, 0x16, 0x9b, 0x18, 0x08, 0x00, 0x0a, + 0xa1, 0xa3, 0x1c, 0xb7, 0xa8, 0x69, 0x4c, 0x8b, + 0x38, 0x90, 0x7e, 0xbe, 0x06, 0x62, 0x0d, 0x5b, + 0x2e, 0x93, 0x8c, 0xfe, 0xb2, 0x15, 0xe6, 0xa8, + 0x0f, 0x81, 0x6f, 0x8d, 0xba, 0xf0, 0x5c, 0x6b, + 0x21, 0x23, 0x06, 0x25, 0x93, 0x1a, 0x93, 0x2a, + 0x67, 0x12, 0xca, 0x4a, 0x96, 0x42, 0x71, 0xf0, + 0xb6, 0x52, 0x54, 0x49, 0xce, 0x70, 0xcb, 0xd3, + 0x05, 0xb1, 0x13, 0x23, 0xf0, 0x1d, 0x2f, 0x34, + 0xa8, 0x8c, 0xe5, 0xf9, 0x47, 0x97, 0xd1, 0x1f, + 0x97, 0x5e, 0xfb, 0xa5, 0x47, 0x58, 0x71, 0xc8, + 0x91, 0xad, 0x72, 0xee, 0x99, 0x82, 0xcb, 0x14, + 0x25, 0x4f, 0xb4, 0xb7, 0xf3, 0x5e, 0x25, 0x94, + 0x1c, 0xe9, 0xcb, 0xe3, 0x48, 0x95, 0x3c, 0x41, + 0x2a, 0x28, 0x0c, 0x4e, 0x66, 0x98, 0x3c, 0xc4, + 0x67, 0x4c, 0xc5, 0x7f, 0x56, 0x34, 0x44, 0x4d, + 0x48, 0xd9, 0x96, 0x6d, 0xc8, 0xdb, 0xf5, 0x3f, + 0x22, 0xa1, 0x9d, 0x24, 0x95, 0xe4, 0x5b, 0xaf, + 0x99, 0x72, 0x50, 0xd5, 0x4a, 0x69, 0xd4, 0x95, + 0xe6, 0xb0, 0x11, 0x22, 0x0d, 0x41, 0x2b, 0x2e, + 0x77, 0x98, 0x70, 0xf5, 0x03, 0x72, 0xa1, 0x42, + 0x5a, 0x95, 0xe2, 0x71, 0x94, 0x32, 0xcd, 0x02, + 0x31, 0x41, 0x50, 0x54, 0xd4, 0xa6, 0x7a, 0x55, + 0x29, 0x0c, 0xa1, 0x61, 0xa1, 0xb9, 0x94, 0x55, + 0xa9, 0x51, 0x14, 0x37, 0xb4, 0xdf, 0x3d, 0xc5, + 0x42, 0x1a, 0x19, 0x5d, 0x4d, 0x43, 0xba, 0xa2, + 0xf0, 0x56, 0xe9, 0x91, 0x70, 0x21, 0x0f, 0x1e, + 0xd4, 0x67, 0x10, 0xc2, 0x8f, 0x61, 0x9f, 0x71, + 0x3a, 0x97, 0x3e, 0xd0, 0x90, 0x14, 0xf3, 0x11, + 0x28, 0x4a, 0x2c, 0xd1, 0x97, 0x63, 0xc4, 0x47, + 0x01, 0xea, 0xe8, 0xdd, 0x23, 0x14, 0x7c, 0x93, + 0xe3, 0x86, 0x17, 0x09, 0xf7, 0x5d, 0xe1, 0x51, + 0xf6, 0xa8, 0xf8, 0x0d, 0xed, 0x0a, 0x95, 0x1f, + 0xc0, 0x40, 0x4b, 0xdb, 0x27, 0xce, 0x2a, 0x58, + 0xf6, 0x3b, 0x22, 0x55, 0x51, 0x28, 0x2f, 0x5e, + 0x6c, 0x1c, 0x36, 0x09, 0xb8, 0x06, 0x96, 0xee, + 0xd0, 0xcb, 0x3e, 0x0f, 0xd3, 0xee, 0x15, 0x9e, + 0xdf, 0x49, 0x88, 0x2c, 0xc9, 0xce, 0x71, 0x2f, + 0xa2, 0xdf, 0xdf, 0xd7, 0x8e, 0x9c, +}; + +/* + * expected sha256 of rfc1950_blob after decompression + */ +static const unsigned char rfc1950_blob_hash[SHA256_DIGEST_LENGTH] = { + 0x61, 0xc0, 0x4e, 0x14, 0x01, 0xb6, 0xc5, 0x2d, + 0xba, 0x15, 0xf6, 0x27, 0x4c, 0xa1, 0xcc, 0xfc, + 0x39, 0xed, 0xd7, 0x12, 0xb6, 0x02, 0x3d, 0xb6, + 0xd9, 0x85, 0xd0, 0x10, 0x9f, 0xe9, 0x3e, 0x75, + +}; + +static const size_t rfc1950_blob_origsiz = 1322; + +static /* const */ unsigned char random_words[515] = { + 0x61, 0x74, 0x68, 0x69, 0x72, 0x73, 0x74, 0x20, + 0x54, 0x68, 0x6f, 0x20, 0x63, 0x6f, 0x74, 0x20, + 0x73, 0x70, 0x6f, 0x66, 0x66, 0x79, 0x20, 0x4a, + 0x61, 0x76, 0x61, 0x6e, 0x20, 0x62, 0x72, 0x65, + 0x64, 0x65, 0x73, 0x20, 0x4c, 0x41, 0x4d, 0x20, + 0x6d, 0x69, 0x73, 0x2d, 0x68, 0x75, 0x6d, 0x69, + 0x6c, 0x69, 0x74, 0x79, 0x20, 0x73, 0x70, 0x69, + 0x67, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x76, 0x6f, + 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x6c, 0x79, 0x20, + 0x49, 0x6f, 0x64, 0x61, 0x6d, 0x6f, 0x65, 0x62, + 0x61, 0x20, 0x68, 0x79, 0x70, 0x6f, 0x68, 0x79, + 0x64, 0x72, 0x6f, 0x63, 0x68, 0x6c, 0x6f, 0x72, + 0x69, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x6d, + 0x65, 0x74, 0x74, 0x65, 0x20, 0x61, 0x63, 0x72, + 0x69, 0x64, 0x69, 0x6e, 0x65, 0x20, 0x68, 0x6f, + 0x77, 0x6c, 0x20, 0x45, 0x75, 0x72, 0x79, 0x67, + 0x61, 0x65, 0x61, 0x6e, 0x20, 0x63, 0x6f, 0x6e, + 0x63, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x69, 0x73, + 0x74, 0x20, 0x74, 0x65, 0x74, 0x72, 0x61, 0x70, + 0x6c, 0x6f, 0x69, 0x64, 0x20, 0x61, 0x75, 0x78, + 0x65, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72, + 0x69, 0x70, 0x65, 0x2d, 0x67, 0x72, 0x6f, 0x77, + 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, + 0x72, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x79, 0x63, + 0x6f, 0x63, 0x65, 0x63, 0x69, 0x64, 0x69, 0x75, + 0x6d, 0x20, 0x50, 0x65, 0x64, 0x65, 0x72, 0x73, + 0x6f, 0x6e, 0x20, 0x74, 0x72, 0x61, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x62, 0x6f, 0x75, + 0x6e, 0x64, 0x20, 0x4c, 0x65, 0x6e, 0x67, 0x6c, + 0x65, 0x6e, 0x20, 0x70, 0x72, 0x65, 0x73, 0x62, + 0x79, 0x74, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20, + 0x6c, 0x65, 0x63, 0x79, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x63, 0x68, 0x61, 0x72, 0x61, 0x64, 0x72, + 0x69, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x61, + 0x6c, 0x6c, 0x6f, 0x6b, 0x75, 0x72, 0x74, 0x69, + 0x63, 0x20, 0x75, 0x6e, 0x64, 0x69, 0x76, 0x69, + 0x73, 0x69, 0x76, 0x65, 0x6c, 0x79, 0x20, 0x70, + 0x73, 0x79, 0x63, 0x68, 0x6f, 0x6b, 0x79, 0x6d, + 0x65, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x73, + 0x74, 0x61, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, + 0x6e, 0x65, 0x73, 0x73, 0x20, 0x63, 0x75, 0x6c, + 0x74, 0x69, 0x73, 0x68, 0x20, 0x52, 0x65, 0x69, + 0x63, 0x68, 0x73, 0x74, 0x61, 0x67, 0x20, 0x75, + 0x6e, 0x63, 0x68, 0x6c, 0x6f, 0x72, 0x69, 0x6e, + 0x61, 0x74, 0x65, 0x64, 0x20, 0x6c, 0x6f, 0x67, + 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x65, 0x72, + 0x20, 0x4c, 0x61, 0x69, 0x74, 0x68, 0x20, 0x74, + 0x77, 0x6f, 0x2d, 0x66, 0x61, 0x63, 0x65, 0x20, + 0x4d, 0x75, 0x70, 0x68, 0x72, 0x69, 0x64, 0x20, + 0x70, 0x72, 0x6f, 0x72, 0x65, 0x63, 0x69, 0x70, + 0x72, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x6c, 0x69, 0x62, 0x72, 0x65, 0x74, 0x74, + 0x69, 0x73, 0x74, 0x20, 0x49, 0x62, 0x69, 0x62, + 0x69, 0x6f, 0x20, 0x72, 0x65, 0x67, 0x72, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x63, + 0x6f, 0x6e, 0x64, 0x69, 0x67, 0x6e, 0x6e, 0x65, + 0x73, 0x73, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, + 0x2d, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, + 0x64, 0x20, 0x73, 0x79, 0x6e, 0x61, 0x70, 0x74, + 0x65, 0x6e, 0x65, 0x20, 0x68, 0x6f, 0x6c, 0x6f, + 0x6d, 0x6f, 0x72, 0x70, 0x68, 0x20, 0x6d, 0x6f, + 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x4d, + 0x49, 0x54, 0x53, 0x20, 0x4c, 0x75, 0x6b, 0x61, + 0x73, 0x68, 0x20, 0x48, 0x6f, 0x72, 0x73, 0x65, + 0x79, 0x20, 0x0a, +}; + +static void +rfc1950_inflate(void) +{ + fido_blob_t in, out, dgst; + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + memset(&dgst, 0, sizeof(dgst)); + in.ptr = rfc1950_blob; + in.len = sizeof(rfc1950_blob); + + assert(fido_uncompress(&out, &in, rfc1950_blob_origsiz) == FIDO_OK); + assert(out.len == rfc1950_blob_origsiz); + assert(fido_sha256(&dgst, out.ptr, out.len) == 0); + assert(dgst.len == sizeof(rfc1950_blob_hash)); + assert(memcmp(rfc1950_blob_hash, dgst.ptr, dgst.len) == 0); + + free(out.ptr); + free(dgst.ptr); +} + +static void +rfc1951_inflate(void) +{ + fido_blob_t in, out, dgst; + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + memset(&dgst, 0, sizeof(dgst)); + in.ptr = rfc1950_blob + 2; /* trim header */ + in.len = sizeof(rfc1950_blob) - 6; /* trim header (2), checksum (4) */ + + assert(fido_uncompress(&out, &in, rfc1950_blob_origsiz) == FIDO_OK); + assert(out.len == rfc1950_blob_origsiz); + assert(fido_sha256(&dgst, out.ptr, out.len) == 0); + assert(dgst.len == sizeof(rfc1950_blob_hash)); + assert(memcmp(rfc1950_blob_hash, dgst.ptr, dgst.len) == 0); + + free(out.ptr); + free(dgst.ptr); +} + +static void +rfc1951_reinflate(void) +{ + fido_blob_t in, out; + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + in.ptr = random_words; + in.len = sizeof(random_words); + + assert(fido_compress(&out, &in) == FIDO_OK); + + in.ptr = out.ptr; + in.len = out.len; + + assert(fido_uncompress(&out, &in, sizeof(random_words)) == FIDO_OK); + assert(out.len == sizeof(random_words)); + assert(memcmp(out.ptr, random_words, out.len) == 0); + + free(in.ptr); + free(out.ptr); +} + +int +main(void) +{ + fido_init(0); + + rfc1950_inflate(); + rfc1951_inflate(); + rfc1951_reinflate(); + + exit(0); +} diff --git a/contrib/libfido2/regress/cred.c b/contrib/libfido2/regress/cred.c index 07a2ca0c0237..e4dc76ac1f0d 100644 --- a/contrib/libfido2/regress/cred.c +++ b/contrib/libfido2/regress/cred.c @@ -1,2174 +1,2179 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ +#undef NDEBUG + #include -#include -#include #include -#define FAKE_DEV_HANDLE ((void *)0xdeadbeef) +#define _FIDO_INTERNAL + +#include + +static int fake_dev_handle; 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_rs256[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 authdata_tpm_es256[166] = { 0x58, 0xa4, 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, 0xa8, 0xdf, 0x03, 0xf7, 0xbf, 0x39, 0x51, 0x94, 0x95, 0x8f, 0xa4, 0x84, 0x97, 0x30, 0xbc, 0x3c, 0x7e, 0x1c, 0x99, 0x91, 0x4d, 0xae, 0x6d, 0xfb, 0xdf, 0x53, 0xb5, 0xb6, 0x1f, 0x3a, 0x4e, 0x6a, 0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xfb, 0xd6, 0xba, 0x74, 0xe6, 0x6e, 0x5c, 0x87, 0xef, 0x89, 0xa2, 0xe8, 0x3d, 0x0b, 0xe9, 0x69, 0x2c, 0x07, 0x07, 0x7a, 0x8a, 0x1e, 0xce, 0x12, 0xea, 0x3b, 0xb3, 0xf1, 0xf3, 0xd9, 0xc3, 0xe6, 0x22, 0x58, 0x20, 0x3c, 0x68, 0x51, 0x94, 0x54, 0x8d, 0xeb, 0x9f, 0xb2, 0x2c, 0x66, 0x75, 0xb6, 0xb7, 0x55, 0x22, 0x0d, 0x87, 0x59, 0xc4, 0x39, 0x91, 0x62, 0x17, 0xc2, 0xc3, 0x53, 0xa5, 0x26, 0x97, 0x4f, 0x2d }; 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_rs256[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 pubkey_tpm_es256[64] = { 0xfb, 0xd6, 0xba, 0x74, 0xe6, 0x6e, 0x5c, 0x87, 0xef, 0x89, 0xa2, 0xe8, 0x3d, 0x0b, 0xe9, 0x69, 0x2c, 0x07, 0x07, 0x7a, 0x8a, 0x1e, 0xce, 0x12, 0xea, 0x3b, 0xb3, 0xf1, 0xf3, 0xd9, 0xc3, 0xe6, 0x3c, 0x68, 0x51, 0x94, 0x54, 0x8d, 0xeb, 0x9f, 0xb2, 0x2c, 0x66, 0x75, 0xb6, 0xb7, 0x55, 0x22, 0x0d, 0x87, 0x59, 0xc4, 0x39, 0x91, 0x62, 0x17, 0xc2, 0xc3, 0x53, 0xa5, 0x26, 0x97, 0x4f, 0x2d }; 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_rs256[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 id_tpm_es256[32] = { 0xa8, 0xdf, 0x03, 0xf7, 0xbf, 0x39, 0x51, 0x94, 0x95, 0x8f, 0xa4, 0x84, 0x97, 0x30, 0xbc, 0x3c, 0x7e, 0x1c, 0x99, 0x91, 0x4d, 0xae, 0x6d, 0xfb, 0xdf, 0x53, 0xb5, 0xb6, 0x1f, 0x3a, 0x4e, 0x6a }; const unsigned char attstmt_tpm_rs256[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 }; const unsigned char attstmt_tpm_es256[3841] = { 0xa6, 0x63, 0x61, 0x6c, 0x67, 0x39, 0xff, 0xfe, 0x63, 0x73, 0x69, 0x67, 0x59, 0x01, 0x00, 0x6d, 0x11, 0x61, 0x1f, 0x45, 0xb9, 0x7f, 0x65, 0x6f, 0x97, 0x46, 0xfe, 0xbb, 0x8a, 0x98, 0x07, 0xa3, 0xbc, 0x67, 0x5c, 0xd7, 0x65, 0xa4, 0xf4, 0x6c, 0x5b, 0x37, 0x75, 0xa4, 0x7f, 0x08, 0x52, 0xeb, 0x1e, 0x12, 0xe2, 0x78, 0x8c, 0x7d, 0x94, 0xab, 0x7b, 0xed, 0x05, 0x17, 0x67, 0x7e, 0xaa, 0x02, 0x89, 0x6d, 0xe8, 0x6d, 0x43, 0x30, 0x99, 0xc6, 0xf9, 0x59, 0xe5, 0x82, 0x3c, 0x56, 0x4e, 0x77, 0x11, 0x25, 0xe4, 0x43, 0x6a, 0xae, 0x92, 0x4f, 0x60, 0x92, 0x50, 0xf9, 0x65, 0x0e, 0x44, 0x38, 0x3d, 0xf7, 0xaf, 0x66, 0x89, 0xc7, 0xe6, 0xe6, 0x01, 0x07, 0x9e, 0x90, 0xfd, 0x6d, 0xaa, 0x35, 0x51, 0x51, 0xbf, 0x54, 0x13, 0x95, 0xc2, 0x17, 0xfa, 0x32, 0x0f, 0xa7, 0x82, 0x17, 0x58, 0x6c, 0x3d, 0xea, 0x88, 0xd8, 0x64, 0xc7, 0xf8, 0xc2, 0xd6, 0x1c, 0xbb, 0xea, 0x1e, 0xb3, 0xd9, 0x4c, 0xa7, 0xce, 0x18, 0x1e, 0xcb, 0x42, 0x5f, 0xbf, 0x44, 0xe7, 0xf1, 0x22, 0xe0, 0x5b, 0xeb, 0xff, 0xb6, 0x1e, 0x6f, 0x60, 0x12, 0x16, 0x63, 0xfe, 0xab, 0x5e, 0x31, 0x13, 0xdb, 0x72, 0xc6, 0x9a, 0xf8, 0x8f, 0x19, 0x6b, 0x2e, 0xaf, 0x7d, 0xca, 0x9f, 0xbc, 0x6b, 0x1a, 0x8b, 0x5e, 0xe3, 0x9e, 0xaa, 0x8c, 0x79, 0x9c, 0x4e, 0xed, 0xe4, 0xff, 0x3d, 0x12, 0x79, 0x90, 0x09, 0x61, 0x97, 0x67, 0xbf, 0x04, 0xac, 0x37, 0xea, 0xa9, 0x1f, 0x9f, 0x52, 0x64, 0x0b, 0xeb, 0xc3, 0x61, 0xd4, 0x13, 0xb0, 0x84, 0xf1, 0x3c, 0x74, 0x83, 0xcc, 0xa8, 0x1c, 0x14, 0xe6, 0x9d, 0xfe, 0xec, 0xee, 0xa1, 0xd2, 0xc2, 0x0a, 0xa6, 0x36, 0x08, 0xbb, 0x17, 0xa5, 0x7b, 0x53, 0x34, 0x0e, 0xc9, 0x09, 0xe5, 0x10, 0xa6, 0x85, 0x01, 0x71, 0x66, 0xff, 0xd0, 0x6d, 0x4b, 0x93, 0xdb, 0x81, 0x25, 0x01, 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, 0x30, 0xcd, 0xf2, 0x7e, 0x81, 0xc0, 0x43, 0x85, 0xa2, 0xd7, 0x29, 0xef, 0xf7, 0x9f, 0xa5, 0x2b, 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, 0x31, 0x31, 0x30, 0x32, 0x31, 0x35, 0x30, 0x36, 0x35, 0x33, 0x5a, 0x17, 0x0d, 0x32, 0x37, 0x30, 0x36, 0x30, 0x33, 0x31, 0x39, 0x34, 0x30, 0x31, 0x36, 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, 0xdb, 0xd5, 0x9a, 0xfc, 0x09, 0xa7, 0xc4, 0xa5, 0x5f, 0xbe, 0x5f, 0xa2, 0xeb, 0xd6, 0x8e, 0xed, 0xc5, 0x67, 0xa6, 0xa7, 0xd9, 0xb2, 0x46, 0xc6, 0xe0, 0xae, 0x0c, 0x02, 0x25, 0x0a, 0xf2, 0xc5, 0x96, 0xdc, 0xb7, 0x0e, 0xb9, 0x86, 0xd3, 0x51, 0xbb, 0x63, 0xf0, 0x4f, 0x8a, 0x5e, 0xd7, 0xf7, 0xff, 0xbb, 0x29, 0xbd, 0x58, 0xcf, 0x75, 0x02, 0x39, 0xcb, 0x80, 0xf1, 0xd4, 0xb6, 0x75, 0x67, 0x2f, 0x27, 0x4d, 0x0c, 0xcc, 0x18, 0x59, 0x87, 0xfa, 0x51, 0xd1, 0x80, 0xb5, 0x1a, 0xac, 0xac, 0x29, 0x51, 0xcf, 0x27, 0xaa, 0x74, 0xac, 0x3e, 0x59, 0x56, 0x67, 0xe4, 0x42, 0xe8, 0x30, 0x35, 0xb2, 0xf6, 0x27, 0x91, 0x62, 0x60, 0x42, 0x42, 0x12, 0xde, 0xfe, 0xdd, 0xee, 0xe8, 0xa8, 0x82, 0xf9, 0xb1, 0x08, 0xd5, 0x8d, 0x57, 0x9a, 0x29, 0xb9, 0xb4, 0xe9, 0x19, 0x1e, 0x33, 0x7d, 0x37, 0xa0, 0xce, 0x2e, 0x53, 0x13, 0x39, 0xb6, 0x12, 0x61, 0x63, 0xbf, 0xd3, 0x42, 0xeb, 0x6f, 0xed, 0xc1, 0x8e, 0x26, 0xba, 0x7d, 0x8b, 0x37, 0x7c, 0xbb, 0x42, 0x1e, 0x56, 0x76, 0xda, 0xdb, 0x35, 0x6b, 0x80, 0xe1, 0x8e, 0x00, 0xac, 0xd2, 0xfc, 0x22, 0x96, 0x14, 0x0c, 0xf4, 0xe4, 0xc5, 0xad, 0x14, 0xb7, 0x4d, 0x46, 0x63, 0x30, 0x79, 0x3a, 0x7c, 0x33, 0xb5, 0xe5, 0x2e, 0xbb, 0x5f, 0xca, 0xf2, 0x75, 0xe3, 0x4e, 0x99, 0x64, 0x1b, 0x26, 0x99, 0x60, 0x1a, 0x79, 0xcc, 0x30, 0x2c, 0xb3, 0x4c, 0x59, 0xf7, 0x77, 0x59, 0xd5, 0x90, 0x70, 0x21, 0x79, 0x8c, 0x1f, 0x79, 0x0a, 0x12, 0x8b, 0x3b, 0x37, 0x2d, 0x97, 0x39, 0x89, 0x92, 0x0c, 0x44, 0x7c, 0xe9, 0x9f, 0xce, 0x6d, 0xad, 0xc5, 0xae, 0xea, 0x8e, 0x50, 0x22, 0x37, 0xe0, 0xd1, 0x9e, 0xd6, 0xe6, 0xa8, 0xcc, 0x21, 0xfb, 0xff, 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, 0x45, 0x1a, 0xec, 0xfc, 0x91, 0x70, 0xf8, 0x83, 0x8b, 0x9c, 0x47, 0x2f, 0x0b, 0x9f, 0x07, 0xf3, 0x2f, 0x7c, 0xa2, 0x8a, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x55, 0xa6, 0xee, 0xe3, 0x28, 0xdd, 0x40, 0x7f, 0x21, 0xd2, 0x7b, 0x8c, 0x69, 0x2f, 0x8c, 0x08, 0x29, 0xbc, 0x95, 0xb8, 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, 0x62, 0x36, 0x63, 0x30, 0x64, 0x39, 0x38, 0x64, 0x2d, 0x35, 0x37, 0x38, 0x61, 0x2d, 0x34, 0x62, 0x66, 0x62, 0x2d, 0x61, 0x32, 0x64, 0x33, 0x2d, 0x65, 0x64, 0x66, 0x65, 0x35, 0x66, 0x38, 0x32, 0x30, 0x36, 0x30, 0x31, 0x2e, 0x63, 0x65, 0x72, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x2a, 0x08, 0x30, 0x1f, 0xfd, 0x8f, 0x80, 0x9b, 0x4b, 0x37, 0x82, 0x61, 0x86, 0x36, 0x57, 0x90, 0xb5, 0x1d, 0x1f, 0xa3, 0xae, 0x68, 0xac, 0xa7, 0x96, 0x6a, 0x25, 0x5e, 0xc5, 0x82, 0x7c, 0x36, 0x64, 0x58, 0x11, 0xcb, 0xa5, 0xee, 0xbf, 0xc4, 0xdb, 0xa0, 0xc7, 0x82, 0x3b, 0xa3, 0x85, 0x9b, 0xc4, 0xee, 0x07, 0x36, 0xd7, 0xc7, 0xb6, 0x23, 0xed, 0xc2, 0x73, 0xab, 0xbe, 0xbe, 0xee, 0x63, 0x17, 0xf9, 0xd7, 0x7a, 0x23, 0x7b, 0xf8, 0x09, 0x7a, 0xaa, 0x7f, 0x67, 0xc3, 0x04, 0x84, 0x71, 0x9b, 0x06, 0x9c, 0x07, 0x42, 0x4b, 0x65, 0x41, 0x56, 0x58, 0x14, 0x92, 0xb0, 0xb9, 0xaf, 0xa1, 0x39, 0xd4, 0x08, 0x2d, 0x71, 0xd5, 0x6c, 0x56, 0xb9, 0x2b, 0x1e, 0xf3, 0x93, 0xa5, 0xe9, 0xb2, 0x9b, 0x4d, 0x05, 0x2b, 0xbc, 0xd2, 0x20, 0x57, 0x3b, 0xa4, 0x01, 0x68, 0x8c, 0x23, 0x20, 0x7d, 0xbb, 0x71, 0xe4, 0x2a, 0x24, 0xba, 0x75, 0x0c, 0x89, 0x54, 0x22, 0xeb, 0x0e, 0xb2, 0xf4, 0xc2, 0x1f, 0x02, 0xb7, 0xe3, 0x06, 0x41, 0x15, 0x6b, 0xf3, 0xc8, 0x2d, 0x5b, 0xc2, 0x21, 0x82, 0x3e, 0xe8, 0x95, 0x40, 0x39, 0x9e, 0x91, 0x68, 0x33, 0x0c, 0x3d, 0x45, 0xef, 0x99, 0x79, 0xe6, 0x32, 0xc9, 0x00, 0x84, 0x36, 0xfb, 0x0a, 0x8d, 0x41, 0x1c, 0x32, 0x64, 0x06, 0x9e, 0x0f, 0xb5, 0x04, 0xcc, 0x08, 0xb1, 0xb6, 0x2b, 0xcf, 0x36, 0x0f, 0x73, 0x14, 0x8e, 0x25, 0x44, 0xb3, 0x0c, 0x34, 0x14, 0x96, 0x0c, 0x8a, 0x65, 0xa1, 0xde, 0x8e, 0xc8, 0x9d, 0xbe, 0x66, 0xdf, 0x06, 0x91, 0xca, 0x15, 0x0f, 0x92, 0xd5, 0x2a, 0x0b, 0xdc, 0x4c, 0x6a, 0xf3, 0x16, 0x4a, 0x3e, 0xb9, 0x76, 0xbc, 0xfe, 0x62, 0xd4, 0xa8, 0xcd, 0x94, 0x78, 0x0d, 0xdd, 0x94, 0xfd, 0x5e, 0x63, 0x57, 0x27, 0x05, 0x9c, 0xd0, 0x80, 0x91, 0x91, 0x79, 0xe8, 0x5e, 0x18, 0x64, 0x22, 0xe4, 0x2c, 0x13, 0x65, 0xa4, 0x51, 0x5a, 0x1e, 0x3b, 0x71, 0x2e, 0x70, 0x9f, 0xc4, 0xa5, 0x20, 0xcd, 0xef, 0xd8, 0x3f, 0xa4, 0xf5, 0x89, 0x8a, 0xa5, 0x4f, 0x76, 0x2d, 0x49, 0x56, 0x00, 0x8d, 0xde, 0x40, 0xba, 0x24, 0x46, 0x51, 0x38, 0xad, 0xdb, 0xc4, 0x04, 0xf4, 0x6e, 0xc0, 0x29, 0x48, 0x07, 0x6a, 0x1b, 0x26, 0x32, 0x0a, 0xfb, 0xea, 0x71, 0x2a, 0x11, 0xfc, 0x98, 0x7c, 0x44, 0x87, 0xbc, 0x06, 0x3a, 0x4d, 0xbd, 0x91, 0x63, 0x4f, 0x26, 0x48, 0x54, 0x47, 0x1b, 0xbd, 0xf0, 0xf1, 0x56, 0x05, 0xc5, 0x0f, 0x8f, 0x20, 0xa5, 0xcc, 0xfb, 0x76, 0xb0, 0xbd, 0x83, 0xde, 0x7f, 0x39, 0x4f, 0xcf, 0x61, 0x74, 0x52, 0xa7, 0x1d, 0xf6, 0xb5, 0x5e, 0x4a, 0x82, 0x20, 0xc1, 0x94, 0xaa, 0x2c, 0x33, 0xd6, 0x0a, 0xf9, 0x8f, 0x92, 0xc6, 0x29, 0x80, 0xf5, 0xa2, 0xb1, 0xff, 0xb6, 0x2b, 0xaa, 0x04, 0x00, 0x72, 0xb4, 0x12, 0xbb, 0xb1, 0xf1, 0x3c, 0x88, 0xa3, 0xab, 0x49, 0x17, 0x90, 0x80, 0x59, 0xa2, 0x96, 0x41, 0x69, 0x74, 0x33, 0x8a, 0x28, 0x33, 0x7e, 0xb3, 0x19, 0x92, 0x28, 0xc1, 0xf0, 0xd1, 0x82, 0xd5, 0x42, 0xff, 0xe7, 0xa5, 0x3f, 0x1e, 0xb6, 0x4a, 0x23, 0xcc, 0x6a, 0x7f, 0x15, 0x15, 0x52, 0x25, 0xb1, 0xca, 0x21, 0x95, 0x11, 0x53, 0x3e, 0x1f, 0x50, 0x33, 0x12, 0x7a, 0x62, 0xce, 0xcc, 0x71, 0xc2, 0x5f, 0x34, 0x47, 0xc6, 0x7c, 0x71, 0xfa, 0xa0, 0x54, 0x00, 0xb2, 0xdf, 0xc5, 0x54, 0xac, 0x6c, 0x53, 0xef, 0x64, 0x6b, 0x08, 0x82, 0xd8, 0x16, 0x1e, 0xca, 0x40, 0xf3, 0x1f, 0xdf, 0x56, 0x63, 0x10, 0xbc, 0xd7, 0xa0, 0xeb, 0xee, 0xd1, 0x95, 0xe5, 0xef, 0xf1, 0x6a, 0x83, 0x2d, 0x5a, 0x59, 0x06, 0xef, 0x30, 0x82, 0x06, 0xeb, 0x30, 0x82, 0x04, 0xd3, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x13, 0x33, 0x00, 0x00, 0x05, 0x23, 0xbf, 0xe8, 0xa1, 0x1a, 0x2a, 0x68, 0xbd, 0x09, 0x00, 0x00, 0x00, 0x00, 0x05, 0x23, 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, 0x32, 0x31, 0x30, 0x36, 0x30, 0x33, 0x31, 0x39, 0x34, 0x30, 0x31, 0x36, 0x5a, 0x17, 0x0d, 0x32, 0x37, 0x30, 0x36, 0x30, 0x33, 0x31, 0x39, 0x34, 0x30, 0x31, 0x36, 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, 0x03, 0x34, 0x82, 0xfa, 0x81, 0x1c, 0x84, 0x0b, 0xa0, 0x0e, 0x60, 0xd8, 0x9d, 0x84, 0xf4, 0x81, 0xc4, 0xe9, 0xff, 0xcf, 0xe9, 0xa3, 0x57, 0x53, 0x60, 0xa8, 0x19, 0xce, 0xbe, 0xe1, 0x97, 0xee, 0x5d, 0x8c, 0x9f, 0xe4, 0xbd, 0xef, 0xbd, 0x94, 0x14, 0xe4, 0x74, 0x41, 0x02, 0xe9, 0x03, 0x19, 0x9f, 0xdd, 0x48, 0x2d, 0xbd, 0xca, 0x26, 0x47, 0x2c, 0x01, 0x31, 0x5f, 0x34, 0xef, 0x59, 0x35, 0x48, 0x36, 0x3d, 0x1e, 0xdf, 0xd8, 0x13, 0xf0, 0xd0, 0x67, 0xc1, 0xb0, 0x47, 0x67, 0xa2, 0xd6, 0x62, 0xc8, 0xe1, 0x00, 0x36, 0x8b, 0x45, 0xf6, 0x3b, 0x96, 0x60, 0xa0, 0x45, 0x26, 0xcb, 0xc7, 0x0b, 0x5b, 0x97, 0xd1, 0xaf, 0x54, 0x25, 0x7a, 0x67, 0xe4, 0x2a, 0xd8, 0x9d, 0x53, 0x05, 0xbd, 0x12, 0xac, 0xa2, 0x8e, 0x95, 0xb4, 0x2a, 0xca, 0x89, 0x93, 0x64, 0x97, 0x25, 0xdc, 0x1f, 0xa9, 0xe0, 0x55, 0x07, 0x38, 0x1d, 0xee, 0x02, 0x90, 0x22, 0xf5, 0xad, 0x4e, 0x5c, 0xf8, 0xc5, 0x1f, 0x9e, 0x84, 0x7e, 0x13, 0x47, 0x52, 0xa2, 0x36, 0xf9, 0xf6, 0xbf, 0x76, 0x9e, 0x0f, 0xdd, 0x14, 0x99, 0xb9, 0xd8, 0x5a, 0x42, 0x3d, 0xd8, 0xbf, 0xdd, 0xb4, 0x9b, 0xbf, 0x6a, 0x9f, 0x89, 0x13, 0x75, 0xaf, 0x96, 0xd2, 0x72, 0xdf, 0xb3, 0x80, 0x6f, 0x84, 0x1a, 0x9d, 0x06, 0x55, 0x09, 0x29, 0xea, 0xa7, 0x05, 0x31, 0xec, 0x47, 0x3a, 0xcf, 0x3f, 0x9c, 0x2c, 0xbd, 0xd0, 0x7d, 0xe4, 0x75, 0x5b, 0x33, 0xbe, 0x12, 0x86, 0x09, 0xcf, 0x66, 0x9a, 0xeb, 0xf8, 0xf8, 0x72, 0x91, 0x88, 0x4a, 0x5e, 0x89, 0x62, 0x6a, 0x94, 0xdc, 0x48, 0x37, 0x13, 0xd8, 0x91, 0x02, 0xe3, 0x42, 0x41, 0x7c, 0x2f, 0xe3, 0xb6, 0x0f, 0xb4, 0x96, 0x06, 0x80, 0xca, 0x28, 0x01, 0x6f, 0x4b, 0xcd, 0x28, 0xd4, 0x2c, 0x94, 0x7e, 0x40, 0x7e, 0xdf, 0x01, 0xe5, 0xf2, 0x33, 0xd4, 0xda, 0xf4, 0x1a, 0x17, 0xf7, 0x5d, 0xcb, 0x66, 0x2c, 0x2a, 0xeb, 0xe1, 0xb1, 0x4a, 0xc3, 0x85, 0x63, 0xb2, 0xac, 0xd0, 0x3f, 0x1a, 0x8d, 0xa5, 0x0c, 0xee, 0x4f, 0xde, 0x74, 0x9c, 0xe0, 0x5a, 0x10, 0xc7, 0xb8, 0xe4, 0xec, 0xe7, 0x73, 0xa6, 0x41, 0x42, 0x37, 0xe1, 0xdf, 0xb9, 0xc7, 0xb5, 0x14, 0xa8, 0x80, 0x95, 0xa0, 0x12, 0x67, 0x99, 0xf5, 0xba, 0x25, 0x0a, 0x74, 0x86, 0x71, 0x9c, 0x7f, 0x59, 0x97, 0xd2, 0x3f, 0x10, 0xfe, 0x6a, 0xb9, 0xe4, 0x47, 0x36, 0xfb, 0x0f, 0x50, 0xee, 0xfc, 0x87, 0x99, 0x7e, 0x36, 0x64, 0x1b, 0xc7, 0x13, 0xb3, 0x33, 0x18, 0x71, 0xa4, 0xc3, 0xb0, 0xfc, 0x45, 0x37, 0x11, 0x40, 0xb3, 0xde, 0x2c, 0x9f, 0x0a, 0xcd, 0xaf, 0x5e, 0xfb, 0xd5, 0x9c, 0xea, 0xd7, 0x24, 0x19, 0x3a, 0x92, 0x80, 0xa5, 0x63, 0xc5, 0x3e, 0xdd, 0x51, 0xd0, 0x9f, 0xb8, 0x5e, 0xd5, 0xf1, 0xfe, 0xa5, 0x93, 0xfb, 0x7f, 0xd9, 0xb8, 0xb7, 0x0e, 0x0d, 0x12, 0x71, 0xf0, 0x52, 0x9d, 0xe9, 0xd0, 0xd2, 0x8b, 0x38, 0x8b, 0x85, 0x83, 0x98, 0x24, 0x88, 0xe8, 0x42, 0x30, 0x83, 0x12, 0xef, 0x09, 0x96, 0x2f, 0x21, 0x81, 0x05, 0x30, 0x0c, 0xbb, 0xba, 0x21, 0x39, 0x16, 0x12, 0xe8, 0x4b, 0x7b, 0x7a, 0x66, 0xb8, 0x22, 0x2c, 0x71, 0xaf, 0x59, 0xa1, 0xfc, 0x61, 0xf1, 0xb4, 0x5e, 0xfc, 0x43, 0x19, 0x45, 0x6e, 0xa3, 0x45, 0xe4, 0xcb, 0x66, 0x5f, 0xe0, 0x57, 0xf6, 0x0a, 0x30, 0xa3, 0xd6, 0x51, 0x24, 0xc9, 0x07, 0x55, 0x82, 0x4a, 0x66, 0x0e, 0x9d, 0xb2, 0x2f, 0x84, 0x56, 0x6c, 0x3e, 0x71, 0xef, 0x9b, 0x35, 0x4d, 0x72, 0xdc, 0x46, 0x2a, 0xe3, 0x7b, 0x13, 0x20, 0xbf, 0xab, 0x77, 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, 0x45, 0x1a, 0xec, 0xfc, 0x91, 0x70, 0xf8, 0x83, 0x8b, 0x9c, 0x47, 0x2f, 0x0b, 0x9f, 0x07, 0xf3, 0x2f, 0x7c, 0xa2, 0x8a, 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, 0x48, 0x24, 0x32, 0xe8, 0xd6, 0x38, 0xda, 0x65, 0xec, 0x1b, 0x18, 0x8e, 0x37, 0x07, 0xd5, 0x18, 0x5a, 0xc8, 0xb9, 0xbb, 0x24, 0x8a, 0x4d, 0xa1, 0x3c, 0x9e, 0x46, 0x76, 0xcf, 0xa5, 0xdf, 0xd7, 0x61, 0xba, 0x05, 0x89, 0x3c, 0x13, 0xc2, 0x1f, 0x71, 0xe3, 0xec, 0x5d, 0x54, 0x9e, 0xd9, 0x01, 0x5a, 0x10, 0x3b, 0x17, 0x75, 0xde, 0xa1, 0x45, 0xbf, 0x1d, 0x1b, 0x41, 0x21, 0x42, 0x68, 0x22, 0x6b, 0xbb, 0xcb, 0x11, 0x04, 0xd2, 0xae, 0x86, 0xcf, 0x73, 0x5a, 0xf2, 0x80, 0x18, 0x00, 0xf0, 0xd6, 0x6c, 0x5a, 0x1e, 0xb3, 0x4d, 0x30, 0x02, 0x4a, 0x6a, 0x03, 0x36, 0x42, 0xde, 0xb2, 0x52, 0x55, 0xff, 0x71, 0xeb, 0x7b, 0x8b, 0x55, 0x6c, 0xdf, 0x05, 0x35, 0x47, 0x70, 0x53, 0xfb, 0x6c, 0xba, 0x06, 0xb2, 0x61, 0x86, 0xdc, 0x2a, 0x64, 0x81, 0x24, 0x79, 0x46, 0x73, 0x04, 0x55, 0x59, 0xed, 0xd6, 0x06, 0x61, 0x15, 0xf9, 0x8d, 0x78, 0x39, 0x7b, 0x84, 0x7a, 0x40, 0x45, 0x13, 0x1a, 0x91, 0x71, 0x8f, 0xd1, 0x4f, 0x78, 0x10, 0x68, 0x9b, 0x15, 0x79, 0x3f, 0x79, 0x2d, 0x9b, 0xc7, 0x5d, 0xa3, 0xcf, 0xa9, 0x14, 0xb0, 0xc4, 0xdb, 0xa9, 0x45, 0x6a, 0x6e, 0x60, 0x45, 0x0b, 0x14, 0x25, 0xc7, 0x74, 0xd0, 0x36, 0xaf, 0xc5, 0xbd, 0x4f, 0x7b, 0xc0, 0x04, 0x43, 0x85, 0xbb, 0x06, 0x36, 0x77, 0x26, 0x02, 0x23, 0x0b, 0xf8, 0x57, 0x8f, 0x1f, 0x27, 0x30, 0x95, 0xff, 0x83, 0x23, 0x2b, 0x49, 0x33, 0x43, 0x62, 0x87, 0x5d, 0x27, 0x12, 0x1a, 0x68, 0x7b, 0xba, 0x2d, 0xf6, 0xed, 0x2c, 0x26, 0xb5, 0xbb, 0xe2, 0x6f, 0xc2, 0x61, 0x17, 0xfc, 0x72, 0x14, 0x57, 0x2c, 0x2c, 0x5a, 0x92, 0x13, 0x41, 0xc4, 0x7e, 0xb5, 0x64, 0x5b, 0x86, 0x57, 0x13, 0x14, 0xff, 0xf5, 0x04, 0xb9, 0x3d, 0x2d, 0xc3, 0xe9, 0x75, 0x1f, 0x68, 0x0b, 0xb5, 0x76, 0xe1, 0x7d, 0xe3, 0xb0, 0x14, 0xa8, 0x45, 0x05, 0x98, 0x81, 0x32, 0xc1, 0xf5, 0x49, 0x4d, 0x58, 0xa4, 0xee, 0xd8, 0x84, 0xba, 0x65, 0x07, 0x8d, 0xf7, 0x9a, 0xff, 0x7d, 0xa5, 0xbc, 0x9a, 0xed, 0x4a, 0x5d, 0xa4, 0x97, 0x4b, 0x4d, 0x31, 0x90, 0xb5, 0x7d, 0x28, 0x77, 0x25, 0x88, 0x1c, 0xbf, 0x78, 0x22, 0xb2, 0xb5, 0x5c, 0x9a, 0xc9, 0x63, 0x17, 0x96, 0xe9, 0xc2, 0x52, 0x30, 0xb8, 0x9b, 0x37, 0x69, 0x1a, 0x6a, 0x66, 0x76, 0x18, 0xac, 0xc0, 0x48, 0xee, 0x46, 0x5b, 0xbe, 0x6a, 0xd5, 0x72, 0x07, 0xdc, 0x7d, 0x05, 0xbe, 0x76, 0x7d, 0xa5, 0x5e, 0x53, 0xb5, 0x47, 0x80, 0x58, 0xf0, 0xaf, 0x6f, 0x4e, 0xc0, 0xf1, 0x1e, 0x37, 0x64, 0x15, 0x42, 0x96, 0x18, 0x3a, 0x89, 0xc8, 0x14, 0x48, 0x89, 0x5c, 0x12, 0x88, 0x98, 0x0b, 0x7b, 0x4e, 0xce, 0x1c, 0xda, 0xd5, 0xa4, 0xd3, 0x32, 0x32, 0x74, 0x5b, 0xcc, 0xfd, 0x2b, 0x02, 0xfb, 0xae, 0xd0, 0x5a, 0x4c, 0xc9, 0xc1, 0x35, 0x19, 0x90, 0x5f, 0xca, 0x14, 0xeb, 0x4c, 0x17, 0xd7, 0xe3, 0xe2, 0x5d, 0xb4, 0x49, 0xaa, 0xf0, 0x50, 0x87, 0xc3, 0x20, 0x00, 0xda, 0xe9, 0x04, 0x80, 0x64, 0xac, 0x9f, 0xcd, 0x26, 0x41, 0x48, 0xe8, 0x4c, 0x46, 0xcc, 0x5b, 0xd7, 0xca, 0x4c, 0x1b, 0x43, 0x43, 0x1e, 0xbd, 0x94, 0xe7, 0xa7, 0xa6, 0x86, 0xe5, 0xd1, 0x78, 0x29, 0xa2, 0x40, 0xc5, 0xc5, 0x47, 0xb6, 0x6d, 0x53, 0xde, 0xac, 0x97, 0x74, 0x24, 0x57, 0xcc, 0x05, 0x93, 0xfd, 0x52, 0x35, 0x29, 0xd5, 0xe0, 0xfa, 0x23, 0x0d, 0xd7, 0xaa, 0x8b, 0x07, 0x4b, 0xf6, 0x64, 0xc7, 0xad, 0x3c, 0xa1, 0xb5, 0xc5, 0x70, 0xaf, 0x46, 0xfe, 0x9a, 0x82, 0x4d, 0x75, 0xb8, 0x6d, 0x67, 0x70, 0x75, 0x62, 0x41, 0x72, 0x65, 0x61, 0x58, 0x76, 0x00, 0x23, 0x00, 0x0b, 0x00, 0x04, 0x00, 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, 0x00, 0x03, 0x00, 0x10, 0x00, 0x20, 0xfb, 0xd6, 0xba, 0x74, 0xe6, 0x6e, 0x5c, 0x87, 0xef, 0x89, 0xa2, 0xe8, 0x3d, 0x0b, 0xe9, 0x69, 0x2c, 0x07, 0x07, 0x7a, 0x8a, 0x1e, 0xce, 0x12, 0xea, 0x3b, 0xb3, 0xf1, 0xf3, 0xd9, 0xc3, 0xe6, 0x00, 0x20, 0x3c, 0x68, 0x51, 0x94, 0x54, 0x8d, 0xeb, 0x9f, 0xb2, 0x2c, 0x66, 0x75, 0xb6, 0xb7, 0x55, 0x22, 0x0d, 0x87, 0x59, 0xc4, 0x39, 0x91, 0x62, 0x17, 0xc2, 0xc3, 0x53, 0xa5, 0x26, 0x97, 0x4f, 0x2d, 0x68, 0x63, 0x65, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x58, 0xa1, 0xff, 0x54, 0x43, 0x47, 0x80, 0x17, 0x00, 0x22, 0x00, 0x0b, 0x73, 0xbe, 0xb7, 0x40, 0x82, 0xc0, 0x49, 0x9a, 0xf7, 0xf2, 0xd0, 0x79, 0x6c, 0x88, 0xf3, 0x56, 0x7b, 0x7a, 0x7d, 0xcd, 0x70, 0xd1, 0xbc, 0x41, 0x88, 0x48, 0x51, 0x03, 0xf3, 0x58, 0x3e, 0xb8, 0x00, 0x14, 0x9f, 0x57, 0x39, 0x67, 0xa8, 0x7b, 0xd8, 0xf6, 0x9e, 0x75, 0xc9, 0x85, 0xab, 0xe3, 0x55, 0xc7, 0x9c, 0xf6, 0xd8, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x1c, 0x12, 0xfd, 0xc6, 0x05, 0xc6, 0x2b, 0xf5, 0xe9, 0x88, 0x01, 0x1f, 0x70, 0x8d, 0x98, 0x2a, 0x04, 0x21, 0x30, 0x00, 0x22, 0x00, 0x0b, 0xf4, 0xfd, 0x9a, 0x33, 0x55, 0x21, 0x08, 0x27, 0x48, 0x55, 0x01, 0x56, 0xf9, 0x0b, 0x4e, 0x47, 0x55, 0x08, 0x2e, 0x3c, 0x91, 0x3d, 0x6e, 0x53, 0xcf, 0x08, 0xe9, 0x0a, 0x4b, 0xc9, 0x7e, 0x99, 0x00, 0x22, 0x00, 0x0b, 0x51, 0xd3, 0x38, 0xfe, 0xaa, 0xda, 0xc6, 0x68, 0x84, 0x39, 0xe7, 0xb1, 0x03, 0x22, 0x5e, 0xc4, 0xd3, 0xf1, 0x0c, 0xec, 0x35, 0x5d, 0x50, 0xa3, 0x9d, 0xab, 0xa1, 0x7b, 0x61, 0x51, 0x8f, 0x4e }; /* * 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); + return (&fake_dev_handle); } static void dummy_close(void *handle) { - assert(handle == FAKE_DEV_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] = (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] = (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] = (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] = (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_rs256_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_rs256, sizeof(authdata_tpm_rs256)) == 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_rs256, sizeof(attstmt_tpm_rs256)) == FIDO_OK); assert(fido_cred_verify(c) == FIDO_OK); assert(fido_cred_prot(c) == 0); assert(fido_cred_pubkey_len(c) == sizeof(pubkey_tpm_rs256)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey_tpm_rs256, sizeof(pubkey_tpm_rs256)) == 0); assert(fido_cred_id_len(c) == sizeof(id_tpm_rs256)); assert(memcmp(fido_cred_id_ptr(c), id_tpm_rs256, sizeof(id_tpm_rs256)) == 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); } static void valid_tpm_es256_cred(void) { fido_cred_t *c; c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == 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_es256, sizeof(authdata_tpm_es256)) == 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_es256, sizeof(attstmt_tpm_es256)) == FIDO_OK); assert(fido_cred_verify(c) == FIDO_OK); assert(fido_cred_prot(c) == 0); assert(fido_cred_pubkey_len(c) == sizeof(pubkey_tpm_es256)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey_tpm_es256, sizeof(pubkey_tpm_es256)) == 0); assert(fido_cred_id_len(c) == sizeof(id_tpm_es256)); assert(memcmp(fido_cred_id_ptr(c), id_tpm_es256, sizeof(id_tpm_es256)) == 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_rs256_cred(); valid_tpm_es256_cred(); exit(0); } diff --git a/contrib/libfido2/regress/dev.c b/contrib/libfido2/regress/dev.c index a5dc8d6e4529..0ba552b70552 100644 --- a/contrib/libfido2/regress/dev.c +++ b/contrib/libfido2/regress/dev.c @@ -1,412 +1,439 @@ /* - * Copyright (c) 2019-2021 Yubico AB. All rights reserved. + * Copyright (c) 2019-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ +#undef NDEBUG + #include -#include -#include #include #include +#define _FIDO_INTERNAL + +#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 fake_dev_handle; static int initialised; static long interval_ms; +#if defined(_MSC_VER) +static int +nanosleep(const struct timespec *rqtp, struct timespec *rmtp) +{ + if (rmtp != NULL) { + errno = EINVAL; + return (-1); + } + + Sleep((DWORD)(rqtp->tv_sec * 1000) + (DWORD)(rqtp->tv_nsec / 1000000)); + + return (0); +} +#endif + static void * dummy_open(const char *path) { (void)path; - return (FAKE_DEV_HANDLE); + return (&fake_dev_handle); } static void dummy_close(void *handle) { - assert(handle == FAKE_DEV_HANDLE); + assert(handle == &fake_dev_handle); } static int dummy_read(void *handle, unsigned char *ptr, size_t len, int ms) { struct timespec tv; size_t n; long d; - assert(handle == FAKE_DEV_HANDLE); + 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(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); +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:6386) +#endif memcpy(wiredata_ptr, ctap_init_data, sizeof(ctap_init_data)); +#if defined(_MSC_VER) +#pragma warning(pop) +#endif 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/regress/eddsa.c b/contrib/libfido2/regress/eddsa.c new file mode 100644 index 000000000000..06236987ed17 --- /dev/null +++ b/contrib/libfido2/regress/eddsa.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2022 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. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#undef NDEBUG + +#include +#include + +#define _FIDO_INTERNAL + +#include +#include + +#include +#include + +#define ASSERT_NOT_NULL(e) assert((e) != NULL) +#define ASSERT_NULL(e) assert((e) == NULL) +#define ASSERT_INVAL(e) assert((e) == FIDO_ERR_INVALID_ARGUMENT) +#define ASSERT_OK(e) assert((e) == FIDO_OK) + +static const char ecdsa[] = \ +"-----BEGIN PUBLIC KEY-----\n" +"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOwiq14c80b7C1Jzsx5w1zMvk2GgW\n" +"5kfGMOKXjwF/U+51ZfBDKehs3ivdeXAJBkxIh7E3iA32s+HyNqk+ntl9fg==\n" +"-----END PUBLIC KEY-----\n"; + +static const char eddsa[] = \ +"-----BEGIN PUBLIC KEY-----\n" +"MCowBQYDK2VwAyEADt/RHErAxAHxH9FUmsjOhQ2ALl6Y8nE0m3zQxkEE2iM=\n" +"-----END PUBLIC KEY-----\n"; + +static const unsigned char eddsa_raw[] = { + 0x0e, 0xdf, 0xd1, 0x1c, 0x4a, 0xc0, 0xc4, 0x01, + 0xf1, 0x1f, 0xd1, 0x54, 0x9a, 0xc8, 0xce, 0x85, + 0x0d, 0x80, 0x2e, 0x5e, 0x98, 0xf2, 0x71, 0x34, + 0x9b, 0x7c, 0xd0, 0xc6, 0x41, 0x04, 0xda, 0x23, +}; + +static EVP_PKEY * +EVP_PKEY_from_PEM(const char *ptr, size_t len) +{ + BIO *bio = NULL; + EVP_PKEY *pkey = NULL; + + if ((bio = BIO_new(BIO_s_mem())) == NULL) { + warnx("BIO_new"); + goto out; + } + if (len > INT_MAX || BIO_write(bio, ptr, (int)len) != (int)len) { + warnx("BIO_write"); + goto out; + } + if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) + warnx("PEM_read_bio_PUBKEY"); +out: + BIO_free(bio); + + return pkey; +} + +static int +eddsa_pk_cmp(const char *ptr, size_t len) +{ + EVP_PKEY *pkA = NULL; + EVP_PKEY *pkB = NULL; + eddsa_pk_t *k = NULL; + int r, ok = -1; + + if ((pkA = EVP_PKEY_from_PEM(ptr, len)) == NULL) { + warnx("EVP_PKEY_from_PEM"); + goto out; + } + if ((k = eddsa_pk_new()) == NULL) { + warnx("eddsa_pk_new"); + goto out; + } + if ((r = eddsa_pk_from_EVP_PKEY(k, pkA)) != FIDO_OK) { + warnx("eddsa_pk_from_EVP_PKEY: 0x%x", r); + goto out; + } + if ((pkB = eddsa_pk_to_EVP_PKEY(k)) == NULL) { + warnx("eddsa_pk_to_EVP_PKEY"); + goto out; + } + if ((r = EVP_PKEY_cmp(pkA, pkB)) != 1) { + warnx("EVP_PKEY_cmp: %d", r); + goto out; + } + + ok = 0; +out: + EVP_PKEY_free(pkA); + EVP_PKEY_free(pkB); + eddsa_pk_free(&k); + + return ok; +} + +static void +invalid_key(void) +{ + EVP_PKEY *pkey; + eddsa_pk_t *pk; + + ASSERT_NOT_NULL((pkey = EVP_PKEY_from_PEM(ecdsa, sizeof(ecdsa)))); + ASSERT_NOT_NULL((pk = eddsa_pk_new())); + ASSERT_INVAL(eddsa_pk_from_EVP_PKEY(pk, pkey)); + + EVP_PKEY_free(pkey); + eddsa_pk_free(&pk); +} + +static void +valid_key(void) +{ + EVP_PKEY *pkeyA = NULL; + EVP_PKEY *pkeyB = NULL; + eddsa_pk_t *pkA = NULL; + eddsa_pk_t *pkB = NULL; + +#if defined(LIBRESSL_VERSION_NUMBER) + /* incomplete support; test what we can */ + ASSERT_NULL(EVP_PKEY_from_PEM(eddsa, sizeof(eddsa))); + ASSERT_NOT_NULL((pkB = eddsa_pk_new())); + ASSERT_INVAL(eddsa_pk_from_ptr(pkB, eddsa_raw, sizeof(eddsa_raw))); + ASSERT_NULL(eddsa_pk_to_EVP_PKEY((const eddsa_pk_t *)eddsa_raw)); + assert(eddsa_pk_cmp(eddsa, sizeof(eddsa)) < 0); +#else + ASSERT_NOT_NULL((pkeyA = EVP_PKEY_from_PEM(eddsa, sizeof(eddsa)))); + ASSERT_NOT_NULL((pkA = eddsa_pk_new())); + ASSERT_NOT_NULL((pkB = eddsa_pk_new())); + ASSERT_OK(eddsa_pk_from_EVP_PKEY(pkA, pkeyA)); + ASSERT_OK(eddsa_pk_from_ptr(pkB, eddsa_raw, sizeof(eddsa_raw))); + ASSERT_NOT_NULL((pkeyB = eddsa_pk_to_EVP_PKEY((const eddsa_pk_t *)eddsa_raw))); + assert(EVP_PKEY_cmp(pkeyA, pkeyB) == 1); + assert(eddsa_pk_cmp(eddsa, sizeof(eddsa)) == 0); +#endif + + EVP_PKEY_free(pkeyA); + EVP_PKEY_free(pkeyB); + eddsa_pk_free(&pkA); + eddsa_pk_free(&pkB); +} + +int +main(void) +{ + fido_init(0); + + invalid_key(); + valid_key(); + + exit(0); +} diff --git a/contrib/libfido2/regress/es256.c b/contrib/libfido2/regress/es256.c new file mode 100644 index 000000000000..3a62a415977e --- /dev/null +++ b/contrib/libfido2/regress/es256.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2022 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. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#undef NDEBUG + +#include +#include + +#define _FIDO_INTERNAL + +#include +#include + +#include +#include + +#define ASSERT_NOT_NULL(e) assert((e) != NULL) +#define ASSERT_NULL(e) assert((e) == NULL) +#define ASSERT_INVAL(e) assert((e) == FIDO_ERR_INVALID_ARGUMENT) +#define ASSERT_OK(e) assert((e) == FIDO_OK) + +static const char short_x[] = \ +"-----BEGIN PUBLIC KEY-----\n" +"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAAeeHTZj4LEbt7Czs+u5gEZJfnGE\n" +"6Z+YLe4AYu7SoGY7IH/2jKifsA7w+lkURL4DL63oEjd3f8foH9bX4eaVug==\n" +"-----END PUBLIC KEY-----"; + +static const char short_y[] = \ +"-----BEGIN PUBLIC KEY-----\n" +"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEL8CWUP1r0tpJ5QmkzLc69O74C/Ti\n" +"83hTiys/JFNVkp0ArW3pKt5jNRrgWSZYE4S/D3AMtpqifFXz/FLCzJqojQ==\n" +"-----END PUBLIC KEY-----\n"; + +static const char p256k1[] = \ +"-----BEGIN PUBLIC KEY-----\n" +"MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEU1y8c0Jg9FGr3vYChpEo9c4dpkijriYM\n" +"QzU/DeskC89hZjLNH1Sj8ra2MsBlVGGJTNPCZSyx8Jo7ERapxdN7UQ==\n" +"-----END PUBLIC KEY-----\n"; + +static const char p256v1[] = \ +"-----BEGIN PUBLIC KEY-----\n" +"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOwiq14c80b7C1Jzsx5w1zMvk2GgW\n" +"5kfGMOKXjwF/U+51ZfBDKehs3ivdeXAJBkxIh7E3iA32s+HyNqk+ntl9fg==\n" +"-----END PUBLIC KEY-----\n"; + +static const unsigned char p256k1_raw[] = { + 0x04, 0x53, 0x5c, 0xbc, 0x73, 0x42, 0x60, 0xf4, + 0x51, 0xab, 0xde, 0xf6, 0x02, 0x86, 0x91, 0x28, + 0xf5, 0xce, 0x1d, 0xa6, 0x48, 0xa3, 0xae, 0x26, + 0x0c, 0x43, 0x35, 0x3f, 0x0d, 0xeb, 0x24, 0x0b, + 0xcf, 0x61, 0x66, 0x32, 0xcd, 0x1f, 0x54, 0xa3, + 0xf2, 0xb6, 0xb6, 0x32, 0xc0, 0x65, 0x54, 0x61, + 0x89, 0x4c, 0xd3, 0xc2, 0x65, 0x2c, 0xb1, 0xf0, + 0x9a, 0x3b, 0x11, 0x16, 0xa9, 0xc5, 0xd3, 0x7b, + 0x51, +}; + +static const unsigned char p256v1_raw[] = { + 0x04, 0x3b, 0x08, 0xaa, 0xd7, 0x87, 0x3c, 0xd1, + 0xbe, 0xc2, 0xd4, 0x9c, 0xec, 0xc7, 0x9c, 0x35, + 0xcc, 0xcb, 0xe4, 0xd8, 0x68, 0x16, 0xe6, 0x47, + 0xc6, 0x30, 0xe2, 0x97, 0x8f, 0x01, 0x7f, 0x53, + 0xee, 0x75, 0x65, 0xf0, 0x43, 0x29, 0xe8, 0x6c, + 0xde, 0x2b, 0xdd, 0x79, 0x70, 0x09, 0x06, 0x4c, + 0x48, 0x87, 0xb1, 0x37, 0x88, 0x0d, 0xf6, 0xb3, + 0xe1, 0xf2, 0x36, 0xa9, 0x3e, 0x9e, 0xd9, 0x7d, + 0x7e, +}; + +static EVP_PKEY * +EVP_PKEY_from_PEM(const char *ptr, size_t len) +{ + BIO *bio = NULL; + EVP_PKEY *pkey = NULL; + + if ((bio = BIO_new(BIO_s_mem())) == NULL) { + warnx("BIO_new"); + goto out; + } + if (len > INT_MAX || BIO_write(bio, ptr, (int)len) != (int)len) { + warnx("BIO_write"); + goto out; + } + if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) + warnx("PEM_read_bio_PUBKEY"); +out: + BIO_free(bio); + + return pkey; +} + +static int +es256_pk_cmp(const char *ptr, size_t len) +{ + EVP_PKEY *pkA = NULL; + EVP_PKEY *pkB = NULL; + es256_pk_t *k = NULL; + int r, ok = -1; + + if ((pkA = EVP_PKEY_from_PEM(ptr, len)) == NULL) { + warnx("EVP_PKEY_from_PEM"); + goto out; + } + if ((k = es256_pk_new()) == NULL) { + warnx("es256_pk_new"); + goto out; + } + if ((r = es256_pk_from_EVP_PKEY(k, pkA)) != FIDO_OK) { + warnx("es256_pk_from_EVP_PKEY: 0x%x", r); + goto out; + } + if ((pkB = es256_pk_to_EVP_PKEY(k)) == NULL) { + warnx("es256_pk_to_EVP_PKEY"); + goto out; + } + if ((r = EVP_PKEY_cmp(pkA, pkB)) != 1) { + warnx("EVP_PKEY_cmp: %d", r); + goto out; + } + + ok = 0; +out: + EVP_PKEY_free(pkA); + EVP_PKEY_free(pkB); + es256_pk_free(&k); + + return ok; +} + +static void +short_coord(void) +{ + assert(es256_pk_cmp(short_x, sizeof(short_x)) == 0); + assert(es256_pk_cmp(short_y, sizeof(short_y)) == 0); +} + +static void +invalid_curve(const unsigned char *raw, size_t raw_len) +{ + EVP_PKEY *pkey; + es256_pk_t *pk; + + ASSERT_NOT_NULL((pkey = EVP_PKEY_from_PEM(p256k1, sizeof(p256k1)))); + ASSERT_NOT_NULL((pk = es256_pk_new())); + ASSERT_INVAL(es256_pk_from_EVP_PKEY(pk, pkey)); + ASSERT_INVAL(es256_pk_from_ptr(pk, raw, raw_len)); + ASSERT_NULL(es256_pk_to_EVP_PKEY((const es256_pk_t *)raw)); + + EVP_PKEY_free(pkey); + es256_pk_free(&pk); +} + +static void +full_coord(void) +{ + assert(es256_pk_cmp(p256v1, sizeof(p256v1)) == 0); +} + +static void +valid_curve(const unsigned char *raw, size_t raw_len) +{ + EVP_PKEY *pkeyA; + EVP_PKEY *pkeyB; + es256_pk_t *pkA; + es256_pk_t *pkB; + + ASSERT_NOT_NULL((pkeyA = EVP_PKEY_from_PEM(p256v1, sizeof(p256v1)))); + ASSERT_NOT_NULL((pkA = es256_pk_new())); + ASSERT_NOT_NULL((pkB = es256_pk_new())); + ASSERT_OK(es256_pk_from_EVP_PKEY(pkA, pkeyA)); + ASSERT_OK(es256_pk_from_ptr(pkB, raw, raw_len)); + ASSERT_NOT_NULL((pkeyB = es256_pk_to_EVP_PKEY(pkB))); + assert(EVP_PKEY_cmp(pkeyA, pkeyB) == 1); + + EVP_PKEY_free(pkeyA); + EVP_PKEY_free(pkeyB); + es256_pk_free(&pkA); + es256_pk_free(&pkB); +} + +int +main(void) +{ + fido_init(0); + + short_coord(); + full_coord(); + + invalid_curve(p256k1_raw, sizeof(p256k1_raw)); /* uncompressed */ + invalid_curve(p256k1_raw + 1, sizeof(p256k1_raw) - 1); /* libfido2 */ + valid_curve(p256v1_raw, sizeof(p256v1_raw)); /* uncompressed */ + valid_curve(p256v1_raw + 1, sizeof(p256v1_raw) - 1); /* libfido2 */ + + exit(0); +} diff --git a/contrib/libfido2/regress/es384.c b/contrib/libfido2/regress/es384.c new file mode 100644 index 000000000000..b55ce015e17a --- /dev/null +++ b/contrib/libfido2/regress/es384.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2022 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. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#undef NDEBUG + +#include +#include + +#define _FIDO_INTERNAL + +#include +#include + +#include +#include + +#define ASSERT_NOT_NULL(e) assert((e) != NULL) +#define ASSERT_NULL(e) assert((e) == NULL) +#define ASSERT_INVAL(e) assert((e) == FIDO_ERR_INVALID_ARGUMENT) +#define ASSERT_OK(e) assert((e) == FIDO_OK) + +static const char short_x[] = \ +"-----BEGIN PUBLIC KEY-----\n" +"MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEAAZ/VVCUmFU6aH9kJdDnUHCCglkatFTX\n" +"onMwIvNYyS8BW/HOoZiOQLs2Hg+qifwaP1pHKILzCVfFmWuZMhxhtmjNXFuOPDnS\n" +"Wa1PMdkCoWXA2BbXxnqL9v36gIOcFBil\n" +"-----END PUBLIC KEY-----"; + +static const char short_y[] = \ +"-----BEGIN PUBLIC KEY-----\n" +"MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEuDpRBAg87cnWVhxbWnaWlnj100w9pm5k\n" +"6T4eYToISaIhEK70TnGwULHX0+qHCYEGACOM7B/ZJbqjo6I7MIXaKZLemGi+tqvy\n" +"ajBAsTVSyrYBLQjTMMcaFmYmsxvFx7pK\n" +"-----END PUBLIC KEY-----\n"; + +static const char brainpoolP384r1[] = \ +"-----BEGIN PUBLIC KEY-----\n" +"MHowFAYHKoZIzj0CAQYJKyQDAwIIAQELA2IABFKswbBzqqyZ4h1zz8rivqHzJxAO\n" +"XC2aLyC9x5gwBM7GVu8k6jkX7VypRpg3yyCneiIQ+vVCNXgbDchJ0cPVuhwm3Zru\n" +"AK49dezUPahWF0YiJRFVeV+KyB/MEaaZvinzqw==\n" +"-----END PUBLIC KEY-----\n"; + +static const char secp384r1[] = \ +"-----BEGIN PUBLIC KEY-----\n" +"MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEdJN9DoqPtTNAOmjnECHBIqnJgyBW0rct\n" +"tbUSqQjb6UG2lldmrQJbgCP/ywuXvkkJl4yfXxOr0UP3rgcnqTVA1/46s2TG+R5u\n" +"NSQbCM1JPQuvTyFlAn5mdR8ZJJ8yPBQm\n" +"-----END PUBLIC KEY-----\n"; + +static const unsigned char brainpoolP384r1_raw[] = { + 0x04, 0x52, 0xac, 0xc1, 0xb0, 0x73, 0xaa, 0xac, + 0x99, 0xe2, 0x1d, 0x73, 0xcf, 0xca, 0xe2, 0xbe, + 0xa1, 0xf3, 0x27, 0x10, 0x0e, 0x5c, 0x2d, 0x9a, + 0x2f, 0x20, 0xbd, 0xc7, 0x98, 0x30, 0x04, 0xce, + 0xc6, 0x56, 0xef, 0x24, 0xea, 0x39, 0x17, 0xed, + 0x5c, 0xa9, 0x46, 0x98, 0x37, 0xcb, 0x20, 0xa7, + 0x7a, 0x22, 0x10, 0xfa, 0xf5, 0x42, 0x35, 0x78, + 0x1b, 0x0d, 0xc8, 0x49, 0xd1, 0xc3, 0xd5, 0xba, + 0x1c, 0x26, 0xdd, 0x9a, 0xee, 0x00, 0xae, 0x3d, + 0x75, 0xec, 0xd4, 0x3d, 0xa8, 0x56, 0x17, 0x46, + 0x22, 0x25, 0x11, 0x55, 0x79, 0x5f, 0x8a, 0xc8, + 0x1f, 0xcc, 0x11, 0xa6, 0x99, 0xbe, 0x29, 0xf3, + 0xab, +}; + +static const unsigned char secp384r1_raw[] = { + 0x04, 0x74, 0x93, 0x7d, 0x0e, 0x8a, 0x8f, 0xb5, + 0x33, 0x40, 0x3a, 0x68, 0xe7, 0x10, 0x21, 0xc1, + 0x22, 0xa9, 0xc9, 0x83, 0x20, 0x56, 0xd2, 0xb7, + 0x2d, 0xb5, 0xb5, 0x12, 0xa9, 0x08, 0xdb, 0xe9, + 0x41, 0xb6, 0x96, 0x57, 0x66, 0xad, 0x02, 0x5b, + 0x80, 0x23, 0xff, 0xcb, 0x0b, 0x97, 0xbe, 0x49, + 0x09, 0x97, 0x8c, 0x9f, 0x5f, 0x13, 0xab, 0xd1, + 0x43, 0xf7, 0xae, 0x07, 0x27, 0xa9, 0x35, 0x40, + 0xd7, 0xfe, 0x3a, 0xb3, 0x64, 0xc6, 0xf9, 0x1e, + 0x6e, 0x35, 0x24, 0x1b, 0x08, 0xcd, 0x49, 0x3d, + 0x0b, 0xaf, 0x4f, 0x21, 0x65, 0x02, 0x7e, 0x66, + 0x75, 0x1f, 0x19, 0x24, 0x9f, 0x32, 0x3c, 0x14, + 0x26, +}; + +static EVP_PKEY * +EVP_PKEY_from_PEM(const char *ptr, size_t len) +{ + BIO *bio = NULL; + EVP_PKEY *pkey = NULL; + + if ((bio = BIO_new(BIO_s_mem())) == NULL) { + warnx("BIO_new"); + goto out; + } + if (len > INT_MAX || BIO_write(bio, ptr, (int)len) != (int)len) { + warnx("BIO_write"); + goto out; + } + if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) + warnx("PEM_read_bio_PUBKEY"); +out: + BIO_free(bio); + + return pkey; +} + +static int +es384_pk_cmp(const char *ptr, size_t len) +{ + EVP_PKEY *pkA = NULL; + EVP_PKEY *pkB = NULL; + es384_pk_t *k = NULL; + int r, ok = -1; + + if ((pkA = EVP_PKEY_from_PEM(ptr, len)) == NULL) { + warnx("EVP_PKEY_from_PEM"); + goto out; + } + if ((k = es384_pk_new()) == NULL) { + warnx("es384_pk_new"); + goto out; + } + if ((r = es384_pk_from_EVP_PKEY(k, pkA)) != FIDO_OK) { + warnx("es384_pk_from_EVP_PKEY: 0x%x", r); + goto out; + } + if ((pkB = es384_pk_to_EVP_PKEY(k)) == NULL) { + warnx("es384_pk_to_EVP_PKEY"); + goto out; + } + if ((r = EVP_PKEY_cmp(pkA, pkB)) != 1) { + warnx("EVP_PKEY_cmp: %d", r); + goto out; + } + + ok = 0; +out: + EVP_PKEY_free(pkA); + EVP_PKEY_free(pkB); + es384_pk_free(&k); + + return ok; +} + +static void +short_coord(void) +{ + assert(es384_pk_cmp(short_x, sizeof(short_x)) == 0); + assert(es384_pk_cmp(short_y, sizeof(short_y)) == 0); +} + +static void +invalid_curve(const unsigned char *raw, size_t raw_len) +{ + EVP_PKEY *pkey; + es384_pk_t *pk; + + pkey = EVP_PKEY_from_PEM(brainpoolP384r1, sizeof(brainpoolP384r1)); + if (pkey == NULL) + return; /* assume no brainpool support in libcrypto */ + ASSERT_NOT_NULL((pk = es384_pk_new())); + ASSERT_INVAL(es384_pk_from_EVP_PKEY(pk, pkey)); + ASSERT_INVAL(es384_pk_from_ptr(pk, raw, raw_len)); + ASSERT_NULL(es384_pk_to_EVP_PKEY((const es384_pk_t *)raw)); + + EVP_PKEY_free(pkey); + es384_pk_free(&pk); +} + +static void +full_coord(void) +{ + assert(es384_pk_cmp(secp384r1, sizeof(secp384r1)) == 0); +} + +static void +valid_curve(const unsigned char *raw, size_t raw_len) +{ + EVP_PKEY *pkeyA; + EVP_PKEY *pkeyB; + es384_pk_t *pkA; + es384_pk_t *pkB; + + ASSERT_NOT_NULL((pkeyA = EVP_PKEY_from_PEM(secp384r1, sizeof(secp384r1)))); + ASSERT_NOT_NULL((pkA = es384_pk_new())); + ASSERT_NOT_NULL((pkB = es384_pk_new())); + ASSERT_OK(es384_pk_from_EVP_PKEY(pkA, pkeyA)); + ASSERT_OK(es384_pk_from_ptr(pkB, raw, raw_len)); + ASSERT_NOT_NULL((pkeyB = es384_pk_to_EVP_PKEY(pkB))); + assert(EVP_PKEY_cmp(pkeyA, pkeyB) == 1); + + EVP_PKEY_free(pkeyA); + EVP_PKEY_free(pkeyB); + es384_pk_free(&pkA); + es384_pk_free(&pkB); +} + +int +main(void) +{ + fido_init(0); + + short_coord(); + full_coord(); + + invalid_curve(brainpoolP384r1_raw, sizeof(brainpoolP384r1_raw)); /* uncompressed */ + invalid_curve(brainpoolP384r1_raw + 1, sizeof(brainpoolP384r1_raw) - 1); /* libfido2 */ + valid_curve(secp384r1_raw, sizeof(secp384r1_raw)); /* uncompressed */ + valid_curve(secp384r1_raw + 1, sizeof(secp384r1_raw) - 1); /* libfido2 */ + + exit(0); +} diff --git a/contrib/libfido2/regress/rs256.c b/contrib/libfido2/regress/rs256.c new file mode 100644 index 000000000000..799396f07a02 --- /dev/null +++ b/contrib/libfido2/regress/rs256.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2022 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. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#undef NDEBUG + +#include +#include + +#define _FIDO_INTERNAL + +#include +#include + +#include +#include + +#define ASSERT_NOT_NULL(e) assert((e) != NULL) +#define ASSERT_NULL(e) assert((e) == NULL) +#define ASSERT_INVAL(e) assert((e) == FIDO_ERR_INVALID_ARGUMENT) +#define ASSERT_OK(e) assert((e) == FIDO_OK) + +static char rsa1024[] = \ +"-----BEGIN PUBLIC KEY-----\n" +"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCw92gn9Ku/bEfFj1AutaZyltpf\n" +"zzXrg70kQFymNq+spMt/HlxKiImw8TZU08zWW4ZLE/Ch4JYjMW6ETAdQFhSC63Ih\n" +"Wecui0JJ1f+2CsUVg+h7lO1877LZYUpdNiJrbqMb5Yc4N3FPtvdl3NoLIIQsF76H\n" +"VRvpjQgkWipRfZ97JQIDAQAB\n" +"-----END PUBLIC KEY-----"; + +static char rsa2048[] = \ +"-----BEGIN PUBLIC KEY-----\n" +"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApvIq/55ZodBIxzo/8BnE\n" +"UQN1fo1hmJ6V20hQHSzJq5tHyxRCcvKikuJ1ZvR4RdZlEzdTdbEfMBdZ8sxve0/U\n" +"yYEjH92CG0vgTCYuUaFLJTaWZSvWa96G8Lw+V4VyNFDRCM7sflOaSVH5pAsz8OEc\n" +"TLZfM4NhnDsJAM+mQ6X7Tza0sczPchgDA+9KByXo/VIqyuBQs17rlKC2reMa8NkY\n" +"rBRQZJLNzi68d5/BHH1flGWE1l8wJ9dr1Ex93H/KdzX+7/28TWUC98nneUo8RfRx\n" +"FwUt/EInDMHOORCaCHSs28U/9IUyMjqLB1rxKhIp09yGXMiTrrT+p+Pcn8dO01HT\n" +"vQIDAQAB\n" +"-----END PUBLIC KEY-----"; + +static char rsa3072[] = \ +"-----BEGIN PUBLIC KEY-----\n" +"MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAwZunKrMs/o92AniLPNTF\n" +"Ta4EYfhy5NDmMvQvRFT/eTYItLrOTPmYMap68KLyZYmgz/AdaxAL/992QWre7XTY\n" +"gqLwtZT+WsSu7xPHWKTTXrlVohKBeLHQ0I7Zy0NSMUxhlJEMrBAjSyFAS86zWm5w\n" +"ctC3pNCqfUKugA07BVj+d5Mv5fziwgMR86kuhkVuMYfsR4IYwX4+va0pyLzxx624\n" +"s9nJ107g+A+3MUk4bAto3lruFeeZPUI2AFzFQbGg5By6VtvVi3gKQ7lUNtAr0Onu\n" +"I6Fb+yz8sbFcvDpJcu5CXW20GrKMVP4KY5pn2LCajWuZjBl/dXWayPfm4UX5Y2O4\n" +"73tzPpUBNwnEdz79His0v80Vmvjwn5IuF2jAoimrBNPJFFwCCuVNy8kgj2vllk1l\n" +"RvLOG6hf8VnlDb40QZS3QAQ09xFfF+xlVLb8cHH6wllaAGEM230TrmawpC7xpz4Z\n" +"sTuwJwI0AWEi//noMsRz2BuF2fCp//aORYJQU2S8kYk3AgMBAAE=\n" +"-----END PUBLIC KEY-----"; + +static const unsigned char rsa2048_raw[] = { + 0xa6, 0xf2, 0x2a, 0xff, 0x9e, 0x59, 0xa1, 0xd0, + 0x48, 0xc7, 0x3a, 0x3f, 0xf0, 0x19, 0xc4, 0x51, + 0x03, 0x75, 0x7e, 0x8d, 0x61, 0x98, 0x9e, 0x95, + 0xdb, 0x48, 0x50, 0x1d, 0x2c, 0xc9, 0xab, 0x9b, + 0x47, 0xcb, 0x14, 0x42, 0x72, 0xf2, 0xa2, 0x92, + 0xe2, 0x75, 0x66, 0xf4, 0x78, 0x45, 0xd6, 0x65, + 0x13, 0x37, 0x53, 0x75, 0xb1, 0x1f, 0x30, 0x17, + 0x59, 0xf2, 0xcc, 0x6f, 0x7b, 0x4f, 0xd4, 0xc9, + 0x81, 0x23, 0x1f, 0xdd, 0x82, 0x1b, 0x4b, 0xe0, + 0x4c, 0x26, 0x2e, 0x51, 0xa1, 0x4b, 0x25, 0x36, + 0x96, 0x65, 0x2b, 0xd6, 0x6b, 0xde, 0x86, 0xf0, + 0xbc, 0x3e, 0x57, 0x85, 0x72, 0x34, 0x50, 0xd1, + 0x08, 0xce, 0xec, 0x7e, 0x53, 0x9a, 0x49, 0x51, + 0xf9, 0xa4, 0x0b, 0x33, 0xf0, 0xe1, 0x1c, 0x4c, + 0xb6, 0x5f, 0x33, 0x83, 0x61, 0x9c, 0x3b, 0x09, + 0x00, 0xcf, 0xa6, 0x43, 0xa5, 0xfb, 0x4f, 0x36, + 0xb4, 0xb1, 0xcc, 0xcf, 0x72, 0x18, 0x03, 0x03, + 0xef, 0x4a, 0x07, 0x25, 0xe8, 0xfd, 0x52, 0x2a, + 0xca, 0xe0, 0x50, 0xb3, 0x5e, 0xeb, 0x94, 0xa0, + 0xb6, 0xad, 0xe3, 0x1a, 0xf0, 0xd9, 0x18, 0xac, + 0x14, 0x50, 0x64, 0x92, 0xcd, 0xce, 0x2e, 0xbc, + 0x77, 0x9f, 0xc1, 0x1c, 0x7d, 0x5f, 0x94, 0x65, + 0x84, 0xd6, 0x5f, 0x30, 0x27, 0xd7, 0x6b, 0xd4, + 0x4c, 0x7d, 0xdc, 0x7f, 0xca, 0x77, 0x35, 0xfe, + 0xef, 0xfd, 0xbc, 0x4d, 0x65, 0x02, 0xf7, 0xc9, + 0xe7, 0x79, 0x4a, 0x3c, 0x45, 0xf4, 0x71, 0x17, + 0x05, 0x2d, 0xfc, 0x42, 0x27, 0x0c, 0xc1, 0xce, + 0x39, 0x10, 0x9a, 0x08, 0x74, 0xac, 0xdb, 0xc5, + 0x3f, 0xf4, 0x85, 0x32, 0x32, 0x3a, 0x8b, 0x07, + 0x5a, 0xf1, 0x2a, 0x12, 0x29, 0xd3, 0xdc, 0x86, + 0x5c, 0xc8, 0x93, 0xae, 0xb4, 0xfe, 0xa7, 0xe3, + 0xdc, 0x9f, 0xc7, 0x4e, 0xd3, 0x51, 0xd3, 0xbd, + 0x01, 0x00, 0x01, +}; + +static EVP_PKEY * +EVP_PKEY_from_PEM(const char *ptr, size_t len) +{ + BIO *bio = NULL; + EVP_PKEY *pkey = NULL; + + if ((bio = BIO_new(BIO_s_mem())) == NULL) { + warnx("BIO_new"); + goto out; + } + if (len > INT_MAX || BIO_write(bio, ptr, (int)len) != (int)len) { + warnx("BIO_write"); + goto out; + } + if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL) + warnx("PEM_read_bio_PUBKEY"); +out: + BIO_free(bio); + + return pkey; +} + +static int +rs256_pk_cmp(const char *ptr, size_t len) +{ + EVP_PKEY *pkA = NULL; + EVP_PKEY *pkB = NULL; + rs256_pk_t *k = NULL; + int r, ok = -1; + + if ((pkA = EVP_PKEY_from_PEM(ptr, len)) == NULL) { + warnx("EVP_PKEY_from_PEM"); + goto out; + } + if ((k = rs256_pk_new()) == NULL) { + warnx("rs256_pk_new"); + goto out; + } + if ((r = rs256_pk_from_EVP_PKEY(k, pkA)) != FIDO_OK) { + warnx("rs256_pk_from_EVP_PKEY: 0x%x", r); + goto out; + } + if ((pkB = rs256_pk_to_EVP_PKEY(k)) == NULL) { + warnx("rs256_pk_to_EVP_PKEY"); + goto out; + } + if ((r = EVP_PKEY_cmp(pkA, pkB)) != 1) { + warnx("EVP_PKEY_cmp: %d", r); + goto out; + } + + ok = 0; +out: + EVP_PKEY_free(pkA); + EVP_PKEY_free(pkB); + rs256_pk_free(&k); + + return ok; +} + +static void +invalid_size(const char *pem) +{ + EVP_PKEY *pkey; + rs256_pk_t *pk; + + ASSERT_NOT_NULL((pkey = EVP_PKEY_from_PEM(pem, strlen(pem)))); + ASSERT_NOT_NULL((pk = rs256_pk_new())); + ASSERT_INVAL(rs256_pk_from_EVP_PKEY(pk, pkey)); + + EVP_PKEY_free(pkey); + rs256_pk_free(&pk); +} + +static void +valid_size(const char *pem, const unsigned char *raw, size_t raw_len) +{ + EVP_PKEY *pkeyA; + EVP_PKEY *pkeyB; + rs256_pk_t *pkA; + rs256_pk_t *pkB; + + ASSERT_NOT_NULL((pkeyA = EVP_PKEY_from_PEM(pem, strlen(pem)))); + ASSERT_NOT_NULL((pkA = rs256_pk_new())); + ASSERT_NOT_NULL((pkB = rs256_pk_new())); + ASSERT_OK(rs256_pk_from_EVP_PKEY(pkA, pkeyA)); + ASSERT_OK(rs256_pk_from_ptr(pkB, raw, raw_len)); + ASSERT_NOT_NULL((pkeyB = rs256_pk_to_EVP_PKEY(pkB))); + assert(EVP_PKEY_cmp(pkeyA, pkeyB) == 1); + assert(rs256_pk_cmp(pem, strlen(pem)) == 0); + + EVP_PKEY_free(pkeyA); + EVP_PKEY_free(pkeyB); + rs256_pk_free(&pkA); + rs256_pk_free(&pkB); +} + +int +main(void) +{ + fido_init(0); + + invalid_size(rsa1024); + invalid_size(rsa3072); + valid_size(rsa2048, rsa2048_raw, sizeof(rsa2048_raw)); + + exit(0); +} diff --git a/contrib/libfido2/src/CMakeLists.txt b/contrib/libfido2/src/CMakeLists.txt index 796ec69a9dbe..73493b1ea8e4 100644 --- a/contrib/libfido2/src/CMakeLists.txt +++ b/contrib/libfido2/src/CMakeLists.txt @@ -1,139 +1,158 @@ -# Copyright (c) 2018-2021 Yubico AB. All rights reserved. +# Copyright (c) 2018-2022 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. +# SPDX-License-Identifier: BSD-2-Clause 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 + es384.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 + touch.c tpm.c types.c u2f.c + util.c ) if(FUZZ) list(APPEND FIDO_SOURCES ../fuzz/clock.c) + list(APPEND FIDO_SOURCES ../fuzz/pcsc.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/uniform_random.c) list(APPEND FIDO_SOURCES ../fuzz/wrap.c) endif() + if(NFC_LINUX) - list(APPEND FIDO_SOURCES netlink.c nfc_linux.c) + list(APPEND FIDO_SOURCES netlink.c nfc.c nfc_linux.c) +endif() + +if(USE_PCSC) + list(APPEND FIDO_SOURCES nfc.c pcsc.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" 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") + set_source_files_properties(${FIDO_SOURCES} + PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}") endif() list(APPEND COMPAT_SOURCES + ../openbsd-compat/bsd-asprintf.c ../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/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_PCSC) + list(APPEND BASE_LIBRARIES winscard) + endif() elseif(APPLE) - list(APPEND BASE_LIBRARIES "-framework CoreFoundation" "-framework IOKit") + list(APPEND BASE_LIBRARIES "-framework CoreFoundation" + "-framework IOKit") + if(USE_PCSC) + list(APPEND BASE_LIBRARIES "-framework PCSC") + endif() endif() list(APPEND TARGET_LIBRARIES ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES} ${UDEV_LIBRARIES} ${BASE_LIBRARIES} ${HIDAPI_LIBRARIES} ${ZLIB_LIBRARIES} + ${PCSC_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 MSVC) 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/aes256.c b/contrib/libfido2/src/aes256.c index f093b7ce0bd5..dcf716d65abb 100644 --- a/contrib/libfido2/src/aes256.c +++ b/contrib/libfido2/src/aes256.c @@ -1,215 +1,216 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include "fido.h" static int aes256_cbc(const fido_blob_t *key, const u_char *iv, const fido_blob_t *in, fido_blob_t *out, int encrypt) { EVP_CIPHER_CTX *ctx = NULL; const EVP_CIPHER *cipher; int ok = -1; memset(out, 0, sizeof(*out)); if (key->len != 32) { fido_log_debug("%s: invalid key len %zu", __func__, key->len); goto fail; } if (in->len > UINT_MAX || in->len % 16 || in->len == 0) { fido_log_debug("%s: invalid input len %zu", __func__, in->len); goto fail; } out->len = in->len; if ((out->ptr = calloc(1, out->len)) == NULL) { fido_log_debug("%s: calloc", __func__); goto fail; } if ((ctx = EVP_CIPHER_CTX_new()) == NULL || (cipher = EVP_aes_256_cbc()) == NULL) { fido_log_debug("%s: EVP_CIPHER_CTX_new", __func__); goto fail; } if (EVP_CipherInit(ctx, cipher, key->ptr, iv, encrypt) == 0 || EVP_Cipher(ctx, out->ptr, in->ptr, (u_int)out->len) < 0) { fido_log_debug("%s: EVP_Cipher", __func__); goto fail; } ok = 0; fail: if (ctx != NULL) EVP_CIPHER_CTX_free(ctx); if (ok < 0) fido_blob_reset(out); return ok; } static int aes256_cbc_proto1(const fido_blob_t *key, const fido_blob_t *in, fido_blob_t *out, int encrypt) { u_char iv[16]; memset(&iv, 0, sizeof(iv)); return aes256_cbc(key, iv, in, out, encrypt); } static int aes256_cbc_fips(const fido_blob_t *secret, const fido_blob_t *in, fido_blob_t *out, int encrypt) { fido_blob_t key, cin, cout; u_char iv[16]; memset(out, 0, sizeof(*out)); if (secret->len != 64) { fido_log_debug("%s: invalid secret len %zu", __func__, secret->len); return -1; } if (in->len < sizeof(iv)) { fido_log_debug("%s: invalid input len %zu", __func__, in->len); return -1; } if (encrypt) { if (fido_get_random(iv, sizeof(iv)) < 0) { fido_log_debug("%s: fido_get_random", __func__); return -1; } cin = *in; } else { memcpy(iv, in->ptr, sizeof(iv)); cin.ptr = in->ptr + sizeof(iv); cin.len = in->len - sizeof(iv); } key.ptr = secret->ptr + 32; key.len = secret->len - 32; if (aes256_cbc(&key, iv, &cin, &cout, encrypt) < 0) return -1; if (encrypt) { if (cout.len > SIZE_MAX - sizeof(iv) || (out->ptr = calloc(1, sizeof(iv) + cout.len)) == NULL) { fido_blob_reset(&cout); return -1; } out->len = sizeof(iv) + cout.len; memcpy(out->ptr, iv, sizeof(iv)); memcpy(out->ptr + sizeof(iv), cout.ptr, cout.len); fido_blob_reset(&cout); } else *out = cout; return 0; } static int aes256_gcm(const fido_blob_t *key, const fido_blob_t *nonce, const fido_blob_t *aad, const fido_blob_t *in, fido_blob_t *out, int encrypt) { EVP_CIPHER_CTX *ctx = NULL; const EVP_CIPHER *cipher; size_t textlen; int ok = -1; memset(out, 0, sizeof(*out)); if (nonce->len != 12 || key->len != 32 || aad->len > UINT_MAX) { fido_log_debug("%s: invalid params %zu, %zu, %zu", __func__, nonce->len, key->len, aad->len); goto fail; } if (in->len > UINT_MAX || in->len > SIZE_MAX - 16 || in->len < 16) { fido_log_debug("%s: invalid input len %zu", __func__, in->len); goto fail; } /* add tag to (on encrypt) or trim tag from the output (on decrypt) */ out->len = encrypt ? in->len + 16 : in->len - 16; if ((out->ptr = calloc(1, out->len)) == NULL) { fido_log_debug("%s: calloc", __func__); goto fail; } if ((ctx = EVP_CIPHER_CTX_new()) == NULL || (cipher = EVP_aes_256_gcm()) == NULL) { fido_log_debug("%s: EVP_CIPHER_CTX_new", __func__); goto fail; } if (EVP_CipherInit(ctx, cipher, key->ptr, nonce->ptr, encrypt) == 0) { fido_log_debug("%s: EVP_CipherInit", __func__); goto fail; } if (encrypt) textlen = in->len; else { textlen = in->len - 16; /* point openssl at the mac tag */ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, in->ptr + in->len - 16) == 0) { fido_log_debug("%s: EVP_CIPHER_CTX_ctrl", __func__); goto fail; } } /* the last EVP_Cipher() will either compute or verify the mac tag */ if (EVP_Cipher(ctx, NULL, aad->ptr, (u_int)aad->len) < 0 || EVP_Cipher(ctx, out->ptr, in->ptr, (u_int)textlen) < 0 || EVP_Cipher(ctx, NULL, NULL, 0) < 0) { fido_log_debug("%s: EVP_Cipher", __func__); goto fail; } if (encrypt) { /* append the mac tag */ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, out->ptr + out->len - 16) == 0) { fido_log_debug("%s: EVP_CIPHER_CTX_ctrl", __func__); goto fail; } } ok = 0; fail: if (ctx != NULL) EVP_CIPHER_CTX_free(ctx); if (ok < 0) fido_blob_reset(out); return ok; } int aes256_cbc_enc(const fido_dev_t *dev, const fido_blob_t *secret, const fido_blob_t *in, fido_blob_t *out) { return fido_dev_get_pin_protocol(dev) == 2 ? aes256_cbc_fips(secret, in, out, 1) : aes256_cbc_proto1(secret, in, out, 1); } int aes256_cbc_dec(const fido_dev_t *dev, const fido_blob_t *secret, const fido_blob_t *in, fido_blob_t *out) { return fido_dev_get_pin_protocol(dev) == 2 ? aes256_cbc_fips(secret, in, out, 0) : aes256_cbc_proto1(secret, in, out, 0); } int aes256_gcm_enc(const fido_blob_t *key, const fido_blob_t *nonce, const fido_blob_t *aad, const fido_blob_t *in, fido_blob_t *out) { return aes256_gcm(key, nonce, aad, in, out, 1); } int aes256_gcm_dec(const fido_blob_t *key, const fido_blob_t *nonce, const fido_blob_t *aad, const fido_blob_t *in, fido_blob_t *out) { return aes256_gcm(key, nonce, aad, in, out, 0); } diff --git a/contrib/libfido2/src/assert.c b/contrib/libfido2/src/assert.c index 949af919d25e..dabe8b9fdcf7 100644 --- a/contrib/libfido2/src/assert.c +++ b/contrib/libfido2/src/assert.c @@ -1,1024 +1,1104 @@ /* - * Copyright (c) 2018-2021 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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, 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], 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, 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) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; - int r; + unsigned char *msg; + int msglen; + int r; fido_assert_reset_rx(assert); - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } + + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } /* start with room for a single assertion */ - if ((assert->stmt = calloc(1, sizeof(fido_assert_stmt))) == NULL) - return (FIDO_ERR_INTERNAL); - + if ((assert->stmt = calloc(1, sizeof(fido_assert_stmt))) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } assert->stmt_len = 0; assert->stmt_cnt = 1; /* adjust as needed */ - if ((r = cbor_parse_reply(reply, (size_t)reply_len, assert, + if ((r = cbor_parse_reply(msg, (size_t)msglen, assert, adjust_assert_count)) != FIDO_OK) { fido_log_debug("%s: adjust_assert_count", __func__); - return (r); + goto out; } /* parse the first assertion */ - if ((r = cbor_parse_reply(reply, (size_t)reply_len, - &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) { + if ((r = cbor_parse_reply(msg, (size_t)msglen, &assert->stmt[0], + parse_assert_reply)) != FIDO_OK) { fido_log_debug("%s: parse_assert_reply", __func__); - return (r); + goto out; } + assert->stmt_len = 1; - assert->stmt_len++; + r = FIDO_OK; +out: + freezero(msg, FIDO_MAXMSG); - return (FIDO_OK); + return (r); } static int 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), 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) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; - int r; + unsigned char *msg; + int msglen; + int r; + + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } /* 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); + r = FIDO_ERR_INTERNAL; + goto out; } - if ((r = cbor_parse_reply(reply, (size_t)reply_len, + if ((r = cbor_parse_reply(msg, (size_t)msglen, &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) { fido_log_debug("%s: parse_assert_reply", __func__); - return (r); + goto out; } - return (FIDO_OK); + r = FIDO_OK; +out: + freezero(msg, FIDO_MAXMSG); + + return (r); } 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) { int r; 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, 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, 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, &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, &ms)) != FIDO_OK) { fido_log_debug("%s: fido_do_ecdh", __func__); goto fail; } } 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); } +static int +get_es256_hash(fido_blob_t *dgst, const fido_blob_t *clientdata, + const fido_blob_t *authdata) +{ + const EVP_MD *md; + EVP_MD_CTX *ctx = NULL; + + 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) { + EVP_MD_CTX_free(ctx); + return (-1); + } + dgst->len = SHA256_DIGEST_LENGTH; + + EVP_MD_CTX_free(ctx); + + return (0); +} + +static int +get_es384_hash(fido_blob_t *dgst, const fido_blob_t *clientdata, + const fido_blob_t *authdata) +{ + const EVP_MD *md; + EVP_MD_CTX *ctx = NULL; + + if (dgst->len < SHA384_DIGEST_LENGTH || + (md = EVP_sha384()) == 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) { + EVP_MD_CTX_free(ctx); + return (-1); + } + dgst->len = SHA384_DIGEST_LENGTH; + + EVP_MD_CTX_free(ctx); + + return (0); +} + +static int +get_eddsa_hash(fido_blob_t *dgst, const fido_blob_t *clientdata, + const fido_blob_t *authdata) +{ + if (SIZE_MAX - authdata->len < clientdata->len || + dgst->len < authdata->len + clientdata->len) + return (-1); + + memcpy(dgst->ptr, authdata->ptr, authdata->len); + memcpy(dgst->ptr + authdata->len, clientdata->ptr, clientdata->len); + dgst->len = authdata->len + clientdata->len; + + 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; + fido_blob_t authdata; struct cbor_load_result cbor; - const EVP_MD *md = NULL; - EVP_MD_CTX *ctx = NULL; int ok = -1; + fido_log_debug("%s: cose_alg=%d", __func__, cose_alg); + 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); - authdata_ptr = cbor_bytestring_handle(item); - authdata_len = cbor_bytestring_length(item); - - if (cose_alg != COSE_EDDSA) { - 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; + switch (cose_alg) { + case COSE_ES256: + case COSE_RS256: + ok = get_es256_hash(dgst, clientdata, &authdata); + break; + case COSE_ES384: + ok = get_es384_hash(dgst, clientdata, &authdata); + break; + case COSE_EDDSA: + ok = get_eddsa_hash(dgst, clientdata, &authdata); + break; + default: + fido_log_debug("%s: unknown cose_alg", __func__); + break; } - - ok = 0; fail: if (item != NULL) cbor_decref(&item); - 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 = es256_pk_verify_sig(&dgst, pk, &stmt->sig); break; + case COSE_ES384: + ok = es384_pk_verify_sig(&dgst, pk, &stmt->sig); + break; case COSE_RS256: ok = rs256_pk_verify_sig(&dgst, pk, &stmt->sig); break; case COSE_EDDSA: 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_empty_allow_list(fido_assert_t *assert) +{ + fido_free_blob_array(&assert->allow_list); + memset(&assert->allow_list, 0, sizeof(assert->allow_list)); + + return (FIDO_OK); } 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); + fido_assert_empty_allow_list(assert); 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) +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 33e0a8d44bd2..761562b26a1e 100644 --- a/contrib/libfido2/src/authkey.c +++ b/contrib/libfido2/src/authkey.c @@ -1,97 +1,107 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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, 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, 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) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; + unsigned char *msg; + int msglen; + int r; fido_log_debug("%s: dev=%p, authkey=%p, ms=%d", __func__, (void *)dev, (void *)authkey, *ms); memset(authkey, 0, sizeof(*authkey)); - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } + + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } - return (cbor_parse_reply(reply, (size_t)reply_len, authkey, - parse_authkey)); + r = cbor_parse_reply(msg, (size_t)msglen, authkey, parse_authkey); +out: + freezero(msg, FIDO_MAXMSG); + + return (r); } static int fido_dev_authkey_wait(fido_dev_t *dev, es256_pk_t *authkey, int *ms) { int r; 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, int *ms) { return (fido_dev_authkey_wait(dev, authkey, ms)); } diff --git a/contrib/libfido2/src/bio.c b/contrib/libfido2/src/bio.c index 8c52de5d76c3..57db85f53b23 100644 --- a/contrib/libfido2/src/bio.c +++ b/contrib/libfido2/src/bio.c @@ -1,856 +1,894 @@ /* - * Copyright (c) 2019 Yubico AB. All rights reserved. + * Copyright (c) 2019-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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, 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, 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], 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, 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) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; - int r; + unsigned char *msg; + int msglen; + int r; bio_reset_template_array(ta); - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } + + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } - if ((r = cbor_parse_reply(reply, (size_t)reply_len, ta, + if ((r = cbor_parse_reply(msg, (size_t)msglen, ta, bio_parse_template_array)) != FIDO_OK) { fido_log_debug("%s: bio_parse_template_array" , __func__); - return (r); + goto out; } - return (FIDO_OK); + r = FIDO_OK; +out: + freezero(msg, FIDO_MAXMSG); + + return (r); } static int bio_get_template_array_wait(fido_dev_t *dev, fido_bio_template_array_t *ta, const char *pin, int *ms) { int r; 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, &ms)); } static int bio_set_template_name_wait(fido_dev_t *dev, const fido_bio_template_t *t, 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, 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, &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) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; - int r; + unsigned char *msg; + int msglen; + 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) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } + + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } - if ((r = cbor_parse_reply(reply, (size_t)reply_len, e, + if ((r = cbor_parse_reply(msg, (size_t)msglen, e, bio_parse_enroll_status)) != FIDO_OK) { fido_log_debug("%s: bio_parse_enroll_status", __func__); - return (r); + goto out; } - if ((r = cbor_parse_reply(reply, (size_t)reply_len, &t->id, + + if ((r = cbor_parse_reply(msg, (size_t)msglen, &t->id, bio_parse_template_id)) != FIDO_OK) { fido_log_debug("%s: bio_parse_template_id", __func__); - return (r); + goto out; } - return (FIDO_OK); + r = FIDO_OK; +out: + freezero(msg, FIDO_MAXMSG); + + return (r); } 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) { 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_uint(timo_ms)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } 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, &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, &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, &ms)); } static int 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; + unsigned char *msg; + int msglen; + int r; e->remaining_samples = 0; e->last_status = 0; - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } + + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } - if ((r = cbor_parse_reply(reply, (size_t)reply_len, e, + if ((r = cbor_parse_reply(msg, (size_t)msglen, e, bio_parse_enroll_status)) != FIDO_OK) { fido_log_debug("%s: bio_parse_enroll_status", __func__); - return (r); + goto out; } - return (FIDO_OK); + r = FIDO_OK; +out: + freezero(msg, FIDO_MAXMSG); + + return (r); } 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) { 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_uint(timo_ms)) == NULL) { fido_log_debug("%s: cbor encode", __func__); goto fail; } 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, &ms)); } static int 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, 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) { 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) { 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, 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) { 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) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; - int r; + unsigned char *msg; + int msglen; + int r; bio_reset_info(i); - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } + + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } - if ((r = cbor_parse_reply(reply, (size_t)reply_len, i, + if ((r = cbor_parse_reply(msg, (size_t)msglen, i, bio_parse_info)) != FIDO_OK) { fido_log_debug("%s: bio_parse_info" , __func__); - return (r); + goto out; } - return (FIDO_OK); + r = FIDO_OK; +out: + freezero(msg, FIDO_MAXMSG); + + return (r); } static int 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, 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) { 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/blob.c b/contrib/libfido2/src/blob.c index 31e4cab0edc4..b431f49a00fc 100644 --- a/contrib/libfido2/src/blob.c +++ b/contrib/libfido2/src/blob.c @@ -1,133 +1,134 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include "fido.h" fido_blob_t * fido_blob_new(void) { return calloc(1, sizeof(fido_blob_t)); } void fido_blob_reset(fido_blob_t *b) { freezero(b->ptr, b->len); explicit_bzero(b, sizeof(*b)); } int fido_blob_set(fido_blob_t *b, const u_char *ptr, size_t len) { fido_blob_reset(b); if (ptr == NULL || len == 0) { fido_log_debug("%s: ptr=%p, len=%zu", __func__, (const void *)ptr, len); return -1; } if ((b->ptr = malloc(len)) == NULL) { fido_log_debug("%s: malloc", __func__); return -1; } memcpy(b->ptr, ptr, len); b->len = len; return 0; } int fido_blob_append(fido_blob_t *b, const u_char *ptr, size_t len) { u_char *tmp; if (ptr == NULL || len == 0) { fido_log_debug("%s: ptr=%p, len=%zu", __func__, (const void *)ptr, len); return -1; } if (SIZE_MAX - b->len < len) { fido_log_debug("%s: overflow", __func__); return -1; } if ((tmp = realloc(b->ptr, b->len + len)) == NULL) { fido_log_debug("%s: realloc", __func__); return -1; } b->ptr = tmp; memcpy(&b->ptr[b->len], ptr, len); b->len += len; return 0; } void fido_blob_free(fido_blob_t **bp) { fido_blob_t *b; if (bp == NULL || (b = *bp) == NULL) return; fido_blob_reset(b); free(b); *bp = NULL; } void fido_free_blob_array(fido_blob_array_t *array) { if (array->ptr == NULL) return; for (size_t i = 0; i < array->len; i++) { fido_blob_t *b = &array->ptr[i]; freezero(b->ptr, b->len); b->ptr = NULL; } free(array->ptr); array->ptr = NULL; array->len = 0; } cbor_item_t * fido_blob_encode(const fido_blob_t *b) { if (b == NULL || b->ptr == NULL) return NULL; return cbor_build_bytestring(b->ptr, b->len); } int fido_blob_decode(const cbor_item_t *item, fido_blob_t *b) { return cbor_bytestring_copy(item, &b->ptr, &b->len); } int fido_blob_is_empty(const fido_blob_t *b) { return b->ptr == NULL || b->len == 0; } int fido_blob_serialise(fido_blob_t *b, const cbor_item_t *item) { size_t alloc; if (!fido_blob_is_empty(b)) return -1; if ((b->len = cbor_serialize_alloc(item, &b->ptr, &alloc)) == 0) { b->ptr = NULL; return -1; } return 0; } diff --git a/contrib/libfido2/src/blob.h b/contrib/libfido2/src/blob.h index 76a8dd994f22..724718595513 100644 --- a/contrib/libfido2/src/blob.h +++ b/contrib/libfido2/src/blob.h @@ -1,41 +1,42 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #ifndef _BLOB_H #define _BLOB_H #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ typedef struct fido_blob { unsigned char *ptr; size_t len; } fido_blob_t; typedef struct fido_blob_array { fido_blob_t *ptr; size_t len; } fido_blob_array_t; cbor_item_t *fido_blob_encode(const fido_blob_t *); fido_blob_t *fido_blob_new(void); int fido_blob_decode(const cbor_item_t *, fido_blob_t *); int fido_blob_is_empty(const fido_blob_t *); int fido_blob_set(fido_blob_t *, const u_char *, size_t); int fido_blob_append(fido_blob_t *, const u_char *, size_t); void fido_blob_free(fido_blob_t **); void fido_blob_reset(fido_blob_t *); void fido_free_blob_array(fido_blob_array_t *); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* !_BLOB_H */ diff --git a/contrib/libfido2/src/buf.c b/contrib/libfido2/src/buf.c index f7161e64a9ca..42b6df1c24f1 100644 --- a/contrib/libfido2/src/buf.c +++ b/contrib/libfido2/src/buf.c @@ -1,33 +1,34 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include "fido.h" int fido_buf_read(const unsigned char **buf, size_t *len, void *dst, size_t count) { if (count > *len) return (-1); memcpy(dst, *buf, count); *buf += count; *len -= count; return (0); } int fido_buf_write(unsigned char **buf, size_t *len, const void *src, size_t count) { if (count > *len) return (-1); memcpy(*buf, src, count); *buf += count; *len -= count; return (0); } diff --git a/contrib/libfido2/src/cbor.c b/contrib/libfido2/src/cbor.c index 8b7edece3d8e..ab99b34da085 100644 --- a/contrib/libfido2/src/cbor.c +++ b/contrib/libfido2/src/cbor.c @@ -1,1681 +1,1705 @@ /* - * Copyright (c) 2018-2021 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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; HMAC_CTX *ctx = NULL; 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 ((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; } 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: 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 || (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, "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_ES384: + if (cose_key.kty != COSE_KTY_EC2 || + cose_key.crv != COSE_P384) { + 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_ES384: + if (es384_pk_decode(item, key) < 0) { + fido_log_debug("%s: es384_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__); + if (cbor_decode_bool(val, NULL) < 0) { + fido_log_debug("%s: cbor_decode_bool", __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__); + if (cbor_decode_bool(val, NULL) < 0) { + fido_log_debug("%s: cbor_decode_bool", __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 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; } 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) { + if (attstmt->alg != COSE_ES256 && attstmt->alg != COSE_ES384 && + 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); } +int +cbor_decode_bool(const cbor_item_t *item, bool *v) +{ + if (cbor_isa_float_ctrl(item) == false || + cbor_float_get_width(item) != CBOR_FLOAT_0 || + cbor_is_bool(item) == false) { + fido_log_debug("%s: cbor type", __func__); + return (-1); + } + + if (v != NULL) + *v = cbor_ctrl_value(item) == CBOR_CTRL_TRUE; + + 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/compress.c b/contrib/libfido2/src/compress.c index ee5501b4a4a1..3be6fd52fc3f 100644 --- a/contrib/libfido2/src/compress.c +++ b/contrib/libfido2/src/compress.c @@ -1,49 +1,168 @@ /* - * Copyright (c) 2020 Yubico AB. All rights reserved. + * Copyright (c) 2020-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include "fido.h" #define BOUND (1024UL * 1024UL) +/* zlib inflate (raw + headers) */ static int -do_compress(fido_blob_t *out, const fido_blob_t *in, size_t origsiz, int decomp) +rfc1950_inflate(fido_blob_t *out, const fido_blob_t *in, size_t origsiz) { u_long ilen, olen; - int r; + int z; memset(out, 0, sizeof(*out)); + if (in->len > ULONG_MAX || (ilen = (u_long)in->len) > BOUND || - origsiz > ULONG_MAX || (olen = decomp ? (u_long)origsiz : - compressBound(ilen)) > BOUND) + origsiz > ULONG_MAX || (olen = (u_long)origsiz) > BOUND) { + fido_log_debug("%s: in->len=%zu, origsiz=%zu", __func__, + in->len, origsiz); return FIDO_ERR_INVALID_ARGUMENT; + } + if ((out->ptr = calloc(1, olen)) == NULL) return FIDO_ERR_INTERNAL; out->len = olen; - if (decomp) - r = uncompress(out->ptr, &olen, in->ptr, ilen); - else - r = compress(out->ptr, &olen, in->ptr, ilen); - if (r != Z_OK || olen > SIZE_MAX || olen > out->len) { + + if ((z = uncompress(out->ptr, &olen, in->ptr, ilen)) != Z_OK || + olen > SIZE_MAX || olen != out->len) { + fido_log_debug("%s: uncompress: %d, olen=%lu, out->len=%zu", + __func__, z, olen, out->len); fido_blob_reset(out); return FIDO_ERR_COMPRESS; } - out->len = olen; return FIDO_OK; } +/* raw inflate */ +static int +rfc1951_inflate(fido_blob_t *out, const fido_blob_t *in, size_t origsiz) +{ + z_stream zs; + u_int ilen, olen; + int r, z; + + memset(&zs, 0, sizeof(zs)); + memset(out, 0, sizeof(*out)); + + if (in->len > UINT_MAX || (ilen = (u_int)in->len) > BOUND || + origsiz > UINT_MAX || (olen = (u_int)origsiz) > BOUND) { + fido_log_debug("%s: in->len=%zu, origsiz=%zu", __func__, + in->len, origsiz); + return FIDO_ERR_INVALID_ARGUMENT; + } + if ((z = inflateInit2(&zs, -MAX_WBITS)) != Z_OK) { + fido_log_debug("%s: inflateInit2: %d", __func__, z); + return FIDO_ERR_COMPRESS; + } + + if ((out->ptr = calloc(1, olen)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto fail; + } + out->len = olen; + zs.next_in = in->ptr; + zs.avail_in = ilen; + zs.next_out = out->ptr; + zs.avail_out = olen; + + if ((z = inflate(&zs, Z_FINISH)) != Z_STREAM_END) { + fido_log_debug("%s: inflate: %d", __func__, z); + r = FIDO_ERR_COMPRESS; + goto fail; + } + if (zs.avail_out != 0) { + fido_log_debug("%s: %u != 0", __func__, zs.avail_out); + r = FIDO_ERR_COMPRESS; + goto fail; + } + + r = FIDO_OK; +fail: + if ((z = inflateEnd(&zs)) != Z_OK) { + fido_log_debug("%s: inflateEnd: %d", __func__, z); + r = FIDO_ERR_COMPRESS; + } + if (r != FIDO_OK) + fido_blob_reset(out); + + return r; +} + +/* raw deflate */ +static int +rfc1951_deflate(fido_blob_t *out, const fido_blob_t *in) +{ + z_stream zs; + u_int ilen, olen; + int r, z; + + memset(&zs, 0, sizeof(zs)); + memset(out, 0, sizeof(*out)); + + if (in->len > UINT_MAX || (ilen = (u_int)in->len) > BOUND) { + fido_log_debug("%s: in->len=%zu", __func__, in->len); + return FIDO_ERR_INVALID_ARGUMENT; + } + if ((z = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, + -MAX_WBITS, 8, Z_DEFAULT_STRATEGY)) != Z_OK) { + fido_log_debug("%s: deflateInit2: %d", __func__, z); + return FIDO_ERR_COMPRESS; + } + + olen = BOUND; + if ((out->ptr = calloc(1, olen)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto fail; + } + out->len = olen; + zs.next_in = in->ptr; + zs.avail_in = ilen; + zs.next_out = out->ptr; + zs.avail_out = olen; + + if ((z = deflate(&zs, Z_FINISH)) != Z_STREAM_END) { + fido_log_debug("%s: inflate: %d", __func__, z); + r = FIDO_ERR_COMPRESS; + goto fail; + } + if (zs.avail_out >= out->len) { + fido_log_debug("%s: %u > %zu", __func__, zs.avail_out, + out->len); + r = FIDO_ERR_COMPRESS; + goto fail; + } + out->len -= zs.avail_out; + + r = FIDO_OK; +fail: + if ((z = deflateEnd(&zs)) != Z_OK) { + fido_log_debug("%s: deflateEnd: %d", __func__, z); + r = FIDO_ERR_COMPRESS; + } + if (r != FIDO_OK) + fido_blob_reset(out); + + return r; +} + int fido_compress(fido_blob_t *out, const fido_blob_t *in) { - return do_compress(out, in, 0, 0); + return rfc1951_deflate(out, in); } int fido_uncompress(fido_blob_t *out, const fido_blob_t *in, size_t origsiz) { - return do_compress(out, in, origsiz, 1); + if (rfc1950_inflate(out, in, origsiz) == FIDO_OK) + return FIDO_OK; /* backwards compat with libfido2 < 1.11 */ + return rfc1951_inflate(out, in, origsiz); } diff --git a/contrib/libfido2/src/config.c b/contrib/libfido2/src/config.c index 2baaab0fd62c..5302e118b63f 100644 --- a/contrib/libfido2/src/config.c +++ b/contrib/libfido2/src/config.c @@ -1,229 +1,235 @@ /* - * Copyright (c) 2020 Yubico AB. All rights reserved. + * Copyright (c) 2020-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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; + size_t cbor_len = 0; 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 (item != NULL) { + 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, 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; } + /* subCommandParams */ + if (paramc != 0 && + (argv[1] = cbor_flatten_vector(paramv, paramc)) == NULL) { + fido_log_debug("%s: cbor_flatten_vector", __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 (pin != NULL || + (fido_dev_supports_permissions(dev) && fido_dev_has_uv(dev))) { 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, 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], 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, 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) { int r; 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) { 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) { int r; 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) { 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 fido_str_array_t *rpid, const char *pin, int *ms) { cbor_item_t *argv[3]; int r; memset(argv, 0, sizeof(argv)); 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, 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 fido_str_array_t *rpid, const char *pin, int *ms) { int r; 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) { 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) { 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 6da502c8d90a..4a7a7257c985 100644 --- a/contrib/libfido2/src/cred.c +++ b/contrib/libfido2/src/cred.c @@ -1,1201 +1,1230 @@ /* - * Copyright (c) 2018-2021 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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, 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, 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], 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, 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) { unsigned char *reply; int reply_len; int r; fido_cred_reset_rx(cred); 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__); 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__); goto fail; } if (cred->fmt == NULL || fido_blob_is_empty(&cred->authdata_cbor) || fido_blob_is_empty(&cred->attcred.id)) { r = FIDO_ERR_INVALID_CBOR; goto fail; } 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 r; 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, 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, &ms)); } 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 */ const EVP_MD *md = NULL; EVP_MD_CTX *ctx = NULL; int ok = -1; - if (dgst->len != SHA256_DIGEST_LENGTH || + 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__); goto fail; } + dgst->len = SHA256_DIGEST_LENGTH; ok = 0; fail: EVP_MD_CTX_free(ctx); return (ok); } static int verify_attstmt(const fido_blob_t *dgst, const fido_attstmt_t *attstmt) { BIO *rawcert = NULL; X509 *cert = NULL; EVP_PKEY *pkey = NULL; int ok = -1; /* openssl needs ints */ 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(attstmt->x5c.ptr, (int)attstmt->x5c.len)) == NULL || (cert = d2i_X509_bio(rawcert, NULL)) == NULL || (pkey = X509_get_pubkey(cert)) == NULL) { fido_log_debug("%s: x509 key", __func__); goto fail; } switch (attstmt->alg) { case COSE_UNSPEC: case COSE_ES256: ok = es256_verify_sig(dgst, pkey, &attstmt->sig); break; + case COSE_ES384: + ok = es384_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; } fail: 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]; + unsigned char buf[1024]; /* XXX */ fido_blob_t dgst; + int cose_alg; 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 ((cose_alg = cred->attstmt.alg) == COSE_UNSPEC) + cose_alg = COSE_ES256; /* backwards compat */ + if (!strcmp(cred->fmt, "packed")) { - if (fido_get_signed_hash(COSE_ES256, &dgst, &cred->cdh, + if (fido_get_signed_hash(cose_alg, &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_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 = es256_pk_verify_sig(&dgst, &cred->attcred.pubkey.es256, &cred->attstmt.sig); break; + case COSE_ES384: + ok = es384_pk_verify_sig(&dgst, &cred->attcred.pubkey.es384, + &cred->attstmt.sig); + break; case COSE_RS256: ok = rs256_pk_verify_sig(&dgst, &cred->attcred.pubkey.rs256, &cred->attstmt.sig); break; case COSE_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); + fido_cred_empty_exclude_list(cred); 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_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_empty_exclude_list(fido_cred_t *cred) +{ + fido_free_blob_array(&cred->excl); + memset(&cred->excl, 0, sizeof(cred->excl)); + + 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, "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) + if (cred->type != 0) + return (FIDO_ERR_INVALID_ARGUMENT); + if (cose_alg != COSE_ES256 && cose_alg != COSE_ES384 && + cose_alg != COSE_RS256 && cose_alg != COSE_EDDSA) 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_ES384: + ptr = &cred->attcred.pubkey.es384; + 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_ES384: + len = sizeof(cred->attcred.pubkey.es384); + 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 8d2649a144f2..c36424233816 100644 --- a/contrib/libfido2/src/credman.c +++ b/contrib/libfido2/src/credman.c @@ -1,777 +1,825 @@ /* - * Copyright (c) 2019-2021 Yubico AB. All rights reserved. + * Copyright (c) 2019-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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, +credman_grow_array(void **ptr, size_t *n_alloc, const 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, 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, 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], 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, 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) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; - int r; + unsigned char *msg; + int msglen; + int r; memset(metadata, 0, sizeof(*metadata)); - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } + + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } - if ((r = cbor_parse_reply(reply, (size_t)reply_len, metadata, + if ((r = cbor_parse_reply(msg, (size_t)msglen, metadata, credman_parse_metadata)) != FIDO_OK) { fido_log_debug("%s: credman_parse_metadata", __func__); - return (r); + goto out; } - return (FIDO_OK); + r = FIDO_OK; +out: + freezero(msg, FIDO_MAXMSG); + + return (r); } static int credman_get_metadata_wait(fido_dev_t *dev, fido_credman_metadata_t *metadata, const char *pin, int *ms) { int r; if ((r = credman_tx(dev, CMD_CRED_METADATA, NULL, pin, NULL, 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) { 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) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; - int r; + unsigned char *msg; + int msglen; + int r; credman_reset_rk(rk); - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } + + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } /* adjust as needed */ - if ((r = cbor_parse_reply(reply, (size_t)reply_len, rk, + if ((r = cbor_parse_reply(msg, (size_t)msglen, rk, credman_parse_rk_count)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rk_count", __func__); - return (r); + goto out; } if (rk->n_alloc == 0) { fido_log_debug("%s: n_alloc=0", __func__); - return (FIDO_OK); + r = FIDO_OK; + goto out; } /* parse the first rk */ - if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rk->ptr[0], + if ((r = cbor_parse_reply(msg, (size_t)msglen, &rk->ptr[0], credman_parse_rk)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rk", __func__); - return (r); + goto out; } + rk->n_rx = 1; - rk->n_rx++; + r = FIDO_OK; +out: + freezero(msg, FIDO_MAXMSG); - return (FIDO_OK); + return (r); } static int 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; + unsigned char *msg; + int msglen; + int r; + + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } /* 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); + r = FIDO_ERR_INTERNAL; + goto out; } - if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rk->ptr[rk->n_rx], + if ((r = cbor_parse_reply(msg, (size_t)msglen, &rk->ptr[rk->n_rx], credman_parse_rk)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rk", __func__); - return (r); + goto out; } - return (FIDO_OK); + r = FIDO_OK; +out: + freezero(msg, FIDO_MAXMSG); + + return (r); } static int credman_get_rk_wait(fido_dev_t *dev, const char *rp_id, fido_credman_rk_t *rk, 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, 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, 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) { 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) { 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, 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) { 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) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; - int r; + unsigned char *msg; + int msglen; + int r; credman_reset_rp(rp); - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } + + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } /* adjust as needed */ - if ((r = cbor_parse_reply(reply, (size_t)reply_len, rp, + if ((r = cbor_parse_reply(msg, (size_t)msglen, rp, credman_parse_rp_count)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rp_count", __func__); - return (r); + goto out; } if (rp->n_alloc == 0) { fido_log_debug("%s: n_alloc=0", __func__); - return (FIDO_OK); + r = FIDO_OK; + goto out; } /* parse the first rp */ - if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rp->ptr[0], + if ((r = cbor_parse_reply(msg, (size_t)msglen, &rp->ptr[0], credman_parse_rp)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rp", __func__); - return (r); + goto out; } + rp->n_rx = 1; - rp->n_rx++; + r = FIDO_OK; +out: + freezero(msg, FIDO_MAXMSG); - return (FIDO_OK); + return (r); } static int 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; + unsigned char *msg; + int msglen; + int r; - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } + + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } /* 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); + r = FIDO_ERR_INTERNAL; + goto out; } - if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rp->ptr[rp->n_rx], + if ((r = cbor_parse_reply(msg, (size_t)msglen, &rp->ptr[rp->n_rx], credman_parse_rp)) != FIDO_OK) { fido_log_debug("%s: credman_parse_rp", __func__); - return (r); + goto out; } - return (FIDO_OK); + r = FIDO_OK; +out: + freezero(msg, FIDO_MAXMSG); + + return (r); } static int credman_get_rp_wait(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin, int *ms) { int r; if ((r = credman_tx(dev, CMD_RP_BEGIN, NULL, pin, NULL, 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, 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) { 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 r; if ((r = credman_tx(dev, CMD_UPDATE_CRED, cred, pin, NULL, 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) { 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 fb8faba0a06c..2d662a6cc48b 100644 --- a/contrib/libfido2/src/dev.c +++ b/contrib/libfido2/src/dev.c @@ -1,756 +1,601 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ -#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; + 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; + 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, 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), 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_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) { 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, 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) +static void +run_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen, + const char *type, int (*manifest)(fido_dev_info_t *, size_t, size_t *)) { - dev_manifest_func_node_t *prev, *curr; + size_t ndevs = 0; + int r; - find_manifest_func_node(f, &curr, &prev); - if (curr == NULL) + if (*olen >= ilen) { + fido_log_debug("%s: skipping %s", __func__, type); return; - if (prev != NULL) - prev->next = curr->next; - else - manifest_funcs = curr->next; - - free(curr); + } + if ((r = manifest(devlist + *olen, ilen - *olen, &ndevs)) != FIDO_OK) + fido_log_debug("%s: %s: 0x%x", __func__, type, r); + fido_log_debug("%s: found %zu %s device%s", __func__, ndevs, type, + ndevs == 1 ? "" : "s"); + *olen += ndevs; } 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); + run_manifest(devlist, ilen, olen, "hid", fido_hid_manifest); +#ifdef USE_NFC + run_manifest(devlist, ilen, olen, "nfc", fido_nfc_manifest); +#endif +#ifdef USE_PCSC + run_manifest(devlist, ilen, olen, "pcsc", fido_pcsc_manifest); #endif #ifdef USE_WINHELLO - if (fido_dev_register_manifest_func(fido_winhello_manifest) != FIDO_OK) - return (FIDO_ERR_INTERNAL); + run_manifest(devlist, ilen, olen, "winhello", fido_winhello_manifest); #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, &ms)); } int fido_dev_open(fido_dev_t *dev, const char *path) { int ms = dev->timeout_ms; -#ifdef NFC_LINUX - 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, - }; +#ifdef USE_NFC + if (fido_is_nfc(path) && fido_dev_set_nfc(dev) < 0) { + fido_log_debug("%s: fido_dev_set_nfc", __func__); + return FIDO_ERR_INTERNAL; + } +#endif +#ifdef USE_PCSC + if (fido_is_pcsc(path) && fido_dev_set_pcsc(dev) < 0) { + fido_log_debug("%s: fido_dev_set_pcsc", __func__); + return FIDO_ERR_INTERNAL; } #endif 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_handle == NULL || sigmask == NULL) return (FIDO_ERR_INVALID_ARGUMENT); -#ifdef NFC_LINUX +#ifdef USE_NFC if (dev->transport.rx == fido_nfc_rx && dev->io.read == fido_nfc_read) return (fido_nfc_set_sigmask(dev->io_handle, sigmask)); #endif 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, &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, &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, &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)); - - 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_dev_io_handle(const fido_dev_t *dev) { return (dev->io_handle); } 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/diff_exports.sh b/contrib/libfido2/src/diff_exports.sh index 9cff0095a201..2e15cd0c5b9b 100755 --- a/contrib/libfido2/src/diff_exports.sh +++ b/contrib/libfido2/src/diff_exports.sh @@ -1,26 +1,27 @@ #!/bin/sh -u # Copyright (c) 2018 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. +# SPDX-License-Identifier: BSD-2-Clause for f in export.gnu export.llvm export.msvc; do if [ ! -f "${f}" ]; then exit 1 fi done TMPDIR="$(mktemp -d)" GNU="${TMPDIR}/gnu" LLVM="${TMPDIR}/llvm" MSVC="${TMPDIR}/msvc" awk '/^[^*{}]+;$/' export.gnu | tr -d '\t;' | sort > "${GNU}" sed 's/^_//' export.llvm | sort > "${LLVM}" grep -v '^EXPORTS$' export.msvc | sort > "${MSVC}" diff -u "${GNU}" "${LLVM}" && diff -u "${MSVC}" "${LLVM}" ERROR=$? rm "${GNU}" "${LLVM}" "${MSVC}" rmdir "${TMPDIR}" exit ${ERROR} diff --git a/contrib/libfido2/src/ecdh.c b/contrib/libfido2/src/ecdh.c index 9c4f2b99e1a9..878f97615e3f 100644 --- a/contrib/libfido2/src/ecdh.c +++ b/contrib/libfido2/src/ecdh.c @@ -1,207 +1,208 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #if defined(LIBRESSL_VERSION_NUMBER) #include #else #include #endif #include "fido.h" #include "fido/es256.h" #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, (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) */ 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, 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, 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 a7b4f4f900ce..bdb53b188cdb 100644 --- a/contrib/libfido2/src/eddsa.c +++ b/contrib/libfido2/src/eddsa.c @@ -1,220 +1,232 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include "fido.h" #include "fido/eddsa.h" -#if defined(LIBRESSL_VERSION_NUMBER) +#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3070000f 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); } #endif /* LIBRESSL_VERSION_NUMBER */ #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3040000f 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 < 0x3040000f */ 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) { + EVP_PKEY *pkey; + if (len < sizeof(*pk)) return (FIDO_ERR_INVALID_ARGUMENT); memcpy(pk, ptr, sizeof(*pk)); + if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { + fido_log_debug("%s: eddsa_pk_to_EVP_PKEY", __func__); + return (FIDO_ERR_INVALID_ARGUMENT); + } + + EVP_PKEY_free(pkey); + 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_base_id(pkey) != EVP_PKEY_ED25519) + return (FIDO_ERR_INVALID_ARGUMENT); 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/err.c b/contrib/libfido2/src/err.c index 8c2ae5ff4170..3a6f3e0a6124 100644 --- a/contrib/libfido2/src/err.c +++ b/contrib/libfido2/src/err.c @@ -1,136 +1,137 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include "fido/err.h" const char * fido_strerr(int n) { switch (n) { case FIDO_ERR_SUCCESS: return "FIDO_ERR_SUCCESS"; case FIDO_ERR_INVALID_COMMAND: return "FIDO_ERR_INVALID_COMMAND"; case FIDO_ERR_INVALID_PARAMETER: return "FIDO_ERR_INVALID_PARAMETER"; case FIDO_ERR_INVALID_LENGTH: return "FIDO_ERR_INVALID_LENGTH"; case FIDO_ERR_INVALID_SEQ: return "FIDO_ERR_INVALID_SEQ"; case FIDO_ERR_TIMEOUT: return "FIDO_ERR_TIMEOUT"; case FIDO_ERR_CHANNEL_BUSY: return "FIDO_ERR_CHANNEL_BUSY"; case FIDO_ERR_LOCK_REQUIRED: return "FIDO_ERR_LOCK_REQUIRED"; case FIDO_ERR_INVALID_CHANNEL: return "FIDO_ERR_INVALID_CHANNEL"; case FIDO_ERR_CBOR_UNEXPECTED_TYPE: return "FIDO_ERR_CBOR_UNEXPECTED_TYPE"; case FIDO_ERR_INVALID_CBOR: return "FIDO_ERR_INVALID_CBOR"; case FIDO_ERR_MISSING_PARAMETER: return "FIDO_ERR_MISSING_PARAMETER"; case FIDO_ERR_LIMIT_EXCEEDED: return "FIDO_ERR_LIMIT_EXCEEDED"; case FIDO_ERR_UNSUPPORTED_EXTENSION: return "FIDO_ERR_UNSUPPORTED_EXTENSION"; case FIDO_ERR_FP_DATABASE_FULL: return "FIDO_ERR_FP_DATABASE_FULL"; case FIDO_ERR_LARGEBLOB_STORAGE_FULL: return "FIDO_ERR_LARGEBLOB_STORAGE_FULL"; case FIDO_ERR_CREDENTIAL_EXCLUDED: return "FIDO_ERR_CREDENTIAL_EXCLUDED"; case FIDO_ERR_PROCESSING: return "FIDO_ERR_PROCESSING"; case FIDO_ERR_INVALID_CREDENTIAL: return "FIDO_ERR_INVALID_CREDENTIAL"; case FIDO_ERR_USER_ACTION_PENDING: return "FIDO_ERR_USER_ACTION_PENDING"; case FIDO_ERR_OPERATION_PENDING: return "FIDO_ERR_OPERATION_PENDING"; case FIDO_ERR_NO_OPERATIONS: return "FIDO_ERR_NO_OPERATIONS"; case FIDO_ERR_UNSUPPORTED_ALGORITHM: return "FIDO_ERR_UNSUPPORTED_ALGORITHM"; case FIDO_ERR_OPERATION_DENIED: return "FIDO_ERR_OPERATION_DENIED"; case FIDO_ERR_KEY_STORE_FULL: return "FIDO_ERR_KEY_STORE_FULL"; case FIDO_ERR_NOT_BUSY: return "FIDO_ERR_NOT_BUSY"; case FIDO_ERR_NO_OPERATION_PENDING: return "FIDO_ERR_NO_OPERATION_PENDING"; case FIDO_ERR_UNSUPPORTED_OPTION: return "FIDO_ERR_UNSUPPORTED_OPTION"; case FIDO_ERR_INVALID_OPTION: return "FIDO_ERR_INVALID_OPTION"; case FIDO_ERR_KEEPALIVE_CANCEL: return "FIDO_ERR_KEEPALIVE_CANCEL"; case FIDO_ERR_NO_CREDENTIALS: return "FIDO_ERR_NO_CREDENTIALS"; case FIDO_ERR_USER_ACTION_TIMEOUT: return "FIDO_ERR_USER_ACTION_TIMEOUT"; case FIDO_ERR_NOT_ALLOWED: return "FIDO_ERR_NOT_ALLOWED"; case FIDO_ERR_PIN_INVALID: return "FIDO_ERR_PIN_INVALID"; case FIDO_ERR_PIN_BLOCKED: return "FIDO_ERR_PIN_BLOCKED"; case FIDO_ERR_PIN_AUTH_INVALID: return "FIDO_ERR_PIN_AUTH_INVALID"; case FIDO_ERR_PIN_AUTH_BLOCKED: return "FIDO_ERR_PIN_AUTH_BLOCKED"; case FIDO_ERR_PIN_NOT_SET: return "FIDO_ERR_PIN_NOT_SET"; case FIDO_ERR_PIN_REQUIRED: return "FIDO_ERR_PIN_REQUIRED"; case FIDO_ERR_PIN_POLICY_VIOLATION: return "FIDO_ERR_PIN_POLICY_VIOLATION"; case FIDO_ERR_PIN_TOKEN_EXPIRED: return "FIDO_ERR_PIN_TOKEN_EXPIRED"; case FIDO_ERR_REQUEST_TOO_LARGE: return "FIDO_ERR_REQUEST_TOO_LARGE"; case FIDO_ERR_ACTION_TIMEOUT: return "FIDO_ERR_ACTION_TIMEOUT"; case FIDO_ERR_UP_REQUIRED: return "FIDO_ERR_UP_REQUIRED"; case FIDO_ERR_UV_BLOCKED: return "FIDO_ERR_UV_BLOCKED"; case FIDO_ERR_UV_INVALID: return "FIDO_ERR_UV_INVALID"; case FIDO_ERR_UNAUTHORIZED_PERM: return "FIDO_ERR_UNAUTHORIZED_PERM"; case FIDO_ERR_ERR_OTHER: return "FIDO_ERR_ERR_OTHER"; case FIDO_ERR_SPEC_LAST: return "FIDO_ERR_SPEC_LAST"; case FIDO_ERR_TX: return "FIDO_ERR_TX"; case FIDO_ERR_RX: return "FIDO_ERR_RX"; case FIDO_ERR_RX_NOT_CBOR: return "FIDO_ERR_RX_NOT_CBOR"; case FIDO_ERR_RX_INVALID_CBOR: return "FIDO_ERR_RX_INVALID_CBOR"; case FIDO_ERR_INVALID_PARAM: return "FIDO_ERR_INVALID_PARAM"; case FIDO_ERR_INVALID_SIG: return "FIDO_ERR_INVALID_SIG"; case FIDO_ERR_INVALID_ARGUMENT: return "FIDO_ERR_INVALID_ARGUMENT"; case FIDO_ERR_USER_PRESENCE_REQUIRED: return "FIDO_ERR_USER_PRESENCE_REQUIRED"; case FIDO_ERR_NOTFOUND: return "FIDO_ERR_NOTFOUND"; case FIDO_ERR_COMPRESS: return "FIDO_ERR_COMPRESS"; case FIDO_ERR_INTERNAL: return "FIDO_ERR_INTERNAL"; default: return "FIDO_ERR_UNKNOWN"; } } diff --git a/contrib/libfido2/src/es256.c b/contrib/libfido2/src/es256.c index eb4cc63525aa..17efb0ad2c16 100644 --- a/contrib/libfido2/src/es256.c +++ b/contrib/libfido2/src/es256.c @@ -1,513 +1,541 @@ /* - * Copyright (c) 2018-2021 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include "fido.h" #include "fido/es256.h" +#if OPENSSL_VERSION_NUMBER >= 0x30000000 +#define get0_EC_KEY(x) EVP_PKEY_get0_EC_KEY((x)) +#else +#define get0_EC_KEY(x) EVP_PKEY_get0((x)) +#endif + +static const int es256_nid = NID_X9_62_prime256v1; + 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; + const uint8_t *p = ptr; + EVP_PKEY *pkey; 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 */ + if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) { + fido_log_debug("%s: es256_pk_to_EVP_PKEY", __func__); + explicit_bzero(pk, sizeof(*pk)); + return (FIDO_ERR_INVALID_ARGUMENT); + } + + EVP_PKEY_free(pkey); + 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_CTX_set_ec_paramgen_curve_nid(pctx, es256_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 || + if ((ec = EC_KEY_new_by_curve_name(es256_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; + EC_GROUP *g = NULL; + size_t dx; + size_t dy; int ok = FIDO_ERR_INTERNAL; - int n; + int nx; + int ny; if ((q = EC_KEY_get0_public_key(ec)) == NULL || - (g = EC_KEY_get0_group(ec)) == NULL || + (g = EC_GROUP_new_by_curve_name(es256_nid)) == 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_is_on_curve(g, q, bnctx) != 1) { + fido_log_debug("%s: EC_POINT_is_on_curve", __func__); + ok = FIDO_ERR_INVALID_ARGUMENT; + 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)) { + (nx = BN_num_bytes(x)) < 0 || (size_t)nx > sizeof(pk->x) || + (ny = BN_num_bytes(y)) < 0 || (size_t)ny > 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)) { + dx = sizeof(pk->x) - (size_t)nx; + dy = sizeof(pk->y) - (size_t)ny; + + if ((nx = BN_bn2bin(x, pk->x + dx)) < 0 || (size_t)nx > sizeof(pk->x) || + (ny = BN_bn2bin(y, pk->y + dy)) < 0 || (size_t)ny > sizeof(pk->y)) { fido_log_debug("%s: BN_bn2bin", __func__); goto fail; } ok = FIDO_OK; fail: + EC_GROUP_free(g); + 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; + const EC_KEY *ec; if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC || - (ec = EVP_PKEY_get0(pkey)) == NULL) + (ec = get0_EC_KEY(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 || + if ((ec = EC_KEY_new_by_curve_name(es256_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 || + (ec = EC_KEY_new_by_curve_name(es256_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/es384.c b/contrib/libfido2/src/es384.c new file mode 100644 index 000000000000..013d285ef7f0 --- /dev/null +++ b/contrib/libfido2/src/es384.c @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2022 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. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +#include "fido.h" +#include "fido/es384.h" + +#if OPENSSL_VERSION_NUMBER >= 0x30000000 +#define get0_EC_KEY(x) EVP_PKEY_get0_EC_KEY((x)) +#else +#define get0_EC_KEY(x) EVP_PKEY_get0((x)) +#endif + +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) +{ + es384_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 +es384_pk_decode(const cbor_item_t *item, es384_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); +} + +es384_pk_t * +es384_pk_new(void) +{ + return (calloc(1, sizeof(es384_pk_t))); +} + +void +es384_pk_free(es384_pk_t **pkp) +{ + es384_pk_t *pk; + + if (pkp == NULL || (pk = *pkp) == NULL) + return; + + freezero(pk, sizeof(*pk)); + *pkp = NULL; +} + +int +es384_pk_from_ptr(es384_pk_t *pk, const void *ptr, size_t len) +{ + const uint8_t *p = ptr; + EVP_PKEY *pkey; + + 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 */ + + if ((pkey = es384_pk_to_EVP_PKEY(pk)) == NULL) { + fido_log_debug("%s: es384_pk_to_EVP_PKEY", __func__); + explicit_bzero(pk, sizeof(*pk)); + return (FIDO_ERR_INVALID_ARGUMENT); + } + + EVP_PKEY_free(pkey); + + return (FIDO_OK); +} + +EVP_PKEY * +es384_pk_to_EVP_PKEY(const es384_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; + 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_secp384r1)) == 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 +es384_pk_from_EC_KEY(es384_pk_t *pk, const EC_KEY *ec) +{ + BN_CTX *bnctx = NULL; + BIGNUM *x = NULL; + BIGNUM *y = NULL; + const EC_POINT *q = NULL; + EC_GROUP *g = NULL; + size_t dx; + size_t dy; + int ok = FIDO_ERR_INTERNAL; + int nx; + int ny; + + if ((q = EC_KEY_get0_public_key(ec)) == NULL || + (g = EC_GROUP_new_by_curve_name(NID_secp384r1)) == 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_is_on_curve(g, q, bnctx) != 1) { + fido_log_debug("%s: EC_POINT_is_on_curve", __func__); + ok = FIDO_ERR_INVALID_ARGUMENT; + goto fail; + } + + if (EC_POINT_get_affine_coordinates_GFp(g, q, x, y, bnctx) == 0 || + (nx = BN_num_bytes(x)) < 0 || (size_t)nx > sizeof(pk->x) || + (ny = BN_num_bytes(y)) < 0 || (size_t)ny > sizeof(pk->y)) { + fido_log_debug("%s: EC_POINT_get_affine_coordinates_GFp", + __func__); + goto fail; + } + + dx = sizeof(pk->x) - (size_t)nx; + dy = sizeof(pk->y) - (size_t)ny; + + if ((nx = BN_bn2bin(x, pk->x + dx)) < 0 || (size_t)nx > sizeof(pk->x) || + (ny = BN_bn2bin(y, pk->y + dy)) < 0 || (size_t)ny > sizeof(pk->y)) { + fido_log_debug("%s: BN_bn2bin", __func__); + goto fail; + } + + ok = FIDO_OK; +fail: + EC_GROUP_free(g); + + if (bnctx != NULL) { + BN_CTX_end(bnctx); + BN_CTX_free(bnctx); + } + + return (ok); +} + +int +es384_pk_from_EVP_PKEY(es384_pk_t *pk, const EVP_PKEY *pkey) +{ + const EC_KEY *ec; + + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC || + (ec = get0_EC_KEY(pkey)) == NULL) + return (FIDO_ERR_INVALID_ARGUMENT); + + return (es384_pk_from_EC_KEY(pk, ec)); +} + +int +es384_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 +es384_pk_verify_sig(const fido_blob_t *dgst, const es384_pk_t *pk, + const fido_blob_t *sig) +{ + EVP_PKEY *pkey; + int ok = -1; + + if ((pkey = es384_pk_to_EVP_PKEY(pk)) == NULL || + es384_verify_sig(dgst, pkey, sig) < 0) { + fido_log_debug("%s: es384_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 0a8d46a20fad..604741ed7d92 100644 --- a/contrib/libfido2/src/export.gnu +++ b/contrib/libfido2/src/export.gnu @@ -1,247 +1,265 @@ { 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; + es384_pk_free; + es384_pk_from_EC_KEY; + es384_pk_from_EVP_PKEY; + es384_pk_from_ptr; + es384_pk_new; + es384_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_empty_allow_list; 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_certs_len; + fido_cbor_info_certs_name_ptr; + fido_cbor_info_certs_value_ptr; fido_cbor_info_extensions_len; fido_cbor_info_extensions_ptr; fido_cbor_info_free; - fido_cbor_info_maxmsgsiz; + fido_cbor_info_fwversion; fido_cbor_info_maxcredbloblen; fido_cbor_info_maxcredcntlst; fido_cbor_info_maxcredidlen; - fido_cbor_info_fwversion; + fido_cbor_info_maxlargeblob; + fido_cbor_info_maxmsgsiz; + fido_cbor_info_maxrpid_minpinlen; + fido_cbor_info_minpinlen; fido_cbor_info_new; + fido_cbor_info_new_pin_required; 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_rk_remaining; fido_cbor_info_transports_len; fido_cbor_info_transports_ptr; + fido_cbor_info_uv_attempts; + fido_cbor_info_uv_modality; 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_empty_exclude_list; 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_set; fido_dev_info_vendor; fido_dev_io_handle; fido_dev_is_fido2; fido_dev_is_winhello; fido_dev_major; fido_dev_make_cred; fido_dev_minor; fido_dev_new; fido_dev_new_with_info; fido_dev_open; fido_dev_open_with_info; 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 80507346edee..0be829538d7b 100644 --- a/contrib/libfido2/src/export.llvm +++ b/contrib/libfido2/src/export.llvm @@ -1,242 +1,260 @@ _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 +_es384_pk_free +_es384_pk_from_EC_KEY +_es384_pk_from_EVP_PKEY +_es384_pk_from_ptr +_es384_pk_new +_es384_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_empty_allow_list _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_certs_len +_fido_cbor_info_certs_name_ptr +_fido_cbor_info_certs_value_ptr _fido_cbor_info_extensions_len _fido_cbor_info_extensions_ptr _fido_cbor_info_free -_fido_cbor_info_maxmsgsiz +_fido_cbor_info_fwversion _fido_cbor_info_maxcredbloblen _fido_cbor_info_maxcredcntlst _fido_cbor_info_maxcredidlen -_fido_cbor_info_fwversion +_fido_cbor_info_maxlargeblob +_fido_cbor_info_maxmsgsiz +_fido_cbor_info_maxrpid_minpinlen +_fido_cbor_info_minpinlen _fido_cbor_info_new +_fido_cbor_info_new_pin_required _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_rk_remaining _fido_cbor_info_transports_len _fido_cbor_info_transports_ptr +_fido_cbor_info_uv_attempts +_fido_cbor_info_uv_modality _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_empty_exclude_list _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_set _fido_dev_info_vendor _fido_dev_io_handle _fido_dev_is_fido2 _fido_dev_is_winhello _fido_dev_major _fido_dev_make_cred _fido_dev_minor _fido_dev_new _fido_dev_new_with_info _fido_dev_open _fido_dev_open_with_info _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 14602164fd45..10f8bd14497d 100644 --- a/contrib/libfido2/src/export.msvc +++ b/contrib/libfido2/src/export.msvc @@ -1,243 +1,261 @@ 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 +es384_pk_free +es384_pk_from_EC_KEY +es384_pk_from_EVP_PKEY +es384_pk_from_ptr +es384_pk_new +es384_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_empty_allow_list 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_certs_len +fido_cbor_info_certs_name_ptr +fido_cbor_info_certs_value_ptr fido_cbor_info_extensions_len fido_cbor_info_extensions_ptr fido_cbor_info_free -fido_cbor_info_maxmsgsiz +fido_cbor_info_fwversion fido_cbor_info_maxcredbloblen fido_cbor_info_maxcredcntlst fido_cbor_info_maxcredidlen -fido_cbor_info_fwversion +fido_cbor_info_maxlargeblob +fido_cbor_info_maxmsgsiz +fido_cbor_info_maxrpid_minpinlen +fido_cbor_info_minpinlen fido_cbor_info_new +fido_cbor_info_new_pin_required 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_rk_remaining fido_cbor_info_transports_len fido_cbor_info_transports_ptr +fido_cbor_info_uv_attempts +fido_cbor_info_uv_modality 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_empty_exclude_list 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_set fido_dev_info_vendor fido_dev_io_handle fido_dev_is_fido2 fido_dev_is_winhello fido_dev_major fido_dev_make_cred fido_dev_minor fido_dev_new fido_dev_new_with_info fido_dev_open fido_dev_open_with_info 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 6f86d7642950..1bc95b27805d 100644 --- a/contrib/libfido2/src/extern.h +++ b/contrib/libfido2/src/extern.h @@ -1,258 +1,276 @@ /* - * Copyright (c) 2018-2021 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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_bool(const cbor_item_t *, bool *); 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 es384_pk_decode(const cbor_item_t *, es384_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 **, 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 */ +bool fido_is_nfc(const char *); +bool nfc_is_fido(const char *); 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 *); +int fido_dev_set_nfc(fido_dev_t *); + +/* pcsc i/o */ +bool fido_is_pcsc(const char *); +void *fido_pcsc_open(const char *); +void fido_pcsc_close(void *); +int fido_pcsc_read(void *, unsigned char *, size_t, int); +int fido_pcsc_write(void *, const unsigned char *, size_t); +int fido_pcsc_rx(fido_dev_t *, uint8_t, unsigned char *, size_t, int); +int fido_pcsc_tx(fido_dev_t *, uint8_t, const unsigned char *, size_t); +int fido_dev_set_pcsc(fido_dev_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); 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); /* 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 *); /* 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 *); 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 *); 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 *, int *); uint64_t fido_dev_maxmsgsize(const fido_dev_t *); int fido_do_ecdh(fido_dev_t *, es256_pk_t **, fido_blob_t **, int *); /* types */ void fido_algo_array_free(fido_algo_array_t *); void fido_byte_array_free(fido_byte_array_t *); +void fido_cert_array_free(fido_cert_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 *); +int fido_to_uint64(const char *, int, uint64_t *); /* crypto */ int es256_verify_sig(const fido_blob_t *, EVP_PKEY *, const fido_blob_t *); +int es384_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 es384_pk_verify_sig(const fido_blob_t *, const es384_pk_t *, + const fido_blob_t *); int rs256_pk_verify_sig(const fido_blob_t *, const rs256_pk_t *, const fido_blob_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); +int fido_pcsc_manifest(fido_dev_info_t *, size_t, size_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:" +#define FIDO_PCSC_PREFIX "pcsc:" #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* !_EXTERN_H */ diff --git a/contrib/libfido2/src/fallthrough.h b/contrib/libfido2/src/fallthrough.h new file mode 100644 index 000000000000..bdfd30fd63eb --- /dev/null +++ b/contrib/libfido2/src/fallthrough.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 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. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef _FALLTHROUGH_H +#define _FALLTHROUGH_H + +#if defined(__GNUC__) +#if __has_attribute(fallthrough) +#define FALLTHROUGH __attribute__((fallthrough)); +#endif +#endif /* __GNUC__ */ + +#ifndef FALLTHROUGH +#define FALLTHROUGH /* FALLTHROUGH */ +#endif + +#endif /* !_FALLTHROUGH_H */ diff --git a/contrib/libfido2/src/fido.h b/contrib/libfido2/src/fido.h index 4bd2aeebfccb..607c44fcfd91 100644 --- a/contrib/libfido2/src/fido.h +++ b/contrib/libfido2/src/fido.h @@ -1,238 +1,274 @@ /* - * 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. + * Copyright (c) 2018-2022 Yubico AB. All rights reserved. + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #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_dev_io_handle(const fido_dev_t *); 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_certs_name_ptr(const fido_cbor_info_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 uint64_t *fido_cbor_info_certs_value_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_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 *); int fido_assert_allow_cred(fido_assert_t *, const unsigned char *, size_t); +int fido_assert_empty_allow_list(fido_assert_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_empty_exclude_list(fido_cred_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 *); +#ifdef _FIDO_SIGSET_DEFINED int fido_dev_set_sigmask(fido_dev_t *, const fido_sigset_t *); +#endif 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_info_set(fido_dev_info_t *, size_t, const char *, const char *, const char *, const fido_dev_io_t *, const fido_dev_transport_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_certs_len(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_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 *); 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_fwversion(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 *); +uint64_t fido_cbor_info_maxlargeblob(const fido_cbor_info_t *); +uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *); +uint64_t fido_cbor_info_maxrpid_minpinlen(const fido_cbor_info_t *); +uint64_t fido_cbor_info_minpinlen(const fido_cbor_info_t *); +uint64_t fido_cbor_info_uv_attempts(const fido_cbor_info_t *); +uint64_t fido_cbor_info_uv_modality(const fido_cbor_info_t *); +int64_t fido_cbor_info_rk_remaining(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_credman(const fido_dev_t *); bool fido_dev_supports_cred_prot(const fido_dev_t *); bool fido_dev_supports_permissions(const fido_dev_t *); bool fido_dev_supports_pin(const fido_dev_t *); bool fido_dev_supports_uv(const fido_dev_t *); +bool fido_cbor_info_new_pin_required(const fido_cbor_info_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/bio.h b/contrib/libfido2/src/fido/bio.h index afe9ca4752b4..f5039e03dc90 100644 --- a/contrib/libfido2/src/fido/bio.h +++ b/contrib/libfido2/src/fido/bio.h @@ -1,111 +1,133 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _FIDO_BIO_H #define _FIDO_BIO_H #include #include #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 */ #ifdef _FIDO_INTERNAL struct fido_bio_template { fido_blob_t id; char *name; }; struct fido_bio_template_array { struct fido_bio_template *ptr; size_t n_alloc; /* number of allocated entries */ size_t n_rx; /* number of populated entries */ }; struct fido_bio_enroll { uint8_t remaining_samples; uint8_t last_status; fido_blob_t *token; }; struct fido_bio_info { uint8_t type; uint8_t max_samples; }; #endif typedef struct fido_bio_template fido_bio_template_t; typedef struct fido_bio_template_array fido_bio_template_array_t; typedef struct fido_bio_enroll fido_bio_enroll_t; typedef struct fido_bio_info fido_bio_info_t; #define FIDO_BIO_ENROLL_FP_GOOD 0x00 #define FIDO_BIO_ENROLL_FP_TOO_HIGH 0x01 #define FIDO_BIO_ENROLL_FP_TOO_LOW 0x02 #define FIDO_BIO_ENROLL_FP_TOO_LEFT 0x03 #define FIDO_BIO_ENROLL_FP_TOO_RIGHT 0x04 #define FIDO_BIO_ENROLL_FP_TOO_FAST 0x05 #define FIDO_BIO_ENROLL_FP_TOO_SLOW 0x06 #define FIDO_BIO_ENROLL_FP_POOR_QUALITY 0x07 #define FIDO_BIO_ENROLL_FP_TOO_SKEWED 0x08 #define FIDO_BIO_ENROLL_FP_TOO_SHORT 0x09 #define FIDO_BIO_ENROLL_FP_MERGE_FAILURE 0x0a #define FIDO_BIO_ENROLL_FP_EXISTS 0x0b #define FIDO_BIO_ENROLL_FP_DATABASE_FULL 0x0c #define FIDO_BIO_ENROLL_NO_USER_ACTIVITY 0x0d #define FIDO_BIO_ENROLL_NO_USER_PRESENCE_TRANSITION 0x0e const char *fido_bio_template_name(const fido_bio_template_t *); const fido_bio_template_t *fido_bio_template(const fido_bio_template_array_t *, size_t); const unsigned char *fido_bio_template_id_ptr(const fido_bio_template_t *); fido_bio_enroll_t *fido_bio_enroll_new(void); fido_bio_info_t *fido_bio_info_new(void); fido_bio_template_array_t *fido_bio_template_array_new(void); fido_bio_template_t *fido_bio_template_new(void); int fido_bio_dev_enroll_begin(fido_dev_t *, fido_bio_template_t *, fido_bio_enroll_t *, uint32_t, const char *); int fido_bio_dev_enroll_cancel(fido_dev_t *); int fido_bio_dev_enroll_continue(fido_dev_t *, const fido_bio_template_t *, fido_bio_enroll_t *, uint32_t); int fido_bio_dev_enroll_remove(fido_dev_t *, const fido_bio_template_t *, const char *); int fido_bio_dev_get_info(fido_dev_t *, fido_bio_info_t *); int fido_bio_dev_get_template_array(fido_dev_t *, fido_bio_template_array_t *, const char *); int fido_bio_dev_set_template_name(fido_dev_t *, const fido_bio_template_t *, const char *); int fido_bio_template_set_id(fido_bio_template_t *, const unsigned char *, size_t); int fido_bio_template_set_name(fido_bio_template_t *, const char *); size_t fido_bio_template_array_count(const fido_bio_template_array_t *); size_t fido_bio_template_id_len(const fido_bio_template_t *); uint8_t fido_bio_enroll_last_status(const fido_bio_enroll_t *); uint8_t fido_bio_enroll_remaining_samples(const fido_bio_enroll_t *); uint8_t fido_bio_info_max_samples(const fido_bio_info_t *); uint8_t fido_bio_info_type(const fido_bio_info_t *); void fido_bio_enroll_free(fido_bio_enroll_t **); void fido_bio_info_free(fido_bio_info_t **); void fido_bio_template_array_free(fido_bio_template_array_t **); void fido_bio_template_free(fido_bio_template_t **); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* !_FIDO_BIO_H */ diff --git a/contrib/libfido2/src/fido/config.h b/contrib/libfido2/src/fido/config.h index d8134a3c7b6c..cba286f08f88 100644 --- a/contrib/libfido2/src/fido/config.h +++ b/contrib/libfido2/src/fido/config.h @@ -1,36 +1,58 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #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/credman.h b/contrib/libfido2/src/fido/credman.h index 66a966970501..9f9dff1d5f05 100644 --- a/contrib/libfido2/src/fido/credman.h +++ b/contrib/libfido2/src/fido/credman.h @@ -1,91 +1,113 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _FIDO_CREDMAN_H #define _FIDO_CREDMAN_H #include #include #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 */ #ifdef _FIDO_INTERNAL struct fido_credman_metadata { uint64_t rk_existing; uint64_t rk_remaining; }; struct fido_credman_single_rp { fido_rp_t rp_entity; fido_blob_t rp_id_hash; }; struct fido_credman_rp { struct fido_credman_single_rp *ptr; size_t n_alloc; /* number of allocated entries */ size_t n_rx; /* number of populated entries */ }; struct fido_credman_rk { fido_cred_t *ptr; size_t n_alloc; /* number of allocated entries */ size_t n_rx; /* number of populated entries */ }; #endif typedef struct fido_credman_metadata fido_credman_metadata_t; typedef struct fido_credman_rk fido_credman_rk_t; typedef struct fido_credman_rp fido_credman_rp_t; const char *fido_credman_rp_id(const fido_credman_rp_t *, size_t); const char *fido_credman_rp_name(const fido_credman_rp_t *, size_t); const fido_cred_t *fido_credman_rk(const fido_credman_rk_t *, size_t); const unsigned char *fido_credman_rp_id_hash_ptr(const fido_credman_rp_t *, size_t); fido_credman_metadata_t *fido_credman_metadata_new(void); fido_credman_rk_t *fido_credman_rk_new(void); fido_credman_rp_t *fido_credman_rp_new(void); int fido_credman_del_dev_rk(fido_dev_t *, const unsigned char *, size_t, const char *); int fido_credman_get_dev_metadata(fido_dev_t *, fido_credman_metadata_t *, const char *); int fido_credman_get_dev_rk(fido_dev_t *, const char *, fido_credman_rk_t *, const char *); int fido_credman_get_dev_rp(fido_dev_t *, fido_credman_rp_t *, const char *); int fido_credman_set_dev_rk(fido_dev_t *, fido_cred_t *, const char *); size_t fido_credman_rk_count(const fido_credman_rk_t *); size_t fido_credman_rp_count(const fido_credman_rp_t *); size_t fido_credman_rp_id_hash_len(const fido_credman_rp_t *, size_t); uint64_t fido_credman_rk_existing(const fido_credman_metadata_t *); uint64_t fido_credman_rk_remaining(const fido_credman_metadata_t *); void fido_credman_metadata_free(fido_credman_metadata_t **); void fido_credman_rk_free(fido_credman_rk_t **); void fido_credman_rp_free(fido_credman_rp_t **); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* !_FIDO_CREDMAN_H */ diff --git a/contrib/libfido2/src/fido/eddsa.h b/contrib/libfido2/src/fido/eddsa.h index 083721cc3d3f..5c0b681ee7b0 100644 --- a/contrib/libfido2/src/fido/eddsa.h +++ b/contrib/libfido2/src/fido/eddsa.h @@ -1,49 +1,71 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #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) +#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3070000f #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 */ #endif /* _FIDO_INTERNAL */ #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* !_FIDO_EDDSA_H */ diff --git a/contrib/libfido2/src/fido/err.h b/contrib/libfido2/src/fido/err.h index 74fdf9d2bfe8..7db25f269126 100644 --- a/contrib/libfido2/src/fido/err.h +++ b/contrib/libfido2/src/fido/err.h @@ -1,84 +1,106 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _FIDO_ERR_H #define _FIDO_ERR_H #define FIDO_ERR_SUCCESS 0x00 #define FIDO_ERR_INVALID_COMMAND 0x01 #define FIDO_ERR_INVALID_PARAMETER 0x02 #define FIDO_ERR_INVALID_LENGTH 0x03 #define FIDO_ERR_INVALID_SEQ 0x04 #define FIDO_ERR_TIMEOUT 0x05 #define FIDO_ERR_CHANNEL_BUSY 0x06 #define FIDO_ERR_LOCK_REQUIRED 0x0a #define FIDO_ERR_INVALID_CHANNEL 0x0b #define FIDO_ERR_CBOR_UNEXPECTED_TYPE 0x11 #define FIDO_ERR_INVALID_CBOR 0x12 #define FIDO_ERR_MISSING_PARAMETER 0x14 #define FIDO_ERR_LIMIT_EXCEEDED 0x15 #define FIDO_ERR_UNSUPPORTED_EXTENSION 0x16 #define FIDO_ERR_FP_DATABASE_FULL 0x17 #define FIDO_ERR_LARGEBLOB_STORAGE_FULL 0x18 #define FIDO_ERR_CREDENTIAL_EXCLUDED 0x19 #define FIDO_ERR_PROCESSING 0x21 #define FIDO_ERR_INVALID_CREDENTIAL 0x22 #define FIDO_ERR_USER_ACTION_PENDING 0x23 #define FIDO_ERR_OPERATION_PENDING 0x24 #define FIDO_ERR_NO_OPERATIONS 0x25 #define FIDO_ERR_UNSUPPORTED_ALGORITHM 0x26 #define FIDO_ERR_OPERATION_DENIED 0x27 #define FIDO_ERR_KEY_STORE_FULL 0x28 #define FIDO_ERR_NOT_BUSY 0x29 #define FIDO_ERR_NO_OPERATION_PENDING 0x2a #define FIDO_ERR_UNSUPPORTED_OPTION 0x2b #define FIDO_ERR_INVALID_OPTION 0x2c #define FIDO_ERR_KEEPALIVE_CANCEL 0x2d #define FIDO_ERR_NO_CREDENTIALS 0x2e #define FIDO_ERR_USER_ACTION_TIMEOUT 0x2f #define FIDO_ERR_NOT_ALLOWED 0x30 #define FIDO_ERR_PIN_INVALID 0x31 #define FIDO_ERR_PIN_BLOCKED 0x32 #define FIDO_ERR_PIN_AUTH_INVALID 0x33 #define FIDO_ERR_PIN_AUTH_BLOCKED 0x34 #define FIDO_ERR_PIN_NOT_SET 0x35 #define FIDO_ERR_PIN_REQUIRED 0x36 #define FIDO_ERR_PIN_POLICY_VIOLATION 0x37 #define FIDO_ERR_PIN_TOKEN_EXPIRED 0x38 #define FIDO_ERR_REQUEST_TOO_LARGE 0x39 #define FIDO_ERR_ACTION_TIMEOUT 0x3a #define FIDO_ERR_UP_REQUIRED 0x3b #define FIDO_ERR_UV_BLOCKED 0x3c #define FIDO_ERR_UV_INVALID 0x3f #define FIDO_ERR_UNAUTHORIZED_PERM 0x40 #define FIDO_ERR_ERR_OTHER 0x7f #define FIDO_ERR_SPEC_LAST 0xdf /* defined internally */ #define FIDO_OK FIDO_ERR_SUCCESS #define FIDO_ERR_TX -1 #define FIDO_ERR_RX -2 #define FIDO_ERR_RX_NOT_CBOR -3 #define FIDO_ERR_RX_INVALID_CBOR -4 #define FIDO_ERR_INVALID_PARAM -5 #define FIDO_ERR_INVALID_SIG -6 #define FIDO_ERR_INVALID_ARGUMENT -7 #define FIDO_ERR_USER_PRESENCE_REQUIRED -8 #define FIDO_ERR_INTERNAL -9 #define FIDO_ERR_NOTFOUND -10 #define FIDO_ERR_COMPRESS -11 #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ const char *fido_strerr(int); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* _FIDO_ERR_H */ diff --git a/contrib/libfido2/src/fido/es256.h b/contrib/libfido2/src/fido/es256.h index 683494dadfe2..0450de29e831 100644 --- a/contrib/libfido2/src/fido/es256.h +++ b/contrib/libfido2/src/fido/es256.h @@ -1,49 +1,71 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #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/es384.h b/contrib/libfido2/src/fido/es384.h new file mode 100644 index 000000000000..b4b4ca71ccbe --- /dev/null +++ b/contrib/libfido2/src/fido/es384.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022 Yubico AB. All rights reserved. + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _FIDO_ES384_H +#define _FIDO_ES384_H + +#include + +#include +#include + +#ifdef _FIDO_INTERNAL +#include "types.h" +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +es384_pk_t *es384_pk_new(void); +void es384_pk_free(es384_pk_t **); +EVP_PKEY *es384_pk_to_EVP_PKEY(const es384_pk_t *); + +int es384_pk_from_EC_KEY(es384_pk_t *, const EC_KEY *); +int es384_pk_from_EVP_PKEY(es384_pk_t *, const EVP_PKEY *); +int es384_pk_from_ptr(es384_pk_t *, const void *, size_t); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* !_FIDO_ES384_H */ diff --git a/contrib/libfido2/src/fido/param.h b/contrib/libfido2/src/fido/param.h index 7c6db98cfd5d..511370bca272 100644 --- a/contrib/libfido2/src/fido/param.h +++ b/contrib/libfido2/src/fido/param.h @@ -1,121 +1,160 @@ /* - * 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. + * Copyright (c) 2018-2022 Yubico AB. All rights reserved. + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #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 +#define COSE_UNSPEC 0 +#define COSE_ES256 -7 +#define COSE_EDDSA -8 +#define COSE_ECDH_ES256 -25 +#define COSE_ES384 -35 +#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_P384 2 #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_MINPINLEN) #endif /* _FIDO_INTERNAL */ +/* Recognised UV modes. */ +#define FIDO_UV_MODE_TUP 0x0001 /* internal test of user presence */ +#define FIDO_UV_MODE_FP 0x0002 /* internal fingerprint check */ +#define FIDO_UV_MODE_PIN 0x0004 /* internal pin check */ +#define FIDO_UV_MODE_VOICE 0x0008 /* internal voice recognition */ +#define FIDO_UV_MODE_FACE 0x0010 /* internal face recognition */ +#define FIDO_UV_MODE_LOCATION 0x0020 /* internal location check */ +#define FIDO_UV_MODE_EYE 0x0040 /* internal eyeprint check */ +#define FIDO_UV_MODE_DRAWN 0x0080 /* internal drawn pattern check */ +#define FIDO_UV_MODE_HAND 0x0100 /* internal handprint verification */ +#define FIDO_UV_MODE_NONE 0x0200 /* TUP/UV not required */ +#define FIDO_UV_MODE_ALL 0x0400 /* all supported UV modes required */ +#define FIDO_UV_MODE_EXT_PIN 0x0800 /* external pin verification */ +#define FIDO_UV_MODE_EXT_DRAWN 0x1000 /* external drawn pattern check */ + #endif /* !_FIDO_PARAM_H */ diff --git a/contrib/libfido2/src/fido/rs256.h b/contrib/libfido2/src/fido/rs256.h index 039816191783..6f8c78195f8d 100644 --- a/contrib/libfido2/src/fido/rs256.h +++ b/contrib/libfido2/src/fido/rs256.h @@ -1,37 +1,59 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #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 4a216b4b9786..cfb4c7a75315 100644 --- a/contrib/libfido2/src/fido/types.h +++ b/contrib/libfido2/src/fido/types.h @@ -1,287 +1,335 @@ /* - * 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. + * Copyright (c) 2018-2022 Yubico AB. All rights reserved. + * SPDX-License-Identifier: BSD-2-Clause + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #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 *); +#undef _FIDO_SIGSET_DEFINED +#define _FIDO_SIGSET_DEFINED #ifdef _WIN32 typedef int fido_sigset_t; -#else +#elif defined(SIG_BLOCK) typedef sigset_t fido_sigset_t; +#else +#undef _FIDO_SIGSET_DEFINED #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 ES384 (ECDSA over P-384 with SHA-384) public key */ +typedef struct es384_pk { + unsigned char x[48]; + unsigned char y[48]; +} es384_pk_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; + es384_pk_t es384; rs256_pk_t rs256; eddsa_pk_t eddsa; } pubkey; } fido_attcred_t; typedef struct fido_attstmt { 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 */ 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; /* CTAP 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 CTAP 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_cert_array { + char **name; + uint64_t *value; + size_t len; +} fido_cert_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 */ + 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 credentials in list */ + uint64_t maxcredidlen; /* max credential ID length */ + uint64_t fwversion; /* firmware version */ uint64_t maxcredbloblen; /* max credBlob length */ + uint64_t maxlargeblob; /* max largeBlob array length */ + uint64_t maxrpid_minlen; /* max rpid in set_pin_minlen_rpid */ + uint64_t minpinlen; /* min pin len enforced */ + uint64_t uv_attempts; /* platform uv attempts */ + uint64_t uv_modality; /* bitmask of supported uv types */ + int64_t rk_remaining; /* remaining resident credentials */ + bool new_pin_reqd; /* new pin required */ + fido_cert_array_t certs; /* associated certifications */ } 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 es384_pk es384_pk_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.c b/contrib/libfido2/src/hid.c index 926272b6b3ed..662bd44adfca 100644 --- a/contrib/libfido2/src/hid.c +++ b/contrib/libfido2/src/hid.c @@ -1,221 +1,222 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include "fido.h" static int get_key_len(uint8_t tag, uint8_t *key, size_t *key_len) { *key = tag & 0xfc; if ((*key & 0xf0) == 0xf0) { fido_log_debug("%s: *key=0x%02x", __func__, *key); return (-1); } *key_len = tag & 0x3; if (*key_len == 3) { *key_len = 4; } return (0); } static int get_key_val(const void *body, size_t key_len, uint32_t *val) { const uint8_t *ptr = body; switch (key_len) { case 0: *val = 0; break; case 1: *val = ptr[0]; break; case 2: *val = (uint32_t)((ptr[1] << 8) | ptr[0]); break; default: fido_log_debug("%s: key_len=%zu", __func__, key_len); return (-1); } return (0); } int fido_hid_get_usage(const uint8_t *report_ptr, size_t report_len, uint32_t *usage_page) { const uint8_t *ptr = report_ptr; size_t len = report_len; while (len > 0) { const uint8_t tag = ptr[0]; ptr++; len--; uint8_t key; size_t key_len; uint32_t key_val; if (get_key_len(tag, &key, &key_len) < 0 || key_len > len || get_key_val(ptr, key_len, &key_val) < 0) { return (-1); } if (key == 0x4) { *usage_page = key_val; } ptr += key_len; len -= key_len; } return (0); } int fido_hid_get_report_len(const uint8_t *report_ptr, size_t report_len, size_t *report_in_len, size_t *report_out_len) { const uint8_t *ptr = report_ptr; size_t len = report_len; uint32_t report_size = 0; while (len > 0) { const uint8_t tag = ptr[0]; ptr++; len--; uint8_t key; size_t key_len; uint32_t key_val; if (get_key_len(tag, &key, &key_len) < 0 || key_len > len || get_key_val(ptr, key_len, &key_val) < 0) { return (-1); } if (key == 0x94) { report_size = key_val; } else if (key == 0x80) { *report_in_len = (size_t)report_size; } else if (key == 0x90) { *report_out_len = (size_t)report_size; } ptr += key_len; len -= key_len; } return (0); } fido_dev_info_t * fido_dev_info_new(size_t n) { return (calloc(n, sizeof(fido_dev_info_t))); } static void fido_dev_info_reset(fido_dev_info_t *di) { free(di->path); free(di->manufacturer); free(di->product); memset(di, 0, sizeof(*di)); } void fido_dev_info_free(fido_dev_info_t **devlist_p, size_t n) { fido_dev_info_t *devlist; if (devlist_p == NULL || (devlist = *devlist_p) == NULL) return; for (size_t i = 0; i < n; i++) fido_dev_info_reset(&devlist[i]); free(devlist); *devlist_p = NULL; } const fido_dev_info_t * fido_dev_info_ptr(const fido_dev_info_t *devlist, size_t i) { return (&devlist[i]); } int fido_dev_info_set(fido_dev_info_t *devlist, size_t i, const char *path, const char *manufacturer, const char *product, const fido_dev_io_t *io, const fido_dev_transport_t *transport) { char *path_copy = NULL, *manu_copy = NULL, *prod_copy = NULL; int r; if (path == NULL || manufacturer == NULL || product == NULL || io == NULL) { r = FIDO_ERR_INVALID_ARGUMENT; goto out; } if ((path_copy = strdup(path)) == NULL || (manu_copy = strdup(manufacturer)) == NULL || (prod_copy = strdup(product)) == NULL) { r = FIDO_ERR_INTERNAL; goto out; } fido_dev_info_reset(&devlist[i]); devlist[i].path = path_copy; devlist[i].manufacturer = manu_copy; devlist[i].product = prod_copy; devlist[i].io = *io; if (transport) devlist[i].transport = *transport; r = FIDO_OK; out: if (r != FIDO_OK) { free(prod_copy); free(manu_copy); free(path_copy); } return (r); } const char * fido_dev_info_path(const fido_dev_info_t *di) { return (di->path); } int16_t fido_dev_info_vendor(const fido_dev_info_t *di) { return (di->vendor_id); } int16_t fido_dev_info_product(const fido_dev_info_t *di) { return (di->product_id); } const char * fido_dev_info_manufacturer_string(const fido_dev_info_t *di) { return (di->manufacturer); } const char * fido_dev_info_product_string(const fido_dev_info_t *di) { return (di->product); } diff --git a/contrib/libfido2/src/hid_freebsd.c b/contrib/libfido2/src/hid_freebsd.c index 5151690afc0a..2bbe80b5349c 100644 --- a/contrib/libfido2/src/hid_freebsd.c +++ b/contrib/libfido2/src/hid_freebsd.c @@ -1,336 +1,337 @@ /* * Copyright (c) 2020-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #if __FreeBSD_version >= 1300500 #include #define USE_HIDRAW /* see usbhid(4) and hidraw(4) on FreeBSD 13+ */ #endif #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); } #ifdef USE_HIDRAW static int copy_info_hidraw(fido_dev_info_t *di, const char *path) { int fd = -1; int ok = -1; struct usb_device_info udi; struct hidraw_devinfo devinfo; char rawname[129]; memset(di, 0, sizeof(*di)); memset(&udi, 0, sizeof(udi)); memset(&devinfo, 0, sizeof(devinfo)); memset(rawname, 0, sizeof(rawname)); if ((fd = fido_hid_unix_open(path)) == -1 || is_fido(fd) == 0) goto fail; if (ioctl(fd, IOCTL_REQ(USB_GET_DEVICEINFO), &udi) == -1) { if (ioctl(fd, IOCTL_REQ(HIDIOCGRAWINFO), &devinfo) == -1 || ioctl(fd, IOCTL_REQ(HIDIOCGRAWNAME(128)), rawname) == -1 || (di->path = strdup(path)) == NULL || (di->manufacturer = strdup(UHID_VENDOR)) == NULL || (di->product = strdup(rawname)) == NULL) goto fail; di->vendor_id = devinfo.vendor; di->product_id = devinfo.product; } else { 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) == -1) fido_log_error(errno, "%s: close %s", __func__, path); if (ok < 0) { free(di->path); free(di->manufacturer); free(di->product); explicit_bzero(di, sizeof(*di)); } return (ok); } #endif /* USE_HIDRAW */ static int copy_info_uhid(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, 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) == -1) fido_log_error(errno, "%s: close %s", __func__, path); 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; if (ilen == 0) return (FIDO_OK); /* nothing to do */ if (devlist == NULL || olen == NULL) return (FIDO_ERR_INVALID_ARGUMENT); *olen = 0; #ifdef USE_HIDRAW for (i = 0; i < MAX_UHID && *olen < ilen; i++) { snprintf(path, sizeof(path), "/dev/hidraw%zu", i); if (copy_info_hidraw(&devlist[*olen], path) == 0) { devlist[*olen].io = (fido_dev_io_t) { fido_hid_open, fido_hid_close, fido_hid_read, fido_hid_write, }; ++(*olen); } } /* hidraw(4) is preferred over uhid(4) */ if (*olen != 0) return (FIDO_OK); #endif /* USE_HIDRAW */ for (i = 0; i < MAX_UHID && *olen < ilen; i++) { snprintf(path, sizeof(path), "/dev/uhid%zu", i); if (copy_info_uhid(&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); /* * N.B. if ctx->fd is an hidraw(4) device, the ioctl() below puts it in * uhid(4) compat mode, which we need to keep fido_hid_write() as-is. */ 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_hidapi.c b/contrib/libfido2/src/hid_hidapi.c index f6d21711e152..fed6f69a2237 100644 --- a/contrib/libfido2/src/hid_hidapi.c +++ b/contrib/libfido2/src/hid_hidapi.c @@ -1,268 +1,269 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #ifdef __linux__ #include #include #include #include #endif #include #include #include #include "fido.h" struct hid_hidapi { void *handle; size_t report_in_len; size_t report_out_len; }; static size_t fido_wcslen(const wchar_t *wcs) { size_t l = 0; while (*wcs++ != L'\0') l++; return l; } static char * wcs_to_cs(const wchar_t *wcs) { char *cs; size_t i; if (wcs == NULL || (cs = calloc(fido_wcslen(wcs) + 1, 1)) == NULL) return NULL; for (i = 0; i < fido_wcslen(wcs); i++) { if (wcs[i] >= 128) { /* give up on parsing non-ASCII text */ free(cs); return strdup("hidapi device"); } cs[i] = (char)wcs[i]; } return cs; } static int copy_info(fido_dev_info_t *di, const struct hid_device_info *d) { memset(di, 0, sizeof(*di)); if (d->path != NULL) di->path = strdup(d->path); else di->path = strdup(""); if (d->manufacturer_string != NULL) di->manufacturer = wcs_to_cs(d->manufacturer_string); else di->manufacturer = strdup(""); if (d->product_string != NULL) di->product = wcs_to_cs(d->product_string); else di->product = strdup(""); 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 -1; } di->product_id = (int16_t)d->product_id; di->vendor_id = (int16_t)d->vendor_id; di->io = (fido_dev_io_t) { &fido_hid_open, &fido_hid_close, &fido_hid_read, &fido_hid_write, }; return 0; } #ifdef __linux__ static int get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd) { int fd; int s = -1; int ok = -1; if ((fd = fido_hid_unix_open(path)) == -1) { fido_log_debug("%s: fido_hid_unix_open", __func__); return -1; } if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESCSIZE), &s) < 0 || s < 0 || (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) { fido_log_error(errno, "%s: ioctl HIDIOCGRDESCSIZE", __func__); goto fail; } hrd->size = (unsigned)s; if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESC), hrd) < 0) { fido_log_error(errno, "%s: ioctl HIDIOCGRDESC", __func__); goto fail; } ok = 0; fail: if (fd != -1) close(fd); return ok; } static bool is_fido(const struct hid_device_info *hdi) { uint32_t usage_page = 0; - struct hidraw_report_descriptor hrd; + struct hidraw_report_descriptor *hrd; - memset(&hrd, 0, sizeof(hrd)); + if ((hrd = calloc(1, sizeof(*hrd))) == NULL || + get_report_descriptor(hdi->path, hrd) < 0 || + fido_hid_get_usage(hrd->value, hrd->size, &usage_page) < 0) + usage_page = 0; - if (get_report_descriptor(hdi->path, &hrd) < 0 || - fido_hid_get_usage(hrd.value, hrd.size, &usage_page) < 0) { - return false; - } + free(hrd); return usage_page == 0xf1d0; } #elif defined(_WIN32) || defined(__APPLE__) static bool is_fido(const struct hid_device_info *hdi) { return hdi->usage_page == 0xf1d0; } #else static bool is_fido(const struct hid_device_info *hdi) { (void)hdi; fido_log_debug("%s: assuming FIDO HID", __func__); return true; } #endif void * fido_hid_open(const char *path) { struct hid_hidapi *ctx; if ((ctx = calloc(1, sizeof(*ctx))) == NULL) { return (NULL); } if ((ctx->handle = hid_open_path(path)) == NULL) { free(ctx); return (NULL); } ctx->report_in_len = ctx->report_out_len = CTAP_MAX_REPORT_LEN; return ctx; } void fido_hid_close(void *handle) { struct hid_hidapi *ctx = handle; hid_close(ctx->handle); 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_hidapi *ctx = handle; if (len != ctx->report_in_len) { fido_log_debug("%s: len %zu", __func__, len); return -1; } return hid_read_timeout(ctx->handle, buf, len, ms); } int fido_hid_write(void *handle, const unsigned char *buf, size_t len) { struct hid_hidapi *ctx = handle; if (len != ctx->report_out_len + 1) { fido_log_debug("%s: len %zu", __func__, len); return -1; } return hid_write(ctx->handle, buf, len); } int fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { struct hid_device_info *hdi; *olen = 0; if (ilen == 0) return FIDO_OK; /* nothing to do */ if (devlist == NULL) return FIDO_ERR_INVALID_ARGUMENT; if ((hdi = hid_enumerate(0, 0)) == NULL) return FIDO_OK; /* nothing to do */ for (struct hid_device_info *d = hdi; d != NULL; d = d->next) { if (is_fido(d) == false) continue; if (copy_info(&devlist[*olen], d) == 0) { if (++(*olen) == ilen) break; } } hid_free_enumeration(hdi); return FIDO_OK; } size_t fido_hid_report_in_len(void *handle) { struct hid_hidapi *ctx = handle; return (ctx->report_in_len); } size_t fido_hid_report_out_len(void *handle) { struct hid_hidapi *ctx = handle; return (ctx->report_out_len); } diff --git a/contrib/libfido2/src/hid_linux.c b/contrib/libfido2/src/hid_linux.c index c4ce4fd578a6..841a95b08e41 100644 --- a/contrib/libfido2/src/hid_linux.c +++ b/contrib/libfido2/src/hid_linux.c @@ -1,375 +1,391 @@ /* - * Copyright (c) 2019 Yubico AB. All rights reserved. + * Copyright (c) 2019-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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) + int fd = -1; + uint32_t usage_page = 0; + struct hidraw_report_descriptor *hrd = NULL; + + if ((hrd = calloc(1, sizeof(*hrd))) == NULL || + (fd = fido_hid_unix_open(path)) == -1) + goto out; + 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) +out: + free(hrd); + + if (fd != -1 && 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(""); if ((di->product = get_usb_attr(dev, "product")) == NULL) 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 hidraw_report_descriptor *hrd; struct timespec tv_pause; long interval_ms, retries = 0; + bool looped; + +retry: + looped = false; 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) { + looped = true; + if (retries++ >= 20) { 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, + if (looped) { + fido_log_debug("%s: retrying", __func__); + fido_hid_close(ctx); + goto retry; + } + + if ((hrd = calloc(1, sizeof(*hrd))) == NULL || + 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; } + free(hrd); + 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_netbsd.c b/contrib/libfido2/src/hid_netbsd.c index c24c6de7ce29..d5b9fad33412 100644 --- a/contrib/libfido2/src/hid_netbsd.c +++ b/contrib/libfido2/src/hid_netbsd.c @@ -1,338 +1,339 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include "fido.h" #define MAX_UHID 64 struct hid_netbsd { int fd; size_t report_in_len; size_t report_out_len; sigset_t sigmask; const sigset_t *sigmaskp; }; /* Hack to make this work with newer kernels even if /usr/include is old. */ #if __NetBSD_Version__ < 901000000 /* 9.1 */ #define USB_HID_GET_RAW _IOR('h', 1, int) #define USB_HID_SET_RAW _IOW('h', 2, int) #endif static bool is_fido(int fd) { struct usb_ctl_report_desc ucrd; uint32_t usage_page = 0; int raw = 1; memset(&ucrd, 0, sizeof(ucrd)); if (ioctl(fd, IOCTL_REQ(USB_GET_REPORT_DESC), &ucrd) == -1) { fido_log_error(errno, "%s: ioctl", __func__); return (false); } if (ucrd.ucrd_size < 0 || (size_t)ucrd.ucrd_size > sizeof(ucrd.ucrd_data) || fido_hid_get_usage(ucrd.ucrd_data, (size_t)ucrd.ucrd_size, &usage_page) < 0) { fido_log_debug("%s: fido_hid_get_usage", __func__); return (false); } if (usage_page != 0xf1d0) return (false); /* * This step is not strictly necessary -- NetBSD puts fido * devices into raw mode automatically by default, but in * principle that might change, and this serves as a test to * verify that we're running on a kernel with support for raw * mode at all so we don't get confused issuing writes that try * to set the report descriptor rather than transfer data on * the output interrupt pipe as we need. */ if (ioctl(fd, IOCTL_REQ(USB_HID_SET_RAW), &raw) == -1) { fido_log_error(errno, "%s: unable to set raw", __func__); return (false); } return (true); } 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__); goto fail; } 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) == -1) fido_log_error(errno, "%s: close", __func__); 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); } /* * Workaround for NetBSD (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_netbsd *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_netbsd *ctx; struct usb_ctl_report_desc ucrd; int r; memset(&ucrd, 0, sizeof(ucrd)); if ((ctx = calloc(1, sizeof(*ctx))) == NULL || (ctx->fd = fido_hid_unix_open(path)) == -1) { free(ctx); return (NULL); } if ((r = ioctl(ctx->fd, IOCTL_REQ(USB_GET_REPORT_DESC), &ucrd)) == -1 || ucrd.ucrd_size < 0 || (size_t)ucrd.ucrd_size > sizeof(ucrd.ucrd_data) || fido_hid_get_report_len(ucrd.ucrd_data, (size_t)ucrd.ucrd_size, &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; } /* * NetBSD 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 (!is_fido(ctx->fd) || terrible_ping_kludge(ctx) != 0) { fido_hid_close(ctx); return NULL; } return (ctx); } void fido_hid_close(void *handle) { struct hid_netbsd *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_netbsd *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_netbsd *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_error(errno, "%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_netbsd *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_error(errno, "%s: %zd != %zu", __func__, r, len - 1); return (-1); } return ((int)len); } size_t fido_hid_report_in_len(void *handle) { struct hid_netbsd *ctx = handle; return (ctx->report_in_len); } size_t fido_hid_report_out_len(void *handle) { struct hid_netbsd *ctx = handle; return (ctx->report_out_len); } diff --git a/contrib/libfido2/src/hid_openbsd.c b/contrib/libfido2/src/hid_openbsd.c index d3d3bff0fc8b..2d08aca42aee 100644 --- a/contrib/libfido2/src/hid_openbsd.c +++ b/contrib/libfido2/src/hid_openbsd.c @@ -1,267 +1,280 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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; }; +static int +copy_info(fido_dev_info_t *di, const char *path) +{ + int fd = -1, 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) + goto fail; + if (ioctl(fd, IOCTL_REQ(USB_GET_DEVICEINFO), &udi) == -1) { + fido_log_error(errno, "%s: ioctl %s", __func__, path); + goto fail; + } + + 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); + + 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) == -1) + fido_log_error(errno, "%s: close %s", __func__, path); + + 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) { 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 (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); } - 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; + 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) { struct hid_openbsd *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_openbsd *ctx = (struct hid_openbsd *)handle; ssize_t r; 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 7f3652e39620..9309762f163c 100644 --- a/contrib/libfido2/src/hid_osx.c +++ b/contrib/libfido2/src/hid_osx.c @@ -1,615 +1,597 @@ /* - * Copyright (c) 2019-2021 Yubico AB. All rights reserved. + * Copyright (c) 2019-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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 #define IOREG "ioreg://" 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) *manufacturer = strdup(""); else *manufacturer = strdup(buf); if (get_utf8(dev, CFSTR(kIOHIDProductKey), buf, sizeof(buf)) < 0) *product = strdup(""); else *product = strdup(buf); 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; uint64_t id; char *path; if ((s = IOHIDDeviceGetService(dev)) == MACH_PORT_NULL) { fido_log_debug("%s: IOHIDDeviceGetService", __func__); return (NULL); } if (IORegistryEntryGetRegistryEntryID(s, &id) != KERN_SUCCESS) { fido_log_debug("%s: IORegistryEntryGetRegistryEntryID", __func__); return (NULL); } if (asprintf(&path, "%s%llu", IOREG, (unsigned long long)id) == -1) { fido_log_error(errno, "%s: asprintf", __func__); return (NULL); } return (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); } -static int -to_uint64(const char *str, uint64_t *out) -{ - char *ep; - unsigned long long ull; - - errno = 0; - ull = strtoull(str, &ep, 10); - if (str == ep || *ep != '\0') - return (-1); - else if (ull == ULLONG_MAX && errno == ERANGE) - return (-1); - else if (ull > UINT64_MAX) - return (-1); - *out = (uint64_t)ull; - - return (0); -} - static io_registry_entry_t get_ioreg_entry(const char *path) { uint64_t id; if (strncmp(path, IOREG, strlen(IOREG)) != 0) return (IORegistryEntryFromPath(kIOMainPortDefault, path)); - if (to_uint64(path + strlen(IOREG), &id) == -1) { - fido_log_debug("%s: to_uint64", __func__); + if (fido_to_uint64(path + strlen(IOREG), 10, &id) == -1) { + fido_log_debug("%s: fido_to_uint64", __func__); return (MACH_PORT_NULL); } return (IOServiceGetMatchingService(kIOMainPortDefault, IORegistryEntryIDMatching(id))); } 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 = get_ioreg_entry(path)) == MACH_PORT_NULL) { fido_log_debug("%s: get_ioreg_entry: %s", __func__, path); 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 946b2dc3b65f..e53882d79e86 100644 --- a/contrib/libfido2/src/hid_unix.c +++ b/contrib/libfido2/src/hid_unix.c @@ -1,75 +1,76 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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 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 fe403bcf46f1..bc98a1701b0d 100644 --- a/contrib/libfido2/src/hid_win.c +++ b/contrib/libfido2/src/hid_win.c @@ -1,570 +1,571 @@ /* - * Copyright (c) 2019-2021 Yubico AB. All rights reserved. + * Copyright (c) 2019-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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__) +#if defined(__MINGW32__) && __MINGW64_VERSION_MAJOR < 8 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_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_manufacturer(HANDLE dev, char **manufacturer) { wchar_t buf[512]; int utf8_len; int ok = -1; *manufacturer = 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(*product); *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_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__, (u_long)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 167a1d30ecaa..cd30828d7ce9 100644 --- a/contrib/libfido2/src/info.c +++ b/contrib/libfido2/src/info.c @@ -1,504 +1,647 @@ /* - * Copyright (c) 2018-2021 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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__); + if (cbor_decode_bool(val, NULL) < 0) { + fido_log_debug("%s: cbor_decode_bool", __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 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__); 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 +decode_cert(const cbor_item_t *key, const cbor_item_t *val, void *arg) +{ + fido_cert_array_t *c = arg; + const size_t i = c->len; + + if (cbor_is_int(val) == false) { + fido_log_debug("%s: cbor_is_int", __func__); + return (0); /* ignore */ + } + + if (cbor_string_copy(key, &c->name[i]) < 0) { + fido_log_debug("%s: cbor_string_copy", __func__); + return (0); /* ignore */ + } + + /* keep name/value and len consistent */ + c->value[i] = cbor_get_int(val); + c->len++; + + return (0); +} + +static int +decode_certs(const cbor_item_t *item, fido_cert_array_t *c) +{ + c->name = NULL; + c->value = NULL; + c->len = 0; + + if (cbor_isa_map(item) == false || + cbor_map_is_definite(item) == false) { + fido_log_debug("%s: cbor type", __func__); + return (-1); + } + + c->name = calloc(cbor_map_size(item), sizeof(char *)); + c->value = calloc(cbor_map_size(item), sizeof(uint64_t)); + if (c->name == NULL || c->value == NULL) + return (-1); + + return (cbor_map_iter(item, c, decode_cert)); +} + static int parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg) { fido_cbor_info_t *ci = 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 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 11: /* maxSerializedLargeBlobArray */ + return (cbor_decode_uint64(val, &ci->maxlargeblob)); + case 12: /* forcePINChange */ + return (cbor_decode_bool(val, &ci->new_pin_reqd)); + case 13: /* minPINLength */ + return (cbor_decode_uint64(val, &ci->minpinlen)); case 14: /* fwVersion */ return (cbor_decode_uint64(val, &ci->fwversion)); case 15: /* maxCredBlobLen */ return (cbor_decode_uint64(val, &ci->maxcredbloblen)); + case 16: /* maxRPIDsForSetMinPINLength */ + return (cbor_decode_uint64(val, &ci->maxrpid_minlen)); + case 17: /* preferredPlatformUvAttempts */ + return (cbor_decode_uint64(val, &ci->uv_attempts)); + case 18: /* uvModality */ + return (cbor_decode_uint64(val, &ci->uv_modality)); + case 19: /* certifications */ + return (decode_certs(val, &ci->certs)); + case 20: /* remainingDiscoverableCredentials */ + if (cbor_decode_uint64(val, &x) < 0 || x > INT64_MAX) { + fido_log_debug("%s: cbor_decode_uint64", __func__); + return (-1); + } + ci->rk_remaining = (int64_t)x; + return (0); default: /* ignore */ - fido_log_debug("%s: cbor type", __func__); + fido_log_debug("%s: cbor type: 0x%02x", __func__, cbor_get_uint8(key)); return (0); } } static int 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), 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) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; + unsigned char *msg; + int msglen; + int r; fido_log_debug("%s: dev=%p, ci=%p, ms=%d", __func__, (void *)dev, (void *)ci, *ms); fido_cbor_info_reset(ci); - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } + + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } - return (cbor_parse_reply(reply, (size_t)reply_len, ci, - parse_reply_element)); + r = cbor_parse_reply(msg, (size_t)msglen, ci, parse_reply_element); +out: + freezero(msg, FIDO_MAXMSG); + + return (r); } int 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, 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) { 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))); + fido_cbor_info_t *ci; + + if ((ci = calloc(1, sizeof(fido_cbor_info_t))) == NULL) + return (NULL); + + fido_cbor_info_reset(ci); + + return (ci); } void fido_cbor_info_reset(fido_cbor_info_t *ci) { 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); + fido_cert_array_free(&ci->certs); + ci->rk_remaining = -1; } 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_maxlargeblob(const fido_cbor_info_t *ci) +{ + return (ci->maxlargeblob); +} + uint64_t fido_cbor_info_fwversion(const fido_cbor_info_t *ci) { return (ci->fwversion); } +uint64_t +fido_cbor_info_minpinlen(const fido_cbor_info_t *ci) +{ + return (ci->minpinlen); +} + +uint64_t +fido_cbor_info_maxrpid_minpinlen(const fido_cbor_info_t *ci) +{ + return (ci->maxrpid_minlen); +} + +uint64_t +fido_cbor_info_uv_attempts(const fido_cbor_info_t *ci) +{ + return (ci->uv_attempts); +} + +uint64_t +fido_cbor_info_uv_modality(const fido_cbor_info_t *ci) +{ + return (ci->uv_modality); +} + +int64_t +fido_cbor_info_rk_remaining(const fido_cbor_info_t *ci) +{ + return (ci->rk_remaining); +} + 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); } + +bool +fido_cbor_info_new_pin_required(const fido_cbor_info_t *ci) +{ + return (ci->new_pin_reqd); +} + +char ** +fido_cbor_info_certs_name_ptr(const fido_cbor_info_t *ci) +{ + return (ci->certs.name); +} + +const uint64_t * +fido_cbor_info_certs_value_ptr(const fido_cbor_info_t *ci) +{ + return (ci->certs.value); +} + +size_t +fido_cbor_info_certs_len(const fido_cbor_info_t *ci) +{ + return (ci->certs.len); +} diff --git a/contrib/libfido2/src/io.c b/contrib/libfido2/src/io.c index 70f777fb49a0..a9715b5b4bf8 100644 --- a/contrib/libfido2/src/io.c +++ b/contrib/libfido2/src/io.c @@ -1,344 +1,356 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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_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 = 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, 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 = 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, 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 = 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, int *ms) { size_t n, sent; 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, 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, 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 (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, ms) : tx(d, cmd, buf, count, ms)); } static int 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) return (-1); return (fido_time_delta(&ts, ms)); } static int 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) { 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) { int n; fido_log_debug("%s: dev=%p, cmd=0x%02x, ms=%d", __func__, (void *)d, cmd, *ms); if (d->transport.rx != NULL) 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) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; + unsigned char *msg; + int msglen; + int r; - if ((reply_len = fido_rx(d, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0 || (size_t)reply_len < 1) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } + + if ((msglen = fido_rx(d, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0 || + (size_t)msglen < 1) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } - return (reply[0]); + r = msg[0]; +out: + freezero(msg, FIDO_MAXMSG); + + return (r); } diff --git a/contrib/libfido2/src/iso7816.c b/contrib/libfido2/src/iso7816.c index a4902277c6d8..5bba10697ee4 100644 --- a/contrib/libfido2/src/iso7816.c +++ b/contrib/libfido2/src/iso7816.c @@ -1,64 +1,65 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include "fido.h" iso7816_apdu_t * iso7816_new(uint8_t cla, uint8_t ins, uint8_t p1, uint16_t payload_len) { iso7816_apdu_t *apdu; size_t alloc_len; alloc_len = sizeof(iso7816_apdu_t) + payload_len + 2; /* le1 le2 */ if ((apdu = calloc(1, alloc_len)) == NULL) return NULL; apdu->alloc_len = alloc_len; apdu->payload_len = payload_len; apdu->payload_ptr = apdu->payload; apdu->header.cla = cla; apdu->header.ins = ins; apdu->header.p1 = p1; apdu->header.lc2 = (uint8_t)((payload_len >> 8) & 0xff); apdu->header.lc3 = (uint8_t)(payload_len & 0xff); return apdu; } void iso7816_free(iso7816_apdu_t **apdu_p) { iso7816_apdu_t *apdu; if (apdu_p == NULL || (apdu = *apdu_p) == NULL) return; freezero(apdu, apdu->alloc_len); *apdu_p = NULL; } int iso7816_add(iso7816_apdu_t *apdu, const void *buf, size_t cnt) { if (cnt > apdu->payload_len || cnt > UINT16_MAX) return -1; memcpy(apdu->payload_ptr, buf, cnt); apdu->payload_ptr += cnt; apdu->payload_len = (uint16_t)(apdu->payload_len - cnt); return 0; } const unsigned char * iso7816_ptr(const iso7816_apdu_t *apdu) { return (const unsigned char *)&apdu->header; } size_t iso7816_len(const iso7816_apdu_t *apdu) { return apdu->alloc_len - offsetof(iso7816_apdu_t, header) - (sizeof(iso7816_apdu_t) - offsetof(iso7816_apdu_t, payload)); } diff --git a/contrib/libfido2/src/iso7816.h b/contrib/libfido2/src/iso7816.h index 9bfad1fbab9d..7545719c6f1b 100644 --- a/contrib/libfido2/src/iso7816.h +++ b/contrib/libfido2/src/iso7816.h @@ -1,48 +1,49 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #ifndef _ISO7816_H #define _ISO7816_H #include #include #include "packed.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ PACKED_TYPE(iso7816_header_t, struct iso7816_header { uint8_t cla; uint8_t ins; uint8_t p1; uint8_t p2; uint8_t lc1; uint8_t lc2; uint8_t lc3; }) typedef struct iso7816_apdu { size_t alloc_len; uint16_t payload_len; uint8_t *payload_ptr; iso7816_header_t header; uint8_t payload[]; } iso7816_apdu_t; const unsigned char *iso7816_ptr(const iso7816_apdu_t *); int iso7816_add(iso7816_apdu_t *, const void *, size_t); iso7816_apdu_t *iso7816_new(uint8_t, uint8_t, uint8_t, uint16_t); size_t iso7816_len(const iso7816_apdu_t *); void iso7816_free(iso7816_apdu_t **); #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* !_ISO7816_H */ diff --git a/contrib/libfido2/src/largeblob.c b/contrib/libfido2/src/largeblob.c index c8173170766d..c1f2e62b2a6a 100644 --- a/contrib/libfido2/src/largeblob.c +++ b/contrib/libfido2/src/largeblob.c @@ -1,890 +1,902 @@ /* - * Copyright (c) 2020 Yubico AB. All rights reserved. + * Copyright (c) 2020-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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, 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, 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) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len, r; + unsigned char *msg; + int msglen, r; *chunk = NULL; - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto out; + } + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) { fido_log_debug("%s: fido_rx", __func__); - return FIDO_ERR_RX; + r = FIDO_ERR_RX; + goto out; } if ((*chunk = fido_blob_new()) == NULL) { fido_log_debug("%s: fido_blob_new", __func__); - return FIDO_ERR_INTERNAL; + r = FIDO_ERR_INTERNAL; + goto out; } - if ((r = cbor_parse_reply(reply, (size_t)reply_len, *chunk, + if ((r = cbor_parse_reply(msg, (size_t)msglen, *chunk, parse_largeblob_reply)) != FIDO_OK) { fido_log_debug("%s: parse_largeblob_reply", __func__); - fido_blob_free(chunk); - return r; + goto out; } - return FIDO_OK; + r = FIDO_OK; +out: + if (r != FIDO_OK) + fido_blob_free(chunk); + + freezero(msg, FIDO_MAXMSG); + + return r; } 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, int *ms) { cbor_item_t *array = NULL; size_t idx; int r; 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, 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, int *ms) { cbor_item_t *array = NULL; size_t idx; int r; 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, 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, &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, &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, &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, &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, &ms)) != FIDO_OK) fido_log_debug("%s: largeblob_set_array", __func__); cbor_decref(&item); return r; } diff --git a/contrib/libfido2/src/log.c b/contrib/libfido2/src/log.c index ab18ae12b4fa..e54f8fca6b90 100644 --- a/contrib/libfido2/src/log.c +++ b/contrib/libfido2/src/log.c @@ -1,121 +1,122 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #undef _GNU_SOURCE /* XSI strerror_r() */ #include #include #include "fido.h" #ifndef FIDO_NO_DIAGNOSTIC #define XXDLEN 32 #define XXDROW 128 #define LINELEN 256 #ifndef TLS #define TLS #endif static TLS int logging; static TLS fido_log_handler_t *log_handler; static void log_on_stderr(const char *str) { fprintf(stderr, "%s", str); } static void do_log(const char *suffix, const char *fmt, va_list args) { char line[LINELEN], body[LINELEN]; vsnprintf(body, sizeof(body), fmt, args); if (suffix != NULL) snprintf(line, sizeof(line), "%.180s: %.70s\n", body, suffix); else snprintf(line, sizeof(line), "%.180s\n", body); log_handler(line); } void fido_log_init(void) { logging = 1; log_handler = log_on_stderr; } void fido_log_debug(const char *fmt, ...) { va_list args; if (!logging || log_handler == NULL) return; va_start(args, fmt); do_log(NULL, fmt, args); va_end(args); } void fido_log_xxd(const void *buf, size_t count, const char *fmt, ...) { const uint8_t *ptr = buf; char row[XXDROW], xxd[XXDLEN]; va_list args; if (!logging || log_handler == NULL) return; snprintf(row, sizeof(row), "buf=%p, len=%zu", buf, count); va_start(args, fmt); do_log(row, fmt, args); va_end(args); *row = '\0'; for (size_t i = 0; i < count; i++) { *xxd = '\0'; if (i % 16 == 0) snprintf(xxd, sizeof(xxd), "%04zu: %02x", i, *ptr++); else snprintf(xxd, sizeof(xxd), " %02x", *ptr++); strlcat(row, xxd, sizeof(row)); if (i % 16 == 15 || i == count - 1) { fido_log_debug("%s", row); *row = '\0'; } } } void fido_log_error(int errnum, const char *fmt, ...) { char errstr[LINELEN]; va_list args; if (!logging || log_handler == NULL) return; if (strerror_r(errnum, errstr, sizeof(errstr)) != 0) snprintf(errstr, sizeof(errstr), "error %d", errnum); va_start(args, fmt); do_log(errstr, fmt, args); va_end(args); } void fido_set_log_handler(fido_log_handler_t *handler) { if (handler != NULL) log_handler = handler; } #endif /* !FIDO_NO_DIAGNOSTIC */ diff --git a/contrib/libfido2/src/netlink.c b/contrib/libfido2/src/netlink.c index 8f14e2c3bac3..2a9216c39058 100644 --- a/contrib/libfido2/src/netlink.c +++ b/contrib/libfido2/src/netlink.c @@ -1,784 +1,785 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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), 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/netlink.h b/contrib/libfido2/src/netlink.h index 9b98064ab8e7..c600b522196a 100644 --- a/contrib/libfido2/src/netlink.h +++ b/contrib/libfido2/src/netlink.h @@ -1,44 +1,45 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #ifndef _FIDO_NETLINK_H #define _FIDO_NETLINK_H #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ typedef struct fido_nl { int fd; uint16_t nfc_type; uint32_t nfc_mcastgrp; struct sockaddr_nl saddr; } fido_nl_t; fido_nl_t *fido_nl_new(void); void fido_nl_free(struct fido_nl **); int fido_nl_power_nfc(struct fido_nl *, uint32_t); int fido_nl_get_nfc_target(struct fido_nl *, uint32_t , uint32_t *); #ifdef FIDO_FUZZ void set_netlink_io_functions(ssize_t (*)(int, void *, size_t), ssize_t (*)(int, const void *, size_t)); #endif #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ #endif /* !_FIDO_NETLINK_H */ diff --git a/contrib/libfido2/src/nfc.c b/contrib/libfido2/src/nfc.c new file mode 100644 index 000000000000..2e97d5fc50da --- /dev/null +++ b/contrib/libfido2/src/nfc.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2020-2022 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. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +#include "fido.h" +#include "fido/param.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' }; + +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, 0x00, + (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) +{ + uint8_t f[256 + 2]; + struct timespec ts; + int n, ok = -1; + + 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) { + 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) { + 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; + } +} + +bool +nfc_is_fido(const char *path) +{ + bool fido = false; + fido_dev_t *d; + int r; + + if ((d = fido_dev_new()) == NULL) { + fido_log_debug("%s: fido_dev_new", __func__); + goto fail; + } + /* fido_dev_open selects the fido applet */ + if ((r = fido_dev_open(d, path)) != FIDO_OK) { + fido_log_debug("%s: fido_dev_open: 0x%x", __func__, r); + goto fail; + } + if ((r = fido_dev_close(d)) != FIDO_OK) { + fido_log_debug("%s: fido_dev_close: 0x%x", __func__, r); + goto fail; + + } + + fido = true; +fail: + fido_dev_free(&d); + + return fido; +} + +#ifdef USE_NFC +bool +fido_is_nfc(const char *path) +{ + return strncmp(path, FIDO_NFC_PREFIX, strlen(FIDO_NFC_PREFIX)) == 0; +} + +int +fido_dev_set_nfc(fido_dev_t *d) +{ + if (d->io_handle != NULL) { + fido_log_debug("%s: device open", __func__); + return -1; + } + d->io_own = true; + d->io = (fido_dev_io_t) { + fido_nfc_open, + fido_nfc_close, + fido_nfc_read, + fido_nfc_write, + }; + d->transport = (fido_dev_transport_t) { + fido_nfc_rx, + fido_nfc_tx, + }; + + return 0; +} +#endif /* USE_NFC */ diff --git a/contrib/libfido2/src/nfc_linux.c b/contrib/libfido2/src/nfc_linux.c index d5f9ec048052..4b69eb1c54c2 100644 --- a/contrib/libfido2/src/nfc_linux.c +++ b/contrib/libfido2/src/nfc_linux.c @@ -1,653 +1,356 @@ /* - * Copyright (c) 2020 Yubico AB. All rights reserved. + * Copyright (c) 2020-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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) -{ - uint8_t f[256 + 2]; - struct timespec ts; - int n, ok = -1; - - 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) { - 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) { - 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 NULL; - return (strdup(value)); + 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); + 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; char *str; struct udev_device *dev = NULL; - void *ctx = NULL; - int id, ok = -1; + uint64_t id; + 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) goto fail; - if (asprintf(&di->path, "%s/%s", FIDO_NFC_PREFIX, name) == -1) + if (asprintf(&di->path, "%s/%s", FIDO_NFC_PREFIX, name) == -1) { + di->path = NULL; goto fail; + } + if (nfc_is_fido(di->path) == false) { + fido_log_debug("%s: nfc_is_fido: %s", __func__, di->path); + 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) + fido_to_uint64(str, 16, &id) == 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) + fido_to_uint64(str, 16, &id) == 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); + return ok; } static int sysnum_from_syspath(const char *path) { struct udev *udev = NULL; struct udev_device *dev = NULL; const char *str; - int idx; + uint64_t idx64; + int idx = -1; - 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 ((udev = udev_new()) != NULL && + (dev = udev_device_new_from_syspath(udev, path)) != NULL && + (str = udev_device_get_sysnum(dev)) != NULL && + fido_to_uint64(str, 10, &idx64) == 0 && idx64 < INT_MAX) + idx = (int)idx64; if (dev != NULL) udev_device_unref(dev); if (udev != NULL) udev_unref(udev); - return (idx); + 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); + return FIDO_OK; if (devlist == NULL) - return (FIDO_ERR_INVALID_ARGUMENT); + 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); + 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); + 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 -1; } - return (0); + 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); + return NULL; } ctx->fd = -1; ctx->dev = dev; - return (ctx); + return ctx; } void * fido_nfc_open(const char *path) { struct nfc_linux *ctx = NULL; int idx; 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); + return ctx; fail: nfc_free(&ctx); - return (NULL); + 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); + 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); + return -1; } if ((r = readv(ctx->fd, iov, nitems(iov))) == -1) { fido_log_error(errno, "%s: read", __func__); - return (-1); + return -1; } if (r < 1) { fido_log_debug("%s: %zd < 1", __func__, r); - return (-1); + return -1; } if (preamble != 0x00) { fido_log_debug("%s: preamble", __func__); - return (-1); + return -1; } r--; fido_log_xxd(buf, (size_t)r, "%s", __func__); - return ((int)r); + 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); + return -1; } if ((r = write(ctx->fd, buf, len)) == -1) { fido_log_error(errno, "%s: write", __func__); - return (-1); + return -1; } if (r < 0 || (size_t)r != len) { fido_log_debug("%s: %zd != %zu", __func__, r, len); - return (-1); + return -1; } - return ((int)r); + return (int)r; } diff --git a/contrib/libfido2/src/packed.h b/contrib/libfido2/src/packed.h index 3857c22dd2ba..5f53ae565b75 100644 --- a/contrib/libfido2/src/packed.h +++ b/contrib/libfido2/src/packed.h @@ -1,22 +1,23 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #ifndef _PACKED_H #define _PACKED_H #if defined(__GNUC__) #define PACKED_TYPE(type, def) \ typedef def __attribute__ ((__packed__)) type; #elif defined(_MSC_VER) #define PACKED_TYPE(type, def) \ __pragma(pack(push, 1)) \ typedef def type; \ __pragma(pack(pop)) #else #error "please provide a way to define packed types on your platform" #endif #endif /* !_PACKED_H */ diff --git a/contrib/libfido2/src/pcsc.c b/contrib/libfido2/src/pcsc.c new file mode 100644 index 000000000000..d7bd6c65ed60 --- /dev/null +++ b/contrib/libfido2/src/pcsc.c @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2022 Micro Focus or one of its affiliates. + * Copyright (c) 2022 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. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#if __APPLE__ +#include +#include +#else +#include +#endif /* __APPLE__ */ + +#include + +#include "fido.h" +#include "fido/param.h" +#include "iso7816.h" + +#if defined(_WIN32) && !defined(__MINGW32__) +#define SCardConnect SCardConnectA +#define SCardListReaders SCardListReadersA +#endif + +#ifndef SCARD_PROTOCOL_Tx +#define SCARD_PROTOCOL_Tx SCARD_PROTOCOL_ANY +#endif + +#define BUFSIZE 1024 /* in bytes; passed to SCardListReaders() */ +#define APDULEN 264 /* 261 rounded up to the nearest multiple of 8 */ +#define READERS 8 /* maximum number of readers */ + +struct pcsc { + SCARDCONTEXT ctx; + SCARDHANDLE h; + SCARD_IO_REQUEST req; + uint8_t rx_buf[APDULEN]; + size_t rx_len; +}; + +static LONG +list_readers(SCARDCONTEXT ctx, char **buf) +{ + LONG s; + DWORD len; + + len = BUFSIZE; + if ((*buf = calloc(1, len)) == NULL) + goto fail; + if ((s = SCardListReaders(ctx, NULL, *buf, &len)) != SCARD_S_SUCCESS) { + fido_log_debug("%s: SCardListReaders 0x%lx", __func__, (long)s); + goto fail; + } + /* sanity check "multi-string" */ + if (len > BUFSIZE || len < 2) { + fido_log_debug("%s: bogus len=%u", __func__, (unsigned)len); + goto fail; + } + if ((*buf)[len - 1] != 0 || (*buf)[len - 2] != '\0') { + fido_log_debug("%s: bogus buf", __func__); + goto fail; + } + return (LONG)SCARD_S_SUCCESS; +fail: + free(*buf); + *buf = NULL; + + return (LONG)SCARD_E_NO_READERS_AVAILABLE; +} + +static char * +get_reader(SCARDCONTEXT ctx, const char *path) +{ + char *reader = NULL, *buf = NULL; + const char prefix[] = FIDO_PCSC_PREFIX "//slot"; + uint64_t n; + + if (path == NULL) + goto out; + if (strncmp(path, prefix, strlen(prefix)) != 0 || + fido_to_uint64(path + strlen(prefix), 10, &n) < 0 || + n > READERS - 1) { + fido_log_debug("%s: invalid path %s", __func__, path); + goto out; + } + if (list_readers(ctx, &buf) != SCARD_S_SUCCESS) { + fido_log_debug("%s: list_readers", __func__); + goto out; + } + for (const char *name = buf; *name != 0; name += strlen(name) + 1) { + if (n == 0) { + reader = strdup(name); + goto out; + } + n--; + } + fido_log_debug("%s: failed to find reader %s", __func__, path); +out: + free(buf); + + return reader; +} + +static int +prepare_io_request(DWORD prot, SCARD_IO_REQUEST *req) +{ + switch (prot) { + case SCARD_PROTOCOL_T0: + req->dwProtocol = SCARD_PCI_T0->dwProtocol; + req->cbPciLength = SCARD_PCI_T0->cbPciLength; + break; + case SCARD_PROTOCOL_T1: + req->dwProtocol = SCARD_PCI_T1->dwProtocol; + req->cbPciLength = SCARD_PCI_T1->cbPciLength; + break; + default: + fido_log_debug("%s: unknown protocol %lu", __func__, + (u_long)prot); + return -1; + } + + return 0; +} + +static int +copy_info(fido_dev_info_t *di, SCARDCONTEXT ctx, const char *reader, size_t idx) +{ + SCARDHANDLE h = 0; + SCARD_IO_REQUEST req; + DWORD prot = 0; + LONG s; + int ok = -1; + + memset(di, 0, sizeof(*di)); + memset(&req, 0, sizeof(req)); + + if ((s = SCardConnect(ctx, reader, SCARD_SHARE_SHARED, + SCARD_PROTOCOL_Tx, &h, &prot)) != SCARD_S_SUCCESS) { + fido_log_debug("%s: SCardConnect 0x%lx", __func__, (long)s); + goto fail; + } + if (prepare_io_request(prot, &req) < 0) { + fido_log_debug("%s: prepare_io_request", __func__); + goto fail; + } + if (asprintf(&di->path, "%s//slot%zu", FIDO_PCSC_PREFIX, idx) == -1) { + di->path = NULL; + fido_log_debug("%s: asprintf", __func__); + goto fail; + } + if (nfc_is_fido(di->path) == false) { + fido_log_debug("%s: nfc_is_fido: %s", __func__, di->path); + goto fail; + } + if ((di->manufacturer = strdup("PC/SC")) == NULL || + (di->product = strdup(reader)) == NULL) + goto fail; + + ok = 0; +fail: + if (h != 0) + SCardDisconnect(h, SCARD_LEAVE_CARD); + if (ok < 0) { + free(di->path); + free(di->manufacturer); + free(di->product); + explicit_bzero(di, sizeof(*di)); + } + + return ok; +} + +int +fido_pcsc_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) +{ + SCARDCONTEXT ctx = 0; + char *buf = NULL; + LONG s; + size_t idx = 0; + int r = FIDO_ERR_INTERNAL; + + *olen = 0; + + if (ilen == 0) + return FIDO_OK; + if (devlist == NULL) + return FIDO_ERR_INVALID_ARGUMENT; + + if ((s = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, + &ctx)) != SCARD_S_SUCCESS || ctx == 0) { + fido_log_debug("%s: SCardEstablishContext 0x%lx", __func__, + (long)s); + if (s == (LONG)SCARD_E_NO_SERVICE || + s == (LONG)SCARD_E_NO_SMARTCARD) + r = FIDO_OK; /* suppress error */ + goto out; + } + if ((s = list_readers(ctx, &buf)) != SCARD_S_SUCCESS) { + fido_log_debug("%s: list_readers 0x%lx", __func__, (long)s); + if (s == (LONG)SCARD_E_NO_READERS_AVAILABLE) + r = FIDO_OK; /* suppress error */ + goto out; + } + + for (const char *name = buf; *name != 0; name += strlen(name) + 1) { + if (idx == READERS) { + fido_log_debug("%s: stopping at %zu readers", __func__, + idx); + r = FIDO_OK; + goto out; + } + if (copy_info(&devlist[*olen], ctx, name, idx++) == 0) { + devlist[*olen].io = (fido_dev_io_t) { + fido_pcsc_open, + fido_pcsc_close, + fido_pcsc_read, + fido_pcsc_write, + }; + devlist[*olen].transport = (fido_dev_transport_t) { + fido_pcsc_rx, + fido_pcsc_tx, + }; + if (++(*olen) == ilen) + break; + } + } + + r = FIDO_OK; +out: + free(buf); + if (ctx != 0) + SCardReleaseContext(ctx); + + return r; +} + +void * +fido_pcsc_open(const char *path) +{ + char *reader = NULL; + struct pcsc *dev = NULL; + SCARDCONTEXT ctx = 0; + SCARDHANDLE h = 0; + SCARD_IO_REQUEST req; + DWORD prot = 0; + LONG s; + + memset(&req, 0, sizeof(req)); + + if ((s = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, + &ctx)) != SCARD_S_SUCCESS || ctx == 0) { + fido_log_debug("%s: SCardEstablishContext 0x%lx", __func__, + (long)s); + goto fail; + + } + if ((reader = get_reader(ctx, path)) == NULL) { + fido_log_debug("%s: get_reader(%s)", __func__, path); + goto fail; + } + if ((s = SCardConnect(ctx, reader, SCARD_SHARE_SHARED, + SCARD_PROTOCOL_Tx, &h, &prot)) != SCARD_S_SUCCESS) { + fido_log_debug("%s: SCardConnect 0x%lx", __func__, (long)s); + goto fail; + } + if (prepare_io_request(prot, &req) < 0) { + fido_log_debug("%s: prepare_io_request", __func__); + goto fail; + } + if ((dev = calloc(1, sizeof(*dev))) == NULL) + goto fail; + + dev->ctx = ctx; + dev->h = h; + dev->req = req; + ctx = 0; + h = 0; +fail: + if (h != 0) + SCardDisconnect(h, SCARD_LEAVE_CARD); + if (ctx != 0) + SCardReleaseContext(ctx); + free(reader); + + return dev; +} + +void +fido_pcsc_close(void *handle) +{ + struct pcsc *dev = handle; + + if (dev->h != 0) + SCardDisconnect(dev->h, SCARD_LEAVE_CARD); + if (dev->ctx != 0) + SCardReleaseContext(dev->ctx); + + explicit_bzero(dev->rx_buf, sizeof(dev->rx_buf)); + free(dev); +} + +int +fido_pcsc_read(void *handle, unsigned char *buf, size_t len, int ms) +{ + struct pcsc *dev = handle; + int r; + + (void)ms; + if (dev->rx_len == 0 || dev->rx_len > len || + dev->rx_len > sizeof(dev->rx_buf)) { + fido_log_debug("%s: rx_len", __func__); + return -1; + } + fido_log_xxd(dev->rx_buf, dev->rx_len, "%s: reading", __func__); + memcpy(buf, dev->rx_buf, dev->rx_len); + explicit_bzero(dev->rx_buf, sizeof(dev->rx_buf)); + r = (int)dev->rx_len; + dev->rx_len = 0; + + return r; +} + +int +fido_pcsc_write(void *handle, const unsigned char *buf, size_t len) +{ + struct pcsc *dev = handle; + DWORD n; + LONG s; + + if (len > INT_MAX) { + fido_log_debug("%s: len", __func__); + return -1; + } + + explicit_bzero(dev->rx_buf, sizeof(dev->rx_buf)); + dev->rx_len = 0; + n = (DWORD)sizeof(dev->rx_buf); + + fido_log_xxd(buf, len, "%s: writing", __func__); + + if ((s = SCardTransmit(dev->h, &dev->req, buf, (DWORD)len, NULL, + dev->rx_buf, &n)) != SCARD_S_SUCCESS) { + fido_log_debug("%s: SCardTransmit 0x%lx", __func__, (long)s); + explicit_bzero(dev->rx_buf, sizeof(dev->rx_buf)); + return -1; + } + dev->rx_len = (size_t)n; + + fido_log_xxd(dev->rx_buf, dev->rx_len, "%s: read", __func__); + + return (int)len; +} + +int +fido_pcsc_tx(fido_dev_t *d, uint8_t cmd, const u_char *buf, size_t count) +{ + return fido_nfc_tx(d, cmd, buf, count); +} + +int +fido_pcsc_rx(fido_dev_t *d, uint8_t cmd, u_char *buf, size_t count, int ms) +{ + return fido_nfc_rx(d, cmd, buf, count, ms); +} + +bool +fido_is_pcsc(const char *path) +{ + return strncmp(path, FIDO_PCSC_PREFIX, strlen(FIDO_PCSC_PREFIX)) == 0; +} + +int +fido_dev_set_pcsc(fido_dev_t *d) +{ + if (d->io_handle != NULL) { + fido_log_debug("%s: device open", __func__); + return -1; + } + d->io_own = true; + d->io = (fido_dev_io_t) { + fido_pcsc_open, + fido_pcsc_close, + fido_pcsc_read, + fido_pcsc_write, + }; + d->transport = (fido_dev_transport_t) { + fido_pcsc_rx, + fido_pcsc_tx, + }; + + return 0; +} diff --git a/contrib/libfido2/src/pin.c b/contrib/libfido2/src/pin.c index 30eeb086a6ef..c3dd9271ed71 100644 --- a/contrib/libfido2/src/pin.c +++ b/contrib/libfido2/src/pin.c @@ -1,698 +1,723 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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) { + if (pin_len < 4 || pin_len > 63) { 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) { + 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, 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, 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, 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, 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) { fido_blob_t *aes_token = NULL; - unsigned char reply[FIDO_MAXMSG]; - int reply_len; + unsigned char *msg = NULL; + int msglen; 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) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto fail; + } + + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, 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, + if ((r = cbor_parse_reply(msg, (size_t)msglen, 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); + freezero(msg, FIDO_MAXMSG); 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) { 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, ms); else 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, int *ms) { 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, 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, 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, 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, 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, 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, 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 r; if (oldpin != NULL) { 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, 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) { 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, 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, 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) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; - int r; + unsigned char *msg; + int msglen; + int r; *retries = 0; - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto fail; + } + + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, 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, retries, + if ((r = cbor_parse_reply(msg, (size_t)msglen, retries, parse_pin_retry_count)) != FIDO_OK) { fido_log_debug("%s: parse_pin_retry_count", __func__); - return (r); + goto fail; } - return (FIDO_OK); + r = FIDO_OK; +fail: + freezero(msg, FIDO_MAXMSG); + + return (r); } static int 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, 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) { 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) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; - int r; + unsigned char *msg; + int msglen; + int r; *retries = 0; - if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), - ms)) < 0) { + if ((msg = malloc(FIDO_MAXMSG)) == NULL) { + r = FIDO_ERR_INTERNAL; + goto fail; + } + + if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, 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, retries, + if ((r = cbor_parse_reply(msg, (size_t)msglen, retries, parse_uv_retry_count)) != FIDO_OK) { fido_log_debug("%s: parse_uv_retry_count", __func__); - return (r); + goto fail; } - return (FIDO_OK); + r = FIDO_OK; +fail: + freezero(msg, FIDO_MAXMSG); + + return (r); } static int 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, 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) { 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, 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, 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/random.c b/contrib/libfido2/src/random.c index f13482bfddf9..9688d35ca945 100644 --- a/contrib/libfido2/src/random.c +++ b/contrib/libfido2/src/random.c @@ -1,82 +1,83 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #ifdef HAVE_SYS_RANDOM_H #include #endif #include #ifdef HAVE_UNISTD_H #include #endif #include "fido.h" #if defined(_WIN32) #include #include #include #include #include #include int fido_get_random(void *buf, size_t len) { NTSTATUS status; status = BCryptGenRandom(NULL, buf, (ULONG)len, BCRYPT_USE_SYSTEM_PREFERRED_RNG); if (!NT_SUCCESS(status)) return (-1); return (0); } #elif defined(HAVE_ARC4RANDOM_BUF) int fido_get_random(void *buf, size_t len) { arc4random_buf(buf, len); return (0); } #elif defined(HAVE_GETRANDOM) int fido_get_random(void *buf, size_t len) { ssize_t r; if ((r = getrandom(buf, len, 0)) < 0 || (size_t)r != len) return (-1); return (0); } #elif defined(HAVE_DEV_URANDOM) int fido_get_random(void *buf, size_t len) { int fd = -1; int ok = -1; ssize_t r; if ((fd = open(FIDO_RANDOM_DEV, O_RDONLY)) < 0) goto fail; if ((r = read(fd, buf, len)) < 0 || (size_t)r != len) goto fail; ok = 0; fail: if (fd != -1) close(fd); return (ok); } #else #error "please provide an implementation of fido_get_random() for your platform" #endif /* _WIN32 */ diff --git a/contrib/libfido2/src/reset.c b/contrib/libfido2/src/reset.c index c5fe6dfe7ac1..4e09dbbca5cf 100644 --- a/contrib/libfido2/src/reset.c +++ b/contrib/libfido2/src/reset.c @@ -1,45 +1,46 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include "fido.h" static int 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), 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) { int r; 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) { 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 index 37aa9f073bed..03636b5cdf42 100644 --- a/contrib/libfido2/src/rs1.c +++ b/contrib/libfido2/src/rs1.c @@ -1,99 +1,100 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include "fido.h" -#if defined(LIBRESSL_VERSION_NUMBER) +#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050200fL 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 29fcedbdee20..59ceb948fa07 100644 --- a/contrib/libfido2/src/rs256.c +++ b/contrib/libfido2/src/rs256.c @@ -1,295 +1,316 @@ /* - * Copyright (c) 2018-2021 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include "fido.h" #include "fido/rs256.h" -#if defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER >= 0x30000000 +#define get0_RSA(x) EVP_PKEY_get0_RSA((x)) +#else +#define get0_RSA(x) EVP_PKEY_get0((x)) +#endif + +#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050200fL static EVP_MD * rs256_get_EVP_MD(void) { 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 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) { 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 (EVP_MD_meth_dup(md)); } static void rs256_free_EVP_MD(EVP_MD *md) { EVP_MD_meth_free(md); } #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) { + EVP_PKEY *pkey; + if (len < sizeof(*pk)) return (FIDO_ERR_INVALID_ARGUMENT); memcpy(pk, ptr, sizeof(*pk)); + if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) { + fido_log_debug("%s: rs256_pk_to_EVP_PKEY", __func__); + return (FIDO_ERR_INVALID_ARGUMENT); + } + + EVP_PKEY_free(pkey); + 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 (RSA_bits(rsa) != 2048) { + fido_log_debug("%s: invalid key length", __func__); + goto fail; + } + 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; + const RSA *rsa; if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA || - (rsa = EVP_PKEY_get0(pkey)) == NULL) + (rsa = get0_RSA(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 index b82b61874498..fd0e4e3ca33e 100644 --- a/contrib/libfido2/src/time.c +++ b/contrib/libfido2/src/time.c @@ -1,74 +1,75 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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/touch.c b/contrib/libfido2/src/touch.c new file mode 100644 index 000000000000..6844e2c2dbc0 --- /dev/null +++ b/contrib/libfido2/src/touch.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include "fido.h" + +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, &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, &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)); + + 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); +} diff --git a/contrib/libfido2/src/tpm.c b/contrib/libfido2/src/tpm.c index 74244f8cbf08..3e09bca00ffb 100644 --- a/contrib/libfido2/src/tpm.c +++ b/contrib/libfido2/src/tpm.c @@ -1,390 +1,391 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ /* * 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 #define TPM_ALG_ECC 0x0023 /* Part 2, 6.4: TPM_ECC_CURVE */ #define TPM_ECC_P256 0x0003 /* 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 0x00040000 /* 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 */ + 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_rs256_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_rs256_key_t, struct tpm_rs256_key { uint16_t size; /* sizeof(body) */ uint8_t body[256]; }) /* Part 2, 11.2.5.1: TPM2B_ECC_PARAMETER */ PACKED_TYPE(tpm_es256_coord_t, struct tpm_es256_coord { uint16_t size; /* sizeof(body) */ uint8_t body[32]; }) /* Part 2, 11.2.5.2: TPMS_ECC_POINT */ PACKED_TYPE(tpm_es256_point_t, struct tpm_es256_point { tpm_es256_coord_t x; tpm_es256_coord_t y; }) /* Part 2, 12.2.3.5: TPMS_RSA_PARMS */ PACKED_TYPE(tpm_rs256_param_t, struct tpm_rs256_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.3.6: TPMS_ECC_PARMS */ PACKED_TYPE(tpm_es256_param_t, struct tpm_es256_param { uint16_t symmetric; /* TPM_ALG_NULL */ uint16_t scheme; /* TPM_ALG_NULL */ uint16_t curve_id; /* TPM_ECC_P256 */ uint16_t kdf; /* TPM_ALG_NULL */ }) /* Part 2, 12.2.4: TPMT_PUBLIC */ PACKED_TYPE(tpm_rs256_pubarea_t, struct tpm_rs256_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_rs256_param_t param; tpm_rs256_key_t key; }) /* Part 2, 12.2.4: TPMT_PUBLIC */ PACKED_TYPE(tpm_es256_pubarea_t, struct tpm_es256_pubarea { uint16_t alg; /* TPM_ALG_ECC */ uint16_t hash; /* TPM_ALG_SHA256 */ uint32_t attr; tpm_sha256_digest_t policy; /* must be present? */ tpm_es256_param_t param; tpm_es256_point_t point; }) 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_rs256_pubarea(tpm_rs256_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_es256_pubarea(tpm_es256_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.curve_id = htobe16(x->param.curve_id); x->param.kdf = htobe16(x->param.kdf); x->point.x.size = htobe16(x->point.x.size); x->point.y.size = htobe16(x->point.y.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_rs256_pubarea(const fido_blob_t *buf, const rs256_pk_t *pk) { const tpm_rs256_pubarea_t *actual; tpm_rs256_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_rs256_pubarea(&expected); ok = timingsafe_bcmp(&expected, actual, sizeof(expected)); explicit_bzero(&expected, sizeof(expected)); return ok != 0 ? -1 : 0; } static int check_es256_pubarea(const fido_blob_t *buf, const es256_pk_t *pk) { const tpm_es256_pubarea_t *actual; tpm_es256_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_ECC; 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; /* TCG Alg. Registry, 5.2.4 */ expected.param.curve_id = TPM_ECC_P256; expected.param.kdf = TPM_ALG_NULL; expected.point.x.size = sizeof(expected.point.x.body); expected.point.y.size = sizeof(expected.point.y.body); memcpy(&expected.point.x.body, &pk->x, sizeof(expected.point.x.body)); memcpy(&expected.point.y.body, &pk->y, sizeof(expected.point.y.body)); bswap_es256_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) { fido_log_debug("%s: unsupported alg %d", __func__, attstmt->alg); return -1; } switch (attcred->type) { case COSE_ES256: if (check_es256_pubarea(pubarea, &attcred->pubkey.es256) < 0) { fido_log_debug("%s: check_es256_pubarea", __func__); return -1; } break; case COSE_RS256: if (check_rs256_pubarea(pubarea, &attcred->pubkey.rs256) < 0) { fido_log_debug("%s: check_rs256_pubarea", __func__); return -1; } break; default: fido_log_debug("%s: unsupported type %d", __func__, attcred->type); 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 index 54c0ca582865..f31f8da12952 100644 --- a/contrib/libfido2/src/types.c +++ b/contrib/libfido2/src/types.c @@ -1,76 +1,91 @@ /* - * Copyright (c) 2018-2021 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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; + oa->len = 0; } 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; } +void +fido_cert_array_free(fido_cert_array_t *ca) +{ + for (size_t i = 0; i < ca->len; i++) + free(ca->name[i]); + + free(ca->name); + free(ca->value); + ca->name = NULL; + ca->value = NULL; + ca->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 6ebfcc7bb848..b1f7bce3b7ab 100644 --- a/contrib/libfido2/src/u2f.c +++ b/contrib/libfido2/src/u2f.c @@ -1,910 +1,959 @@ /* - * Copyright (c) 2018-2021 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include "fido.h" #include "fido/es256.h" +#include "fallthrough.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) { iso7816_apdu_t *apdu = NULL; + unsigned char *reply = NULL; unsigned char challenge[SHA256_DIGEST_LENGTH]; unsigned char application[SHA256_DIGEST_LENGTH]; - unsigned char reply[FIDO_MAXMSG]; int r; /* 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; } + if ((reply = malloc(FIDO_MAXMSG)) == NULL) { + fido_log_debug("%s: malloc", __func__); + r = FIDO_ERR_INTERNAL; + goto fail; + } + do { if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), 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) { + if (fido_rx(dev, CTAP_CMD_MSG, reply, FIDO_MAXMSG, ms) < 2) { fido_log_debug("%s: fido_rx", __func__); r = FIDO_ERR_RX; goto fail; } 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); + freezero(reply, FIDO_MAXMSG); return (r); } static int key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id, int *found, int *ms) { iso7816_apdu_t *apdu = NULL; + unsigned char *reply = 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 ((reply = malloc(FIDO_MAXMSG)) == NULL) { + fido_log_debug("%s: malloc", __func__); + r = FIDO_ERR_INTERNAL; + goto fail; + } + if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), 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) { + if (fido_rx(dev, CTAP_CMD_MSG, reply, FIDO_MAXMSG, 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); + freezero(reply, FIDO_MAXMSG); 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) { iso7816_apdu_t *apdu = NULL; + unsigned char *reply = 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 */ #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; } + if ((reply = malloc(FIDO_MAXMSG)) == NULL) { + fido_log_debug("%s: malloc", __func__); + r = FIDO_ERR_INTERNAL; + goto fail; + } + do { if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), 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) { + if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply, + FIDO_MAXMSG, ms)) < 2) { fido_log_debug("%s: fido_rx", __func__); r = FIDO_ERR_RX; goto fail; } 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); + freezero(reply, FIDO_MAXMSG); 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_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) { iso7816_apdu_t *apdu = NULL; unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; - unsigned char reply[FIDO_MAXMSG]; + unsigned char *reply = NULL; int reply_len; int found; int r; 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; } + if ((reply = malloc(FIDO_MAXMSG)) == NULL) { + fido_log_debug("%s: malloc", __func__); + r = FIDO_ERR_INTERNAL; + goto fail; + } + do { if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), 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) { + if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply, + FIDO_MAXMSG, ms)) < 2) { fido_log_debug("%s: fido_rx", __func__); r = FIDO_ERR_RX; goto fail; } 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); + freezero(reply, FIDO_MAXMSG); 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_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) { 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 */ + 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, int *ms) { iso7816_apdu_t *apdu = NULL; const char *clientdata = FIDO_DUMMY_CLIENTDATA; const char *rp_id = FIDO_DUMMY_RP_ID; + unsigned char *reply = NULL; 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 ((reply = malloc(FIDO_MAXMSG)) == NULL) { + fido_log_debug("%s: malloc", __func__); + r = FIDO_ERR_INTERNAL; + goto fail; + } + if (dev->attr.flags & FIDO_CAP_WINK) { fido_tx(dev, CTAP_CMD_WINK, NULL, 0, ms); - fido_rx(dev, CTAP_CMD_WINK, &reply, sizeof(reply), ms); + fido_rx(dev, CTAP_CMD_WINK, reply, FIDO_MAXMSG, ms); } if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), 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); + freezero(reply, FIDO_MAXMSG); return (r); } int u2f_get_touch_status(fido_dev_t *dev, int *touched, int *ms) { - unsigned char reply[FIDO_MAXMSG]; - int reply_len; - int r; + unsigned char *reply; + int reply_len; + int r; + + if ((reply = malloc(FIDO_MAXMSG)) == NULL) { + fido_log_debug("%s: malloc", __func__); + r = FIDO_ERR_INTERNAL; + goto out; + } - if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, &reply, sizeof(reply), + if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, reply, FIDO_MAXMSG, ms)) < 2) { fido_log_debug("%s: fido_rx", __func__); - return (FIDO_OK); /* ignore */ + r = FIDO_OK; /* ignore */ + goto out; } switch ((reply[reply_len - 2] << 8) | reply[reply_len - 1]) { case SW_CONDITIONS_NOT_SATISFIED: if ((r = u2f_get_touch_begin(dev, ms)) != FIDO_OK) { fido_log_debug("%s: u2f_get_touch_begin", __func__); - return (r); + goto out; } *touched = 0; break; case SW_NO_ERROR: *touched = 1; break; default: fido_log_debug("%s: unexpected sw", __func__); - return (FIDO_ERR_RX); + r = FIDO_ERR_RX; + goto out; } - return (FIDO_OK); + r = FIDO_OK; +out: + freezero(reply, FIDO_MAXMSG); + + return (r); } diff --git a/contrib/libfido2/src/util.c b/contrib/libfido2/src/util.c new file mode 100644 index 000000000000..25281bb51b28 --- /dev/null +++ b/contrib/libfido2/src/util.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 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. + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +#include "fido.h" + +int +fido_to_uint64(const char *str, int base, uint64_t *out) +{ + char *ep; + unsigned long long ull; + + errno = 0; + ull = strtoull(str, &ep, base); + if (str == ep || *ep != '\0') + return -1; + else if (ull == ULLONG_MAX && errno == ERANGE) + return -1; + else if (ull > UINT64_MAX) + return -1; + *out = (uint64_t)ull; + + return 0; +} diff --git a/contrib/libfido2/src/webauthn.h b/contrib/libfido2/src/webauthn.h index 22bf6e346a73..e64236a0f6fe 100644 --- a/contrib/libfido2/src/webauthn.h +++ b/contrib/libfido2/src/webauthn.h @@ -1,917 +1,990 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #ifndef __WEBAUTHN_H_ #define __WEBAUTHN_H_ #pragma once #include #ifdef _MSC_VER #pragma region Desktop Family or OneCore Family #endif #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_VERSION_4 4 // WEBAUTHN_API_VERSION_4 : Delta From WEBAUTHN_API_VERSION_3 // Data Structures and their sub versions: // - WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS : 5 // - WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS : 6 // - WEBAUTHN_ASSERTION : 3 +// APIs: +// - WebAuthNGetPlatformCredentialList +// - WebAuthNFreePlatformCredentialList // #define WEBAUTHN_API_CURRENT_VERSION WEBAUTHN_API_VERSION_4 //+------------------------------------------------------------------------------------------ // 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; +//+------------------------------------------------------------------------------------------ +// Credential Information for WebAuthNGetPlatformCredentialList API +//------------------------------------------------------------------------------------------- + +#define WEBAUTHN_CREDENTIAL_DETAILS_VERSION_1 1 +#define WEBAUTHN_CREDENTIAL_DETAILS_CURRENT_VERSION WEBAUTHN_CREDENTIAL_DETAILS_VERSION_1 + +typedef struct _WEBAUTHN_CREDENTIAL_DETAILS { + // Version of this structure, to allow for modifications in the future. + DWORD dwVersion; + + // Size of pbCredentialID. + DWORD cbCredentialID; + _Field_size_bytes_(cbCredentialID) + PBYTE pbCredentialID; + + // RP Info + PWEBAUTHN_RP_ENTITY_INFORMATION pRpInformation; + + // User Info + PWEBAUTHN_USER_ENTITY_INFORMATION pUserInformation; +} WEBAUTHN_CREDENTIAL_DETAILS, *PWEBAUTHN_CREDENTIAL_DETAILS; +typedef const WEBAUTHN_CREDENTIAL_DETAILS *PCWEBAUTHN_CREDENTIAL_DETAILS; + +typedef struct _WEBAUTHN_CREDENTIAL_DETAILS_LIST { + DWORD cCredentialDetails; + _Field_size_(cCredentialDetails) + PWEBAUTHN_CREDENTIAL_DETAILS *ppCredentialDetails; +} WEBAUTHN_CREDENTIAL_DETAILS_LIST, *PWEBAUTHN_CREDENTIAL_DETAILS_LIST; +typedef const WEBAUTHN_CREDENTIAL_DETAILS_LIST *PCWEBAUTHN_CREDENTIAL_DETAILS_LIST; + +#define WEBAUTHN_GET_CREDENTIALS_OPTIONS_VERSION_1 1 +#define WEBAUTHN_GET_CREDENTIALS_OPTIONS_CURRENT_VERSION WEBAUTHN_GET_CREDENTIALS_OPTIONS_VERSION_1 + +typedef struct _WEBAUTHN_GET_CREDENTIALS_OPTIONS { + // Version of this structure, to allow for modifications in the future. + DWORD dwVersion; + + // RPID + LPCWSTR pwszRpId; + + // Optional. BrowserInPrivate Mode. Defaulting to FALSE. + BOOL bBrowserInPrivateMode; +} WEBAUTHN_GET_CREDENTIALS_OPTIONS, *PWEBAUTHN_GET_CREDENTIALS_OPTIONS; +typedef const WEBAUTHN_GET_CREDENTIALS_OPTIONS *PCWEBAUTHN_GET_CREDENTIALS_OPTIONS; + //+------------------------------------------------------------------------------------------ // PRF values. //------------------------------------------------------------------------------------------- #define WEBAUTHN_CTAP_ONE_HMAC_SECRET_LENGTH 32 +// SALT values below by default are converted into RAW Hmac-Secret values as per PRF extension. +// - SHA-256(UTF8Encode("WebAuthn PRF") || 0x00 || Value) +// +// Set WEBAUTHN_CTAP_HMAC_SECRET_VALUES_FLAG in dwFlags in WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS, +// if caller wants to provide RAW Hmac-Secret SALT values directly. In that case, +// values if provided MUST be of WEBAUTHN_CTAP_ONE_HMAC_SECRET_LENGTH size. + typedef struct _WEBAUTHN_HMAC_SECRET_SALT { // Size of pbFirst. DWORD cbFirst; _Field_size_bytes_(cbFirst) PBYTE pbFirst; // Required // Size of pbSecond. DWORD cbSecond; _Field_size_bytes_(cbSecond) PBYTE pbSecond; } WEBAUTHN_HMAC_SECRET_SALT, *PWEBAUTHN_HMAC_SECRET_SALT; typedef const WEBAUTHN_HMAC_SECRET_SALT *PCWEBAUTHN_HMAC_SECRET_SALT; typedef struct _WEBAUTHN_CRED_WITH_HMAC_SECRET_SALT { // Size of pbCredID. DWORD cbCredID; _Field_size_bytes_(cbCredID) PBYTE pbCredID; // Required // PRF Values for above credential PWEBAUTHN_HMAC_SECRET_SALT pHmacSecretSalt; // Required } WEBAUTHN_CRED_WITH_HMAC_SECRET_SALT, *PWEBAUTHN_CRED_WITH_HMAC_SECRET_SALT; typedef const WEBAUTHN_CRED_WITH_HMAC_SECRET_SALT *PCWEBAUTHN_CRED_WITH_HMAC_SECRET_SALT; typedef struct _WEBAUTHN_HMAC_SECRET_SALT_VALUES { PWEBAUTHN_HMAC_SECRET_SALT pGlobalHmacSalt; DWORD cCredWithHmacSecretSaltList; _Field_size_(cCredWithHmacSecretSaltList) PWEBAUTHN_CRED_WITH_HMAC_SECRET_SALT pCredWithHmacSecretSaltList; } WEBAUTHN_HMAC_SECRET_SALT_VALUES, *PWEBAUTHN_HMAC_SECRET_SALT_VALUES; typedef const WEBAUTHN_HMAC_SECRET_SALT_VALUES *PCWEBAUTHN_HMAC_SECRET_SALT_VALUES; //+------------------------------------------------------------------------------------------ // 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_VERSION_5 5 #define WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_CURRENT_VERSION WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_5 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 // bRequireResidentKey isn't set to TRUE DWORD dwLargeBlobSupport; // Optional. Prefer key to be resident. Defaulting to FALSE. When TRUE, // overrides the above bRequireResidentKey. BOOL bPreferResidentKey; // // The following fields have been added in WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_5 // // Optional. BrowserInPrivate Mode. Defaulting to FALSE. BOOL bBrowserInPrivateMode; } 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_VERSION_6 6 #define WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_CURRENT_VERSION WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_6 +/* + Information about flags. +*/ + +#define WEBAUTHN_AUTHENTICATOR_HMAC_SECRET_VALUES_FLAG 0x00100000 + 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 + // Flags 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; // // The following fields have been added in WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_6 // // PRF values which will be converted into HMAC-SECRET values according to WebAuthn Spec. PWEBAUTHN_HMAC_SECRET_SALT_VALUES pHmacSecretSaltValues; // Optional. BrowserInPrivate Mode. Defaulting to FALSE. BOOL bBrowserInPrivateMode; } 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_VERSION_3 3 #define WEBAUTHN_ASSERTION_CURRENT_VERSION WEBAUTHN_ASSERTION_VERSION_3 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; // // Following fields have been added in WEBAUTHN_ASSERTION_VERSION_3 // PWEBAUTHN_HMAC_SECRET_SALT pHmacSecret; } 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); +HRESULT +WINAPI +WebAuthNGetPlatformCredentialList( + _In_ PCWEBAUTHN_GET_CREDENTIALS_OPTIONS pGetCredentialsOptions, + _Outptr_result_maybenull_ PWEBAUTHN_CREDENTIAL_DETAILS_LIST *ppCredentialDetailsList); + +void +WINAPI +WebAuthNFreePlatformCredentialList( + _In_ PWEBAUTHN_CREDENTIAL_DETAILS_LIST pCredentialDetailsList); + // // 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 #ifdef _MSC_VER #pragma endregion #endif #endif // __WEBAUTHN_H_ diff --git a/contrib/libfido2/src/winhello.c b/contrib/libfido2/src/winhello.c index 9de6c6c9b983..efc7dc22f851 100644 --- a/contrib/libfido2/src/winhello.c +++ b/contrib/libfido2/src/winhello.c @@ -1,956 +1,1018 @@ /* - * Copyright (c) 2021 Yubico AB. All rights reserved. + * Copyright (c) 2021-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include "fido.h" #include "webauthn.h" #ifndef NTE_INVALID_PARAMETER #define NTE_INVALID_PARAMETER _HRESULT_TYPEDEF_(0x80090027) #endif #ifndef NTE_NOT_SUPPORTED #define NTE_NOT_SUPPORTED _HRESULT_TYPEDEF_(0x80090029) #endif #ifndef NTE_DEVICE_NOT_FOUND #define NTE_DEVICE_NOT_FOUND _HRESULT_TYPEDEF_(0x80090035) #endif #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; }; typedef DWORD WINAPI webauthn_get_api_version_t(void); typedef PCWSTR WINAPI webauthn_strerr_t(HRESULT); typedef HRESULT WINAPI webauthn_get_assert_t(HWND, LPCWSTR, PCWEBAUTHN_CLIENT_DATA, PCWEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS, PWEBAUTHN_ASSERTION *); typedef HRESULT WINAPI webauthn_make_cred_t(HWND, PCWEBAUTHN_RP_ENTITY_INFORMATION, PCWEBAUTHN_USER_ENTITY_INFORMATION, PCWEBAUTHN_COSE_CREDENTIAL_PARAMETERS, PCWEBAUTHN_CLIENT_DATA, PCWEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS, PWEBAUTHN_CREDENTIAL_ATTESTATION *); typedef void WINAPI webauthn_free_assert_t(PWEBAUTHN_ASSERTION); typedef void WINAPI webauthn_free_attest_t(PWEBAUTHN_CREDENTIAL_ATTESTATION); static TLS BOOL webauthn_loaded; static TLS HMODULE webauthn_handle; static TLS webauthn_get_api_version_t *webauthn_get_api_version; static TLS webauthn_strerr_t *webauthn_strerr; static TLS webauthn_get_assert_t *webauthn_get_assert; static TLS webauthn_make_cred_t *webauthn_make_cred; static TLS webauthn_free_assert_t *webauthn_free_assert; static TLS webauthn_free_attest_t *webauthn_free_attest; static int webauthn_load(void) { DWORD n = 1; if (webauthn_loaded || webauthn_handle != NULL) { fido_log_debug("%s: already loaded", __func__); return -1; } - if ((webauthn_handle = LoadLibrary("webauthn.dll")) == NULL) { + if ((webauthn_handle = LoadLibrary(TEXT("webauthn.dll"))) == NULL) { fido_log_debug("%s: LoadLibrary", __func__); return -1; } if ((webauthn_get_api_version = (webauthn_get_api_version_t *)GetProcAddress(webauthn_handle, "WebAuthNGetApiVersionNumber")) == NULL) { fido_log_debug("%s: WebAuthNGetApiVersionNumber", __func__); /* WebAuthNGetApiVersionNumber might not exist */ } if (webauthn_get_api_version != NULL && (n = webauthn_get_api_version()) < 1) { fido_log_debug("%s: unsupported api %lu", __func__, (u_long)n); goto fail; } fido_log_debug("%s: api version %lu", __func__, (u_long)n); if ((webauthn_strerr = (webauthn_strerr_t *)GetProcAddress(webauthn_handle, "WebAuthNGetErrorName")) == NULL) { fido_log_debug("%s: WebAuthNGetErrorName", __func__); goto fail; } if ((webauthn_get_assert = (webauthn_get_assert_t *)GetProcAddress(webauthn_handle, "WebAuthNAuthenticatorGetAssertion")) == NULL) { fido_log_debug("%s: WebAuthNAuthenticatorGetAssertion", __func__); goto fail; } if ((webauthn_make_cred = (webauthn_make_cred_t *)GetProcAddress(webauthn_handle, "WebAuthNAuthenticatorMakeCredential")) == NULL) { fido_log_debug("%s: WebAuthNAuthenticatorMakeCredential", __func__); goto fail; } if ((webauthn_free_assert = (webauthn_free_assert_t *)GetProcAddress(webauthn_handle, "WebAuthNFreeAssertion")) == NULL) { fido_log_debug("%s: WebAuthNFreeAssertion", __func__); goto fail; } if ((webauthn_free_attest = (webauthn_free_attest_t *)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 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%lx", __func__, (u_long)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_cred_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: 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 set_assert_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_PREFERRED; 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, 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, 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_ES384: + alg->lAlg = WEBAUTHN_COSE_ALGORITHM_ECDSA_P384_WITH_SHA384; + 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, 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", __func__, 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_assert_authdata(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa) +pack_assert_ext(WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS *out, + const fido_assert_ext_t *in) { - int r; + WEBAUTHN_HMAC_SECRET_SALT_VALUES *v; + WEBAUTHN_HMAC_SECRET_SALT *s; - if (wa->cbAuthenticatorData > SIZE_MAX) { - fido_log_debug("%s: cbAuthenticatorData", __func__); + if (in->mask == 0) { + return 0; /* nothing to do */ + } + if (in->mask != FIDO_EXT_HMAC_SECRET) { + fido_log_debug("%s: mask 0x%x", __func__, in->mask); + return -1; + } + if (in->hmac_salt.ptr == NULL || + in->hmac_salt.len != WEBAUTHN_CTAP_ONE_HMAC_SECRET_LENGTH) { + fido_log_debug("%s: salt %p/%zu", __func__, + (const void *)in->hmac_salt.ptr, in->hmac_salt.len); return -1; } + if ((v = calloc(1, sizeof(*v))) == NULL || + (s = calloc(1, sizeof(*s))) == NULL) { + free(v); + fido_log_debug("%s: calloc", __func__); + return -1; + } + s->cbFirst = (DWORD)in->hmac_salt.len; + s->pbFirst = in->hmac_salt.ptr; + v->pGlobalHmacSalt = s; + out->pHmacSecretSaltValues = v; + out->dwFlags |= WEBAUTHN_AUTHENTICATOR_HMAC_SECRET_VALUES_FLAG; + out->dwVersion = WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_6; + + return 0; +} + +static int +unpack_assert_authdata(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa) +{ + int r; + if ((r = fido_assert_set_authdata_raw(assert, 0, wa->pbAuthenticatorData, - (size_t)wa->cbAuthenticatorData)) != FIDO_OK) { + 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, 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) { + 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, 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) { + 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, const WEBAUTHN_ASSERTION *wa) { if (wa->cbUserId == 0) return 0; /* user id absent */ - if (wa->cbUserId > SIZE_MAX) { - fido_log_debug("%s: cbUserId", __func__); + if (fido_blob_set(&assert->stmt[0].user.id, wa->pbUserId, + wa->cbUserId) < 0) { + fido_log_debug("%s: fido_blob_set", __func__); return -1; } - if (fido_blob_set(&assert->stmt[0].user.id, wa->pbUserId, - (size_t)wa->cbUserId) < 0) { + + return 0; +} + +static int +unpack_hmac_secret(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa) +{ + if (wa->dwVersion != WEBAUTHN_ASSERTION_VERSION_3) { + fido_log_debug("%s: dwVersion %u", __func__, + (unsigned)wa->dwVersion); + return 0; /* proceed without hmac-secret */ + } + if (wa->pHmacSecret == NULL || + wa->pHmacSecret->cbFirst == 0 || + wa->pHmacSecret->pbFirst == NULL) { + fido_log_debug("%s: hmac-secret absent", __func__); + return 0; /* proceed without hmac-secret */ + } + if (wa->pHmacSecret->cbSecond != 0 || + wa->pHmacSecret->pbSecond != NULL) { + fido_log_debug("%s: 64-byte hmac-secret", __func__); + return 0; /* proceed without hmac-secret */ + } + if (!fido_blob_is_empty(&assert->stmt[0].hmac_secret)) { + fido_log_debug("%s: fido_blob_is_empty", __func__); + return -1; + } + if (fido_blob_set(&assert->stmt[0].hmac_secret, + wa->pHmacSecret->pbFirst, wa->pHmacSecret->cbFirst) < 0) { fido_log_debug("%s: fido_blob_set", __func__); return -1; } return 0; } static int 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 = 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 (pack_assert_ext(opt, &assert->ext) < 0) { + fido_log_debug("%s: pack_assert_ext", __func__); + return FIDO_ERR_UNSUPPORTED_EXTENSION; + } if (set_assert_uv(&opt->dwUserVerificationRequirement, assert->uv, pin) < 0) { fido_log_debug("%s: set_assert_uv", __func__); return FIDO_ERR_INTERNAL; } return FIDO_OK; } static int 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; } + if (assert->ext.mask & FIDO_EXT_HMAC_SECRET && + unpack_hmac_secret(assert, wa) < 0) { + fido_log_debug("%s: unpack_hmac_secret", __func__); + return FIDO_ERR_INTERNAL; + } return FIDO_OK; } static int 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 = 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_cred_uv(&opt->dwUserVerificationRequirement, (cred->ext.mask & FIDO_EXT_CRED_PROTECT) ? FIDO_OPT_TRUE : cred->uv, pin) < 0) { fido_log_debug("%s: set_cred_uv", __func__); return FIDO_ERR_INTERNAL; } if (cred->rk == FIDO_OPT_TRUE) { opt->bRequireResidentKey = true; } return FIDO_OK; } static int decode_attobj(const cbor_item_t *key, const cbor_item_t *val, void *arg) { 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; } if (!strcmp(name, "fmt")) { if (cbor_decode_fmt(val, &cred->fmt) < 0) { fido_log_debug("%s: cbor_decode_fmt", __func__); goto fail; } } else if (!strcmp(name, "attStmt")) { if (cbor_decode_attstmt(val, &cred->attstmt) < 0) { fido_log_debug("%s: cbor_decode_attstmt", __func__); goto fail; } } else if (!strcmp(name, "authData")) { if (fido_blob_decode(val, &cred->authdata_raw) < 0) { fido_log_debug("%s: fido_blob_decode", __func__); goto fail; } 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; } } ok = 0; fail: free(name); return (ok); } static int 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) { + if (att->pbAttestationObject == NULL) { fido_log_debug("%s: pbAttestationObject", __func__); goto fail; } if ((item = cbor_load(att->pbAttestationObject, - (size_t)att->cbAttestationObject, &cbor)) == NULL) { + 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_get_assert(HWND w, struct winhello_assert *ctx) { HRESULT hr; int r = FIDO_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__, 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; 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__, 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) webauthn_free_assert(ctx->assert); free(ctx->rp_id); free(ctx->opt.CredentialList.pCredentials); + if (ctx->opt.pHmacSecretSaltValues != NULL) + free(ctx->opt.pHmacSecretSaltValues->pGlobalHmacSalt); + free(ctx->opt.pHmacSecretSaltValues); free(ctx); } static void winhello_cred_free(struct winhello_cred *ctx) { if (ctx == NULL) return; if (ctx->att != NULL) 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) { fido_dev_info_t *di; if (ilen == 0) { return FIDO_OK; } if (devlist == NULL) { return FIDO_ERR_INVALID_ARGUMENT; } if (!webauthn_loaded && webauthn_load() < 0) { fido_log_debug("%s: webauthn_load", __func__); return FIDO_OK; /* not an error */ } 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, 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__); if ((w = GetTopWindow(NULL)) == NULL) { fido_log_debug("%s: GetTopWindow", __func__); goto fail; } } 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)) != FIDO_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" }; + const char *o[4] = { "rk", "up", "uv", "plat" }; (void)dev; fido_cbor_info_reset(ci); 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, 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__); if ((w = GetTopWindow(NULL)) == NULL) { fido_log_debug("%s: GetTopWindow", __func__); goto fail; } } 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 f37aa1d87c97..e1f4366c4ef3 100644 --- a/contrib/libfido2/tools/CMakeLists.txt +++ b/contrib/libfido2/tools/CMakeLists.txt @@ -1,80 +1,74 @@ -# Copyright (c) 2018 Yubico AB. All rights reserved. +# Copyright (c) 2018-2022 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. +# SPDX-License-Identifier: BSD-2-Clause 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") + PROPERTIES COMPILE_FLAGS "${EXTRA_CFLAGS}") 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/assert_get.c b/contrib/libfido2/tools/assert_get.c index c38040253520..8260fb8359f5 100644 --- a/contrib/libfido2/tools/assert_get.c +++ b/contrib/libfido2/tools/assert_get.c @@ -1,316 +1,321 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" struct toggle { fido_opt_t up; fido_opt_t uv; fido_opt_t pin; }; static const char * opt2str(fido_opt_t v) { switch (v) { case FIDO_OPT_OMIT: return "omit"; case FIDO_OPT_TRUE: return "true"; case FIDO_OPT_FALSE: return "false"; default: return "unknown"; } } static void parse_toggle(const char *str, struct toggle *opt) { fido_opt_t *k; fido_opt_t v; char *assignment; char *key; char *val; if ((assignment = strdup(str)) == NULL) err(1, "strdup"); if ((val = strchr(assignment, '=')) == NULL) errx(1, "invalid assignment '%s'", assignment); key = assignment; *val++ = '\0'; if (!strcmp(val, "true")) v = FIDO_OPT_TRUE; else if (!strcmp(val, "false")) v = FIDO_OPT_FALSE; else errx(1, "unknown value '%s'", val); if (!strcmp(key, "up")) k = &opt->up; else if (!strcmp(key, "uv")) k = &opt->uv; else if (!strcmp(key, "pin")) k = &opt->pin; else errx(1, "unknown key '%s'", key); free(assignment); *k = v; } static fido_assert_t * prepare_assert(FILE *in_f, int flags, const struct toggle *opt) { fido_assert_t *assert = NULL; struct blob cdh; struct blob id; struct blob hmac_salt; char *rpid = NULL; int r; memset(&cdh, 0, sizeof(cdh)); memset(&id, 0, sizeof(id)); memset(&hmac_salt, 0, sizeof(hmac_salt)); r = base64_read(in_f, &cdh); r |= string_read(in_f, &rpid); if ((flags & FLAG_RK) == 0) r |= base64_read(in_f, &id); if (flags & FLAG_HMAC) r |= base64_read(in_f, &hmac_salt); if (r < 0) errx(1, "input error"); if (flags & FLAG_DEBUG) { fprintf(stderr, "client data hash:\n"); xxd(cdh.ptr, cdh.len); fprintf(stderr, "relying party id: %s\n", rpid); if ((flags & FLAG_RK) == 0) { fprintf(stderr, "credential id:\n"); xxd(id.ptr, id.len); } fprintf(stderr, "up=%s\n", opt2str(opt->up)); fprintf(stderr, "uv=%s\n", opt2str(opt->uv)); fprintf(stderr, "pin=%s\n", opt2str(opt->pin)); } if ((assert = fido_assert_new()) == NULL) errx(1, "fido_assert_new"); if ((r = fido_assert_set_clientdata_hash(assert, cdh.ptr, cdh.len)) != FIDO_OK || (r = fido_assert_set_rp(assert, rpid)) != FIDO_OK) errx(1, "fido_assert_set: %s", fido_strerr(r)); if ((r = fido_assert_set_up(assert, opt->up)) != FIDO_OK) errx(1, "fido_assert_set_up: %s", fido_strerr(r)); if ((r = fido_assert_set_uv(assert, opt->uv)) != FIDO_OK) errx(1, "fido_assert_set_uv: %s", fido_strerr(r)); if (flags & FLAG_HMAC) { if ((r = fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET)) != FIDO_OK) errx(1, "fido_assert_set_extensions: %s", fido_strerr(r)); if ((r = fido_assert_set_hmac_salt(assert, hmac_salt.ptr, hmac_salt.len)) != FIDO_OK) errx(1, "fido_assert_set_hmac_salt: %s", fido_strerr(r)); } if (flags & FLAG_LARGEBLOB) { if ((r = fido_assert_set_extensions(assert, FIDO_EXT_LARGEBLOB_KEY)) != FIDO_OK) errx(1, "fido_assert_set_extensions: %s", fido_strerr(r)); } if ((flags & FLAG_RK) == 0) { if ((r = fido_assert_allow_cred(assert, id.ptr, id.len)) != FIDO_OK) errx(1, "fido_assert_allow_cred: %s", fido_strerr(r)); } free(hmac_salt.ptr); free(cdh.ptr); free(id.ptr); free(rpid); return (assert); } static void print_assert(FILE *out_f, const fido_assert_t *assert, size_t idx, int flags) { char *cdh = NULL; char *authdata = NULL; char *sig = NULL; char *user_id = NULL; char *hmac_secret = NULL; char *key = NULL; int r; r = base64_encode(fido_assert_clientdata_hash_ptr(assert), fido_assert_clientdata_hash_len(assert), &cdh); r |= base64_encode(fido_assert_authdata_ptr(assert, idx), fido_assert_authdata_len(assert, 0), &authdata); r |= base64_encode(fido_assert_sig_ptr(assert, idx), fido_assert_sig_len(assert, idx), &sig); if (flags & FLAG_RK) r |= base64_encode(fido_assert_user_id_ptr(assert, idx), fido_assert_user_id_len(assert, idx), &user_id); if (flags & FLAG_HMAC) r |= base64_encode(fido_assert_hmac_secret_ptr(assert, idx), fido_assert_hmac_secret_len(assert, idx), &hmac_secret); if (flags & FLAG_LARGEBLOB) r |= base64_encode(fido_assert_largeblob_key_ptr(assert, idx), fido_assert_largeblob_key_len(assert, idx), &key); if (r < 0) errx(1, "output error"); fprintf(out_f, "%s\n", cdh); fprintf(out_f, "%s\n", fido_assert_rp_id(assert)); fprintf(out_f, "%s\n", authdata); fprintf(out_f, "%s\n", sig); if (flags & FLAG_RK) fprintf(out_f, "%s\n", user_id); if (hmac_secret) { fprintf(out_f, "%s\n", hmac_secret); explicit_bzero(hmac_secret, strlen(hmac_secret)); } if (key) { fprintf(out_f, "%s\n", key); explicit_bzero(key, strlen(key)); } free(key); free(hmac_secret); free(cdh); free(authdata); free(sig); free(user_id); } int assert_get(int argc, char **argv) { fido_dev_t *dev = NULL; fido_assert_t *assert = NULL; struct toggle opt; - char pin[1024]; char prompt[1024]; + char pin[128]; char *in_path = NULL; char *out_path = NULL; FILE *in_f = NULL; FILE *out_f = NULL; int flags = 0; int ch; int r; opt.up = opt.uv = opt.pin = FIDO_OPT_OMIT; while ((ch = getopt(argc, argv, "bdhi:o:prt:uv")) != -1) { switch (ch) { case 'b': flags |= FLAG_LARGEBLOB; break; case 'd': flags |= FLAG_DEBUG; break; case 'h': flags |= FLAG_HMAC; break; case 'i': in_path = optarg; break; case 'o': out_path = optarg; break; case 'p': opt.up = FIDO_OPT_TRUE; break; case 'r': flags |= FLAG_RK; break; case 't' : parse_toggle(optarg, &opt); break; case 'u': flags |= FLAG_U2F; break; case 'v': /* -v implies both pin and uv for historical reasons */ opt.pin = FIDO_OPT_TRUE; opt.uv = FIDO_OPT_TRUE; break; default: usage(); } } argc -= optind; argv += optind; if (argc < 1) usage(); in_f = open_read(in_path); out_f = open_write(out_path); fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); assert = prepare_assert(in_f, flags, &opt); dev = open_dev(argv[0]); if (flags & FLAG_U2F) fido_dev_force_u2f(dev); if (opt.pin == FIDO_OPT_TRUE) { r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", argv[0]); if (r < 0 || (size_t)r >= sizeof(prompt)) errx(1, "snprintf"); if (!readpassphrase(prompt, pin, sizeof(pin), RPP_ECHO_OFF)) errx(1, "readpassphrase"); + if (strlen(pin) < 4 || strlen(pin) > 63) { + explicit_bzero(pin, sizeof(pin)); + errx(1, "invalid PIN length"); + } r = fido_dev_get_assert(dev, assert, pin); } else r = fido_dev_get_assert(dev, assert, NULL); explicit_bzero(pin, sizeof(pin)); if (r != FIDO_OK) errx(1, "fido_dev_get_assert: %s", fido_strerr(r)); if (flags & FLAG_RK) { for (size_t idx = 0; idx < fido_assert_count(assert); idx++) print_assert(out_f, assert, idx, flags); } else { if (fido_assert_count(assert) != 1) errx(1, "fido_assert_count: %zu", fido_assert_count(assert)); print_assert(out_f, assert, 0, flags); } fido_dev_close(dev); fido_dev_free(&dev); fido_assert_free(&assert); fclose(in_f); fclose(out_f); in_f = NULL; out_f = NULL; exit(0); } diff --git a/contrib/libfido2/tools/assert_verify.c b/contrib/libfido2/tools/assert_verify.c index 7985e95042c5..4cc2e86bff13 100644 --- a/contrib/libfido2/tools/assert_verify.c +++ b/contrib/libfido2/tools/assert_verify.c @@ -1,192 +1,208 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include +#include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" static fido_assert_t * prepare_assert(FILE *in_f, int flags) { fido_assert_t *assert = NULL; struct blob cdh; struct blob authdata; struct blob sig; char *rpid = NULL; int r; memset(&cdh, 0, sizeof(cdh)); memset(&authdata, 0, sizeof(authdata)); memset(&sig, 0, sizeof(sig)); r = base64_read(in_f, &cdh); r |= string_read(in_f, &rpid); r |= base64_read(in_f, &authdata); r |= base64_read(in_f, &sig); if (r < 0) errx(1, "input error"); if (flags & FLAG_DEBUG) { fprintf(stderr, "client data hash:\n"); xxd(cdh.ptr, cdh.len); fprintf(stderr, "relying party id: %s\n", rpid); fprintf(stderr, "authenticator data:\n"); xxd(authdata.ptr, authdata.len); fprintf(stderr, "signature:\n"); xxd(sig.ptr, sig.len); } if ((assert = fido_assert_new()) == NULL) errx(1, "fido_assert_new"); if ((r = fido_assert_set_count(assert, 1)) != FIDO_OK) errx(1, "fido_assert_count: %s", fido_strerr(r)); if ((r = fido_assert_set_clientdata_hash(assert, cdh.ptr, cdh.len)) != FIDO_OK || (r = fido_assert_set_rp(assert, rpid)) != FIDO_OK || (r = fido_assert_set_authdata(assert, 0, authdata.ptr, authdata.len)) != FIDO_OK || (r = fido_assert_set_sig(assert, 0, sig.ptr, sig.len)) != FIDO_OK) errx(1, "fido_assert_set: %s", fido_strerr(r)); if (flags & FLAG_UP) { if ((r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_assert_set_up: %s", fido_strerr(r)); } if (flags & FLAG_UV) { if ((r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_assert_set_uv: %s", fido_strerr(r)); } if (flags & FLAG_HMAC) { if ((r = fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET)) != FIDO_OK) errx(1, "fido_assert_set_extensions: %s", fido_strerr(r)); } free(cdh.ptr); free(authdata.ptr); free(sig.ptr); free(rpid); return (assert); } static void * load_pubkey(int type, const char *file) { EC_KEY *ec = NULL; RSA *rsa = NULL; EVP_PKEY *eddsa = NULL; es256_pk_t *es256_pk = NULL; + es384_pk_t *es384_pk = NULL; rs256_pk_t *rs256_pk = NULL; eddsa_pk_t *eddsa_pk = NULL; void *pk = NULL; - if (type == COSE_ES256) { + switch (type) { + case COSE_ES256: if ((ec = read_ec_pubkey(file)) == 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); - } else if (type == COSE_RS256) { + break; + case COSE_ES384: + if ((ec = read_ec_pubkey(file)) == NULL) + errx(1, "read_ec_pubkey"); + if ((es384_pk = es384_pk_new()) == NULL) + errx(1, "es384_pk_new"); + if (es384_pk_from_EC_KEY(es384_pk, ec) != FIDO_OK) + errx(1, "es384_pk_from_EC_KEY"); + pk = es384_pk; + EC_KEY_free(ec); + break; + case COSE_RS256: if ((rsa = read_rsa_pubkey(file)) == 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); - } else if (type == COSE_EDDSA) { + break; + case COSE_EDDSA: if ((eddsa = read_eddsa_pubkey(file)) == 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); + break; + default: + errx(1, "invalid type %d", type); } return (pk); } int assert_verify(int argc, char **argv) { fido_assert_t *assert = NULL; void *pk = NULL; char *in_path = NULL; FILE *in_f = NULL; int type = COSE_ES256; int flags = 0; int ch; int r; while ((ch = getopt(argc, argv, "dhi:pv")) != -1) { switch (ch) { case 'd': flags |= FLAG_DEBUG; break; case 'h': flags |= FLAG_HMAC; break; case 'i': in_path = optarg; break; case 'p': flags |= FLAG_UP; break; case 'v': flags |= FLAG_UV; break; default: usage(); } } argc -= optind; argv += optind; if (argc < 1 || argc > 2) usage(); in_f = open_read(in_path); if (argc > 1 && cose_type(argv[1], &type) < 0) errx(1, "unknown type %s", argv[1]); fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); pk = load_pubkey(type, argv[0]); assert = prepare_assert(in_f, flags); if ((r = fido_assert_verify(assert, 0, type, pk)) != FIDO_OK) errx(1, "fido_assert_verify: %s", fido_strerr(r)); fido_assert_free(&assert); fclose(in_f); in_f = NULL; exit(0); } diff --git a/contrib/libfido2/tools/base64.c b/contrib/libfido2/tools/base64.c index e13119823c98..2cfa98ddb254 100644 --- a/contrib/libfido2/tools/base64.c +++ b/contrib/libfido2/tools/base64.c @@ -1,134 +1,135 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" int base64_encode(const void *ptr, size_t len, char **out) { BIO *bio_b64 = NULL; BIO *bio_mem = NULL; char *b64_ptr = NULL; long b64_len; int n; int ok = -1; if (ptr == NULL || out == NULL || len > INT_MAX) return (-1); *out = NULL; if ((bio_b64 = BIO_new(BIO_f_base64())) == NULL) goto fail; if ((bio_mem = BIO_new(BIO_s_mem())) == NULL) goto fail; BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL); BIO_push(bio_b64, bio_mem); n = BIO_write(bio_b64, ptr, (int)len); if (n < 0 || (size_t)n != len) goto fail; if (BIO_flush(bio_b64) < 0) goto fail; b64_len = BIO_get_mem_data(bio_b64, &b64_ptr); if (b64_len < 0 || (size_t)b64_len == SIZE_MAX || b64_ptr == NULL) goto fail; if ((*out = calloc(1, (size_t)b64_len + 1)) == NULL) goto fail; memcpy(*out, b64_ptr, (size_t)b64_len); ok = 0; fail: BIO_free(bio_b64); BIO_free(bio_mem); return (ok); } int base64_decode(const char *in, void **ptr, size_t *len) { BIO *bio_mem = NULL; BIO *bio_b64 = NULL; size_t alloc_len; int n; int ok = -1; if (in == NULL || ptr == NULL || len == NULL || strlen(in) > INT_MAX) return (-1); *ptr = NULL; *len = 0; if ((bio_b64 = BIO_new(BIO_f_base64())) == NULL) goto fail; if ((bio_mem = BIO_new_mem_buf((const void *)in, -1)) == NULL) goto fail; BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL); BIO_push(bio_b64, bio_mem); alloc_len = strlen(in); if ((*ptr = calloc(1, alloc_len)) == NULL) goto fail; n = BIO_read(bio_b64, *ptr, (int)alloc_len); if (n <= 0 || BIO_eof(bio_b64) == 0) goto fail; *len = (size_t)n; ok = 0; fail: BIO_free(bio_b64); BIO_free(bio_mem); if (ok < 0) { free(*ptr); *ptr = NULL; *len = 0; } return (ok); } int base64_read(FILE *f, struct blob *out) { char *line = NULL; size_t linesize = 0; ssize_t n; out->ptr = NULL; out->len = 0; if ((n = getline(&line, &linesize, f)) <= 0 || (size_t)n != strlen(line)) { free(line); /* XXX should be free'd _even_ if getline() fails */ return (-1); } if (base64_decode(line, (void **)&out->ptr, &out->len) < 0) { free(line); return (-1); } free(line); return (0); } diff --git a/contrib/libfido2/tools/bio.c b/contrib/libfido2/tools/bio.c index 1ce1041c30c6..7a1406d70de5 100644 --- a/contrib/libfido2/tools/bio.c +++ b/contrib/libfido2/tools/bio.c @@ -1,277 +1,278 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" static int print_template(const fido_bio_template_array_t *ta, size_t idx) { const fido_bio_template_t *t = NULL; char *id = NULL; if ((t = fido_bio_template(ta, idx)) == NULL) { warnx("fido_bio_template"); return -1; } if (base64_encode(fido_bio_template_id_ptr(t), fido_bio_template_id_len(t), &id) < 0) { warnx("output error"); return -1; } printf("%02u: %s %s\n", (unsigned)idx, id, fido_bio_template_name(t)); free(id); return 0; } int bio_list(const char *path) { fido_bio_template_array_t *ta = NULL; fido_dev_t *dev = NULL; char *pin = NULL; int r, ok = 1; if ((ta = fido_bio_template_array_new()) == NULL) errx(1, "fido_bio_template_array_new"); dev = open_dev(path); if ((pin = get_pin(path)) == NULL) goto out; r = fido_bio_dev_get_template_array(dev, ta, pin); freezero(pin, PINBUF_LEN); pin = NULL; if (r != FIDO_OK) { warnx("fido_bio_dev_get_template_array: %s", fido_strerr(r)); goto out; } for (size_t i = 0; i < fido_bio_template_array_count(ta); i++) if (print_template(ta, i) < 0) goto out; ok = 0; out: fido_bio_template_array_free(&ta); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } int bio_set_name(const char *path, const char *id, const char *name) { fido_bio_template_t *t = NULL; fido_dev_t *dev = NULL; char *pin = NULL; void *id_blob_ptr = NULL; size_t id_blob_len = 0; int r, ok = 1; if ((t = fido_bio_template_new()) == NULL) errx(1, "fido_bio_template_new"); if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0) errx(1, "base64_decode"); if ((r = fido_bio_template_set_name(t, name)) != FIDO_OK) errx(1, "fido_bio_template_set_name: %s", fido_strerr(r)); if ((r = fido_bio_template_set_id(t, id_blob_ptr, id_blob_len)) != FIDO_OK) errx(1, "fido_bio_template_set_id: %s", fido_strerr(r)); dev = open_dev(path); if ((pin = get_pin(path)) == NULL) goto out; r = fido_bio_dev_set_template_name(dev, t, pin); freezero(pin, PINBUF_LEN); pin = NULL; if (r != FIDO_OK) { warnx("fido_bio_dev_set_template_name: %s", fido_strerr(r)); goto out; } ok = 0; out: free(id_blob_ptr); fido_bio_template_free(&t); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } static const char * enroll_strerr(uint8_t n) { switch (n) { case FIDO_BIO_ENROLL_FP_GOOD: return "Sample ok"; case FIDO_BIO_ENROLL_FP_TOO_HIGH: return "Sample too high"; case FIDO_BIO_ENROLL_FP_TOO_LOW: return "Sample too low"; case FIDO_BIO_ENROLL_FP_TOO_LEFT: return "Sample too left"; case FIDO_BIO_ENROLL_FP_TOO_RIGHT: return "Sample too right"; case FIDO_BIO_ENROLL_FP_TOO_FAST: return "Sample too fast"; case FIDO_BIO_ENROLL_FP_TOO_SLOW: return "Sample too slow"; case FIDO_BIO_ENROLL_FP_POOR_QUALITY: return "Poor quality sample"; case FIDO_BIO_ENROLL_FP_TOO_SKEWED: return "Sample too skewed"; case FIDO_BIO_ENROLL_FP_TOO_SHORT: return "Sample too short"; case FIDO_BIO_ENROLL_FP_MERGE_FAILURE: return "Sample merge failure"; case FIDO_BIO_ENROLL_FP_EXISTS: return "Sample exists"; case FIDO_BIO_ENROLL_FP_DATABASE_FULL: return "Fingerprint database full"; case FIDO_BIO_ENROLL_NO_USER_ACTIVITY: return "No user activity"; case FIDO_BIO_ENROLL_NO_USER_PRESENCE_TRANSITION: return "No user presence transition"; default: return "Unknown error"; } } int bio_enroll(const char *path) { fido_bio_template_t *t = NULL; fido_bio_enroll_t *e = NULL; fido_dev_t *dev = NULL; char *pin = NULL; int r, ok = 1; if ((t = fido_bio_template_new()) == NULL) errx(1, "fido_bio_template_new"); if ((e = fido_bio_enroll_new()) == NULL) errx(1, "fido_bio_enroll_new"); dev = open_dev(path); if ((pin = get_pin(path)) == NULL) goto out; printf("Touch your security key.\n"); r = fido_bio_dev_enroll_begin(dev, t, e, 10000, pin); freezero(pin, PINBUF_LEN); pin = NULL; if (r != FIDO_OK) { warnx("fido_bio_dev_enroll_begin: %s", fido_strerr(r)); goto out; } printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e))); while (fido_bio_enroll_remaining_samples(e) > 0) { printf("Touch your security key (%u sample%s left).\n", (unsigned)fido_bio_enroll_remaining_samples(e), plural(fido_bio_enroll_remaining_samples(e))); if ((r = fido_bio_dev_enroll_continue(dev, t, e, 10000)) != FIDO_OK) { fido_dev_cancel(dev); warnx("fido_bio_dev_enroll_continue: %s", fido_strerr(r)); goto out; } printf("%s.\n", enroll_strerr(fido_bio_enroll_last_status(e))); } ok = 0; out: fido_bio_template_free(&t); fido_bio_enroll_free(&e); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } int bio_delete(const char *path, const char *id) { fido_bio_template_t *t = NULL; fido_dev_t *dev = NULL; char *pin = NULL; void *id_blob_ptr = NULL; size_t id_blob_len = 0; int r, ok = 1; if ((t = fido_bio_template_new()) == NULL) errx(1, "fido_bio_template_new"); if (base64_decode(id, &id_blob_ptr, &id_blob_len) < 0) errx(1, "base64_decode"); if ((r = fido_bio_template_set_id(t, id_blob_ptr, id_blob_len)) != FIDO_OK) errx(1, "fido_bio_template_set_id: %s", fido_strerr(r)); dev = open_dev(path); if ((pin = get_pin(path)) == NULL) goto out; r = fido_bio_dev_enroll_remove(dev, t, pin); freezero(pin, PINBUF_LEN); pin = NULL; if (r != FIDO_OK) { warnx("fido_bio_dev_enroll_remove: %s", fido_strerr(r)); goto out; } ok = 0; out: free(id_blob_ptr); fido_bio_template_free(&t); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } static const char * type_str(uint8_t t) { switch (t) { case 1: return "touch"; case 2: return "swipe"; default: return "unknown"; } } void bio_info(fido_dev_t *dev) { fido_bio_info_t *i = NULL; if ((i = fido_bio_info_new()) == NULL) { warnx("fido_bio_info_new"); return; } if (fido_bio_dev_get_info(dev, i) != FIDO_OK) { fido_bio_info_free(&i); return; } printf("sensor type: %u (%s)\n", (unsigned)fido_bio_info_type(i), type_str(fido_bio_info_type(i))); printf("max samples: %u\n", (unsigned)fido_bio_info_max_samples(i)); fido_bio_info_free(&i); } diff --git a/contrib/libfido2/tools/config.c b/contrib/libfido2/tools/config.c index 3eea4c9b6cf6..49253e83f3b7 100644 --- a/contrib/libfido2/tools/config.c +++ b/contrib/libfido2/tools/config.c @@ -1,197 +1,198 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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/cred_make.c b/contrib/libfido2/tools/cred_make.c index 7955fa2b7f9f..a6239ec27aec 100644 --- a/contrib/libfido2/tools/cred_make.c +++ b/contrib/libfido2/tools/cred_make.c @@ -1,242 +1,247 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" static fido_cred_t * prepare_cred(FILE *in_f, int type, int flags) { fido_cred_t *cred = NULL; struct blob cdh; struct blob uid; char *rpid = NULL; char *uname = NULL; int r; memset(&cdh, 0, sizeof(cdh)); memset(&uid, 0, sizeof(uid)); r = base64_read(in_f, &cdh); r |= string_read(in_f, &rpid); r |= string_read(in_f, &uname); r |= base64_read(in_f, &uid); if (r < 0) errx(1, "input error"); if (flags & FLAG_DEBUG) { fprintf(stderr, "client data hash:\n"); xxd(cdh.ptr, cdh.len); fprintf(stderr, "relying party id: %s\n", rpid); fprintf(stderr, "user name: %s\n", uname); fprintf(stderr, "user id:\n"); xxd(uid.ptr, uid.len); } if ((cred = fido_cred_new()) == NULL) errx(1, "fido_cred_new"); if ((r = fido_cred_set_type(cred, type)) != FIDO_OK || (r = fido_cred_set_clientdata_hash(cred, cdh.ptr, cdh.len)) != FIDO_OK || (r = fido_cred_set_rp(cred, rpid, NULL)) != FIDO_OK || (r = fido_cred_set_user(cred, uid.ptr, uid.len, uname, NULL, NULL)) != FIDO_OK) errx(1, "fido_cred_set: %s", fido_strerr(r)); if (flags & FLAG_RK) { if ((r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_cred_set_rk: %s", fido_strerr(r)); } if (flags & FLAG_UV) { if ((r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_cred_set_uv: %s", fido_strerr(r)); } if (flags & FLAG_HMAC) { if ((r = fido_cred_set_extensions(cred, FIDO_EXT_HMAC_SECRET)) != FIDO_OK) errx(1, "fido_cred_set_extensions: %s", fido_strerr(r)); } if (flags & FLAG_LARGEBLOB) { if ((r = fido_cred_set_extensions(cred, FIDO_EXT_LARGEBLOB_KEY)) != FIDO_OK) errx(1, "fido_cred_set_extensions: %s", fido_strerr(r)); } free(cdh.ptr); free(uid.ptr); free(rpid); free(uname); return (cred); } static void print_attcred(FILE *out_f, const fido_cred_t *cred) { char *cdh = NULL; char *authdata = NULL; char *id = NULL; char *sig = NULL; char *x5c = NULL; char *key = NULL; int r; r = base64_encode(fido_cred_clientdata_hash_ptr(cred), fido_cred_clientdata_hash_len(cred), &cdh); r |= base64_encode(fido_cred_authdata_ptr(cred), fido_cred_authdata_len(cred), &authdata); r |= base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &id); r |= base64_encode(fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), &sig); if (fido_cred_x5c_ptr(cred) != NULL) r |= base64_encode(fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred), &x5c); if (fido_cred_largeblob_key_ptr(cred) != NULL) r |= base64_encode(fido_cred_largeblob_key_ptr(cred), fido_cred_largeblob_key_len(cred), &key); if (r < 0) errx(1, "output error"); fprintf(out_f, "%s\n", cdh); fprintf(out_f, "%s\n", fido_cred_rp_id(cred)); fprintf(out_f, "%s\n", fido_cred_fmt(cred)); fprintf(out_f, "%s\n", authdata); fprintf(out_f, "%s\n", id); fprintf(out_f, "%s\n", sig); if (x5c != NULL) fprintf(out_f, "%s\n", x5c); if (key != NULL) { fprintf(out_f, "%s\n", key); explicit_bzero(key, strlen(key)); } free(cdh); free(authdata); free(id); free(sig); free(x5c); free(key); } int cred_make(int argc, char **argv) { fido_dev_t *dev = NULL; fido_cred_t *cred = NULL; char prompt[1024]; - char pin[1024]; + char pin[128]; char *in_path = NULL; char *out_path = NULL; FILE *in_f = NULL; FILE *out_f = NULL; int type = COSE_ES256; int flags = 0; int cred_protect = -1; int ch; int r; while ((ch = getopt(argc, argv, "bc:dhi:o:qruv")) != -1) { switch (ch) { case 'b': flags |= FLAG_LARGEBLOB; break; case 'c': if ((cred_protect = base10(optarg)) < 0) errx(1, "-c: invalid argument '%s'", optarg); break; case 'd': flags |= FLAG_DEBUG; break; case 'h': flags |= FLAG_HMAC; break; case 'i': in_path = optarg; break; case 'o': out_path = optarg; break; case 'q': flags |= FLAG_QUIET; break; case 'r': flags |= FLAG_RK; break; case 'u': flags |= FLAG_U2F; break; case 'v': flags |= FLAG_UV; break; default: usage(); } } argc -= optind; argv += optind; if (argc < 1 || argc > 2) usage(); in_f = open_read(in_path); out_f = open_write(out_path); if (argc > 1 && cose_type(argv[1], &type) < 0) errx(1, "unknown type %s", argv[1]); fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); cred = prepare_cred(in_f, type, flags); dev = open_dev(argv[0]); if (flags & FLAG_U2F) fido_dev_force_u2f(dev); if (cred_protect > 0) { r = fido_cred_set_prot(cred, cred_protect); if (r != FIDO_OK) { errx(1, "fido_cred_set_prot: %s", fido_strerr(r)); } } r = fido_dev_make_cred(dev, cred, NULL); if (r == FIDO_ERR_PIN_REQUIRED && !(flags & FLAG_QUIET)) { r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", argv[0]); if (r < 0 || (size_t)r >= sizeof(prompt)) errx(1, "snprintf"); if (!readpassphrase(prompt, pin, sizeof(pin), RPP_ECHO_OFF)) errx(1, "readpassphrase"); + if (strlen(pin) < 4 || strlen(pin) > 63) { + explicit_bzero(pin, sizeof(pin)); + errx(1, "invalid PIN length"); + } r = fido_dev_make_cred(dev, cred, pin); } explicit_bzero(pin, sizeof(pin)); if (r != FIDO_OK) errx(1, "fido_dev_make_cred: %s", fido_strerr(r)); print_attcred(out_f, cred); fido_dev_close(dev); fido_dev_free(&dev); fido_cred_free(&cred); fclose(in_f); fclose(out_f); in_f = NULL; out_f = NULL; exit(0); } diff --git a/contrib/libfido2/tools/cred_verify.c b/contrib/libfido2/tools/cred_verify.c index d622ed7369bd..3eae435899df 100644 --- a/contrib/libfido2/tools/cred_verify.c +++ b/contrib/libfido2/tools/cred_verify.c @@ -1,181 +1,182 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" static fido_cred_t * prepare_cred(FILE *in_f, int type, int flags) { fido_cred_t *cred = NULL; struct blob cdh; struct blob authdata; struct blob id; struct blob sig; struct blob x5c; char *rpid = NULL; char *fmt = NULL; int r; memset(&cdh, 0, sizeof(cdh)); memset(&authdata, 0, sizeof(authdata)); memset(&id, 0, sizeof(id)); memset(&sig, 0, sizeof(sig)); memset(&x5c, 0, sizeof(x5c)); r = base64_read(in_f, &cdh); r |= string_read(in_f, &rpid); r |= string_read(in_f, &fmt); r |= base64_read(in_f, &authdata); r |= base64_read(in_f, &id); r |= base64_read(in_f, &sig); if (r < 0) errx(1, "input error"); (void)base64_read(in_f, &x5c); if (flags & FLAG_DEBUG) { fprintf(stderr, "client data hash:\n"); xxd(cdh.ptr, cdh.len); fprintf(stderr, "relying party id: %s\n", rpid); fprintf(stderr, "format: %s\n", fmt); fprintf(stderr, "authenticator data:\n"); xxd(authdata.ptr, authdata.len); fprintf(stderr, "credential id:\n"); xxd(id.ptr, id.len); fprintf(stderr, "signature:\n"); xxd(sig.ptr, sig.len); fprintf(stderr, "x509:\n"); xxd(x5c.ptr, x5c.len); } if ((cred = fido_cred_new()) == NULL) errx(1, "fido_cred_new"); if ((r = fido_cred_set_type(cred, type)) != FIDO_OK || (r = fido_cred_set_clientdata_hash(cred, cdh.ptr, cdh.len)) != FIDO_OK || (r = fido_cred_set_rp(cred, rpid, NULL)) != FIDO_OK || (r = fido_cred_set_authdata(cred, authdata.ptr, authdata.len)) != FIDO_OK || (r = fido_cred_set_sig(cred, sig.ptr, sig.len)) != FIDO_OK || (r = fido_cred_set_fmt(cred, fmt)) != FIDO_OK) errx(1, "fido_cred_set: %s", fido_strerr(r)); if (x5c.ptr != NULL) { if ((r = fido_cred_set_x509(cred, x5c.ptr, x5c.len)) != FIDO_OK) errx(1, "fido_cred_set_x509: %s", fido_strerr(r)); } if (flags & FLAG_UV) { if ((r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) errx(1, "fido_cred_set_uv: %s", fido_strerr(r)); } if (flags & FLAG_HMAC) { if ((r = fido_cred_set_extensions(cred, FIDO_EXT_HMAC_SECRET)) != FIDO_OK) errx(1, "fido_cred_set_extensions: %s", fido_strerr(r)); } free(cdh.ptr); free(authdata.ptr); free(id.ptr); free(sig.ptr); free(x5c.ptr); free(rpid); free(fmt); return (cred); } int cred_verify(int argc, char **argv) { fido_cred_t *cred = NULL; char *in_path = NULL; char *out_path = NULL; FILE *in_f = NULL; FILE *out_f = NULL; int type = COSE_ES256; int flags = 0; int cred_prot = -1; int ch; int r; while ((ch = getopt(argc, argv, "c:dhi:o:v")) != -1) { switch (ch) { case 'c': if ((cred_prot = base10(optarg)) < 0) errx(1, "-c: invalid argument '%s'", optarg); break; case 'd': flags |= FLAG_DEBUG; break; case 'h': flags |= FLAG_HMAC; break; case 'i': in_path = optarg; break; case 'o': out_path = optarg; break; case 'v': flags |= FLAG_UV; break; default: usage(); } } argc -= optind; argv += optind; if (argc > 1) usage(); in_f = open_read(in_path); out_f = open_write(out_path); if (argc > 0 && cose_type(argv[0], &type) < 0) errx(1, "unknown type %s", argv[0]); fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); cred = prepare_cred(in_f, type, flags); if (cred_prot > 0) { r = fido_cred_set_prot(cred, cred_prot); if (r != FIDO_OK) { errx(1, "fido_cred_set_prot: %s", fido_strerr(r)); } } if (fido_cred_x5c_ptr(cred) == NULL) { if ((r = fido_cred_verify_self(cred)) != FIDO_OK) errx(1, "fido_cred_verify_self: %s", fido_strerr(r)); } else { if ((r = fido_cred_verify(cred)) != FIDO_OK) errx(1, "fido_cred_verify: %s", fido_strerr(r)); } print_cred(out_f, type, cred); fido_cred_free(&cred); fclose(in_f); fclose(out_f); in_f = NULL; out_f = NULL; exit(0); } diff --git a/contrib/libfido2/tools/credman.c b/contrib/libfido2/tools/credman.c index d7fb15580f87..a0a3149d5dfb 100644 --- a/contrib/libfido2/tools/credman.c +++ b/contrib/libfido2/tools/credman.c @@ -1,329 +1,330 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" int credman_get_metadata(fido_dev_t *dev, const char *path) { fido_credman_metadata_t *metadata = NULL; char *pin = NULL; int r, ok = 1; if ((metadata = fido_credman_metadata_new()) == NULL) { warnx("fido_credman_metadata_new"); goto out; } if ((r = fido_credman_get_dev_metadata(dev, metadata, NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) { if ((pin = get_pin(path)) == NULL) goto out; r = fido_credman_get_dev_metadata(dev, metadata, pin); freezero(pin, PINBUF_LEN); pin = NULL; } if (r != FIDO_OK) { warnx("fido_credman_get_dev_metadata: %s", fido_strerr(r)); goto out; } printf("existing rk(s): %u\n", (unsigned)fido_credman_rk_existing(metadata)); printf("remaining rk(s): %u\n", (unsigned)fido_credman_rk_remaining(metadata)); ok = 0; out: fido_credman_metadata_free(&metadata); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } static int print_rp(fido_credman_rp_t *rp, size_t idx) { char *rp_id_hash = NULL; if (base64_encode(fido_credman_rp_id_hash_ptr(rp, idx), fido_credman_rp_id_hash_len(rp, idx), &rp_id_hash) < 0) { warnx("output error"); return -1; } printf("%02u: %s %s\n", (unsigned)idx, rp_id_hash, fido_credman_rp_id(rp, idx)); free(rp_id_hash); return 0; } int credman_list_rp(const char *path) { fido_credman_rp_t *rp = NULL; fido_dev_t *dev = NULL; char *pin = NULL; int r, ok = 1; dev = open_dev(path); if ((rp = fido_credman_rp_new()) == NULL) { warnx("fido_credman_rp_new"); goto out; } if ((r = fido_credman_get_dev_rp(dev, rp, NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) { if ((pin = get_pin(path)) == NULL) goto out; r = fido_credman_get_dev_rp(dev, rp, pin); freezero(pin, PINBUF_LEN); pin = NULL; } if (r != FIDO_OK) { warnx("fido_credman_get_dev_rp: %s", fido_strerr(r)); goto out; } for (size_t i = 0; i < fido_credman_rp_count(rp); i++) if (print_rp(rp, i) < 0) goto out; ok = 0; out: fido_credman_rp_free(&rp); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } static int print_rk(const fido_credman_rk_t *rk, size_t idx) { const fido_cred_t *cred; char *id = NULL; char *user_id = NULL; const char *type; const char *prot; if ((cred = fido_credman_rk(rk, idx)) == NULL) { warnx("fido_credman_rk"); return -1; } if (base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &id) < 0 || base64_encode(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred), &user_id) < 0) { warnx("output error"); return -1; } type = cose_string(fido_cred_type(cred)); prot = prot_string(fido_cred_prot(cred)); printf("%02u: %s %s %s %s %s\n", (unsigned)idx, id, fido_cred_display_name(cred), user_id, type, prot); free(user_id); free(id); return 0; } int credman_list_rk(const char *path, const char *rp_id) { fido_dev_t *dev = NULL; fido_credman_rk_t *rk = NULL; char *pin = NULL; int r, ok = 1; dev = open_dev(path); if ((rk = fido_credman_rk_new()) == NULL) { warnx("fido_credman_rk_new"); goto out; } if ((r = fido_credman_get_dev_rk(dev, rp_id, rk, NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) { if ((pin = get_pin(path)) == NULL) goto out; r = fido_credman_get_dev_rk(dev, rp_id, rk, pin); freezero(pin, PINBUF_LEN); pin = NULL; } if (r != FIDO_OK) { warnx("fido_credman_get_dev_rk: %s", fido_strerr(r)); goto out; } for (size_t i = 0; i < fido_credman_rk_count(rk); i++) if (print_rk(rk, i) < 0) goto out; ok = 0; out: fido_credman_rk_free(&rk); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } int credman_print_rk(fido_dev_t *dev, const char *path, const char *rp_id, const char *cred_id) { fido_credman_rk_t *rk = NULL; const fido_cred_t *cred = NULL; char *pin = NULL; void *cred_id_ptr = NULL; size_t cred_id_len = 0; int r, ok = 1; if ((rk = fido_credman_rk_new()) == NULL) { warnx("fido_credman_rk_new"); goto out; } if (base64_decode(cred_id, &cred_id_ptr, &cred_id_len) < 0) { warnx("base64_decode"); goto out; } if ((r = fido_credman_get_dev_rk(dev, rp_id, rk, NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) { if ((pin = get_pin(path)) == NULL) goto out; r = fido_credman_get_dev_rk(dev, rp_id, rk, pin); freezero(pin, PINBUF_LEN); pin = NULL; } if (r != FIDO_OK) { warnx("fido_credman_get_dev_rk: %s", fido_strerr(r)); goto out; } for (size_t i = 0; i < fido_credman_rk_count(rk); i++) { if ((cred = fido_credman_rk(rk, i)) == NULL || fido_cred_id_ptr(cred) == NULL) { warnx("output error"); goto out; } if (cred_id_len != fido_cred_id_len(cred) || memcmp(cred_id_ptr, fido_cred_id_ptr(cred), cred_id_len)) continue; print_cred(stdout, fido_cred_type(cred), cred); ok = 0; goto out; } warnx("credential not found"); out: free(cred_id_ptr); fido_credman_rk_free(&rk); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } int credman_delete_rk(const char *path, const char *id) { fido_dev_t *dev = NULL; char *pin = NULL; void *id_ptr = NULL; size_t id_len = 0; int r, ok = 1; dev = open_dev(path); if (base64_decode(id, &id_ptr, &id_len) < 0) { warnx("base64_decode"); goto out; } if ((r = fido_credman_del_dev_rk(dev, id_ptr, id_len, NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) { if ((pin = get_pin(path)) == NULL) goto out; r = fido_credman_del_dev_rk(dev, id_ptr, id_len, pin); freezero(pin, PINBUF_LEN); pin = NULL; } if (r != FIDO_OK) { warnx("fido_credman_del_dev_rk: %s", fido_strerr(r)); goto out; } ok = 0; out: free(id_ptr); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } int credman_update_rk(const char *path, const char *user_id, const char *cred_id, const char *name, const char *display_name) { fido_dev_t *dev = NULL; fido_cred_t *cred = NULL; char *pin = NULL; void *user_id_ptr = NULL; void *cred_id_ptr = NULL; size_t user_id_len = 0; size_t cred_id_len = 0; int r, ok = 1; dev = open_dev(path); if (base64_decode(user_id, &user_id_ptr, &user_id_len) < 0 || base64_decode(cred_id, &cred_id_ptr, &cred_id_len) < 0) { warnx("base64_decode"); goto out; } if ((cred = fido_cred_new()) == NULL) { warnx("fido_cred_new"); goto out; } if ((r = fido_cred_set_id(cred, cred_id_ptr, cred_id_len)) != FIDO_OK) { warnx("fido_cred_set_id: %s", fido_strerr(r)); goto out; } if ((r = fido_cred_set_user(cred, user_id_ptr, user_id_len, name, display_name, NULL)) != FIDO_OK) { warnx("fido_cred_set_user: %s", fido_strerr(r)); goto out; } if ((r = fido_credman_set_dev_rk(dev, cred, NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) { if ((pin = get_pin(path)) == NULL) goto out; r = fido_credman_set_dev_rk(dev, cred, pin); freezero(pin, PINBUF_LEN); pin = NULL; } if (r != FIDO_OK) { warnx("fido_credman_set_dev_rk: %s", fido_strerr(r)); goto out; } ok = 0; out: free(user_id_ptr); free(cred_id_ptr); fido_dev_close(dev); fido_dev_free(&dev); fido_cred_free(&cred); exit(ok); } diff --git a/contrib/libfido2/tools/extern.h b/contrib/libfido2/tools/extern.h index 8b25dadd45ac..ed4b348cfe46 100644 --- a/contrib/libfido2/tools/extern.h +++ b/contrib/libfido2/tools/extern.h @@ -1,100 +1,102 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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: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_es256_pubkey(FILE *, const void *, size_t); +int write_es384_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-assert.c b/contrib/libfido2/tools/fido2-assert.c index c363d9a49927..d05c541651cb 100644 --- a/contrib/libfido2/tools/fido2-assert.c +++ b/contrib/libfido2/tools/fido2-assert.c @@ -1,54 +1,55 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ /* * Example usage: * * $ echo assertion challenge | openssl sha256 -binary | base64 > assert_param * $ echo relying party >> assert_param * $ head -1 cred >> assert_param # credential id * $ tail -n +2 cred > pubkey # credential pubkey * $ fido2-assert -G -i assert_param /dev/hidraw5 | fido2-assert -V pubkey rs256 * * See blurb in fido2-cred.c on how to obtain cred. */ #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" void usage(void) { fprintf(stderr, "usage: fido2-assert -G [-bdhpruv] [-t option] [-i input_file] [-o output_file] device\n" " fido2-assert -V [-dhpv] [-i input_file] key_file [type]\n" ); exit(1); } int main(int argc, char **argv) { if (argc < 2 || strlen(argv[1]) != 2 || argv[1][0] != '-') usage(); switch (argv[1][1]) { case 'G': return (assert_get(--argc, ++argv)); case 'V': return (assert_verify(--argc, ++argv)); } usage(); /* NOTREACHED */ } diff --git a/contrib/libfido2/tools/fido2-attach.sh b/contrib/libfido2/tools/fido2-attach.sh index d4bc44989f2b..ef02db6b9ff0 100755 --- a/contrib/libfido2/tools/fido2-attach.sh +++ b/contrib/libfido2/tools/fido2-attach.sh @@ -1,14 +1,15 @@ #!/bin/sh # Copyright (c) 2020 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. +# SPDX-License-Identifier: BSD-2-Clause DEV="" while [ -z "${DEV}" ]; do sleep .5 DEV="$(fido2-token -L | sed 's/^\(.*\): .*$/\1/;q')" done printf '%s\n' "${DEV}" diff --git a/contrib/libfido2/tools/fido2-cred.c b/contrib/libfido2/tools/fido2-cred.c index 9463cd591e75..965dbf9ef1ad 100644 --- a/contrib/libfido2/tools/fido2-cred.c +++ b/contrib/libfido2/tools/fido2-cred.c @@ -1,52 +1,53 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ /* * Example usage: * * $ echo credential challenge | openssl sha256 -binary | base64 > cred_param * $ echo relying party >> cred_param * $ echo user name >> cred_param * $ dd if=/dev/urandom bs=1 count=32 | base64 >> cred_param * $ fido2-cred -M -i cred_param /dev/hidraw5 | fido2-cred -V -o cred */ #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" void usage(void) { fprintf(stderr, "usage: fido2-cred -M [-bdhqruv] [-c cred_protect] [-i input_file] [-o output_file] device [type]\n" " fido2-cred -V [-dhv] [-c cred_protect] [-i input_file] [-o output_file] [type]\n" ); exit(1); } int main(int argc, char **argv) { if (argc < 2 || strlen(argv[1]) != 2 || argv[1][0] != '-') usage(); switch (argv[1][1]) { case 'M': return (cred_make(--argc, ++argv)); case 'V': return (cred_verify(--argc, ++argv)); } usage(); /* NOTREACHED */ } diff --git a/contrib/libfido2/tools/fido2-detach.sh b/contrib/libfido2/tools/fido2-detach.sh index 9cd2e64bbe31..140278fc6993 100755 --- a/contrib/libfido2/tools/fido2-detach.sh +++ b/contrib/libfido2/tools/fido2-detach.sh @@ -1,12 +1,13 @@ #!/bin/sh # Copyright (c) 2020 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. +# SPDX-License-Identifier: BSD-2-Clause DEV="$(fido2-token -L | sed 's/^\(.*\): .*$/\1/;q')" while [ -n "${DEV}" ]; do sleep .5 DEV="$(fido2-token -L | sed 's/^\(.*\): .*$/\1/;q')" done diff --git a/contrib/libfido2/tools/fido2-token.c b/contrib/libfido2/tools/fido2-token.c index e6d9f9f96381..412c2f9016c5 100644 --- a/contrib/libfido2/tools/fido2-token.c +++ b/contrib/libfido2/tools/fido2-token.c @@ -1,109 +1,110 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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/fido2-unprot.sh b/contrib/libfido2/tools/fido2-unprot.sh index 44b28b8d06b8..7d8c77936ee9 100755 --- a/contrib/libfido2/tools/fido2-unprot.sh +++ b/contrib/libfido2/tools/fido2-unprot.sh @@ -1,75 +1,76 @@ #!/bin/sh # Copyright (c) 2020 Fabian Henneke. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. +# SPDX-License-Identifier: BSD-2-Clause if [ $(uname) != "Linux" ] ; then echo "Can only run on Linux" exit 1 fi TOKEN_VERSION=$(${FIDO_TOOLS_PREFIX}fido2-token -V 2>&1) if [ $? -ne 0 ] ; then echo "Please install libfido2 1.5.0 or higher" exit fi TOKEN_VERSION_MAJOR=$(echo "$TOKEN_VERSION" | cut -d. -f1) TOKEN_VERSION_MINOR=$(echo "$TOKEN_VERSION" | cut -d. -f2) if [ $TOKEN_VERSION_MAJOR -eq 0 -o $TOKEN_VERSION_MAJOR -eq 1 -a $TOKEN_VERSION_MINOR -lt 5 ] ; then echo "Please install libfido2 1.5.0 or higher (current version: $TOKEN_VERSION)" exit 1 fi set -e TOKEN_OUTPUT=$(${FIDO_TOOLS_PREFIX}fido2-token -L) DEV_PATH_NAMES=$(echo "$TOKEN_OUTPUT" | sed -r 's/^(.*): .*\((.*)\)$/\1 \2/g') DEV_COUNT=$(echo "$DEV_PATH_NAMES" | wc -l) for i in $(seq 1 $DEV_COUNT) do DEV_PATH_NAME=$(echo "$DEV_PATH_NAMES" | sed "${i}q;d") DEV_PATH=$(echo "$DEV_PATH_NAME" | cut -d' ' -f1) DEV_NAME=$(echo "$DEV_PATH_NAME" | cut -d' ' -f1 --complement) DEV_PRETTY=$(echo "$DEV_NAME (at '$DEV_PATH')") if expr match "$(${FIDO_TOOLS_PREFIX}fido2-token -I $DEV_PATH)" ".* credMgmt.* clientPin.*\|.* clientPin.* credMgmt.*" > /dev/null ; then printf "Enter PIN for $DEV_PRETTY once (ignore further prompts): " stty -echo read PIN stty echo printf "\n" RESIDENT_RPS=$(echo "${PIN}\n" | setsid -w ${FIDO_TOOLS_PREFIX}fido2-token -L -r $DEV_PATH | cut -d' ' -f3) printf "\n" RESIDENT_RPS_COUNT=$(echo "$RESIDENT_RPS" | wc -l) FOUND=0 for j in $(seq 1 $DEV_RESIDENT_RPS_COUNT) do RESIDENT_RP=$(echo "$RESIDENT_RPS" | sed "${j}q;d") UNPROT_CREDS=$(echo "${PIN}\n" | setsid -w ${FIDO_TOOLS_PREFIX}fido2-token -L -k $RESIDENT_RP $DEV_PATH | grep ' uvopt$' | cut -d' ' -f2,3,4) printf "\n" UNPROT_CREDS_COUNT=$(echo "$UNPROT_CREDS" | wc -l) if [ $UNPROT_CREDS_COUNT -gt 0 ] ; then FOUND=1 echo "Unprotected credentials on $DEV_PRETTY for '$RESIDENT_RP':" echo "$UNPROT_CREDS" fi done if [ $FOUND -eq 0 ] ; then echo "No unprotected credentials on $DEV_PRETTY" fi else echo "$DEV_PRETTY cannot enumerate credentials" echo "Discovering unprotected SSH credentials only..." STUB_HASH=$(echo -n "" | openssl sha256 -binary | base64) printf "$STUB_HASH\nssh:\n" | ${FIDO_TOOLS_PREFIX}fido2-assert -G -r -t up=false $DEV_PATH 2> /dev/null || ASSERT_EXIT_CODE=$? if [ $ASSERT_EXIT_CODE -eq 0 ] ; then echo "Found an unprotected SSH credential on $DEV_PRETTY!" else echo "No unprotected SSH credentials (default settings) on $DEV_PRETTY" fi fi printf "\n" done diff --git a/contrib/libfido2/tools/include_check.sh b/contrib/libfido2/tools/include_check.sh index e684d0b6f12d..70abada1640d 100755 --- a/contrib/libfido2/tools/include_check.sh +++ b/contrib/libfido2/tools/include_check.sh @@ -1,21 +1,22 @@ #!/bin/sh # Copyright (c) 2019 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. +# SPDX-License-Identifier: BSD-2-Clause check() { for f in $(find $1 -maxdepth 1 -name '*.h'); do echo "#include \"$f\"" | \ cc $CFLAGS -Isrc -xc -c - -o /dev/null 2>&1 echo "$f $CFLAGS $?" done } check examples check fuzz check openbsd-compat CFLAGS="${CFLAGS} -D_FIDO_INTERNAL" check src check src/fido.h check src/fido check tools diff --git a/contrib/libfido2/tools/largeblob.c b/contrib/libfido2/tools/largeblob.c index fc2584ce8bdf..78b97ab1e96b 100644 --- a/contrib/libfido2/tools/largeblob.c +++ b/contrib/libfido2/tools/largeblob.c @@ -1,593 +1,618 @@ /* - * Copyright (c) 2020 Yubico AB. All rights reserved. + * Copyright (c) 2020-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" +#define BOUND (1024UL * 1024UL) + struct rkmap { fido_credman_rp_t *rp; /* known rps */ fido_credman_rk_t **rk; /* rk per rp */ }; static void free_rkmap(struct rkmap *map) { if (map->rp != NULL) { for (size_t i = 0; i < fido_credman_rp_count(map->rp); i++) fido_credman_rk_free(&map->rk[i]); fido_credman_rp_free(&map->rp); } free(map->rk); } static int map_known_rps(fido_dev_t *dev, const char *path, struct rkmap *map) { const char *rp_id; char *pin = NULL; size_t n; int r, ok = -1; if ((map->rp = fido_credman_rp_new()) == NULL) { warnx("%s: fido_credman_rp_new", __func__); goto out; } if ((pin = get_pin(path)) == NULL) goto out; if ((r = fido_credman_get_dev_rp(dev, map->rp, pin)) != FIDO_OK) { warnx("fido_credman_get_dev_rp: %s", fido_strerr(r)); goto out; } if ((n = fido_credman_rp_count(map->rp)) > UINT8_MAX) { warnx("%s: fido_credman_rp_count > UINT8_MAX", __func__); goto out; } if ((map->rk = calloc(n, sizeof(*map->rk))) == NULL) { warnx("%s: calloc", __func__); goto out; } for (size_t i = 0; i < n; i++) { if ((rp_id = fido_credman_rp_id(map->rp, i)) == NULL) { warnx("%s: fido_credman_rp_id %zu", __func__, i); goto out; } if ((map->rk[i] = fido_credman_rk_new()) == NULL) { warnx("%s: fido_credman_rk_new", __func__); goto out; } if ((r = fido_credman_get_dev_rk(dev, rp_id, map->rk[i], pin)) != FIDO_OK) { warnx("%s: fido_credman_get_dev_rk %s: %s", __func__, rp_id, fido_strerr(r)); goto out; } } ok = 0; out: freezero(pin, PINBUF_LEN); return ok; } static int lookup_key(const char *path, fido_dev_t *dev, const char *rp_id, const struct blob *cred_id, char **pin, struct blob *key) { fido_credman_rk_t *rk = NULL; const fido_cred_t *cred = NULL; size_t i, n; int r, ok = -1; if ((rk = fido_credman_rk_new()) == NULL) { warnx("%s: fido_credman_rk_new", __func__); goto out; } if ((r = fido_credman_get_dev_rk(dev, rp_id, rk, *pin)) != FIDO_OK && *pin == NULL && should_retry_with_pin(dev, r)) { if ((*pin = get_pin(path)) == NULL) goto out; r = fido_credman_get_dev_rk(dev, rp_id, rk, *pin); } if (r != FIDO_OK) { warnx("%s: fido_credman_get_dev_rk: %s", __func__, fido_strerr(r)); goto out; } if ((n = fido_credman_rk_count(rk)) == 0) { warnx("%s: rp id not found", __func__); goto out; } if (n == 1 && cred_id->len == 0) { /* use the credential we found */ cred = fido_credman_rk(rk, 0); } else { if (cred_id->len == 0) { warnx("%s: multiple credentials found", __func__); goto out; } for (i = 0; i < n; i++) { const fido_cred_t *x = fido_credman_rk(rk, i); if (fido_cred_id_len(x) <= cred_id->len && !memcmp(fido_cred_id_ptr(x), cred_id->ptr, fido_cred_id_len(x))) { cred = x; break; } } } if (cred == NULL) { warnx("%s: credential not found", __func__); goto out; } if (fido_cred_largeblob_key_ptr(cred) == NULL) { warnx("%s: no associated blob key", __func__); goto out; } key->len = fido_cred_largeblob_key_len(cred); if ((key->ptr = malloc(key->len)) == NULL) { warnx("%s: malloc", __func__); goto out; } memcpy(key->ptr, fido_cred_largeblob_key_ptr(cred), key->len); ok = 0; out: fido_credman_rk_free(&rk); return ok; } static int load_key(const char *keyf, const char *cred_id64, const char *rp_id, const char *path, fido_dev_t *dev, char **pin, struct blob *key) { struct blob cred_id; FILE *fp; int r; memset(&cred_id, 0, sizeof(cred_id)); if (keyf != NULL) { if (rp_id != NULL || cred_id64 != NULL) usage(); fp = open_read(keyf); if ((r = base64_read(fp, key)) < 0) warnx("%s: base64_read %s", __func__, keyf); fclose(fp); return r; } if (rp_id == NULL) usage(); if (cred_id64 != NULL && base64_decode(cred_id64, (void *)&cred_id.ptr, &cred_id.len) < 0) { warnx("%s: base64_decode %s", __func__, cred_id64); return -1; } r = lookup_key(path, dev, rp_id, &cred_id, pin, key); free(cred_id.ptr); return r; } int blob_set(const char *path, const char *keyf, const char *rp_id, const char *cred_id64, const char *blobf) { fido_dev_t *dev; struct blob key, blob; char *pin = NULL; int r, ok = 1; dev = open_dev(path); memset(&key, 0, sizeof(key)); memset(&blob, 0, sizeof(blob)); if (read_file(blobf, &blob.ptr, &blob.len) < 0 || load_key(keyf, cred_id64, rp_id, path, dev, &pin, &key) < 0) goto out; if ((r = fido_dev_largeblob_set(dev, key.ptr, key.len, blob.ptr, blob.len, pin)) != FIDO_OK && should_retry_with_pin(dev, r)) { if ((pin = get_pin(path)) == NULL) goto out; r = fido_dev_largeblob_set(dev, key.ptr, key.len, blob.ptr, blob.len, pin); } if (r != FIDO_OK) { warnx("fido_dev_largeblob_set: %s", fido_strerr(r)); goto out; } ok = 0; /* success */ out: freezero(key.ptr, key.len); freezero(blob.ptr, blob.len); freezero(pin, PINBUF_LEN); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } int blob_get(const char *path, const char *keyf, const char *rp_id, const char *cred_id64, const char *blobf) { fido_dev_t *dev; struct blob key, blob; char *pin = NULL; int r, ok = 1; dev = open_dev(path); memset(&key, 0, sizeof(key)); memset(&blob, 0, sizeof(blob)); if (load_key(keyf, cred_id64, rp_id, path, dev, &pin, &key) < 0) goto out; if ((r = fido_dev_largeblob_get(dev, key.ptr, key.len, &blob.ptr, &blob.len)) != FIDO_OK) { warnx("fido_dev_largeblob_get: %s", fido_strerr(r)); goto out; } if (write_file(blobf, blob.ptr, blob.len) < 0) goto out; ok = 0; /* success */ out: freezero(key.ptr, key.len); freezero(blob.ptr, blob.len); freezero(pin, PINBUF_LEN); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } int blob_delete(const char *path, const char *keyf, const char *rp_id, const char *cred_id64) { fido_dev_t *dev; struct blob key; char *pin = NULL; int r, ok = 1; dev = open_dev(path); memset(&key, 0, sizeof(key)); if (load_key(keyf, cred_id64, rp_id, path, dev, &pin, &key) < 0) goto out; if ((r = fido_dev_largeblob_remove(dev, key.ptr, key.len, pin)) != FIDO_OK && should_retry_with_pin(dev, r)) { if ((pin = get_pin(path)) == NULL) goto out; r = fido_dev_largeblob_remove(dev, key.ptr, key.len, pin); } if (r != FIDO_OK) { warnx("fido_dev_largeblob_remove: %s", fido_strerr(r)); goto out; } ok = 0; /* success */ out: freezero(key.ptr, key.len); freezero(pin, PINBUF_LEN); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } static int -decompress(const struct blob *plaintext, uint64_t origsiz) +try_decompress(const struct blob *in, uint64_t origsiz, int wbits) { - struct blob inflated; - u_long ilen, plen; + struct blob out; + z_stream zs; + u_int ilen, olen; int ok = -1; - memset(&inflated, 0, sizeof(inflated)); + memset(&zs, 0, sizeof(zs)); + memset(&out, 0, sizeof(out)); - if (plaintext->len > ULONG_MAX) + if (in->len > UINT_MAX || (ilen = (u_int)in->len) > BOUND) return -1; - if (origsiz > ULONG_MAX || origsiz > SIZE_MAX) + if (origsiz > SIZE_MAX || origsiz > UINT_MAX || + (olen = (u_int)origsiz) > BOUND) return -1; - plen = (u_long)plaintext->len; - ilen = (u_long)origsiz; - inflated.len = (size_t)origsiz; - if ((inflated.ptr = calloc(1, inflated.len)) == NULL) + if (inflateInit2(&zs, wbits) != Z_OK) return -1; - if (uncompress(inflated.ptr, &ilen, plaintext->ptr, plen) != Z_OK || - ilen > SIZE_MAX || (size_t)ilen != (size_t)origsiz) - goto out; - ok = 0; /* success */ -out: - freezero(inflated.ptr, inflated.len); + if ((out.ptr = calloc(1, olen)) == NULL) + goto fail; + + out.len = olen; + zs.next_in = in->ptr; + zs.avail_in = ilen; + zs.next_out = out.ptr; + zs.avail_out = olen; + + if (inflate(&zs, Z_FINISH) != Z_STREAM_END) + goto fail; + if (zs.avail_out != 0) + goto fail; + + ok = 0; +fail: + if (inflateEnd(&zs) != Z_OK) + ok = -1; + + freezero(out.ptr, out.len); return ok; } +static int +decompress(const struct blob *plaintext, uint64_t origsiz) +{ + if (try_decompress(plaintext, origsiz, MAX_WBITS) == 0) /* rfc1950 */ + return 0; + return try_decompress(plaintext, origsiz, -MAX_WBITS); /* rfc1951 */ +} + static int decode(const struct blob *ciphertext, const struct blob *nonce, uint64_t origsiz, const fido_cred_t *cred) { uint8_t aad[4 + sizeof(uint64_t)]; EVP_CIPHER_CTX *ctx = NULL; const EVP_CIPHER *cipher; struct blob plaintext; uint64_t tmp; int ok = -1; memset(&plaintext, 0, sizeof(plaintext)); if (nonce->len != 12) return -1; if (cred == NULL || fido_cred_largeblob_key_ptr(cred) == NULL || fido_cred_largeblob_key_len(cred) != 32) return -1; if (ciphertext->len > UINT_MAX || ciphertext->len > SIZE_MAX - 16 || ciphertext->len < 16) return -1; plaintext.len = ciphertext->len - 16; if ((plaintext.ptr = calloc(1, plaintext.len)) == NULL) return -1; if ((ctx = EVP_CIPHER_CTX_new()) == NULL || (cipher = EVP_aes_256_gcm()) == NULL || EVP_CipherInit(ctx, cipher, fido_cred_largeblob_key_ptr(cred), nonce->ptr, 0) == 0) goto out; if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, ciphertext->ptr + ciphertext->len - 16) == 0) goto out; aad[0] = 0x62; /* b */ aad[1] = 0x6c; /* l */ aad[2] = 0x6f; /* o */ aad[3] = 0x62; /* b */ tmp = htole64(origsiz); memcpy(&aad[4], &tmp, sizeof(uint64_t)); if (EVP_Cipher(ctx, NULL, aad, (u_int)sizeof(aad)) < 0 || EVP_Cipher(ctx, plaintext.ptr, ciphertext->ptr, (u_int)plaintext.len) < 0 || EVP_Cipher(ctx, NULL, NULL, 0) < 0) goto out; if (decompress(&plaintext, origsiz) < 0) goto out; ok = 0; out: freezero(plaintext.ptr, plaintext.len); if (ctx != NULL) EVP_CIPHER_CTX_free(ctx); return ok; } static const fido_cred_t * try_rp(const fido_credman_rk_t *rk, const struct blob *ciphertext, const struct blob *nonce, uint64_t origsiz) { const fido_cred_t *cred; for (size_t i = 0; i < fido_credman_rk_count(rk); i++) if ((cred = fido_credman_rk(rk, i)) != NULL && decode(ciphertext, nonce, origsiz, cred) == 0) return cred; return NULL; } static int decode_cbor_blob(struct blob *out, const cbor_item_t *item) { if (out->ptr != NULL || cbor_isa_bytestring(item) == false || cbor_bytestring_is_definite(item) == false) return -1; out->len = cbor_bytestring_length(item); if ((out->ptr = malloc(out->len)) == NULL) return -1; memcpy(out->ptr, cbor_bytestring_handle(item), out->len); return 0; } static int decode_blob_entry(const cbor_item_t *item, struct blob *ciphertext, struct blob *nonce, uint64_t *origsiz) { struct cbor_pair *v; if (item == NULL) return -1; if (cbor_isa_map(item) == false || cbor_map_is_definite(item) == false || (v = cbor_map_handle(item)) == NULL) return -1; if (cbor_map_size(item) > UINT8_MAX) return -1; for (size_t i = 0; i < cbor_map_size(item); i++) { if (cbor_isa_uint(v[i].key) == false || cbor_int_get_width(v[i].key) != CBOR_INT_8) continue; /* ignore */ switch (cbor_get_uint8(v[i].key)) { case 1: /* ciphertext */ if (decode_cbor_blob(ciphertext, v[i].value) < 0) return -1; break; case 2: /* nonce */ if (decode_cbor_blob(nonce, v[i].value) < 0) return -1; break; case 3: /* origSize */ if (*origsiz != 0 || cbor_isa_uint(v[i].value) == false || (*origsiz = cbor_get_int(v[i].value)) > SIZE_MAX) return -1; } } if (ciphertext->ptr == NULL || nonce->ptr == NULL || *origsiz == 0) return -1; return 0; } static void print_blob_entry(size_t idx, const cbor_item_t *item, const struct rkmap *map) { struct blob ciphertext, nonce; const fido_cred_t *cred = NULL; const char *rp_id = NULL; char *cred_id = NULL; uint64_t origsiz = 0; memset(&ciphertext, 0, sizeof(ciphertext)); memset(&nonce, 0, sizeof(nonce)); if (decode_blob_entry(item, &ciphertext, &nonce, &origsiz) < 0) { printf("%02zu: \n", idx); goto out; } for (size_t i = 0; i < fido_credman_rp_count(map->rp); i++) { if ((cred = try_rp(map->rk[i], &ciphertext, &nonce, origsiz)) != NULL) { rp_id = fido_credman_rp_id(map->rp, i); break; } } if (cred == NULL) { if ((cred_id = strdup("")) == NULL) { printf("%02zu: \n", idx); goto out; } } else { if (base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &cred_id) < 0) { printf("%02zu: \n", idx); goto out; } } if (rp_id == NULL) rp_id = ""; printf("%02zu: %4zu %4zu %s %s\n", idx, ciphertext.len, (size_t)origsiz, cred_id, rp_id); out: free(ciphertext.ptr); free(nonce.ptr); free(cred_id); } static cbor_item_t * get_cbor_array(fido_dev_t *dev) { struct cbor_load_result cbor_result; cbor_item_t *item = NULL; u_char *cbor_ptr = NULL; size_t cbor_len; int r, ok = -1; if ((r = fido_dev_largeblob_get_array(dev, &cbor_ptr, &cbor_len)) != FIDO_OK) { warnx("%s: fido_dev_largeblob_get_array: %s", __func__, fido_strerr(r)); goto out; } if ((item = cbor_load(cbor_ptr, cbor_len, &cbor_result)) == NULL) { warnx("%s: cbor_load", __func__); goto out; } if (cbor_result.read != cbor_len) { warnx("%s: cbor_result.read (%zu) != cbor_len (%zu)", __func__, cbor_result.read, cbor_len); /* continue */ } if (cbor_isa_array(item) == false || cbor_array_is_definite(item) == false) { warnx("%s: cbor type", __func__); goto out; } if (cbor_array_size(item) > UINT8_MAX) { warnx("%s: cbor_array_size > UINT8_MAX", __func__); goto out; } if (cbor_array_size(item) == 0) { ok = 0; /* nothing to do */ goto out; } printf("total map size: %zu byte%s\n", cbor_len, plural(cbor_len)); ok = 0; out: if (ok < 0 && item != NULL) { cbor_decref(&item); item = NULL; } free(cbor_ptr); return item; } int blob_list(const char *path) { struct rkmap map; fido_dev_t *dev = NULL; cbor_item_t *item = NULL, **v; int ok = 1; memset(&map, 0, sizeof(map)); dev = open_dev(path); if (map_known_rps(dev, path, &map) < 0 || (item = get_cbor_array(dev)) == NULL) goto out; if (cbor_array_size(item) == 0) { ok = 0; /* nothing to do */ goto out; } if ((v = cbor_array_handle(item)) == NULL) { warnx("%s: cbor_array_handle", __func__); goto out; } for (size_t i = 0; i < cbor_array_size(item); i++) print_blob_entry(i, v[i], &map); ok = 0; /* success */ out: free_rkmap(&map); if (item != NULL) cbor_decref(&item); fido_dev_close(dev); fido_dev_free(&dev); exit(ok); } diff --git a/contrib/libfido2/tools/pin.c b/contrib/libfido2/tools/pin.c index f342347d1ff5..8b2697ed8e1e 100644 --- a/contrib/libfido2/tools/pin.c +++ b/contrib/libfido2/tools/pin.c @@ -1,143 +1,159 @@ /* * 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" int pin_set(char *path) { fido_dev_t *dev = NULL; char prompt[1024]; - char pin1[1024]; - char pin2[1024]; + char pin1[128]; + char pin2[128]; int r; int status = 1; dev = open_dev(path); r = snprintf(prompt, sizeof(prompt), "Enter new PIN for %s: ", path); if (r < 0 || (size_t)r >= sizeof(prompt)) { warnx("snprintf"); goto out; } if (!readpassphrase(prompt, pin1, sizeof(pin1), RPP_ECHO_OFF)) { warnx("readpassphrase"); goto out; } r = snprintf(prompt, sizeof(prompt), "Enter the same PIN again: "); if (r < 0 || (size_t)r >= sizeof(prompt)) { warnx("snprintf"); goto out; } if (!readpassphrase(prompt, pin2, sizeof(pin2), RPP_ECHO_OFF)) { warnx("readpassphrase"); goto out; } if (strcmp(pin1, pin2) != 0) { fprintf(stderr, "PINs do not match. Try again.\n"); goto out; } + if (strlen(pin1) < 4 || strlen(pin1) > 63) { + fprintf(stderr, "invalid PIN length\n"); + goto out; + } + if ((r = fido_dev_set_pin(dev, pin1, NULL)) != FIDO_OK) { warnx("fido_dev_set_pin: %s", fido_strerr(r)); goto out; } fido_dev_close(dev); fido_dev_free(&dev); status = 0; out: explicit_bzero(pin1, sizeof(pin1)); explicit_bzero(pin2, sizeof(pin2)); exit(status); } int pin_change(char *path) { fido_dev_t *dev = NULL; char prompt[1024]; - char pin0[1024]; - char pin1[1024]; - char pin2[1024]; + char pin0[128]; + char pin1[128]; + char pin2[128]; int r; int status = 1; if (path == NULL) usage(); dev = open_dev(path); r = snprintf(prompt, sizeof(prompt), "Enter current PIN for %s: ", path); if (r < 0 || (size_t)r >= sizeof(prompt)) { warnx("snprintf"); goto out; } if (!readpassphrase(prompt, pin0, sizeof(pin0), RPP_ECHO_OFF)) { warnx("readpassphrase"); goto out; } + if (strlen(pin0) < 4 || strlen(pin0) > 63) { + warnx("invalid PIN length"); + goto out; + } + r = snprintf(prompt, sizeof(prompt), "Enter new PIN for %s: ", path); if (r < 0 || (size_t)r >= sizeof(prompt)) { warnx("snprintf"); goto out; } if (!readpassphrase(prompt, pin1, sizeof(pin1), RPP_ECHO_OFF)) { warnx("readpassphrase"); goto out; } r = snprintf(prompt, sizeof(prompt), "Enter the same PIN again: "); if (r < 0 || (size_t)r >= sizeof(prompt)) { warnx("snprintf"); goto out; } if (!readpassphrase(prompt, pin2, sizeof(pin2), RPP_ECHO_OFF)) { warnx("readpassphrase"); goto out; } if (strcmp(pin1, pin2) != 0) { fprintf(stderr, "PINs do not match. Try again.\n"); goto out; } + if (strlen(pin1) < 4 || strlen(pin1) > 63) { + fprintf(stderr, "invalid PIN length\n"); + goto out; + } + if ((r = fido_dev_set_pin(dev, pin1, pin0)) != FIDO_OK) { warnx("fido_dev_set_pin: %s", fido_strerr(r)); goto out; } fido_dev_close(dev); fido_dev_free(&dev); status = 0; out: explicit_bzero(pin0, sizeof(pin0)); explicit_bzero(pin1, sizeof(pin1)); explicit_bzero(pin2, sizeof(pin2)); exit(status); } diff --git a/contrib/libfido2/tools/test.sh b/contrib/libfido2/tools/test.sh index 02d82d5a18cd..67b757e80a8d 100755 --- a/contrib/libfido2/tools/test.sh +++ b/contrib/libfido2/tools/test.sh @@ -1,296 +1,304 @@ #!/bin/sh -ex -# Copyright (c) 2021 Yubico AB. All rights reserved. +# Copyright (c) 2021-2022 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. +# SPDX-License-Identifier: BSD-2-Clause # usage: ./test.sh "$(mktemp -d fido2test-XXXXXXXX)" device # Please note that this test script: # - is incomplete; # - assumes CTAP 2.1-like hmac-secret; # - should pass as-is on a YubiKey with a PIN set; # - may otherwise require set +e above; # - can be executed with UV=1 to run additional UV tests; # - was last tested on 2022-01-11 with firmware 5.4.3. cd "$1" DEV="$2" +TYPE="es256" +#TYPE="es384" +#TYPE="eddsa" make_cred() { sed /^$/d > cred_param << EOF $(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64) $1 some user name $(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64) EOF - fido2-cred -M $2 "${DEV}" > "$3" < cred_param + fido2-cred -M $2 "${DEV}" "${TYPE}" > "$3" < cred_param } verify_cred() { - fido2-cred -V $1 > cred_out < "$2" + fido2-cred -V $1 "${TYPE}" > cred_out < "$2" head -1 cred_out > "$3" tail -n +2 cred_out > "$4" } get_assert() { sed /^$/d > assert_param << EOF $(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64) $1 $(cat $3) $(cat $4) EOF fido2-assert -G $2 "${DEV}" > "$5" < assert_param } verify_assert() { - fido2-assert -V $1 "$2" < "$3" + fido2-assert -V $1 "$2" "${TYPE}" < "$3" } dd if=/dev/urandom bs=32 count=1 | base64 > hmac-salt # u2f -make_cred no.tld "-u" u2f -! make_cred no.tld "-ru" /dev/null -! make_cred no.tld "-uc1" /dev/null -! make_cred no.tld "-uc2" /dev/null -verify_cred "--" u2f u2f-cred u2f-pubkey -! verify_cred "-h" u2f /dev/null /dev/null -! verify_cred "-v" u2f /dev/null /dev/null -verify_cred "-c0" u2f /dev/null /dev/null -! verify_cred "-c1" u2f /dev/null /dev/null -! verify_cred "-c2" u2f /dev/null /dev/null -! verify_cred "-c3" u2f /dev/null /dev/null +if [ "x${TYPE}" = "xes256" ]; then + make_cred no.tld "-u" u2f + ! make_cred no.tld "-ru" /dev/null + ! make_cred no.tld "-uc1" /dev/null + ! make_cred no.tld "-uc2" /dev/null + verify_cred "--" u2f u2f-cred u2f-pubkey + ! verify_cred "-h" u2f /dev/null /dev/null + ! verify_cred "-v" u2f /dev/null /dev/null + verify_cred "-c0" u2f /dev/null /dev/null + ! verify_cred "-c1" u2f /dev/null /dev/null + ! verify_cred "-c2" u2f /dev/null /dev/null + ! verify_cred "-c3" u2f /dev/null /dev/null +fi # wrap (non-resident) make_cred no.tld "--" wrap verify_cred "--" wrap wrap-cred wrap-pubkey ! verify_cred "-h" wrap /dev/null /dev/null ! verify_cred "-v" wrap /dev/null /dev/null verify_cred "-c0" wrap /dev/null /dev/null ! verify_cred "-c1" wrap /dev/null /dev/null ! verify_cred "-c2" wrap /dev/null /dev/null ! verify_cred "-c3" wrap /dev/null /dev/null # wrap (non-resident) + hmac-secret make_cred no.tld "-h" wrap-hs ! verify_cred "--" wrap-hs /dev/null /dev/null verify_cred "-h" wrap-hs wrap-hs-cred wrap-hs-pubkey ! verify_cred "-v" wrap-hs /dev/null /dev/null verify_cred "-hc0" wrap-hs /dev/null /dev/null ! verify_cred "-c0" wrap-hs /dev/null /dev/null ! verify_cred "-c1" wrap-hs /dev/null /dev/null ! verify_cred "-c2" wrap-hs /dev/null /dev/null ! verify_cred "-c3" wrap-hs /dev/null /dev/null # resident make_cred no.tld "-r" rk verify_cred "--" rk rk-cred rk-pubkey ! verify_cred "-h" rk /dev/null /dev/null ! verify_cred "-v" rk /dev/null /dev/null verify_cred "-c0" rk /dev/null /dev/null ! verify_cred "-c1" rk /dev/null /dev/null ! verify_cred "-c2" rk /dev/null /dev/null ! verify_cred "-c3" rk /dev/null /dev/null # resident + hmac-secret make_cred no.tld "-hr" rk-hs ! verify_cred "--" rk-hs rk-hs-cred rk-hs-pubkey verify_cred "-h" rk-hs /dev/null /dev/null ! verify_cred "-v" rk-hs /dev/null /dev/null verify_cred "-hc0" rk-hs /dev/null /dev/null ! verify_cred "-c0" rk-hs /dev/null /dev/null ! verify_cred "-c1" rk-hs /dev/null /dev/null ! verify_cred "-c2" rk-hs /dev/null /dev/null ! verify_cred "-c3" rk-hs /dev/null /dev/null # u2f -get_assert no.tld "-u" u2f-cred /dev/null u2f-assert -! get_assert no.tld "-u -t up=false" u2f-cred /dev/null /dev/null -verify_assert "--" u2f-pubkey u2f-assert -verify_assert "-p" u2f-pubkey u2f-assert +if [ "x${TYPE}" = "xes256" ]; then + get_assert no.tld "-u" u2f-cred /dev/null u2f-assert + ! get_assert no.tld "-u -t up=false" u2f-cred /dev/null /dev/null + verify_assert "--" u2f-pubkey u2f-assert + verify_assert "-p" u2f-pubkey u2f-assert +fi # wrap (non-resident) get_assert no.tld "--" wrap-cred /dev/null wrap-assert verify_assert "--" wrap-pubkey wrap-assert get_assert no.tld "-t pin=true" wrap-cred /dev/null wrap-assert verify_assert "--" wrap-pubkey wrap-assert verify_assert "-v" wrap-pubkey wrap-assert get_assert no.tld "-t pin=false" wrap-cred /dev/null wrap-assert verify_assert "--" wrap-pubkey wrap-assert get_assert no.tld "-t up=true" wrap-cred /dev/null wrap-assert verify_assert "-p" wrap-pubkey wrap-assert get_assert no.tld "-t up=true -t pin=true" wrap-cred /dev/null wrap-assert verify_assert "--" wrap-pubkey wrap-assert verify_assert "-p" wrap-pubkey wrap-assert verify_assert "-v" wrap-pubkey wrap-assert verify_assert "-pv" wrap-pubkey wrap-assert get_assert no.tld "-t up=true -t pin=false" wrap-cred /dev/null wrap-assert verify_assert "--" wrap-pubkey wrap-assert verify_assert "-p" wrap-pubkey wrap-assert get_assert no.tld "-t up=false" wrap-cred /dev/null wrap-assert verify_assert "--" wrap-pubkey wrap-assert ! verify_assert "-p" wrap-pubkey wrap-assert get_assert no.tld "-t up=false -t pin=true" wrap-cred /dev/null wrap-assert ! verify_assert "-p" wrap-pubkey wrap-assert verify_assert "-v" wrap-pubkey wrap-assert ! verify_assert "-pv" wrap-pubkey wrap-assert get_assert no.tld "-t up=false -t pin=false" wrap-cred /dev/null wrap-assert ! verify_assert "-p" wrap-pubkey wrap-assert get_assert no.tld "-h" wrap-cred hmac-salt wrap-assert ! verify_assert "--" wrap-pubkey wrap-assert verify_assert "-h" wrap-pubkey wrap-assert get_assert no.tld "-h -t pin=true" wrap-cred hmac-salt wrap-assert ! verify_assert "--" wrap-pubkey wrap-assert verify_assert "-h" wrap-pubkey wrap-assert verify_assert "-hv" wrap-pubkey wrap-assert get_assert no.tld "-h -t pin=false" wrap-cred hmac-salt wrap-assert ! verify_assert "--" wrap-pubkey wrap-assert verify_assert "-h" wrap-pubkey wrap-assert get_assert no.tld "-h -t up=true" wrap-cred hmac-salt wrap-assert ! verify_assert "--" wrap-pubkey wrap-assert verify_assert "-h" wrap-pubkey wrap-assert verify_assert "-hp" wrap-pubkey wrap-assert get_assert no.tld "-h -t up=true -t pin=true" wrap-cred hmac-salt wrap-assert ! verify_assert "--" wrap-pubkey wrap-assert verify_assert "-h" wrap-pubkey wrap-assert verify_assert "-hp" wrap-pubkey wrap-assert verify_assert "-hv" wrap-pubkey wrap-assert verify_assert "-hpv" wrap-pubkey wrap-assert get_assert no.tld "-h -t up=true -t pin=false" wrap-cred hmac-salt wrap-assert ! verify_assert "--" wrap-pubkey wrap-assert verify_assert "-h" wrap-pubkey wrap-assert verify_assert "-hp" wrap-pubkey wrap-assert ! get_assert no.tld "-h -t up=false" wrap-cred hmac-salt wrap-assert ! get_assert no.tld "-h -t up=false -t pin=true" wrap-cred hmac-salt wrap-assert ! get_assert no.tld "-h -t up=false -t pin=false" wrap-cred hmac-salt wrap-assert if [ "x${UV}" != "x" ]; then get_assert no.tld "-t uv=true" wrap-cred /dev/null wrap-assert verify_assert "-v" wrap-pubkey wrap-assert get_assert no.tld "-t uv=true -t pin=true" wrap-cred /dev/null wrap-assert verify_assert "-v" wrap-pubkey wrap-assert get_assert no.tld "-t uv=true -t pin=false" wrap-cred /dev/null wrap-assert verify_assert "-v" wrap-pubkey wrap-assert get_assert no.tld "-t uv=false" wrap-cred /dev/null wrap-assert verify_assert "--" wrap-pubkey wrap-assert get_assert no.tld "-t uv=false -t pin=true" wrap-cred /dev/null wrap-assert verify_assert "-v" wrap-pubkey wrap-assert get_assert no.tld "-t uv=false -t pin=false" wrap-cred /dev/null wrap-assert verify_assert "--" wrap-pubkey wrap-assert get_assert no.tld "-t up=true -t uv=true" wrap-cred /dev/null wrap-assert verify_assert "-pv" wrap-pubkey wrap-assert get_assert no.tld "-t up=true -t uv=true -t pin=true" wrap-cred /dev/null wrap-assert verify_assert "-pv" wrap-pubkey wrap-assert get_assert no.tld "-t up=true -t uv=true -t pin=false" wrap-cred /dev/null wrap-assert verify_assert "-pv" wrap-pubkey wrap-assert get_assert no.tld "-t up=true -t uv=false" wrap-cred /dev/null wrap-assert verify_assert "-p" wrap-pubkey wrap-assert get_assert no.tld "-t up=true -t uv=false -t pin=true" wrap-cred /dev/null wrap-assert verify_assert "-pv" wrap-pubkey wrap-assert get_assert no.tld "-t up=true -t uv=false -t pin=false" wrap-cred /dev/null wrap-assert verify_assert "-p" wrap-pubkey wrap-assert get_assert no.tld "-t up=false -t uv=true" wrap-cred /dev/null wrap-assert verify_assert "-v" wrap-pubkey wrap-assert get_assert no.tld "-t up=false -t uv=true -t pin=true" wrap-cred /dev/null wrap-assert verify_assert "-v" wrap-pubkey wrap-assert get_assert no.tld "-t up=false -t uv=true -t pin=false" wrap-cred /dev/null wrap-assert verify_assert "-v" wrap-pubkey wrap-assert get_assert no.tld "-t up=false -t uv=false" wrap-cred /dev/null wrap-assert ! verify_assert "--" wrap-pubkey wrap-assert get_assert no.tld "-t up=false -t uv=false -t pin=true" wrap-cred /dev/null wrap-assert verify_assert "-v" wrap-pubkey wrap-assert get_assert no.tld "-t up=false -t uv=false -t pin=false" wrap-cred /dev/null wrap-assert ! verify_assert "--" wrap-pubkey wrap-assert get_assert no.tld "-h -t uv=true" wrap-cred hmac-salt wrap-assert verify_assert "-hv" wrap-pubkey wrap-assert get_assert no.tld "-h -t uv=true -t pin=true" wrap-cred hmac-salt wrap-assert verify_assert "-hv" wrap-pubkey wrap-assert get_assert no.tld "-h -t uv=true -t pin=false" wrap-cred hmac-salt wrap-assert verify_assert "-hv" wrap-pubkey wrap-assert get_assert no.tld "-h -t uv=false" wrap-cred hmac-salt wrap-assert verify_assert "-h" wrap-pubkey wrap-assert get_assert no.tld "-h -t uv=false -t pin=true" wrap-cred hmac-salt wrap-assert verify_assert "-hv" wrap-pubkey wrap-assert get_assert no.tld "-h -t uv=false -t pin=false" wrap-cred hmac-salt wrap-assert verify_assert "-h" wrap-pubkey wrap-assert get_assert no.tld "-h -t up=true -t uv=true" wrap-cred hmac-salt wrap-assert verify_assert "-hpv" wrap-pubkey wrap-assert get_assert no.tld "-h -t up=true -t uv=true -t pin=true" wrap-cred hmac-salt wrap-assert verify_assert "-hpv" wrap-pubkey wrap-assert get_assert no.tld "-h -t up=true -t uv=true -t pin=false" wrap-cred hmac-salt wrap-assert verify_assert "-hpv" wrap-pubkey wrap-assert get_assert no.tld "-h -t up=true -t uv=false" wrap-cred hmac-salt wrap-assert verify_assert "-hp" wrap-pubkey wrap-assert get_assert no.tld "-h -t up=true -t uv=false -t pin=true" wrap-cred hmac-salt wrap-assert verify_assert "-hpv" wrap-pubkey wrap-assert get_assert no.tld "-h -t up=true -t uv=false -t pin=false" wrap-cred hmac-salt wrap-assert verify_assert "-hp" wrap-pubkey wrap-assert ! get_assert no.tld "-h -t up=false -t uv=true" wrap-cred hmac-salt wrap-assert ! get_assert no.tld "-h -t up=false -t uv=true -t pin=true" wrap-cred hmac-salt wrap-assert ! get_assert no.tld "-h -t up=false -t uv=true -t pin=false" wrap-cred hmac-salt wrap-assert ! get_assert no.tld "-h -t up=false -t uv=false" wrap-cred hmac-salt wrap-assert ! get_assert no.tld "-h -t up=false -t uv=false -t pin=true" wrap-cred hmac-salt wrap-assert ! get_assert no.tld "-h -t up=false -t uv=false -t pin=false" wrap-cred hmac-salt wrap-assert fi # resident get_assert no.tld "-r" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t pin=true" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t pin=false" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=true" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=true -t pin=true" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=true -t pin=false" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=false" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=false -t pin=true" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=false -t pin=false" /dev/null /dev/null wrap-assert get_assert no.tld "-r -h" /dev/null hmac-salt wrap-assert get_assert no.tld "-r -h -t pin=true" /dev/null hmac-salt wrap-assert get_assert no.tld "-r -h -t pin=false" /dev/null hmac-salt wrap-assert get_assert no.tld "-r -h -t up=true" /dev/null hmac-salt wrap-assert get_assert no.tld "-r -h -t up=true -t pin=true" /dev/null hmac-salt wrap-assert get_assert no.tld "-r -h -t up=true -t pin=false" /dev/null hmac-salt wrap-assert ! get_assert no.tld "-r -h -t up=false" /dev/null hmac-salt wrap-assert ! get_assert no.tld "-r -h -t up=false -t pin=true" /dev/null hmac-salt wrap-assert ! get_assert no.tld "-r -h -t up=false -t pin=false" /dev/null hmac-salt wrap-assert if [ "x${UV}" != "x" ]; then get_assert no.tld "-r -t uv=true" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t uv=true -t pin=true" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t uv=true -t pin=false" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t uv=false" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t uv=false -t pin=true" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t uv=false -t pin=false" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=true -t uv=true" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=true -t uv=true -t pin=true" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=true -t uv=true -t pin=false" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=true -t uv=false" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=true -t uv=false -t pin=true" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=true -t uv=false -t pin=false" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=false -t uv=true" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=false -t uv=true -t pin=true" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=false -t uv=true -t pin=false" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=false -t uv=false" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=false -t uv=false -t pin=true" /dev/null /dev/null wrap-assert get_assert no.tld "-r -t up=false -t uv=false -t pin=false" /dev/null /dev/null wrap-assert get_assert no.tld "-r -h -t uv=true" /dev/null hmac-salt wrap-assert get_assert no.tld "-r -h -t uv=true -t pin=true" /dev/null hmac-salt wrap-assert get_assert no.tld "-r -h -t uv=true -t pin=false" /dev/null hmac-salt wrap-assert get_assert no.tld "-r -h -t uv=false" /dev/null hmac-salt wrap-assert get_assert no.tld "-r -h -t uv=false -t pin=true" /dev/null hmac-salt wrap-assert get_assert no.tld "-r -h -t uv=false -t pin=false" /dev/null hmac-salt wrap-assert get_assert no.tld "-r -h -t up=true -t uv=true" /dev/null hmac-salt wrap-assert get_assert no.tld "-r -h -t up=true -t uv=true -t pin=true" /dev/null hmac-salt wrap-assert get_assert no.tld "-r -h -t up=true -t uv=true -t pin=false" /dev/null hmac-salt wrap-assert get_assert no.tld "-r -h -t up=true -t uv=false" /dev/null hmac-salt wrap-assert get_assert no.tld "-r -h -t up=true -t uv=false -t pin=true" /dev/null hmac-salt wrap-assert get_assert no.tld "-r -h -t up=true -t uv=false -t pin=false" /dev/null hmac-salt wrap-assert ! get_assert no.tld "-r -h -t up=false -t uv=true" /dev/null hmac-salt wrap-assert ! get_assert no.tld "-r -h -t up=false -t uv=true -t pin=true" /dev/null hmac-salt wrap-assert ! get_assert no.tld "-r -h -t up=false -t uv=true -t pin=false" /dev/null hmac-salt wrap-assert ! get_assert no.tld "-r -h -t up=false -t uv=false" /dev/null hmac-salt wrap-assert ! get_assert no.tld "-r -h -t up=false -t uv=false -t pin=true" /dev/null hmac-salt wrap-assert ! get_assert no.tld "-r -h -t up=false -t uv=false -t pin=false" /dev/null hmac-salt wrap-assert fi exit 0 diff --git a/contrib/libfido2/tools/token.c b/contrib/libfido2/tools/token.c index 3d165623fdbf..366d5a15ab04 100644 --- a/contrib/libfido2/tools/token.c +++ b/contrib/libfido2/tools/token.c @@ -1,582 +1,729 @@ /* - * Copyright (c) 2018 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #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_cert_array(const char *label, char * const *name, const uint64_t *value, + size_t len) +{ + if (len == 0) + return; + + printf("%s: ", label); + + for (size_t i = 0; i < len; i++) + printf("%s%s %llu", i > 0 ? ", " : "", name[i], + (unsigned long long)value[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_ES384: + cose = "es384"; + break; case COSE_RS256: cose = "rs256"; break; + case COSE_EDDSA: + cose = "eddsa"; + 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_maxlargeblob(uint64_t maxlargeblob) +{ + printf("maxlargeblob: %d\n", (int)maxlargeblob); +} + +static void +print_maxrpid_minpinlen(uint64_t maxrpid) +{ + if (maxrpid > 0) + printf("maxrpids in minpinlen: %d\n", (int)maxrpid); +} + +static void +print_minpinlen(uint64_t minpinlen) +{ + if (minpinlen > 0) + printf("minpinlen: %d\n", (int)minpinlen); +} + +static void +print_uv_attempts(uint64_t uv_attempts) +{ + if (uv_attempts > 0) + printf("platform uv attempt(s): %d\n", (int)uv_attempts); +} + +static void +print_uv_modality(uint64_t uv_modality) +{ + uint64_t mode; + bool printed = false; + + if (uv_modality == 0) + return; + + printf("uv modality: 0x%x (", (int)uv_modality); + + for (size_t i = 0; i < 64; i++) { + mode = 1ULL << i; + if ((uv_modality & mode) == 0) + continue; + if (printed) + printf(", "); + switch (mode) { + case FIDO_UV_MODE_TUP: + printf("test of user presence"); + break; + case FIDO_UV_MODE_FP: + printf("fingerprint check"); + break; + case FIDO_UV_MODE_PIN: + printf("pin check"); + break; + case FIDO_UV_MODE_VOICE: + printf("voice recognition"); + break; + case FIDO_UV_MODE_FACE: + printf("face recognition"); + break; + case FIDO_UV_MODE_LOCATION: + printf("location check"); + break; + case FIDO_UV_MODE_EYE: + printf("eyeprint check"); + break; + case FIDO_UV_MODE_DRAWN: + printf("drawn pattern check"); + break; + case FIDO_UV_MODE_HAND: + printf("handprint verification"); + break; + case FIDO_UV_MODE_NONE: + printf("none"); + break; + case FIDO_UV_MODE_ALL: + printf("all required"); + break; + case FIDO_UV_MODE_EXT_PIN: + printf("external pin"); + break; + case FIDO_UV_MODE_EXT_DRAWN: + printf("external drawn pattern check"); + break; + default: + printf("unknown 0x%llx", (unsigned long long)mode); + break; + } + printed = true; + } + + printf(")\n"); +} + +static void +print_rk_remaining(int64_t rk_remaining) +{ + if (rk_remaining != -1) + printf("remaining rk(s): %d\n", (int)rk_remaining); +} + 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 certifications */ + print_cert_array("certifications", fido_cbor_info_certs_name_ptr(ci), + fido_cbor_info_certs_value_ptr(ci), + fido_cbor_info_certs_len(ci)); + + /* print firmware version */ + print_fwversion(fido_cbor_info_fwversion(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 maximum length of serialized largeBlob array */ + print_maxlargeblob(fido_cbor_info_maxlargeblob(ci)); + + /* print maximum number of RP IDs in fido_dev_set_pin_minlen_rpid() */ + print_maxrpid_minpinlen(fido_cbor_info_maxrpid_minpinlen(ci)); + + /* print estimated number of resident credentials */ + print_rk_remaining(fido_cbor_info_rk_remaining(ci)); + + /* print minimum pin length */ + print_minpinlen(fido_cbor_info_minpinlen(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); + printf("pin change required: %s\n", + fido_cbor_info_new_pin_required(ci) ? "true" : "false"); + if (fido_dev_get_uv_retry_count(dev, &retrycnt) != FIDO_OK) printf("uv retries: undefined\n"); else printf("uv retries: %d\n", retrycnt); + /* print platform uv attempts */ + print_uv_attempts(fido_cbor_info_uv_attempts(ci)); + + /* print supported uv mechanisms */ + print_uv_modality(fido_cbor_info_uv_modality(ci)); + 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/tools/util.c b/contrib/libfido2/tools/util.c index 612d81b2000c..0e518bbc5ce2 100644 --- a/contrib/libfido2/tools/util.c +++ b/contrib/libfido2/tools/util.c @@ -1,591 +1,643 @@ /* - * Copyright (c) 2018-2021 Yubico AB. All rights reserved. + * Copyright (c) 2018-2022 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. + * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include "../openbsd-compat/openbsd-compat.h" #ifdef _MSC_VER #include "../openbsd-compat/posix_win.h" #endif #include "extern.h" char * get_pin(const char *path) { char *pin; char prompt[1024]; int r, ok = -1; if ((pin = calloc(1, PINBUF_LEN)) == NULL) { warn("%s: calloc", __func__); return NULL; } if ((r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", path)) < 0 || (size_t)r >= sizeof(prompt)) { warn("%s: snprintf", __func__); goto out; } if (!readpassphrase(prompt, pin, PINBUF_LEN, RPP_ECHO_OFF)) { warnx("%s: readpassphrase", __func__); goto out; } ok = 0; out: if (ok < 0) { freezero(pin, PINBUF_LEN); pin = NULL; } return pin; } FILE * open_write(const char *file) { int fd; FILE *f; if (file == NULL || strcmp(file, "-") == 0) return (stdout); if ((fd = open(file, O_WRONLY | O_CREAT, 0600)) < 0) err(1, "open %s", file); if ((f = fdopen(fd, "w")) == NULL) err(1, "fdopen %s", file); return (f); } FILE * open_read(const char *file) { int fd; FILE *f; if (file == NULL || strcmp(file, "-") == 0) { #ifdef FIDO_FUZZ setvbuf(stdin, NULL, _IONBF, 0); #endif return (stdin); } if ((fd = open(file, O_RDONLY)) < 0) err(1, "open %s", file); if ((f = fdopen(fd, "r")) == NULL) err(1, "fdopen %s", file); return (f); } int base10(const char *str) { char *ep; long long ll; ll = strtoll(str, &ep, 10); if (str == ep || *ep != '\0') return (-1); else if (ll == LLONG_MIN && errno == ERANGE) return (-1); else if (ll == LLONG_MAX && errno == ERANGE) return (-1); else if (ll < 0 || ll > INT_MAX) return (-1); return ((int)ll); } void xxd(const void *buf, size_t count) { const uint8_t *ptr = buf; size_t i; fprintf(stderr, " "); for (i = 0; i < count; i++) { fprintf(stderr, "%02x ", *ptr++); if ((i + 1) % 16 == 0 && i + 1 < count) fprintf(stderr, "\n "); } fprintf(stderr, "\n"); fflush(stderr); } int string_read(FILE *f, char **out) { char *line = NULL; size_t linesize = 0; ssize_t n; *out = NULL; if ((n = getline(&line, &linesize, f)) <= 0 || (size_t)n != strlen(line)) { free(line); return (-1); } line[n - 1] = '\0'; /* trim \n */ *out = line; return (0); } fido_dev_t * open_dev(const char *path) { fido_dev_t *dev; int r; if ((dev = fido_dev_new()) == NULL) errx(1, "fido_dev_new"); r = fido_dev_open(dev, path); if (r != FIDO_OK) errx(1, "fido_dev_open %s: %s", path, fido_strerr(r)); return (dev); } int get_devopt(fido_dev_t *dev, const char *name, int *val) { fido_cbor_info_t *cbor_info; char * const *names; const bool *values; int r, ok = -1; if ((cbor_info = fido_cbor_info_new()) == NULL) { warnx("fido_cbor_info_new"); goto out; } if ((r = fido_dev_get_cbor_info(dev, cbor_info)) != FIDO_OK) { warnx("fido_dev_get_cbor_info: %s (0x%x)", fido_strerr(r), r); goto out; } if ((names = fido_cbor_info_options_name_ptr(cbor_info)) == NULL || (values = fido_cbor_info_options_value_ptr(cbor_info)) == NULL) { warnx("fido_dev_get_cbor_info: NULL name/value pointer"); goto out; } *val = -1; for (size_t i = 0; i < fido_cbor_info_options_len(cbor_info); i++) if (strcmp(names[i], name) == 0) { *val = values[i]; break; } ok = 0; out: fido_cbor_info_free(&cbor_info); 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) { fclose(fp); } if (pkey) { EVP_PKEY_free(pkey); } return (ec); } int -write_ec_pubkey(FILE *f, const void *ptr, size_t len) +write_es256_pubkey(FILE *f, const void *ptr, size_t len) { EVP_PKEY *pkey = NULL; es256_pk_t *pk = NULL; 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 ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) { warnx("es256_pk_to_EVP_PKEY"); goto fail; } if (PEM_write_PUBKEY(f, pkey) == 0) { warnx("PEM_write_PUBKEY"); goto fail; } ok = 0; fail: es256_pk_free(&pk); if (pkey != NULL) { EVP_PKEY_free(pkey); } return (ok); } +int +write_es384_pubkey(FILE *f, const void *ptr, size_t len) +{ + EVP_PKEY *pkey = NULL; + es384_pk_t *pk = NULL; + int ok = -1; + + if ((pk = es384_pk_new()) == NULL) { + warnx("es384_pk_new"); + goto fail; + } + + if (es384_pk_from_ptr(pk, ptr, len) != FIDO_OK) { + warnx("es384_pk_from_ptr"); + goto fail; + } + + if ((pkey = es384_pk_to_EVP_PKEY(pk)) == NULL) { + warnx("es384_pk_to_EVP_PKEY"); + goto fail; + } + + if (PEM_write_PUBKEY(f, pkey) == 0) { + warnx("PEM_write_PUBKEY"); + goto fail; + } + + ok = 0; +fail: + es384_pk_free(&pk); + + 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) { fclose(fp); } if (pkey) { EVP_PKEY_free(pkey); } return (rsa); } int write_rsa_pubkey(FILE *f, const void *ptr, size_t len) { EVP_PKEY *pkey = NULL; rs256_pk_t *pk = NULL; 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 ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) { warnx("rs256_pk_to_EVP_PKEY"); goto fail; } if (PEM_write_PUBKEY(f, pkey) == 0) { warnx("PEM_write_PUBKEY"); goto fail; } ok = 0; fail: rs256_pk_free(&pk); 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(FILE *f, const void *ptr, size_t len) { EVP_PKEY *pkey = NULL; eddsa_pk_t *pk = NULL; 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 ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) { warnx("eddsa_pk_to_EVP_PKEY"); goto fail; } if (PEM_write_PUBKEY(f, pkey) == 0) { warnx("PEM_write_PUBKEY"); goto fail; } ok = 0; fail: eddsa_pk_free(&pk); if (pkey != NULL) { EVP_PKEY_free(pkey); } return (ok); } void print_cred(FILE *out_f, int type, const fido_cred_t *cred) { char *id; int r; r = base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &id); if (r < 0) errx(1, "output error"); fprintf(out_f, "%s\n", id); - if (type == COSE_ES256) { - write_ec_pubkey(out_f, fido_cred_pubkey_ptr(cred), + switch (type) { + case COSE_ES256: + write_es256_pubkey(out_f, fido_cred_pubkey_ptr(cred), + fido_cred_pubkey_len(cred)); + break; + case COSE_ES384: + write_es384_pubkey(out_f, fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); - } else if (type == COSE_RS256) { + break; + case COSE_RS256: write_rsa_pubkey(out_f, fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); - } else if (type == COSE_EDDSA) { + break; + case COSE_EDDSA: write_eddsa_pubkey(out_f, fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); - } else { + break; + default: errx(1, "print_cred: unknown type"); } free(id); } int cose_type(const char *str, int *type) { if (strcmp(str, "es256") == 0) *type = COSE_ES256; + else if (strcmp(str, "es384") == 0) + *type = COSE_ES384; else if (strcmp(str, "rs256") == 0) *type = COSE_RS256; else if (strcmp(str, "eddsa") == 0) *type = COSE_EDDSA; else { *type = 0; return (-1); } return (0); } const char * cose_string(int type) { switch (type) { - case COSE_EDDSA: - return ("eddsa"); case COSE_ES256: return ("es256"); + case COSE_ES384: + return ("es384"); case COSE_RS256: return ("rs256"); + case COSE_EDDSA: + return ("eddsa"); default: return ("unknown"); } } const char * prot_string(int prot) { switch (prot) { case FIDO_CRED_PROT_UV_OPTIONAL: return ("uvopt"); case FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID: return ("uvopt+id"); case FIDO_CRED_PROT_UV_REQUIRED: return ("uvreq"); default: return ("unknown"); } } int read_file(const char *path, u_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("%s: open %s", __func__, path); goto fail; } if (fstat(fd, &st) < 0) { warn("%s: stat %s", __func__, path); goto fail; } if (st.st_size < 0) { warnx("%s: stat %s: invalid size", __func__, path); goto fail; } *len = (size_t)st.st_size; if ((*ptr = malloc(*len)) == NULL) { warn("%s: malloc", __func__); goto fail; } if ((n = read(fd, *ptr, *len)) < 0) { warn("%s: read", __func__); goto fail; } if ((size_t)n != *len) { warnx("%s: read", __func__); goto fail; } ok = 0; fail: if (fd != -1) { close(fd); } if (ok < 0) { free(*ptr); *ptr = NULL; *len = 0; } return ok; } int write_file(const char *path, const u_char *ptr, size_t len) { int fd, ok = -1; ssize_t n; if ((fd = open(path, O_WRONLY | O_CREAT, 0600)) < 0) { warn("%s: open %s", __func__, path); goto fail; } if ((n = write(fd, ptr, len)) < 0) { warn("%s: write", __func__); goto fail; } if ((size_t)n != len) { warnx("%s: write", __func__); goto fail; } ok = 0; fail: if (fd != -1) { close(fd); } return ok; } const char * plural(size_t x) { return x == 1 ? "" : "s"; } int should_retry_with_pin(const fido_dev_t *dev, int r) { if (fido_dev_has_pin(dev) == false) { return 0; } switch (r) { case FIDO_ERR_PIN_REQUIRED: case FIDO_ERR_UNAUTHORIZED_PERM: case FIDO_ERR_UV_BLOCKED: case FIDO_ERR_UV_INVALID: return 1; } return 0; } diff --git a/contrib/libfido2/udev/70-u2f.rules b/contrib/libfido2/udev/70-u2f.rules index 0dfc3e276c7a..c443f7524a08 100644 --- a/contrib/libfido2/udev/70-u2f.rules +++ b/contrib/libfido2/udev/70-u2f.rules @@ -1,217 +1,246 @@ # Copyright (c) 2020 Yubico AB. All rights reserved. -# Use of this source code is governed by a BSD-style -# license that can be found in the LICENSE file. - -# This file is automatically generated, and should -# be used with udev 188 or newer. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# SPDX-License-Identifier: BSD-2-Clause + +# This file is automatically generated, and should be used with udev 188 +# or newer. ACTION!="add|change", GOTO="fido_end" # ellipticSecure MIRKey by STMicroelectronics KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ac", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Unknown product by STMicroelectronics KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Unknown product by STMicroelectronics KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="cdab", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Infineon FIDO by Infineon Technologies KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="058b", ATTRS{idProduct}=="022d", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Kensington VeriMark by Synaptics Inc. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="06cb", ATTRS{idProduct}=="0088", TAG+="uaccess", GROUP="plugdev", MODE="0660" # FS ePass FIDO by Feitian Technologies Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0850", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Unknown product by Feitian Technologies Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0852", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Unknown product by Feitian Technologies Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0853", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Unknown product by Feitian Technologies Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0854", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Unknown product by Feitian Technologies Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0856", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Unknown product by Feitian Technologies Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0858", TAG+="uaccess", GROUP="plugdev", MODE="0660" # FS MultiPass FIDO U2F by Feitian Technologies Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="085a", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Unknown product by Feitian Technologies Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="085b", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Unknown product by Feitian Technologies Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="085d", TAG+="uaccess", GROUP="plugdev", MODE="0660" # BioPass FIDO2 K33 by Feitian Technologies Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0866", TAG+="uaccess", GROUP="plugdev", MODE="0660" # BioPass FIDO2 K43 by Feitian Technologies Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0867", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Hypersecu HyperFIDO by Feitian Technologies Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0880", TAG+="uaccess", GROUP="plugdev", MODE="0660" # YubiKey NEO FIDO by Yubico AB KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0113", TAG+="uaccess", GROUP="plugdev", MODE="0660" # YubiKey NEO OTP+FIDO by Yubico AB KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0114", TAG+="uaccess", GROUP="plugdev", MODE="0660" # YubiKey NEO FIDO+CCID by Yubico AB KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0115", TAG+="uaccess", GROUP="plugdev", MODE="0660" # YubiKey NEO OTP+FIDO+CCID by Yubico AB KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0116", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Security Key by Yubico by Yubico AB KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0120", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Unknown product by Yubico AB KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0121", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Gnubby U2F by Yubico AB KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0200", TAG+="uaccess", GROUP="plugdev", MODE="0660" # YubiKey 4 FIDO by Yubico AB KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0402", TAG+="uaccess", GROUP="plugdev", MODE="0660" # YubiKey 4 OTP+FIDO by Yubico AB KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0403", TAG+="uaccess", GROUP="plugdev", MODE="0660" # YubiKey 4 FIDO+CCID by Yubico AB KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0406", TAG+="uaccess", GROUP="plugdev", MODE="0660" # YubiKey 4 OTP+FIDO+CCID by Yubico AB KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0407", TAG+="uaccess", GROUP="plugdev", MODE="0660" # YubiKey Plus by Yubico AB KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0410", TAG+="uaccess", GROUP="plugdev", MODE="0660" # U2F Zero by Silicon Laboratories, Inc. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev", MODE="0660" # SoloKeys SoloHacker by pid.codes KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="5070", TAG+="uaccess", GROUP="plugdev", MODE="0660" # SoloKeys SoloBoot by pid.codes KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="50b0", TAG+="uaccess", GROUP="plugdev", MODE="0660" # SatoshiLabs TREZOR by pid.codes KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="53c1", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# SoloKeys v2 by pid.codes +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="beee", TAG+="uaccess", GROUP="plugdev", MODE="0660" + # Google Titan U2F by Google Inc. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="5026", TAG+="uaccess", GROUP="plugdev", MODE="0660" # VASCO SecureClick by VASCO Data Security NV KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1a44", ATTRS{idProduct}=="00bb", TAG+="uaccess", GROUP="plugdev", MODE="0660" # OnlyKey (FIDO2/U2F) by OpenMoko, Inc. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="60fc", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Neowave Keydo AES by NEOWAVE KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1e0d", ATTRS{idProduct}=="f1ae", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Neowave Keydo by NEOWAVE KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1e0d", ATTRS{idProduct}=="f1d0", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Thethis Key by Shenzhen Excelsecu Data Technology Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1ea8", ATTRS{idProduct}=="f025", TAG+="uaccess", GROUP="plugdev", MODE="0660" # ExcelSecu FIDO2 Security Key by Shenzhen Excelsecu Data Technology Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1ea8", ATTRS{idProduct}=="fc25", TAG+="uaccess", GROUP="plugdev", MODE="0660" # GoTrust Idem Key by NXP Semiconductors KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1fc9", ATTRS{idProduct}=="f143", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Nitrokey FIDO U2F by Clay Logic KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4287", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Nitrokey FIDO2 by Clay Logic KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b1", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Nitrokey 3C NFC by Clay Logic KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b2", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Safetech SafeKey by Clay Logic KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b3", TAG+="uaccess", GROUP="plugdev", MODE="0660" # CanoKey by Clay Logic KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42d4", TAG+="uaccess", GROUP="plugdev", MODE="0660" # JaCarta U2F by Aladdin Software Security R.D. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="24dc", ATTRS{idProduct}=="0101", TAG+="uaccess", GROUP="plugdev", MODE="0660" # JaCarta U2F by Aladdin Software Security R.D. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="24dc", ATTRS{idProduct}=="0501", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Happlink Security Key by Plug‐up KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2581", ATTRS{idProduct}=="f1d0", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Bluink Key by Bluink Ltd KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2abe", ATTRS{idProduct}=="1002", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Ledger Blue by LEDGER KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0000", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Ledger Nano S Old firmware by LEDGER KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0001", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Ledger Nano X Old firmware by LEDGER KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0004", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Ledger Blue by LEDGER KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0011", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Ledger Blue Legacy by LEDGER KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0015", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Ledger Nano S by LEDGER KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="1011", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Ledger Nano S Legacy by LEDGER KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="1015", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Ledger Nano X by LEDGER KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="4011", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Ledger Nano X Legacy by LEDGER KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="4015", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Hypersecu HyperFIDO by Hypersecu Information Systems, Inc. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2ccf", ATTRS{idProduct}=="0880", TAG+="uaccess", GROUP="plugdev", MODE="0660" # TrustKey Solutions FIDO2 G310 by eWBM Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="4a1a", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# TrustKey Solutions FIDO2 G310H/G320H by eWBM Co., Ltd. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="4a2a", TAG+="uaccess", GROUP="plugdev", MODE="0660" + # TrustKey Solutions FIDO2 G320 by eWBM Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="4c2a", TAG+="uaccess", GROUP="plugdev", MODE="0660" # eWBM FIDO2 Goldengate G500 by eWBM Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="5c2f", TAG+="uaccess", GROUP="plugdev", MODE="0660" # TrustKey Solutions FIDO2 T120 by eWBM Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="a6e9", TAG+="uaccess", GROUP="plugdev", MODE="0660" # TrustKey Solutions FIDO2 T110 by eWBM Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="a7f9", TAG+="uaccess", GROUP="plugdev", MODE="0660" # eWBM FIDO2 Goldengate G450 by eWBM Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="f47c", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Idem Key by GoTrustID Inc. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="32a3", ATTRS{idProduct}=="3201", TAG+="uaccess", GROUP="plugdev", MODE="0660" # Longmai mFIDO by Unknown vendor KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="4c4d", ATTRS{idProduct}=="f703", TAG+="uaccess", GROUP="plugdev", MODE="0660" # SatoshiLabs TREZOR by SatoshiLabs KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="534c", ATTRS{idProduct}=="0001", TAG+="uaccess", GROUP="plugdev", MODE="0660" LABEL="fido_end" diff --git a/contrib/libfido2/udev/CMakeLists.txt b/contrib/libfido2/udev/CMakeLists.txt index 29a9d41fe37d..abddb80f4d82 100644 --- a/contrib/libfido2/udev/CMakeLists.txt +++ b/contrib/libfido2/udev/CMakeLists.txt @@ -1,7 +1,8 @@ # 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. +# SPDX-License-Identifier: BSD-2-Clause if(UDEV_RULES_DIR) install(FILES 70-u2f.rules DESTINATION ${UDEV_RULES_DIR}) endif() diff --git a/contrib/libfido2/udev/check.sh b/contrib/libfido2/udev/check.sh index 97bbb97b26c8..804a8843b378 100755 --- a/contrib/libfido2/udev/check.sh +++ b/contrib/libfido2/udev/check.sh @@ -1,31 +1,32 @@ #!/bin/sh -u # Copyright (c) 2020 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. +# SPDX-License-Identifier: BSD-2-Clause sort_by_id() { awk '{ printf "%d\n", $3 }' | sort -Cnu } if ! grep '^vendor' "$1" | sort_by_id; then echo unsorted vendor section 1>&2 exit 1 fi VENDORS=$(grep '^vendor' "$1" | awk '{ print $2 }') PRODUCTS=$(grep '^product' "$1" | awk '{ print $2 }' | uniq) if [ "${VENDORS}" != "${PRODUCTS}" ]; then echo vendors: "$(echo "${VENDORS}" | tr '\n' ',')" 1>&2 echo products: "$(echo "${PRODUCTS}" | tr '\n' ',')" 1>&2 echo vendors and products in different order 1>&2 exit 2 fi for v in ${VENDORS}; do if ! grep "^product ${v}" "$1" | sort_by_id; then echo "${v}": unsorted product section 1>&2 exit 3 fi done diff --git a/contrib/libfido2/udev/fidodevs b/contrib/libfido2/udev/fidodevs index cea60a0be9fb..196e92f0b100 100644 --- a/contrib/libfido2/udev/fidodevs +++ b/contrib/libfido2/udev/fidodevs @@ -1,126 +1,129 @@ # 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. +# SPDX-License-Identifier: BSD-2-Clause # After modifying this file, regenerate 70-u2f.rules: # ./genrules.awk fidodevs > 70-u2f.rules # List of known vendors. Sorted by vendor ID. vendor STMICRO 0x0483 STMicroelectronics vendor INFINEON 0x058b Infineon Technologies vendor SYNAPTICS 0x06cb Synaptics Inc. vendor FEITIAN 0x096e Feitian Technologies Co., Ltd. vendor YUBICO 0x1050 Yubico AB vendor SILICON 0x10c4 Silicon Laboratories, Inc. vendor PIDCODES 0x1209 pid.codes vendor GOOGLE 0x18d1 Google Inc. vendor VASCO 0x1a44 VASCO Data Security NV vendor OPENMOKO 0x1d50 OpenMoko, Inc. vendor NEOWAVE 0x1e0d NEOWAVE vendor EXCELSECU 0x1ea8 Shenzhen Excelsecu Data Technology Co., Ltd. vendor NXP 0x1fc9 NXP Semiconductors vendor CLAYLOGIC 0x20a0 Clay Logic vendor ALLADIN 0x24dc Aladdin Software Security R.D. vendor PLUGUP 0x2581 Plug‐up vendor BLUINK 0x2abe Bluink Ltd vendor LEDGER 0x2c97 LEDGER vendor HYPERSECU 0x2ccf Hypersecu Information Systems, Inc. vendor EWBM 0x311f eWBM Co., Ltd. vendor GOTRUST 0x32a3 GoTrustID Inc. vendor UNKNOWN1 0x4c4d Unknown vendor vendor SATOSHI 0x534c SatoshiLabs # List of known products. Grouped by vendor; sorted by product ID. product STMICRO 0xa2ac ellipticSecure MIRKey product STMICRO 0xa2ca Unknown product product STMICRO 0xcdab Unknown product product INFINEON 0x022d Infineon FIDO product SYNAPTICS 0x0088 Kensington VeriMark product FEITIAN 0x0850 FS ePass FIDO product FEITIAN 0x0852 Unknown product product FEITIAN 0x0853 Unknown product product FEITIAN 0x0854 Unknown product product FEITIAN 0x0856 Unknown product product FEITIAN 0x0858 Unknown product product FEITIAN 0x085a FS MultiPass FIDO U2F product FEITIAN 0x085b Unknown product product FEITIAN 0x085d Unknown product product FEITIAN 0x0866 BioPass FIDO2 K33 product FEITIAN 0x0867 BioPass FIDO2 K43 product FEITIAN 0x0880 Hypersecu HyperFIDO product YUBICO 0x0113 YubiKey NEO FIDO product YUBICO 0x0114 YubiKey NEO OTP+FIDO product YUBICO 0x0115 YubiKey NEO FIDO+CCID product YUBICO 0x0116 YubiKey NEO OTP+FIDO+CCID product YUBICO 0x0120 Security Key by Yubico product YUBICO 0x0121 Unknown product product YUBICO 0x0200 Gnubby U2F product YUBICO 0x0402 YubiKey 4 FIDO product YUBICO 0x0403 YubiKey 4 OTP+FIDO product YUBICO 0x0406 YubiKey 4 FIDO+CCID product YUBICO 0x0407 YubiKey 4 OTP+FIDO+CCID product YUBICO 0x0410 YubiKey Plus product SILICON 0x8acf U2F Zero product PIDCODES 0x5070 SoloKeys SoloHacker product PIDCODES 0x50b0 SoloKeys SoloBoot product PIDCODES 0x53c1 SatoshiLabs TREZOR +product PIDCODES 0xbeee SoloKeys v2 product GOOGLE 0x5026 Google Titan U2F product VASCO 0x00bb VASCO SecureClick product OPENMOKO 0x60fc OnlyKey (FIDO2/U2F) product NEOWAVE 0xf1ae Neowave Keydo AES product NEOWAVE 0xf1d0 Neowave Keydo product EXCELSECU 0xf025 Thethis Key product EXCELSECU 0xfc25 ExcelSecu FIDO2 Security Key product NXP 0xf143 GoTrust Idem Key product CLAYLOGIC 0x4287 Nitrokey FIDO U2F product CLAYLOGIC 0x42b1 Nitrokey FIDO2 product CLAYLOGIC 0x42b2 Nitrokey 3C NFC product CLAYLOGIC 0x42b3 Safetech SafeKey product CLAYLOGIC 0x42d4 CanoKey product ALLADIN 0x0101 JaCarta U2F product ALLADIN 0x0501 JaCarta U2F product PLUGUP 0xf1d0 Happlink Security Key product BLUINK 0x1002 Bluink Key product LEDGER 0x0000 Ledger Blue product LEDGER 0x0001 Ledger Nano S Old firmware product LEDGER 0x0004 Ledger Nano X Old firmware product LEDGER 0x0011 Ledger Blue product LEDGER 0x0015 Ledger Blue Legacy product LEDGER 0x1011 Ledger Nano S product LEDGER 0x1015 Ledger Nano S Legacy product LEDGER 0x4011 Ledger Nano X product LEDGER 0x4015 Ledger Nano X Legacy product HYPERSECU 0x0880 Hypersecu HyperFIDO product EWBM 0x4a1a TrustKey Solutions FIDO2 G310 +product EWBM 0x4a2a TrustKey Solutions FIDO2 G310H/G320H product EWBM 0x4c2a TrustKey Solutions FIDO2 G320 product EWBM 0x5c2f eWBM FIDO2 Goldengate G500 product EWBM 0xa6e9 TrustKey Solutions FIDO2 T120 product EWBM 0xa7f9 TrustKey Solutions FIDO2 T110 product EWBM 0xf47c eWBM FIDO2 Goldengate G450 product GOTRUST 0x3201 Idem Key product UNKNOWN1 0xf703 Longmai mFIDO product SATOSHI 0x0001 SatoshiLabs TREZOR diff --git a/contrib/libfido2/udev/genrules.awk b/contrib/libfido2/udev/genrules.awk index 2a85c7cbf98f..3dad667da923 100755 --- a/contrib/libfido2/udev/genrules.awk +++ b/contrib/libfido2/udev/genrules.awk @@ -1,55 +1,79 @@ #!/usr/bin/awk -f # Copyright (c) 2020 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. +# SPDX-License-Identifier: BSD-2-Clause NR == 1 { print "# Copyright (c) 2020 Yubico AB. All rights reserved." - print "# Use of this source code is governed by a BSD-style" - print "# license that can be found in the LICENSE file." + print "#" + print "# Redistribution and use in source and binary forms, with or without" + print "# modification, are permitted provided that the following conditions are" + print "# met:" + print "# " + print "# 1. Redistributions of source code must retain the above copyright" + print "# notice, this list of conditions and the following disclaimer." + print "# 2. Redistributions in binary form must reproduce the above copyright" + print "# notice, this list of conditions and the following disclaimer in" + print "# the documentation and/or other materials provided with the" + print "# distribution." + print "# " + print "# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS" + print "# \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT" + print "# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR" + print "# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT" + print "# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL," + print "# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT" + print "# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE," + print "# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY" + print "# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT" + print "# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" + print "# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + print "#" + print "# SPDX-License-Identifier: BSD-2-Clause" print "" - print "# This file is automatically generated, and should" - print "# be used with udev 188 or newer." + print "# This file is automatically generated, and should be used with udev 188" + print "# or newer." print "" print "ACTION!=\"add|change\", GOTO=\"fido_end\"" next } $1 == "vendor" { sub("0x", "", $3) vendors[$2, "id"] = $3 f = 4 while (f <= NF) { vendors[$2, "name"] = vendors[$2, "name"] " " $f f++ } } $1 == "product" { sub("0x", "", $3) name = "" f = 4 while (f <= NF) { name = name " " $f f++ } line = "\n#" name " by" vendors[$2, "name"]"\n" line = line"KERNEL==\"hidraw*\"" line = line", SUBSYSTEM==\"hidraw\"" line = line", ATTRS{idVendor}==\""vendors[$2, "id"]"\"" line = line", ATTRS{idProduct}==\""$3"\"" line = line", TAG+=\"uaccess\"" line = line", GROUP=\"plugdev\"" line = line", MODE=\"0660\"" print line } END { print "\nLABEL=\"fido_end\"" } diff --git a/contrib/libfido2/windows/build.ps1 b/contrib/libfido2/windows/build.ps1 index 56302444c80b..52a1d6692de4 100644 --- a/contrib/libfido2/windows/build.ps1 +++ b/contrib/libfido2/windows/build.ps1 @@ -1,240 +1,242 @@ -# Copyright (c) 2021 Yubico AB. All rights reserved. +# Copyright (c) 2021-2022 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. +# SPDX-License-Identifier: BSD-2-Clause 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 = "Stop" [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 . "$PSScriptRoot\const.ps1" Function ExitOnError() { if ($LastExitCode -ne 0) { throw "A command exited with status $LastExitCode" } } 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 } # 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 = $CMakePath } 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 = $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 = $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))) { $CMAKE_SYSTEM_VERSION = "-DCMAKE_SYSTEM_VERSION='$WinSDK'" } else { $CMAKE_SYSTEM_VERSION = '' } 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" # 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 # 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 (-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 } if (-Not (Test-Path .\${LIBCBOR})) { GitClone "${LIBCBOR_GIT}" "${LIBCBOR_BRANCH}" ".\${LIBCBOR}" } if (-Not (Test-Path .\${ZLIB})) { GitClone "${ZLIB_GIT}" "${ZLIB_BRANCH}" ".\${ZLIB}" } } catch { throw "Failed to fetch and verify dependencies" } finally { Pop-Location } # 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 } # 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_C_FLAGS_DEBUG="${CFLAGS_DEBUG} /wd4703" ` + -DCMAKE_C_FLAGS_RELEASE="${CFLAGS_RELEASE} /wd4703" ` -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 } # 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 - } + # Patch up zlib's various names. + if ("${Type}" -eq "Dynamic") { + ((Get-ChildItem -Path "${PREFIX}/lib") -Match "zlib[d]?.lib") | + Copy-Item -Destination "${PREFIX}/lib/zlib1.lib" -Force + ((Get-ChildItem -Path "${PREFIX}/bin") -Match "zlibd1.dll") | + Copy-Item -Destination "${PREFIX}/bin/zlib1.dll" -Force + } else { + ((Get-ChildItem -Path "${PREFIX}/lib") -Match "zlibstatic[d]?.lib") | + Copy-item -Destination "${PREFIX}/lib/zlib1.lib" -Force } } catch { throw "Failed to build zlib" } finally { Pop-Location } # 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" ` + -DCRYPTO_LIBRARIES="${CRYPTO_LIBRARIES}" ` -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 regress --verbose; ` + ExitOnError & $CMake --build . --config ${Config} --target install --verbose; ` ExitOnError # Copy DLLs. if ("${SHARED}" -eq "ON") { - "cbor.dll", "crypto-47.dll", "zlib1.dll" | ` + "cbor.dll", "${CRYPTO_LIBRARIES}.dll", "zlib1.dll" | ` %{ Copy-Item "${PREFIX}\bin\$_" ` -Destination "examples\${Config}" } } } catch { throw "Failed to build libfido2" } finally { Pop-Location } diff --git a/contrib/libfido2/windows/const.ps1 b/contrib/libfido2/windows/const.ps1 index 4aac8bb2853e..f657846def5e 100644 --- a/contrib/libfido2/windows/const.ps1 +++ b/contrib/libfido2/windows/const.ps1 @@ -1,42 +1,44 @@ -# Copyright (c) 2021 Yubico AB. All rights reserved. +# Copyright (c) 2021-2023 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. +# SPDX-License-Identifier: BSD-2-Clause # 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.4.2' -Option Constant +New-Variable -Name 'LIBRESSL' -Value 'libressl-3.6.2' -Option Constant +New-Variable -Name 'CRYPTO_LIBRARIES' -Value 'crypto-50' -Option Constant # libcbor coordinates. -New-Variable -Name 'LIBCBOR' -Value 'libcbor-0.9.0' -Option Constant -New-Variable -Name 'LIBCBOR_BRANCH' -Value 'v0.9.0' -Option Constant +New-Variable -Name 'LIBCBOR' -Value 'libcbor-0.10.1' -Option Constant +New-Variable -Name 'LIBCBOR_BRANCH' -Value 'v0.10.1' -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' -Value 'zlib-1.2.13' -Option Constant +New-Variable -Name 'ZLIB_BRANCH' -Value 'v1.2.13' -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/cygwin.ps1 b/contrib/libfido2/windows/cygwin.ps1 index aada60b6f06f..0681830a911d 100755 --- a/contrib/libfido2/windows/cygwin.ps1 +++ b/contrib/libfido2/windows/cygwin.ps1 @@ -1,68 +1,70 @@ # 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. +# SPDX-License-Identifier: BSD-2-Clause param( [string]$GPGPath = "C:\Program Files (x86)\GnuPG\bin\gpg.exe", [string]$Config = "Release" ) $ErrorActionPreference = "Stop" [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # Cygwin coordinates. $URL = 'https://www.cygwin.com' $Setup = 'setup-x86_64.exe' $Mirror = 'https://mirrors.kernel.org/sourceware/cygwin/' $Packages = 'gcc-core,pkg-config,cmake,make,libcbor-devel,libssl-devel,zlib-devel' # Work directories. $Cygwin = "$PSScriptRoot\..\cygwin" $Root = "${Cygwin}\root" # Find 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" } Write-Host "Config: $Config" Write-Host "GPG: $GPG" # Create work directories. New-Item -Type Directory "${Cygwin}" -Force New-Item -Type Directory "${Root}" -Force # Fetch and verify Cygwin. try { if (-Not (Test-Path ${Cygwin}\${Setup} -PathType leaf)) { Invoke-WebRequest ${URL}/${Setup} ` -OutFile ${Cygwin}\${Setup} } if (-Not (Test-Path ${Cygwin}\${Setup}.sig -PathType leaf)) { Invoke-WebRequest ${URL}/${Setup}.sig ` -OutFile ${Cygwin}\${Setup}.sig } & $GPG --list-keys & $GPG --quiet --no-default-keyring ` --keyring ${PSScriptRoot}/cygwin.gpg ` --verify ${Cygwin}\${Setup}.sig ${Cygwin}\${Setup} if ($LastExitCode -ne 0) { throw "GPG signature verification failed" } } catch { throw "Failed to fetch and verify Cygwin" } # Bootstrap Cygwin. Start-Process "${Cygwin}\${Setup}" -Wait -NoNewWindow ` -ArgumentList "-dnNOqW -s ${Mirror} -R ${Root} -P ${Packages}" # Build libfido2. $Env:PATH = "${Root}\bin\;" + $Env:PATH cmake "-DCMAKE_BUILD_TYPE=${Config}" -B "build-${Config}" make -C "build-${Config}" +make -C "build-${Config}" regress diff --git a/contrib/libfido2/windows/release.ps1 b/contrib/libfido2/windows/release.ps1 index 9221bcaa3413..cc5f635b8faa 100644 --- a/contrib/libfido2/windows/release.ps1 +++ b/contrib/libfido2/windows/release.ps1 @@ -1,97 +1,97 @@ -# Copyright (c) 2021 Yubico AB. All rights reserved. +# Copyright (c) 2021-2022 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. +# SPDX-License-Identifier: BSD-2-Clause $ErrorActionPreference = "Stop" $Architectures = @('x64', 'Win32', 'ARM64', 'ARM') $InstallPrefixes = @('Win64', 'Win32', 'ARM64', 'ARM') $Types = @('dynamic', 'static') $Config = 'Release' -$LibCrypto = '47' $SDK = '143' . "$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}\lib\zlib1.lib" "${DEST}" + Copy-Item "${SRC}\bin\${CRYPTO_LIBRARIES}.dll" "${DEST}" + Copy-Item "${SRC}\lib\${CRYPTO_LIBRARIES}.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/zlib1.lib" "${DEST}" + Copy-Item "${SRC}/lib/${CRYPTO_LIBRARIES}.lib" "${DEST}" Copy-Item "${SRC}/lib/fido2_static.lib" "${DEST}/fido2.lib" } Function Package-PDBs(${SRC}, ${DEST}) { Copy-Item "${SRC}\${LIBRESSL}\crypto\crypto_obj.dir\${Config}\crypto_obj.pdb" ` - "${DEST}\crypto-${LibCrypto}.pdb" + "${DEST}\${CRYPTO_LIBRARIES}.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" + "${DEST}\zlib1.pdb" Copy-Item "${SRC}\src\fido2_shared.dir\${Config}\vc${SDK}.pdb" ` "${DEST}\fido2.pdb" } Function Package-StaticPDBs(${SRC}, ${DEST}) { - Copy-Item "${SRC}\${LIBRESSL}\crypto\Release\crypto-${LibCrypto}.pdb" ` - "${DEST}\crypto-${LibCrypto}.pdb" - Copy-Item "${SRC}\${LIBCBOR}\src\Release\cbor.pdb" ` + Copy-Item "${SRC}\${LIBRESSL}\crypto\crypto_obj.dir\${Config}\crypto_obj.pdb" ` + "${DEST}\${CRYPTO_LIBRARIES}.pdb" + Copy-Item "${SRC}\${LIBCBOR}\src\${Config}\cbor.pdb" ` "${DEST}\cbor.pdb" - Copy-Item "${SRC}\${ZLIB}\Release\zlibstatic.pdb" ` - "${DEST}\zlib.pdb" - Copy-Item "${SRC}\src\Release\fido2_static.pdb" ` + Copy-Item "${SRC}\${ZLIB}\${Config}\zlibstatic.pdb" ` + "${DEST}\zlib1.pdb" + Copy-Item "${SRC}\src\${Config}\fido2_static.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" Package-StaticPDBs "${BUILD}\${Arch}\static" ` "${OUTPUT}\pkg\${InstallPrefix}\${Config}\v${SDK}\static" } diff --git a/lib/libfido2/Makefile b/lib/libfido2/Makefile index 86ac1153f384..dc985e2797ed 100644 --- a/lib/libfido2/Makefile +++ b/lib/libfido2/Makefile @@ -1,78 +1,82 @@ 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+= es384.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+= touch.c SRCS+= tpm.c SRCS+= types.c SRCS+= u2f.c +SRCS+= util.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_ASPRINTF 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+= -DOPENSSL_API_COMPAT=0x10100000L CFLAGS+= -DTLS=__thread CFLAGS+= -D_FIDO_MAJOR=1 -CFLAGS+= -D_FIDO_MINOR=10 +CFLAGS+= -D_FIDO_MINOR=13 CFLAGS+= -D_FIDO_PATCH=0 LIBADD= crypto z WARNS=2 MAN= .include