Import libfido2 1.7.0; changes:
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.
This commit is contained in:
parent
38862c874c
commit
95dbdf3206
|
@ -7,6 +7,10 @@ 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)
|
||||
|
@ -15,16 +19,29 @@ 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_COLOR_MAKEFILE off)
|
||||
set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(CMAKE_COLOR_MAKEFILE OFF)
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
set(FIDO_MAJOR "1")
|
||||
set(FIDO_MINOR "5")
|
||||
set(FIDO_MINOR "7")
|
||||
set(FIDO_PATCH "0")
|
||||
set(FIDO_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}.${FIDO_PATCH})
|
||||
|
||||
option(BUILD_EXAMPLES "Build example programs" ON)
|
||||
option(BUILD_MANPAGES "Build man pages" ON)
|
||||
option(BUILD_SHARED_LIBS "Build the shared library" ON)
|
||||
option(BUILD_STATIC_LIBS "Build the static library" ON)
|
||||
option(BUILD_TOOLS "Build tool programs" ON)
|
||||
option(FUZZ "Enable fuzzing instrumentation" OFF)
|
||||
option(LIBFUZZER "Build libfuzzer harnesses" OFF)
|
||||
option(USE_HIDAPI "Use hidapi as the HID backend" OFF)
|
||||
option(NFC_LINUX "Experimental NFC support on Linux" OFF)
|
||||
|
||||
add_definitions(-D_FIDO_MAJOR=${FIDO_MAJOR})
|
||||
add_definitions(-D_FIDO_MINOR=${FIDO_MINOR})
|
||||
add_definitions(-D_FIDO_PATCH=${FIDO_PATCH})
|
||||
|
@ -43,14 +60,116 @@ if(APPLE)
|
|||
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
|
||||
if(NOT MSVC)
|
||||
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_POSIX_C_SOURCE=200809L")
|
||||
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_BSD_SOURCE")
|
||||
if(APPLE)
|
||||
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_DARWIN_C_SOURCE")
|
||||
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D__STDC_WANT_LIB_EXT1__=1")
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_GNU_SOURCE")
|
||||
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_DEFAULT_SOURCE")
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
||||
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D__BSD_VISIBLE=1")
|
||||
endif()
|
||||
set(FIDO_CFLAGS "${FIDO_CFLAGS} -std=c99")
|
||||
set(CMAKE_C_FLAGS "${FIDO_CFLAGS} ${CMAKE_C_FLAGS}")
|
||||
endif()
|
||||
|
||||
check_c_compiler_flag("-Wshorten-64-to-32" HAVE_SHORTEN_64_TO_32)
|
||||
check_c_compiler_flag("-fstack-protector-all" HAVE_STACK_PROTECTOR_ALL)
|
||||
|
||||
check_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(clock_gettime time.h HAVE_CLOCK_GETTIME)
|
||||
check_symbol_exists(explicit_bzero string.h HAVE_EXPLICIT_BZERO)
|
||||
check_symbol_exists(freezero stdlib.h HAVE_FREEZERO)
|
||||
check_symbol_exists(getline stdio.h HAVE_GETLINE)
|
||||
check_symbol_exists(getopt unistd.h HAVE_GETOPT)
|
||||
check_symbol_exists(getpagesize unistd.h HAVE_GETPAGESIZE)
|
||||
check_symbol_exists(getrandom sys/random.h HAVE_GETRANDOM)
|
||||
check_symbol_exists(memset_s string.h HAVE_MEMSET_S)
|
||||
check_symbol_exists(readpassphrase readpassphrase.h HAVE_READPASSPHRASE)
|
||||
check_symbol_exists(recallocarray stdlib.h HAVE_RECALLOCARRAY)
|
||||
check_symbol_exists(sigaction signal.h HAVE_SIGACTION)
|
||||
check_symbol_exists(strlcat string.h HAVE_STRLCAT)
|
||||
check_symbol_exists(strlcpy string.h HAVE_STRLCPY)
|
||||
check_symbol_exists(sysconf unistd.h HAVE_SYSCONF)
|
||||
check_symbol_exists(timespecsub sys/time.h HAVE_TIMESPECSUB)
|
||||
check_symbol_exists(timingsafe_bcmp string.h HAVE_TIMINGSAFE_BCMP)
|
||||
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES signal.h)
|
||||
check_type_size("sig_atomic_t" HAVE_SIG_ATOMIC_T)
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES)
|
||||
|
||||
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
|
||||
try_compile(HAVE_POSIX_IOCTL
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/posix_ioctl_check.o"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/openbsd-compat/posix_ioctl_check.c"
|
||||
COMPILE_DEFINITIONS "-Werror -Woverflow -Wsign-conversion")
|
||||
|
||||
list(APPEND CHECK_VARIABLES
|
||||
HAVE_ARC4RANDOM_BUF
|
||||
HAVE_CBOR_H
|
||||
HAVE_CLOCK_GETTIME
|
||||
HAVE_ENDIAN_H
|
||||
HAVE_ERR_H
|
||||
HAVE_FREEZERO
|
||||
HAVE_GETLINE
|
||||
HAVE_GETOPT
|
||||
HAVE_GETPAGESIZE
|
||||
HAVE_GETRANDOM
|
||||
HAVE_MEMSET_S
|
||||
HAVE_OPENSSLV_H
|
||||
HAVE_POSIX_IOCTL
|
||||
HAVE_READPASSPHRASE
|
||||
HAVE_RECALLOCARRAY
|
||||
HAVE_SIGACTION
|
||||
HAVE_SIGNAL_H
|
||||
HAVE_STRLCAT
|
||||
HAVE_STRLCPY
|
||||
HAVE_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)
|
||||
add_definitions(-DHAVE_EXPLICIT_BZERO)
|
||||
endif()
|
||||
|
||||
if(HAVE_SIGACTION AND (NOT HAVE_SIG_ATOMIC_T STREQUAL ""))
|
||||
add_definitions(-DSIGNAL_EXAMPLE)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
add_definitions(-DHAVE_DEV_URANDOM)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
if((NOT CBOR_INCLUDE_DIRS) OR (NOT CBOR_LIBRARY_DIRS) OR
|
||||
(NOT CRYPTO_INCLUDE_DIRS) OR (NOT CRYPTO_LIBRARY_DIRS))
|
||||
(NOT CRYPTO_INCLUDE_DIRS) OR (NOT CRYPTO_LIBRARY_DIRS) OR
|
||||
(NOT ZLIB_INCLUDE_DIRS) OR (NOT ZLIB_LIBRARY_DIRS))
|
||||
message(FATAL_ERROR "please provide definitions for "
|
||||
"{CBOR,CRYPTO}_{INCLUDE,LIBRARY}_DIRS when building "
|
||||
"{CBOR,CRYPTO,ZLIB}_{INCLUDE,LIBRARY}_DIRS when building "
|
||||
"under msvc")
|
||||
endif()
|
||||
set(CBOR_LIBRARIES cbor)
|
||||
set(ZLIB_LIBRARIES zlib)
|
||||
set(CRYPTO_LIBRARIES crypto-46)
|
||||
set(MSVC_DISABLED_WARNINGS_LIST
|
||||
"C4200" # nonstandard extension used: zero-sized array in
|
||||
|
@ -67,45 +186,40 @@ if(MSVC)
|
|||
${MSVC_DISABLED_WARNINGS_LIST})
|
||||
string(REGEX REPLACE "[/-]W[1234][ ]?" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MP -W4 -WX ${MSVC_DISABLED_WARNINGS_STR}")
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Z7")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi")
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Z7 /guard:cf /sdl /RTCcsu")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi /guard:cf /sdl")
|
||||
else()
|
||||
include(FindPkgConfig)
|
||||
pkg_search_module(CBOR libcbor)
|
||||
pkg_search_module(CRYPTO libcrypto)
|
||||
pkg_search_module(ZLIB zlib)
|
||||
|
||||
# XXX workaround libcbor's missing .pc file
|
||||
if(NOT CBOR_FOUND)
|
||||
check_include_files(cbor.h HAVE_CBOR_H)
|
||||
if(NOT HAVE_CBOR_H)
|
||||
message(FATAL_ERROR "could not find cbor header files")
|
||||
endif()
|
||||
set(CBOR_LIBRARIES "cbor")
|
||||
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()
|
||||
|
||||
# XXX workaround libcrypto's missing .pc file
|
||||
if(NOT CRYPTO_FOUND)
|
||||
check_include_files(openssl/opensslv.h HAVE_OPENSSLV_H)
|
||||
if(NOT HAVE_OPENSSLV_H)
|
||||
message(FATAL_ERROR "could not find crypto header files")
|
||||
endif()
|
||||
set(CRYPTO_LIBRARIES "crypto")
|
||||
endif()
|
||||
set(CBOR_LIBRARIES "cbor")
|
||||
set(CRYPTO_LIBRARIES "crypto")
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
pkg_search_module(UDEV libudev REQUIRED)
|
||||
set(UDEV_NAME "udev")
|
||||
include_directories(${UDEV_INCLUDE_DIRS})
|
||||
link_directories(${UDEV_LIBRARY_DIRS})
|
||||
# Define be32toh().
|
||||
add_definitions(-D_GNU_SOURCE)
|
||||
# If using hidapi, use hidapi-hidraw.
|
||||
set(HIDAPI_SUFFIX -hidraw)
|
||||
# Look for clock_gettime in librt.
|
||||
check_library_exists(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME)
|
||||
if(HAVE_CLOCK_GETTIME)
|
||||
set(BASE_LIBRARIES ${BASE_LIBRARIES} rt)
|
||||
add_definitions(-DHAVE_CLOCK_GETTIME)
|
||||
if(NOT HAVE_CLOCK_GETTIME)
|
||||
# Look for clock_gettime in librt.
|
||||
check_library_exists(rt clock_gettime "time.h"
|
||||
HAVE_CLOCK_GETTIME)
|
||||
if (HAVE_CLOCK_GETTIME)
|
||||
add_definitions(-DHAVE_CLOCK_GETTIME)
|
||||
set(BASE_LIBRARIES ${BASE_LIBRARIES} rt)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -113,57 +227,56 @@ else()
|
|||
# MinGW is stuck with a flavour of C89.
|
||||
add_definitions(-DFIDO_NO_DIAGNOSTIC)
|
||||
add_definitions(-DWC_ERR_INVALID_CHARS=0x80)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-parameter")
|
||||
add_compile_options(-Wno-unused-parameter)
|
||||
endif()
|
||||
|
||||
if(USE_HIDAPI)
|
||||
add_definitions(-DUSE_HIDAPI)
|
||||
pkg_search_module(HIDAPI hidapi${HIDAPI_SUFFIX} REQUIRED)
|
||||
if(HIDAPI_FOUND)
|
||||
include_directories(${HIDAPI_INCLUDE_DIRS})
|
||||
link_directories(${HIDAPI_LIBRARY_DIRS})
|
||||
set(HIDAPI_LIBRARIES hidapi${HIDAPI_SUFFIX})
|
||||
endif()
|
||||
set(HIDAPI_LIBRARIES hidapi${HIDAPI_SUFFIX})
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wwrite-strings")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-prototypes")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wbad-function-cast")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic-errors")
|
||||
check_c_compiler_flag("-fstack-protector-all" HAVE_STACK_PROTECTOR_ALL)
|
||||
if(FUZZ)
|
||||
set(NFC_LINUX ON)
|
||||
endif()
|
||||
|
||||
if(NFC_LINUX)
|
||||
add_definitions(-DNFC_LINUX)
|
||||
endif()
|
||||
|
||||
add_compile_options(-Wall)
|
||||
add_compile_options(-Wextra)
|
||||
add_compile_options(-Werror)
|
||||
add_compile_options(-Wshadow)
|
||||
add_compile_options(-Wcast-qual)
|
||||
add_compile_options(-Wwrite-strings)
|
||||
add_compile_options(-Wmissing-prototypes)
|
||||
add_compile_options(-Wbad-function-cast)
|
||||
add_compile_options(-pedantic)
|
||||
add_compile_options(-pedantic-errors)
|
||||
|
||||
if(HAVE_SHORTEN_64_TO_32)
|
||||
add_compile_options(-Wshorten-64-to-32)
|
||||
endif()
|
||||
if(HAVE_STACK_PROTECTOR_ALL)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-all")
|
||||
add_compile_options(-fstack-protector-all)
|
||||
endif()
|
||||
|
||||
add_definitions(-D_DEFAULT_SOURCE)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")
|
||||
|
||||
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(FUZZ)
|
||||
if(LIBFUZZER)
|
||||
set(FUZZ_LDFLAGS "-fsanitize=fuzzer")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=fuzzer-no-link")
|
||||
endif()
|
||||
add_definitions(-DFIDO_FUZZ)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Use -Wshorten-64-to-32 if available.
|
||||
check_c_compiler_flag("-Wshorten-64-to-32" HAVE_SHORTEN_64_TO_32)
|
||||
if(HAVE_SHORTEN_64_TO_32)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshorten-64-to-32")
|
||||
if(LIBFUZZER)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=fuzzer-no-link")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Avoid https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-result")
|
||||
add_compile_options(-Wno-unused-result)
|
||||
endif()
|
||||
|
||||
# Decide which keyword to use for thread-local storage.
|
||||
|
@ -174,161 +287,8 @@ if(CMAKE_COMPILER_IS_GNUCC OR
|
|||
elseif(WIN32)
|
||||
set(TLS "__declspec(thread)")
|
||||
endif()
|
||||
|
||||
add_definitions(-DTLS=${TLS})
|
||||
|
||||
# endian.h
|
||||
check_include_files(endian.h HAVE_ENDIAN_H)
|
||||
if(HAVE_ENDIAN_H)
|
||||
add_definitions(-DHAVE_ENDIAN_H)
|
||||
endif()
|
||||
|
||||
# err.h
|
||||
check_include_files(err.h HAVE_ERR_H)
|
||||
if(HAVE_ERR_H)
|
||||
add_definitions(-DHAVE_ERR_H)
|
||||
endif()
|
||||
|
||||
# unistd.h
|
||||
check_include_files(unistd.h HAVE_UNISTD_H)
|
||||
if(HAVE_UNISTD_H)
|
||||
add_definitions(-DHAVE_UNISTD_H)
|
||||
endif()
|
||||
|
||||
# signal.h
|
||||
check_include_files(signal.h HAVE_SIGNAL_H)
|
||||
if(HAVE_SIGNAL_H)
|
||||
add_definitions(-DHAVE_SIGNAL_H)
|
||||
endif()
|
||||
|
||||
# sys/random.h
|
||||
check_include_files(sys/random.h HAVE_SYS_RANDOM_H)
|
||||
if(HAVE_SYS_RANDOM_H)
|
||||
add_definitions(-DHAVE_SYS_RANDOM_H)
|
||||
endif()
|
||||
|
||||
# strlcpy
|
||||
check_function_exists(strlcpy HAVE_STRLCPY)
|
||||
if(HAVE_STRLCPY)
|
||||
add_definitions(-DHAVE_STRLCPY)
|
||||
endif()
|
||||
|
||||
# strlcat
|
||||
check_function_exists(strlcpy HAVE_STRLCAT)
|
||||
if(HAVE_STRLCAT)
|
||||
add_definitions(-DHAVE_STRLCAT)
|
||||
endif()
|
||||
|
||||
# recallocarray
|
||||
check_function_exists(recallocarray HAVE_RECALLOCARRAY)
|
||||
if(HAVE_RECALLOCARRAY)
|
||||
add_definitions(-DHAVE_RECALLOCARRAY)
|
||||
endif()
|
||||
|
||||
# XXX getpagesize is incorrectly detected when cross-compiling
|
||||
# with mingw on Linux. Avoid.
|
||||
if(NOT WIN32)
|
||||
check_function_exists(getpagesize HAVE_GETPAGESIZE)
|
||||
endif()
|
||||
if(HAVE_GETPAGESIZE)
|
||||
add_definitions(-DHAVE_GETPAGESIZE)
|
||||
endif()
|
||||
|
||||
# sysconf
|
||||
check_function_exists(sysconf HAVE_SYSCONF)
|
||||
if(HAVE_SYSCONF)
|
||||
add_definitions(-DHAVE_SYSCONF)
|
||||
endif()
|
||||
|
||||
# memset_s
|
||||
if(APPLE)
|
||||
add_definitions(-D__STDC_WANT_LIB_EXT1__=1)
|
||||
endif()
|
||||
check_function_exists(memset_s HAVE_MEMSET_S)
|
||||
if(HAVE_MEMSET_S)
|
||||
add_definitions(-DHAVE_MEMSET_S)
|
||||
endif()
|
||||
|
||||
# explicit_bzero
|
||||
if(NOT LIBFUZZER)
|
||||
check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO)
|
||||
if(HAVE_EXPLICIT_BZERO)
|
||||
add_definitions(-DHAVE_EXPLICIT_BZERO)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# timingsafe_bcmp
|
||||
check_function_exists(timingsafe_bcmp HAVE_TIMINGSAFE_BCMP)
|
||||
if(HAVE_TIMINGSAFE_BCMP)
|
||||
add_definitions(-DHAVE_TIMINGSAFE_BCMP)
|
||||
endif()
|
||||
|
||||
# readpassphrase
|
||||
check_function_exists(readpassphrase HAVE_READPASSPHRASE)
|
||||
if(HAVE_READPASSPHRASE)
|
||||
add_definitions(-DHAVE_READPASSPHRASE)
|
||||
endif()
|
||||
|
||||
# getline
|
||||
check_function_exists(getline HAVE_GETLINE)
|
||||
if(HAVE_GETLINE)
|
||||
add_definitions(-DHAVE_GETLINE)
|
||||
endif()
|
||||
|
||||
# getopt
|
||||
check_function_exists(getopt HAVE_GETOPT)
|
||||
if(HAVE_GETOPT)
|
||||
add_definitions(-DHAVE_GETOPT)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-qual")
|
||||
else()
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-discarded-qualifiers")
|
||||
endif()
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-incompatible-pointer-types-discards-qualifiers")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# usable sigaction
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES signal.h)
|
||||
check_function_exists(sigaction HAVE_SIGACTION)
|
||||
check_type_size("sig_atomic_t" HAVE_SIG_ATOMIC_T)
|
||||
if(HAVE_SIGACTION AND (NOT HAVE_SIG_ATOMIC_T STREQUAL ""))
|
||||
add_definitions(-DSIGNAL_EXAMPLE)
|
||||
endif()
|
||||
set(CMAKE_EXTRA_INCLUDE_FILES)
|
||||
|
||||
# arc4random_buf
|
||||
check_function_exists(arc4random_buf HAVE_ARC4RANDOM_BUF)
|
||||
if(HAVE_ARC4RANDOM_BUF)
|
||||
add_definitions(-DHAVE_ARC4RANDOM_BUF)
|
||||
endif()
|
||||
|
||||
# getrandom
|
||||
check_function_exists(getrandom HAVE_GETRANDOM)
|
||||
if(HAVE_GETRANDOM)
|
||||
add_definitions(-DHAVE_GETRANDOM)
|
||||
endif()
|
||||
|
||||
# /dev/urandom
|
||||
if(UNIX)
|
||||
add_definitions(-DHAVE_DEV_URANDOM)
|
||||
endif()
|
||||
|
||||
# clock_gettime
|
||||
if(NOT HAVE_CLOCK_GETTIME)
|
||||
check_function_exists(clock_gettime HAVE_CLOCK_GETTIME)
|
||||
if(HAVE_CLOCK_GETTIME)
|
||||
add_definitions(-DHAVE_CLOCK_GETTIME)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# timespecsub
|
||||
check_symbol_exists(timespecsub sys/time.h HAVE_TIMESPECSUB)
|
||||
if(HAVE_TIMESPECSUB)
|
||||
add_definitions(-DHAVE_TIMESPECSUB)
|
||||
endif()
|
||||
|
||||
# export list
|
||||
if(APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR
|
||||
CMAKE_C_COMPILER_ID STREQUAL "AppleClang"))
|
||||
|
@ -368,28 +328,47 @@ endif()
|
|||
include_directories(${CMAKE_SOURCE_DIR}/src)
|
||||
include_directories(${CBOR_INCLUDE_DIRS})
|
||||
include_directories(${CRYPTO_INCLUDE_DIRS})
|
||||
include_directories(${HIDAPI_INCLUDE_DIRS})
|
||||
include_directories(${UDEV_INCLUDE_DIRS})
|
||||
include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
|
||||
link_directories(${CBOR_LIBRARY_DIRS})
|
||||
link_directories(${CRYPTO_LIBRARY_DIRS})
|
||||
link_directories(${HIDAPI_LIBRARY_DIRS})
|
||||
link_directories(${UDEV_LIBRARY_DIRS})
|
||||
link_directories(${ZLIB_LIBRARY_DIRS})
|
||||
|
||||
message(STATUS "BASE_LIBRARIES: ${BASE_LIBRARIES}")
|
||||
message(STATUS "BUILD_EXAMPLES: ${BUILD_EXAMPLES}")
|
||||
message(STATUS "BUILD_MANPAGES: ${BUILD_MANPAGES}")
|
||||
message(STATUS "BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}")
|
||||
message(STATUS "BUILD_STATIC_LIBS: ${BUILD_STATIC_LIBS}")
|
||||
message(STATUS "BUILD_TOOLS: ${BUILD_TOOLS}")
|
||||
message(STATUS "CBOR_INCLUDE_DIRS: ${CBOR_INCLUDE_DIRS}")
|
||||
message(STATUS "CBOR_LIBRARIES: ${CBOR_LIBRARIES}")
|
||||
message(STATUS "CBOR_LIBRARY_DIRS: ${CBOR_LIBRARY_DIRS}")
|
||||
message(STATUS "CBOR_VERSION: ${CBOR_VERSION}")
|
||||
message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
|
||||
message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}")
|
||||
message(STATUS "CMAKE_C_COMPILER_ID: ${CMAKE_C_COMPILER_ID}")
|
||||
message(STATUS "CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}")
|
||||
message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}")
|
||||
message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
|
||||
message(STATUS "CRYPTO_INCLUDE_DIRS: ${CRYPTO_INCLUDE_DIRS}")
|
||||
message(STATUS "CRYPTO_LIBRARIES: ${CRYPTO_LIBRARIES}")
|
||||
message(STATUS "CRYPTO_LIBRARY_DIRS: ${CRYPTO_LIBRARY_DIRS}")
|
||||
message(STATUS "CRYPTO_VERSION: ${CRYPTO_VERSION}")
|
||||
message(STATUS "FIDO_VERSION: ${FIDO_VERSION}")
|
||||
message(STATUS "FUZZ: ${FUZZ}")
|
||||
message(STATUS "ZLIB_INCLUDE_DIRS: ${ZLIB_INCLUDE_DIRS}")
|
||||
message(STATUS "ZLIB_LIBRARIES: ${ZLIB_LIBRARIES}")
|
||||
message(STATUS "ZLIB_LIBRARY_DIRS: ${ZLIB_LIBRARY_DIRS}")
|
||||
message(STATUS "ZLIB_VERSION: ${ZLIB_VERSION}")
|
||||
if(USE_HIDAPI)
|
||||
message(STATUS "HIDAPI_INCLUDE_DIRS: ${HIDAPI_INCLUDE_DIRS}")
|
||||
message(STATUS "HIDAPI_LIBRARIES: ${HIDAPI_LIBRARIES}")
|
||||
message(STATUS "HIDAPI_LIBRARY_DIRS: ${HIDAPI_LIBRARY_DIRS}")
|
||||
message(STATUS "HIDAPI_VERSION: ${HIDAPI_VERSION}")
|
||||
endif()
|
||||
message(STATUS "LIBFUZZER: ${LIBFUZZER}")
|
||||
message(STATUS "TLS: ${TLS}")
|
||||
|
@ -397,12 +376,20 @@ 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 "NFC_LINUX: ${NFC_LINUX}")
|
||||
|
||||
subdirs(src)
|
||||
subdirs(examples)
|
||||
subdirs(tools)
|
||||
subdirs(man)
|
||||
if(BUILD_EXAMPLES)
|
||||
subdirs(examples)
|
||||
endif()
|
||||
if(BUILD_TOOLS)
|
||||
subdirs(tools)
|
||||
endif()
|
||||
if(BUILD_MANPAGES)
|
||||
subdirs(man)
|
||||
endif()
|
||||
|
||||
if(NOT WIN32)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
|
@ -413,7 +400,6 @@ if(NOT WIN32)
|
|||
if(FUZZ)
|
||||
subdirs(fuzz)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
subdirs(udev)
|
||||
endif()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2018 Yubico AB. All rights reserved.
|
||||
Copyright (c) 2018-2021 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
|
||||
|
|
|
@ -1,3 +1,52 @@
|
|||
* 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:
|
||||
|
|
|
@ -21,7 +21,7 @@ file for the full license text.
|
|||
|
||||
=== Supported Platforms
|
||||
|
||||
*libfido2* is known to work on Linux, MacOS, Windows, and OpenBSD.
|
||||
*libfido2* is known to work on Linux, MacOS, Windows, OpenBSD, and FreeBSD.
|
||||
|
||||
=== Documentation
|
||||
|
||||
|
@ -29,11 +29,18 @@ Documentation is available in troff and HTML formats. An
|
|||
https://developers.yubico.com/libfido2/Manuals/[online mirror of *libfido2*'s documentation]
|
||||
is also available.
|
||||
|
||||
=== Bindings
|
||||
|
||||
* .NET: https://github.com/borrrden/Fido2Net[Fido2Net]
|
||||
* Go: https://github.com/keys-pub/go-libfido2[go-libfido2]
|
||||
* Perl: https://github.com/jacquesg/p5-FIDO-Raw[p5-FIDO-Raw]
|
||||
* Rust: https://github.com/PvdBerg1998/libfido2[libfido2]
|
||||
|
||||
=== Installation
|
||||
|
||||
==== Releases
|
||||
|
||||
The current release of *libfido2* is 1.5.0. Please consult Yubico's
|
||||
The current release of *libfido2* is 1.7.0. Please consult Yubico's
|
||||
https://developers.yubico.com/libfido2/Releases[release page] for source
|
||||
and binary releases.
|
||||
|
||||
|
@ -43,6 +50,9 @@ and binary releases.
|
|||
$ sudo apt install libfido2-dev
|
||||
$ sudo apt install libfido2-doc
|
||||
|
||||
Alternatively, newer versions of *libfido2* are available in Yubico's PPA.
|
||||
Follow the instructions for Ubuntu 18.04 (Bionic) and 16.04 (Xenial) below.
|
||||
|
||||
==== Ubuntu 18.04 (Bionic) and 16.04 (Xenial)
|
||||
|
||||
$ sudo apt install software-properties-common
|
||||
|
@ -64,9 +74,10 @@ 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] and
|
||||
https://www.openssl.org[OpenSSL]. On Linux, libudev (part of
|
||||
https://www.freedesktop.org/wiki/Software/systemd[systemd]) is also required.
|
||||
*libfido2* depends on https://github.com/pjk/libcbor[libcbor],
|
||||
https://www.openssl.org[OpenSSL], 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.
|
||||
|
|
|
@ -9,12 +9,20 @@ list(APPEND COMPAT_SOURCES
|
|||
../openbsd-compat/strlcpy.c
|
||||
)
|
||||
|
||||
if(WIN32 AND NOT CYGWIN AND NOT MSYS)
|
||||
if(WIN32 AND BUILD_SHARED_LIBS AND NOT CYGWIN AND NOT MSYS)
|
||||
list(APPEND COMPAT_SOURCES ../openbsd-compat/posix_win.c)
|
||||
endif()
|
||||
|
||||
# drop -rdynamic
|
||||
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
||||
# 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)
|
||||
|
@ -25,35 +33,36 @@ endif()
|
|||
|
||||
# manifest
|
||||
add_executable(manifest manifest.c ${COMPAT_SOURCES})
|
||||
target_link_libraries(manifest fido2)
|
||||
target_link_libraries(manifest ${_FIDO2_LIBRARY})
|
||||
|
||||
# info
|
||||
add_executable(info info.c ${COMPAT_SOURCES})
|
||||
target_link_libraries(info fido2)
|
||||
target_link_libraries(info ${_FIDO2_LIBRARY})
|
||||
|
||||
# reset
|
||||
add_executable(reset reset.c util.c ${COMPAT_SOURCES})
|
||||
target_link_libraries(reset fido2)
|
||||
target_link_libraries(reset ${_FIDO2_LIBRARY})
|
||||
|
||||
# cred
|
||||
add_executable(cred cred.c util.c ${COMPAT_SOURCES})
|
||||
target_link_libraries(cred fido2)
|
||||
target_link_libraries(cred ${_FIDO2_LIBRARY})
|
||||
|
||||
# assert
|
||||
add_executable(assert assert.c util.c ${COMPAT_SOURCES})
|
||||
target_link_libraries(assert fido2)
|
||||
target_link_libraries(assert ${_FIDO2_LIBRARY})
|
||||
|
||||
# setpin
|
||||
add_executable(setpin setpin.c ${COMPAT_SOURCES})
|
||||
target_link_libraries(setpin fido2)
|
||||
target_link_libraries(setpin ${_FIDO2_LIBRARY})
|
||||
|
||||
# retries
|
||||
add_executable(retries retries.c ${COMPAT_SOURCES})
|
||||
target_link_libraries(retries fido2)
|
||||
target_link_libraries(retries ${_FIDO2_LIBRARY})
|
||||
|
||||
# select
|
||||
add_executable(select select.c ${COMPAT_SOURCES})
|
||||
target_link_libraries(select fido2)
|
||||
target_link_libraries(select ${_FIDO2_LIBRARY})
|
||||
|
||||
if(MINGW)
|
||||
# needed for nanosleep() in mingw
|
||||
target_link_libraries(select winpthread)
|
||||
|
|
|
@ -23,6 +23,10 @@ The following definitions are used in the description below:
|
|||
The file system path of a file containing a NIST P-256 public key in
|
||||
PEM format.
|
||||
|
||||
- <blobkey>
|
||||
|
||||
A credential's associated FIDO2.1 "largeBlob" symmetric key.
|
||||
|
||||
=== Description
|
||||
|
||||
The following examples are provided:
|
||||
|
@ -45,7 +49,7 @@ The following examples are provided:
|
|||
the device's PIN is changed from [oldpin] to <pin>.
|
||||
|
||||
- cred [-t ecdsa|rsa|eddsa] [-k pubkey] [-ei cred_id] [-P pin] [-T seconds]
|
||||
[-hruv] <device>
|
||||
[-b blobkey] [-hruv] <device>
|
||||
|
||||
Creates a new credential on <device> and verify that the credential
|
||||
was signed by the authenticator. The device's attestation certificate
|
||||
|
@ -58,10 +62,12 @@ The following examples are provided:
|
|||
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 <seconds>.
|
||||
The -T option may be used to enforce a timeout of <seconds>. If the
|
||||
option -b is specified, the credential's "largeBlob" key is stored in
|
||||
<blobkey>.
|
||||
|
||||
- assert [-t ecdsa|rsa|eddsa] [-a cred_id] [-h hmac_secret] [-s hmac_salt]
|
||||
[-P pin] [-T seconds] [-puv] <pubkey> <device>
|
||||
[-P pin] [-T seconds] [-b blobkey] [-puv] <pubkey> <device>
|
||||
|
||||
Asks <device> for a FIDO2 assertion corresponding to [cred_id],
|
||||
which may be omitted for resident keys. The obtained assertion
|
||||
|
@ -72,7 +78,9 @@ The following examples are provided:
|
|||
specified, a FIDO2 hmac-secret is requested from the authenticator,
|
||||
and the contents of <hmac_salt> are used as the salt. If option -h
|
||||
is specified, the resulting hmac-secret is stored in <hmac_secret>.
|
||||
The -T option may be used to enforce a timeout of <seconds>.
|
||||
The -T option may be used to enforce a timeout of <seconds>. If the
|
||||
option -b specified, the credential's "largeBlob" key is stored in
|
||||
<blobkey>.
|
||||
|
||||
- retries <device>
|
||||
Get the number of PIN attempts left on <device> before lockout.
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <openssl/ec.h>
|
||||
#include <fido.h>
|
||||
#include <fido/es256.h>
|
||||
#include <fido/rs256.h>
|
||||
#include <fido/eddsa.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
@ -14,12 +17,8 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "fido.h"
|
||||
#include "fido/es256.h"
|
||||
#include "fido/rs256.h"
|
||||
#include "fido/eddsa.h"
|
||||
#include "extern.h"
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
#include "extern.h"
|
||||
|
||||
static const unsigned char cdh[32] = {
|
||||
0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7,
|
||||
|
@ -32,8 +31,8 @@ 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] [-puv] "
|
||||
"<pubkey> <device>\n");
|
||||
"[-h hmac_secret] [-s hmac_salt] [-P pin] [-T seconds] "
|
||||
"[-b blobkey] [-puv] <pubkey> <device>\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
@ -164,6 +163,7 @@ main(int argc, char **argv)
|
|||
fido_dev_t *dev = NULL;
|
||||
fido_assert_t *assert = NULL;
|
||||
const char *pin = NULL;
|
||||
const char *blobkey_out = NULL;
|
||||
const char *hmac_out = NULL;
|
||||
unsigned char *body = NULL;
|
||||
long long seconds = 0;
|
||||
|
@ -176,7 +176,7 @@ main(int argc, char **argv)
|
|||
if ((assert = fido_assert_new()) == NULL)
|
||||
errx(1, "fido_assert_new");
|
||||
|
||||
while ((ch = getopt(argc, argv, "P:T:a:h:ps:t:uv")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "P:T:a:b:h:ps:t:uv")) != -1) {
|
||||
switch (ch) {
|
||||
case 'P':
|
||||
pin = optarg;
|
||||
|
@ -202,6 +202,10 @@ main(int argc, char **argv)
|
|||
free(body);
|
||||
body = NULL;
|
||||
break;
|
||||
case 'b':
|
||||
ext |= FIDO_EXT_LARGEBLOB_KEY;
|
||||
blobkey_out = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
hmac_out = optarg;
|
||||
break;
|
||||
|
@ -209,7 +213,7 @@ main(int argc, char **argv)
|
|||
up = true;
|
||||
break;
|
||||
case 's':
|
||||
ext = FIDO_EXT_HMAC_SECRET;
|
||||
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,
|
||||
|
@ -324,6 +328,14 @@ main(int argc, char **argv)
|
|||
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);
|
||||
|
|
|
@ -4,10 +4,8 @@
|
|||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fido.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -16,9 +14,8 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "fido.h"
|
||||
#include "extern.h"
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
#include "extern.h"
|
||||
|
||||
static const unsigned char cdh[32] = {
|
||||
0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb,
|
||||
|
@ -38,7 +35,8 @@ static void
|
|||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: cred [-t ecdsa|rsa|eddsa] [-k pubkey] "
|
||||
"[-ei cred_id] [-P pin] [-T seconds] [-hruv] <device>\n");
|
||||
"[-ei cred_id] [-P pin] [-T seconds] [-b blobkey] [-hruv] "
|
||||
"<device>\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
@ -164,6 +162,7 @@ main(int argc, char **argv)
|
|||
fido_dev_t *dev;
|
||||
fido_cred_t *cred = NULL;
|
||||
const char *pin = NULL;
|
||||
const char *blobkey_out = NULL;
|
||||
const char *key_out = NULL;
|
||||
const char *id_out = NULL;
|
||||
const char *path = NULL;
|
||||
|
@ -180,7 +179,7 @@ main(int argc, char **argv)
|
|||
if ((cred = fido_cred_new()) == NULL)
|
||||
errx(1, "fido_cred_new");
|
||||
|
||||
while ((ch = getopt(argc, argv, "P:T:e:hi:k:rt:uv")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "P:T:b:e:hi:k:rt:uv")) != -1) {
|
||||
switch (ch) {
|
||||
case 'P':
|
||||
pin = optarg;
|
||||
|
@ -196,6 +195,10 @@ main(int argc, char **argv)
|
|||
errx(1, "-T: %s must be in (0,30]", optarg);
|
||||
break;
|
||||
#endif
|
||||
case 'b':
|
||||
ext |= FIDO_EXT_LARGEBLOB_KEY;
|
||||
blobkey_out = optarg;
|
||||
break;
|
||||
case 'e':
|
||||
if (read_blob(optarg, &body, &len) < 0)
|
||||
errx(1, "read_blob: %s", optarg);
|
||||
|
@ -207,7 +210,7 @@ main(int argc, char **argv)
|
|||
body = NULL;
|
||||
break;
|
||||
case 'h':
|
||||
ext = FIDO_EXT_HMAC_SECRET;
|
||||
ext |= FIDO_EXT_HMAC_SECRET;
|
||||
break;
|
||||
case 'i':
|
||||
id_out = optarg;
|
||||
|
@ -324,6 +327,13 @@ main(int argc, char **argv)
|
|||
fido_cred_x5c_len(cred), fido_cred_sig_ptr(cred),
|
||||
fido_cred_sig_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);
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <fido.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fido.h"
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
|
||||
/*
|
||||
|
|
|
@ -4,11 +4,10 @@
|
|||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <fido.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "fido.h"
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
|
||||
int
|
||||
|
|
|
@ -8,14 +8,12 @@
|
|||
* Perform a factory reset on a given authenticator.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <fido.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "fido.h"
|
||||
#include "extern.h"
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
#include "extern.h"
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
|
|
|
@ -8,11 +8,10 @@
|
|||
* Get an authenticator's number of PIN attempts left.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <fido.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "fido.h"
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
|
||||
int
|
||||
|
|
|
@ -5,12 +5,11 @@
|
|||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <fido.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "fido.h"
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
|
||||
#define FIDO_POLL_MS 50
|
||||
|
|
|
@ -8,12 +8,10 @@
|
|||
* Configure a PIN on a given authenticator.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <fido.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "fido.h"
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
|
||||
static void
|
||||
|
|
|
@ -11,10 +11,14 @@
|
|||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include <fido.h>
|
||||
#include <fido/es256.h>
|
||||
#include <fido/rs256.h>
|
||||
#include <fido/eddsa.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
|
@ -26,13 +30,8 @@
|
|||
#ifdef _MSC_VER
|
||||
#include "../openbsd-compat/posix_win.h"
|
||||
#endif
|
||||
|
||||
#include "fido.h"
|
||||
#include "fido/es256.h"
|
||||
#include "fido/rs256.h"
|
||||
#include "fido/eddsa.h"
|
||||
#include "extern.h"
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
#include "extern.h"
|
||||
|
||||
#ifdef SIGNAL_EXAMPLE
|
||||
volatile sig_atomic_t got_signal = 0;
|
||||
|
@ -81,7 +80,7 @@ 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, 0644)) < 0) {
|
||||
if ((fd = open(path, O_WRONLY | O_CREAT, 0600)) < 0) {
|
||||
warn("open %s", path);
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ list(APPEND COMMON_SOURCES
|
|||
mutator_aux.c
|
||||
)
|
||||
|
||||
set(FUZZ_LDFLAGS "-fsanitize=fuzzer")
|
||||
|
||||
# fuzz_cred
|
||||
add_executable(fuzz_cred fuzz_cred.c ${COMMON_SOURCES} ${COMPAT_SOURCES})
|
||||
target_compile_options(fuzz_cred PRIVATE ${FUZZ_LDFLAGS})
|
||||
|
@ -41,3 +43,21 @@ 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})
|
||||
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})
|
||||
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})
|
||||
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})
|
||||
target_link_libraries(fuzz_largeblob fido2_shared)
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
FROM ubuntu:focal
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y clang-10 cmake git libssl-dev libudev-dev make pkg-config
|
||||
RUN git clone --branch v0.7.0 https://github.com/PJK/libcbor
|
||||
RUN apt-get install -y clang-11 cmake git libssl-dev libudev-dev make pkg-config
|
||||
RUN apt-get install -y zlib1g-dev
|
||||
RUN git clone --branch v0.8.0 https://github.com/PJK/libcbor
|
||||
RUN git clone https://github.com/yubico/libfido2
|
||||
RUN CC=clang-10 CXX=clang++-10 /libfido2/fuzz/build-coverage /libcbor /libfido2
|
||||
RUN CC=clang-11 CXX=clang++-11 /libfido2/fuzz/build-coverage /libcbor /libfido2
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
IMAGE := libfido2-coverage:1.5.0
|
||||
IMAGE := libfido2-coverage:1.7.0
|
||||
RUNNER := libfido2-runner
|
||||
PROFDATA := llvm-profdata-10
|
||||
COV := llvm-cov-10
|
||||
TARGETS := fuzz_assert fuzz_bio fuzz_cred fuzz_credman fuzz_mgmt
|
||||
PROFDATA := llvm-profdata-11
|
||||
COV := llvm-cov-11
|
||||
TARGETS := fuzz_assert fuzz_bio fuzz_cred fuzz_credman fuzz_hid \
|
||||
fuzz_largeblob fuzz_netlink fuzz_mgmt
|
||||
CORPORA := $(foreach f,${TARGETS},${f}/corpus)
|
||||
MINIFY := $(foreach f,${TARGETS},/minify/${f}/corpus)
|
||||
REMOTE := gs://libfido2-corpus.clusterfuzz-external.appspot.com
|
||||
|
|
|
@ -3,12 +3,12 @@ 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=1, and
|
||||
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, and fuzz_mgmt.c for examples. To build these harnesses,
|
||||
use -DFUZZ=1 -DLIBFUZZER=1.
|
||||
fuzz_assert.c, fuzz_hid.c, and fuzz_mgmt.c for examples. To build these
|
||||
harnesses, use -DFUZZ=ON -DLIBFUZZER=ON.
|
||||
|
||||
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
|
||||
|
|
|
@ -18,13 +18,14 @@ 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 -DCMAKE_INSTALL_PREFIX="${LIBCBOR}/install" ..)
|
||||
make -C "${LIBCBOR}/build" all 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 LDFLAGS="${CFLAGS}"
|
||||
(cd "${LIBFIDO2}/build" && cmake -DFUZZ=1 -DLIBFUZZER=1 \
|
||||
(cd "${LIBFIDO2}/build" && cmake -DFUZZ=ON -DLIBFUZZER=ON \
|
||||
-DCMAKE_BUILD_TYPE=Debug ..)
|
||||
make -C "${LIBFIDO2}/build"
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
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;
|
||||
|
@ -22,6 +24,8 @@
|
|||
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;
|
||||
|
@ -30,6 +34,7 @@
|
|||
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;
|
||||
|
@ -76,6 +81,7 @@
|
|||
fido_cbor_info_extensions_ptr;
|
||||
fido_cbor_info_free;
|
||||
fido_cbor_info_maxmsgsiz;
|
||||
fido_cbor_info_maxcredbloblen;
|
||||
fido_cbor_info_maxcredcntlst;
|
||||
fido_cbor_info_maxcredidlen;
|
||||
fido_cbor_info_fwversion;
|
||||
|
@ -89,11 +95,16 @@
|
|||
fido_cbor_info_versions_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;
|
||||
|
@ -127,6 +138,7 @@
|
|||
fido_cred_rp_name;
|
||||
fido_cred_set_authdata;
|
||||
fido_cred_set_authdata_raw;
|
||||
fido_cred_set_blob;
|
||||
fido_cred_set_clientdata_hash;
|
||||
fido_cred_set_extensions;
|
||||
fido_cred_set_fmt;
|
||||
|
@ -152,16 +164,20 @@
|
|||
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;
|
||||
|
@ -181,10 +197,28 @@
|
|||
fido_dev_reset;
|
||||
fido_dev_set_io_functions;
|
||||
fido_dev_set_pin;
|
||||
fido_dev_set_pin_minlen;
|
||||
fido_dev_set_transport_functions;
|
||||
fido_dev_supports_cred_prot;
|
||||
fido_dev_supports_credman;
|
||||
fido_dev_supports_permissions;
|
||||
fido_dev_supports_pin;
|
||||
fido_dev_supports_uv;
|
||||
fido_dev_toggle_always_uv;
|
||||
fido_dev_largeblob_get;
|
||||
fido_dev_largeblob_get_array;
|
||||
fido_dev_largeblob_remove;
|
||||
fido_dev_largeblob_set;
|
||||
fido_dev_largeblob_set_array;
|
||||
fido_hid_get_report_len;
|
||||
fido_hid_get_usage;
|
||||
fido_init;
|
||||
fido_nfc_rx;
|
||||
fido_nfc_tx;
|
||||
fido_nl_free;
|
||||
fido_nl_get_nfc_target;
|
||||
fido_nl_new;
|
||||
fido_nl_power_nfc;
|
||||
fido_set_log_handler;
|
||||
fido_strerr;
|
||||
rs256_pk_free;
|
||||
|
@ -193,6 +227,7 @@
|
|||
rs256_pk_new;
|
||||
rs256_pk_to_EVP_PKEY;
|
||||
prng_init;
|
||||
set_netlink_io_functions;
|
||||
uniform_random;
|
||||
local:
|
||||
*;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,22 +5,16 @@
|
|||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mutator_aux.h"
|
||||
#include "wiredata_fido2.h"
|
||||
#include "wiredata_u2f.h"
|
||||
#include "dummy.h"
|
||||
|
||||
#include "fido.h"
|
||||
#include "fido/es256.h"
|
||||
#include "fido/rs256.h"
|
||||
#include "fido/eddsa.h"
|
||||
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
|
||||
/* Parameter set defining a FIDO2 get assertion operation. */
|
||||
|
@ -37,7 +31,7 @@ struct param {
|
|||
struct blob wire_data;
|
||||
uint8_t cred_count;
|
||||
uint8_t type;
|
||||
uint8_t u2f;
|
||||
uint8_t opt;
|
||||
uint8_t up;
|
||||
uint8_t uv;
|
||||
};
|
||||
|
@ -86,7 +80,7 @@ unpack(const uint8_t *ptr, size_t len)
|
|||
|
||||
if (unpack_byte(v[0], &p->uv) < 0 ||
|
||||
unpack_byte(v[1], &p->up) < 0 ||
|
||||
unpack_byte(v[2], &p->u2f) < 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 ||
|
||||
|
@ -126,7 +120,7 @@ pack(uint8_t *ptr, size_t len, const struct param *p)
|
|||
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->u2f)) == 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 ||
|
||||
|
@ -208,33 +202,25 @@ pack_dummy(uint8_t *ptr, size_t len)
|
|||
}
|
||||
|
||||
static void
|
||||
get_assert(fido_assert_t *assert, uint8_t u2f, const struct blob *cdh,
|
||||
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;
|
||||
fido_dev_io_t io;
|
||||
|
||||
memset(&io, 0, sizeof(io));
|
||||
|
||||
io.open = dev_open;
|
||||
io.close = dev_close;
|
||||
io.read = dev_read;
|
||||
io.write = dev_write;
|
||||
|
||||
if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
|
||||
&io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
|
||||
fido_dev_free(&dev);
|
||||
if ((dev = open_dev(opt & 2)) == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
if (u2f & 1)
|
||||
if (opt & 1)
|
||||
fido_dev_force_u2f(dev);
|
||||
if (ext & 1)
|
||||
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 (u2f &1)
|
||||
else if (opt & 1)
|
||||
fido_assert_set_up(assert, FIDO_OPT_FALSE);
|
||||
if (uv & 1)
|
||||
fido_assert_set_uv(assert, FIDO_OPT_TRUE);
|
||||
|
@ -255,7 +241,7 @@ get_assert(fido_assert_t *assert, uint8_t u2f, const struct blob *cdh,
|
|||
if (strlen(pin) == 0)
|
||||
pin = NULL;
|
||||
|
||||
fido_dev_get_assert(dev, assert, u2f & 1 ? NULL : pin);
|
||||
fido_dev_get_assert(dev, assert, (opt & 1) ? NULL : pin);
|
||||
|
||||
fido_dev_cancel(dev);
|
||||
fido_dev_close(dev);
|
||||
|
@ -408,7 +394,7 @@ test(const struct param *p)
|
|||
|
||||
set_wire_data(p->wire_data.body, p->wire_data.len);
|
||||
|
||||
get_assert(assert, p->u2f, &p->cdh, p->rp_id, p->ext, p->up, p->uv,
|
||||
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 */
|
||||
|
@ -433,6 +419,10 @@ test(const struct param *p)
|
|||
xstrlen(fido_assert_user_name(assert, i)));
|
||||
consume(fido_assert_user_display_name(assert, i),
|
||||
xstrlen(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);
|
||||
|
@ -456,7 +446,7 @@ mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
|
|||
if (flags & MUTATE_PARAM) {
|
||||
mutate_byte(&p->uv);
|
||||
mutate_byte(&p->up);
|
||||
mutate_byte(&p->u2f);
|
||||
mutate_byte(&p->opt);
|
||||
mutate_byte(&p->type);
|
||||
mutate_byte(&p->cred_count);
|
||||
mutate_int(&p->ext);
|
||||
|
@ -470,7 +460,7 @@ mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
|
|||
}
|
||||
|
||||
if (flags & MUTATE_WIREDATA) {
|
||||
if (p->u2f & 1) {
|
||||
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);
|
||||
|
|
|
@ -6,17 +6,14 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mutator_aux.h"
|
||||
#include "wiredata_fido2.h"
|
||||
#include "dummy.h"
|
||||
|
||||
#include "fido.h"
|
||||
#include "fido/bio.h"
|
||||
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
|
||||
/* Parameter set defining a FIDO2 credential management operation. */
|
||||
|
@ -223,21 +220,10 @@ static fido_dev_t *
|
|||
prepare_dev(void)
|
||||
{
|
||||
fido_dev_t *dev;
|
||||
fido_dev_io_t io;
|
||||
bool x;
|
||||
|
||||
memset(&io, 0, sizeof(io));
|
||||
|
||||
io.open = dev_open;
|
||||
io.close = dev_close;
|
||||
io.read = dev_read;
|
||||
io.write = dev_write;
|
||||
|
||||
if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
|
||||
&io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
|
||||
fido_dev_free(&dev);
|
||||
if ((dev = open_dev(0)) == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
x = fido_dev_is_fido2(dev);
|
||||
consume(&x, sizeof(x));
|
||||
|
@ -245,6 +231,10 @@ prepare_dev(void)
|
|||
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;
|
||||
}
|
||||
|
@ -313,7 +303,7 @@ enroll(const struct param *p)
|
|||
(e = fido_bio_enroll_new()) == NULL)
|
||||
goto done;
|
||||
|
||||
fido_bio_dev_enroll_begin(dev, t, e, p->seed, p->pin);
|
||||
fido_bio_dev_enroll_begin(dev, t, e, (uint32_t)p->seed, p->pin);
|
||||
|
||||
consume_template(t);
|
||||
consume_enroll(e);
|
||||
|
|
|
@ -6,15 +6,14 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mutator_aux.h"
|
||||
#include "wiredata_fido2.h"
|
||||
#include "wiredata_u2f.h"
|
||||
#include "dummy.h"
|
||||
#include "fido.h"
|
||||
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
|
||||
|
@ -35,7 +34,7 @@ struct param {
|
|||
uint8_t excl_count;
|
||||
uint8_t rk;
|
||||
uint8_t type;
|
||||
uint8_t u2f;
|
||||
uint8_t opt;
|
||||
uint8_t uv;
|
||||
};
|
||||
|
||||
|
@ -87,7 +86,7 @@ unpack(const uint8_t *ptr, size_t len)
|
|||
|
||||
if (unpack_byte(v[0], &p->rk) < 0 ||
|
||||
unpack_byte(v[1], &p->type) < 0 ||
|
||||
unpack_byte(v[2], &p->u2f) < 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 ||
|
||||
|
@ -129,7 +128,7 @@ pack(uint8_t *ptr, size_t len, const struct param *p)
|
|||
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->u2f)) == 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 ||
|
||||
|
@ -211,29 +210,17 @@ pack_dummy(uint8_t *ptr, size_t len)
|
|||
}
|
||||
|
||||
static void
|
||||
make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh,
|
||||
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;
|
||||
fido_dev_io_t io;
|
||||
|
||||
memset(&io, 0, sizeof(io));
|
||||
|
||||
io.open = dev_open;
|
||||
io.close = dev_close;
|
||||
io.read = dev_read;
|
||||
io.write = dev_write;
|
||||
|
||||
if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
|
||||
&io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
|
||||
fido_dev_free(&dev);
|
||||
if ((dev = open_dev(opt & 2)) == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
if (u2f & 1)
|
||||
if (opt & 1)
|
||||
fido_dev_force_u2f(dev);
|
||||
|
||||
for (uint8_t i = 0; i < excl_count; i++)
|
||||
|
@ -244,7 +231,12 @@ make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh,
|
|||
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);
|
||||
fido_cred_set_extensions(cred, ext);
|
||||
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 (rk & 1)
|
||||
fido_cred_set_rk(cred, FIDO_OPT_TRUE);
|
||||
|
@ -263,7 +255,7 @@ make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh,
|
|||
if (strlen(pin) == 0)
|
||||
pin = NULL;
|
||||
|
||||
fido_dev_make_cred(dev, cred, u2f & 1 ? NULL : pin);
|
||||
fido_dev_make_cred(dev, cred, (opt & 1) ? NULL : pin);
|
||||
|
||||
fido_dev_cancel(dev);
|
||||
fido_dev_close(dev);
|
||||
|
@ -273,12 +265,14 @@ make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh,
|
|||
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, int ext, uint8_t rk, uint8_t uv,
|
||||
size_t authdata_len, const unsigned char *authdata_raw_ptr,
|
||||
size_t authdata_raw_len, int ext, uint8_t rk, uint8_t uv,
|
||||
const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr,
|
||||
size_t sig_len, const char *fmt, int prot)
|
||||
{
|
||||
fido_cred_t *cred;
|
||||
uint8_t flags;
|
||||
uint32_t sigcount;
|
||||
|
||||
if ((cred = fido_cred_new()) == NULL)
|
||||
return;
|
||||
|
@ -286,8 +280,11 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len,
|
|||
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);
|
||||
if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK)
|
||||
fido_cred_set_authdata_raw(cred, authdata_ptr, authdata_len);
|
||||
fido_cred_set_authdata_raw(cred, authdata_raw_ptr,
|
||||
authdata_raw_len);
|
||||
fido_cred_set_extensions(cred, ext);
|
||||
fido_cred_set_x509(cred, x5c_ptr, x5c_len);
|
||||
fido_cred_set_sig(cred, sig_ptr, sig_len);
|
||||
|
@ -316,9 +313,13 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len,
|
|||
consume(fido_cred_user_name(cred), xstrlen(fido_cred_user_name(cred)));
|
||||
consume(fido_cred_display_name(cred),
|
||||
xstrlen(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));
|
||||
|
||||
|
@ -348,7 +349,7 @@ test_cred(const struct param *p)
|
|||
|
||||
set_wire_data(p->wire_data.body, p->wire_data.len);
|
||||
|
||||
make_cred(cred, p->u2f, cose_alg, &p->cdh, p->rp_id, p->rp_name,
|
||||
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);
|
||||
|
||||
|
@ -356,7 +357,8 @@ test_cred(const struct param *p)
|
|||
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), p->ext, p->rk, p->uv,
|
||||
fido_cred_authdata_len(cred), fido_cred_authdata_raw_ptr(cred),
|
||||
fido_cred_authdata_raw_len(cred), p->ext, p->rk, p->uv,
|
||||
fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred),
|
||||
fido_cred_sig_ptr(cred), fido_cred_sig_len(cred),
|
||||
fido_cred_fmt(cred), fido_cred_prot(cred));
|
||||
|
@ -368,26 +370,14 @@ static void
|
|||
test_touch(const struct param *p)
|
||||
{
|
||||
fido_dev_t *dev;
|
||||
fido_dev_io_t io;
|
||||
int r;
|
||||
int touched;
|
||||
|
||||
memset(&io, 0, sizeof(io));
|
||||
|
||||
io.open = dev_open;
|
||||
io.close = dev_close;
|
||||
io.read = dev_read;
|
||||
io.write = dev_write;
|
||||
|
||||
set_wire_data(p->wire_data.body, p->wire_data.len);
|
||||
|
||||
if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
|
||||
&io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
|
||||
fido_dev_free(&dev);
|
||||
if ((dev = open_dev(p->opt & 2)) == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
if (p->u2f & 1)
|
||||
if (p->opt & 1)
|
||||
fido_dev_force_u2f(dev);
|
||||
|
||||
r = fido_dev_get_touch_begin(dev);
|
||||
|
@ -421,7 +411,7 @@ mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
|
|||
if (flags & MUTATE_PARAM) {
|
||||
mutate_byte(&p->rk);
|
||||
mutate_byte(&p->type);
|
||||
mutate_byte(&p->u2f);
|
||||
mutate_byte(&p->opt);
|
||||
mutate_byte(&p->uv);
|
||||
mutate_byte(&p->excl_count);
|
||||
mutate_int(&p->ext);
|
||||
|
@ -437,7 +427,7 @@ mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
|
|||
}
|
||||
|
||||
if (flags & MUTATE_WIREDATA) {
|
||||
if (p->u2f & 1) {
|
||||
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);
|
||||
|
|
|
@ -6,17 +6,14 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mutator_aux.h"
|
||||
#include "wiredata_fido2.h"
|
||||
#include "dummy.h"
|
||||
|
||||
#include "fido.h"
|
||||
#include "fido/credman.h"
|
||||
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
|
||||
/* Parameter set defining a FIDO2 credential management operation. */
|
||||
|
@ -207,26 +204,17 @@ static fido_dev_t *
|
|||
prepare_dev(void)
|
||||
{
|
||||
fido_dev_t *dev;
|
||||
fido_dev_io_t io;
|
||||
bool x;
|
||||
|
||||
memset(&io, 0, sizeof(io));
|
||||
|
||||
io.open = dev_open;
|
||||
io.close = dev_close;
|
||||
io.read = dev_read;
|
||||
io.write = dev_write;
|
||||
|
||||
if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
|
||||
&io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
|
||||
fido_dev_free(&dev);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
#include "mutator_aux.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 *);
|
||||
|
||||
struct param {
|
||||
int seed;
|
||||
struct blob report_descriptor;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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
|
||||
};
|
||||
|
||||
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) != 2 ||
|
||||
(v = cbor_array_handle(item)) == NULL)
|
||||
goto fail;
|
||||
|
||||
if (unpack_int(v[0], &p->seed) < 0 ||
|
||||
unpack_blob(v[1], &p->report_descriptor) < 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[2], *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(2)) == NULL ||
|
||||
(argv[0] = pack_int(p->seed)) == NULL ||
|
||||
(argv[1] = pack_blob(&p->report_descriptor)) == NULL)
|
||||
goto fail;
|
||||
|
||||
for (size_t i = 0; i < 2; i++)
|
||||
if (cbor_array_push(array, argv[i]) == false)
|
||||
goto fail;
|
||||
|
||||
if ((cbor_len = cbor_serialize_alloc(array, &cbor,
|
||||
&cbor_alloc_len)) > len) {
|
||||
cbor_len = 0;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(ptr, cbor, cbor_len);
|
||||
fail:
|
||||
for (size_t i = 0; i < 2; i++)
|
||||
if (argv[i])
|
||||
cbor_decref(&argv[i]);
|
||||
|
||||
if (array)
|
||||
cbor_decref(&array);
|
||||
|
||||
free(cbor);
|
||||
|
||||
return cbor_len;
|
||||
}
|
||||
|
||||
size_t
|
||||
pack_dummy(uint8_t *ptr, size_t len)
|
||||
{
|
||||
struct param dummy;
|
||||
uint8_t blob[4096];
|
||||
size_t blob_len;
|
||||
|
||||
memset(&dummy, 0, sizeof(dummy));
|
||||
|
||||
dummy.report_descriptor.len = sizeof(dummy_report_descriptor);
|
||||
memcpy(&dummy.report_descriptor.body, &dummy_report_descriptor,
|
||||
dummy.report_descriptor.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_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));
|
||||
}
|
||||
|
||||
void
|
||||
test(const struct param *p)
|
||||
{
|
||||
prng_init((unsigned int)p->seed);
|
||||
fido_init(FIDO_DEBUG);
|
||||
fido_set_log_handler(consume_str);
|
||||
|
||||
get_usage(p);
|
||||
get_report_len(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);
|
||||
}
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mutator_aux.h"
|
||||
#include "wiredata_fido2.h"
|
||||
#include "dummy.h"
|
||||
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
|
||||
/* Parameter set defining a FIDO2 "large blob" operation. */
|
||||
struct param {
|
||||
char pin[MAXSTR];
|
||||
int seed;
|
||||
struct blob key;
|
||||
struct blob get_wiredata;
|
||||
struct blob set_wiredata;
|
||||
};
|
||||
|
||||
/*
|
||||
* Collection of HID reports from an authenticator issued with a FIDO2
|
||||
* 'authenticatorLargeBlobs' 'get' command.
|
||||
*/
|
||||
static const uint8_t dummy_get_wiredata[] = {
|
||||
WIREDATA_CTAP_INIT,
|
||||
WIREDATA_CTAP_CBOR_INFO,
|
||||
WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY
|
||||
};
|
||||
|
||||
/*
|
||||
* Collection of HID reports from an authenticator issued with a FIDO2
|
||||
* 'authenticatorLargeBlobs' 'set' command.
|
||||
*/
|
||||
static const uint8_t dummy_set_wiredata[] = {
|
||||
WIREDATA_CTAP_INIT,
|
||||
WIREDATA_CTAP_CBOR_INFO,
|
||||
WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY,
|
||||
WIREDATA_CTAP_CBOR_AUTHKEY,
|
||||
WIREDATA_CTAP_CBOR_PINTOKEN,
|
||||
WIREDATA_CTAP_CBOR_STATUS
|
||||
};
|
||||
|
||||
/*
|
||||
* XXX this needs to match the encrypted blob embedded in
|
||||
* WIREDATA_CTAP_CBOR_LARGEBLOB_GET_ARRAY.
|
||||
*/
|
||||
static const uint8_t dummy_key[] = {
|
||||
0xa9, 0x1b, 0xc4, 0xdd, 0xfc, 0x9a, 0x93, 0x79,
|
||||
0x75, 0xba, 0xf7, 0x7f, 0x4d, 0x57, 0xfc, 0xa6,
|
||||
0xe1, 0xf8, 0x06, 0x43, 0x23, 0x99, 0x51, 0x32,
|
||||
0xce, 0x6e, 0x19, 0x84, 0x50, 0x13, 0x2d, 0x7b
|
||||
};
|
||||
|
||||
struct param *
|
||||
unpack(const uint8_t *ptr, size_t len)
|
||||
{
|
||||
cbor_item_t *item = NULL, **v;
|
||||
struct cbor_load_result cbor;
|
||||
struct param *p;
|
||||
int ok = -1;
|
||||
|
||||
if ((p = calloc(1, sizeof(*p))) == NULL ||
|
||||
(item = cbor_load(ptr, len, &cbor)) == NULL ||
|
||||
cbor.read != len ||
|
||||
cbor_isa_array(item) == false ||
|
||||
cbor_array_is_definite(item) == false ||
|
||||
cbor_array_size(item) != 5 ||
|
||||
(v = cbor_array_handle(item)) == NULL)
|
||||
goto fail;
|
||||
|
||||
if (unpack_int(v[0], &p->seed) < 0 ||
|
||||
unpack_string(v[1], p->pin) < 0 ||
|
||||
unpack_blob(v[2], &p->key) < 0 ||
|
||||
unpack_blob(v[3], &p->get_wiredata) < 0 ||
|
||||
unpack_blob(v[4], &p->set_wiredata) < 0)
|
||||
goto fail;
|
||||
|
||||
ok = 0;
|
||||
fail:
|
||||
if (ok < 0) {
|
||||
free(p);
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
if (item)
|
||||
cbor_decref(&item);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
size_t
|
||||
pack(uint8_t *ptr, size_t len, const struct param *p)
|
||||
{
|
||||
cbor_item_t *argv[5], *array = NULL;
|
||||
size_t cbor_alloc_len, cbor_len = 0;
|
||||
unsigned char *cbor = NULL;
|
||||
|
||||
memset(argv, 0, sizeof(argv));
|
||||
|
||||
if ((array = cbor_new_definite_array(5)) == NULL ||
|
||||
(argv[0] = pack_int(p->seed)) == NULL ||
|
||||
(argv[1] = pack_string(p->pin)) == NULL ||
|
||||
(argv[2] = pack_blob(&p->key)) == NULL ||
|
||||
(argv[3] = pack_blob(&p->get_wiredata)) == NULL ||
|
||||
(argv[4] = pack_blob(&p->set_wiredata)) == NULL)
|
||||
goto fail;
|
||||
|
||||
for (size_t i = 0; i < 5; i++)
|
||||
if (cbor_array_push(array, argv[i]) == false)
|
||||
goto fail;
|
||||
|
||||
if ((cbor_len = cbor_serialize_alloc(array, &cbor,
|
||||
&cbor_alloc_len)) > len) {
|
||||
cbor_len = 0;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(ptr, cbor, cbor_len);
|
||||
fail:
|
||||
for (size_t i = 0; i < 5; i++)
|
||||
if (argv[i])
|
||||
cbor_decref(&argv[i]);
|
||||
|
||||
if (array)
|
||||
cbor_decref(&array);
|
||||
|
||||
free(cbor);
|
||||
|
||||
return cbor_len;
|
||||
}
|
||||
|
||||
size_t
|
||||
pack_dummy(uint8_t *ptr, size_t len)
|
||||
{
|
||||
struct param dummy;
|
||||
uint8_t blob[4096];
|
||||
size_t blob_len;
|
||||
|
||||
memset(&dummy, 0, sizeof(dummy));
|
||||
|
||||
strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
|
||||
|
||||
dummy.get_wiredata.len = sizeof(dummy_get_wiredata);
|
||||
dummy.set_wiredata.len = sizeof(dummy_set_wiredata);
|
||||
dummy.key.len = sizeof(dummy_key);
|
||||
|
||||
memcpy(&dummy.get_wiredata.body, &dummy_get_wiredata,
|
||||
dummy.get_wiredata.len);
|
||||
memcpy(&dummy.set_wiredata.body, &dummy_set_wiredata,
|
||||
dummy.set_wiredata.len);
|
||||
memcpy(&dummy.key.body, &dummy_key, dummy.key.len);
|
||||
|
||||
assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
|
||||
|
||||
if (blob_len > len) {
|
||||
memcpy(ptr, blob, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
memcpy(ptr, blob, blob_len);
|
||||
|
||||
return blob_len;
|
||||
}
|
||||
|
||||
static fido_dev_t *
|
||||
prepare_dev(void)
|
||||
{
|
||||
fido_dev_t *dev;
|
||||
|
||||
if ((dev = open_dev(0)) == NULL)
|
||||
return NULL;
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void
|
||||
get_blob(const struct param *p, int array)
|
||||
{
|
||||
fido_dev_t *dev;
|
||||
u_char *ptr = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
set_wire_data(p->get_wiredata.body, p->get_wiredata.len);
|
||||
|
||||
if ((dev = prepare_dev()) == NULL)
|
||||
return;
|
||||
|
||||
if (array)
|
||||
fido_dev_largeblob_get_array(dev, &ptr, &len);
|
||||
else
|
||||
fido_dev_largeblob_get(dev, p->key.body, p->key.len, &ptr, &len);
|
||||
consume(ptr, len);
|
||||
free(ptr);
|
||||
|
||||
fido_dev_close(dev);
|
||||
fido_dev_free(&dev);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
set_blob(const struct param *p, int op)
|
||||
{
|
||||
fido_dev_t *dev;
|
||||
const char *pin;
|
||||
|
||||
set_wire_data(p->set_wiredata.body, p->set_wiredata.len);
|
||||
|
||||
if ((dev = prepare_dev()) == NULL)
|
||||
return;
|
||||
pin = p->pin;
|
||||
if (strlen(pin) == 0)
|
||||
pin = NULL;
|
||||
|
||||
switch (op) {
|
||||
case 0:
|
||||
fido_dev_largeblob_remove(dev, p->key.body, p->key.len, pin);
|
||||
break;
|
||||
case 1:
|
||||
/* XXX reuse p->get_wiredata as the blob to be set */
|
||||
fido_dev_largeblob_set(dev, p->key.body, p->key.len,
|
||||
p->get_wiredata.body, p->get_wiredata.len, pin);
|
||||
break;
|
||||
case 2:
|
||||
/* XXX reuse p->get_wiredata as the body of the cbor array */
|
||||
fido_dev_largeblob_set_array(dev, p->get_wiredata.body,
|
||||
p->get_wiredata.len, pin);
|
||||
}
|
||||
|
||||
fido_dev_close(dev);
|
||||
fido_dev_free(&dev);
|
||||
}
|
||||
|
||||
void
|
||||
test(const struct param *p)
|
||||
{
|
||||
prng_init((unsigned int)p->seed);
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -13,7 +13,6 @@
|
|||
#include "mutator_aux.h"
|
||||
#include "wiredata_fido2.h"
|
||||
#include "dummy.h"
|
||||
#include "fido.h"
|
||||
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
|
||||
|
@ -25,6 +24,7 @@ struct param {
|
|||
struct blob set_pin_wire_data;
|
||||
struct blob change_pin_wire_data;
|
||||
struct blob retry_wire_data;
|
||||
struct blob config_wire_data;
|
||||
int seed;
|
||||
};
|
||||
|
||||
|
@ -34,7 +34,7 @@ static const uint8_t dummy_reset_wire_data[] = {
|
|||
WIREDATA_CTAP_KEEPALIVE,
|
||||
WIREDATA_CTAP_KEEPALIVE,
|
||||
WIREDATA_CTAP_KEEPALIVE,
|
||||
WIREDATA_CTAP_CBOR_RESET,
|
||||
WIREDATA_CTAP_CBOR_STATUS,
|
||||
};
|
||||
|
||||
static const uint8_t dummy_info_wire_data[] = {
|
||||
|
@ -63,6 +63,12 @@ static const uint8_t dummy_retry_wire_data[] = {
|
|||
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)
|
||||
{
|
||||
|
@ -76,7 +82,7 @@ unpack(const uint8_t *ptr, size_t len)
|
|||
cbor.read != len ||
|
||||
cbor_isa_array(item) == false ||
|
||||
cbor_array_is_definite(item) == false ||
|
||||
cbor_array_size(item) != 8 ||
|
||||
cbor_array_size(item) != 9 ||
|
||||
(v = cbor_array_handle(item)) == NULL)
|
||||
goto fail;
|
||||
|
||||
|
@ -87,7 +93,8 @@ unpack(const uint8_t *ptr, size_t len)
|
|||
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[7], &p->retry_wire_data) < 0 ||
|
||||
unpack_blob(v[8], &p->config_wire_data) < 0)
|
||||
goto fail;
|
||||
|
||||
ok = 0;
|
||||
|
@ -106,13 +113,13 @@ fail:
|
|||
size_t
|
||||
pack(uint8_t *ptr, size_t len, const struct param *p)
|
||||
{
|
||||
cbor_item_t *argv[8], *array = NULL;
|
||||
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(8)) == NULL ||
|
||||
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 ||
|
||||
|
@ -120,10 +127,11 @@ pack(uint8_t *ptr, size_t len, const struct param *p)
|
|||
(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[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 < 8; i++)
|
||||
for (size_t i = 0; i < 9; i++)
|
||||
if (cbor_array_push(array, argv[i]) == false)
|
||||
goto fail;
|
||||
|
||||
|
@ -135,7 +143,7 @@ pack(uint8_t *ptr, size_t len, const struct param *p)
|
|||
|
||||
memcpy(ptr, cbor, cbor_len);
|
||||
fail:
|
||||
for (size_t i = 0; i < 8; i++)
|
||||
for (size_t i = 0; i < 9; i++)
|
||||
if (argv[i])
|
||||
cbor_decref(&argv[i]);
|
||||
|
||||
|
@ -164,6 +172,7 @@ pack_dummy(uint8_t *ptr, size_t len)
|
|||
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);
|
||||
|
@ -175,6 +184,8 @@ pack_dummy(uint8_t *ptr, size_t len)
|
|||
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);
|
||||
|
||||
|
@ -188,28 +199,6 @@ pack_dummy(uint8_t *ptr, size_t len)
|
|||
return blob_len;
|
||||
}
|
||||
|
||||
static fido_dev_t *
|
||||
prepare_dev(void)
|
||||
{
|
||||
fido_dev_t *dev;
|
||||
fido_dev_io_t io;
|
||||
|
||||
memset(&io, 0, sizeof(io));
|
||||
|
||||
io.open = dev_open;
|
||||
io.close = dev_close;
|
||||
io.read = dev_read;
|
||||
io.write = dev_write;
|
||||
|
||||
if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
|
||||
&io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
|
||||
fido_dev_free(&dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void
|
||||
dev_reset(const struct param *p)
|
||||
{
|
||||
|
@ -217,7 +206,7 @@ dev_reset(const struct param *p)
|
|||
|
||||
set_wire_data(p->reset_wire_data.body, p->reset_wire_data.len);
|
||||
|
||||
if ((dev = prepare_dev()) == NULL)
|
||||
if ((dev = open_dev(0)) == NULL)
|
||||
return;
|
||||
|
||||
fido_dev_reset(dev);
|
||||
|
@ -235,7 +224,7 @@ dev_get_cbor_info(const struct param *p)
|
|||
|
||||
set_wire_data(p->info_wire_data.body, p->info_wire_data.len);
|
||||
|
||||
if ((dev = prepare_dev()) == NULL)
|
||||
if ((dev = open_dev(0)) == NULL)
|
||||
return;
|
||||
|
||||
proto = fido_dev_protocol(dev);
|
||||
|
@ -275,6 +264,9 @@ dev_get_cbor_info(const struct param *p)
|
|||
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));
|
||||
|
||||
|
@ -302,7 +294,7 @@ dev_set_pin(const struct param *p)
|
|||
|
||||
set_wire_data(p->set_pin_wire_data.body, p->set_pin_wire_data.len);
|
||||
|
||||
if ((dev = prepare_dev()) == NULL)
|
||||
if ((dev = open_dev(0)) == NULL)
|
||||
return;
|
||||
|
||||
fido_dev_set_pin(dev, p->pin1, NULL);
|
||||
|
@ -317,7 +309,7 @@ dev_change_pin(const struct param *p)
|
|||
|
||||
set_wire_data(p->change_pin_wire_data.body, p->change_pin_wire_data.len);
|
||||
|
||||
if ((dev = prepare_dev()) == NULL)
|
||||
if ((dev = open_dev(0)) == NULL)
|
||||
return;
|
||||
|
||||
fido_dev_set_pin(dev, p->pin2, p->pin1);
|
||||
|
@ -333,7 +325,7 @@ dev_get_retry_count(const struct param *p)
|
|||
|
||||
set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len);
|
||||
|
||||
if ((dev = prepare_dev()) == NULL)
|
||||
if ((dev = open_dev(0)) == NULL)
|
||||
return;
|
||||
|
||||
fido_dev_get_retry_count(dev, &n);
|
||||
|
@ -342,6 +334,99 @@ dev_get_retry_count(const struct param *p)
|
|||
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);
|
||||
}
|
||||
|
||||
void
|
||||
test(const struct param *p)
|
||||
{
|
||||
|
@ -354,6 +439,11 @@ test(const struct param *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);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
#include "mutator_aux.h"
|
||||
|
||||
struct param {
|
||||
int seed;
|
||||
int dev;
|
||||
struct blob wiredata;
|
||||
};
|
||||
|
||||
/*
|
||||
* Sample netlink messages. These are unlikely to get the harness very far in
|
||||
* terms of coverage, but serve to give libFuzzer a sense of the underlying
|
||||
* structure.
|
||||
*/
|
||||
static const uint8_t sample_netlink_wiredata[] = {
|
||||
0xd8, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x9d, 0x2e, 0x00, 0x00,
|
||||
0x01, 0x02, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
|
||||
0x6e, 0x66, 0x63, 0x00, 0x06, 0x00, 0x01, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x05, 0x00,
|
||||
0x1f, 0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0x00,
|
||||
0x14, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
|
||||
0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00,
|
||||
0x08, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x03, 0x00, 0x08, 0x00, 0x01, 0x00,
|
||||
0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x04, 0x00,
|
||||
0x08, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x05, 0x00, 0x08, 0x00, 0x01, 0x00,
|
||||
0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x06, 0x00,
|
||||
0x08, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x07, 0x00, 0x08, 0x00, 0x01, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x08, 0x00,
|
||||
0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x09, 0x00, 0x08, 0x00, 0x01, 0x00,
|
||||
0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0a, 0x00,
|
||||
0x08, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x01, 0x00,
|
||||
0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0c, 0x00,
|
||||
0x08, 0x00, 0x01, 0x00, 0x15, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x01, 0x00,
|
||||
0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0e, 0x00,
|
||||
0x08, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x01, 0x00,
|
||||
0x1a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
|
||||
0x0c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x10, 0x00,
|
||||
0x08, 0x00, 0x01, 0x00, 0x1b, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x11, 0x00, 0x08, 0x00, 0x01, 0x00,
|
||||
0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00,
|
||||
0x08, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
|
||||
0x14, 0x00, 0x13, 0x00, 0x08, 0x00, 0x01, 0x00,
|
||||
0x1e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
|
||||
0x0a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x07, 0x00,
|
||||
0x18, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00,
|
||||
0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x00, 0x00,
|
||||
0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x9d, 0x2e, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x9d, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x05, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x1c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x09, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
|
||||
0x1e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x9d, 0x2e, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00,
|
||||
0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x05, 0x00, 0x44, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x06, 0x00, 0x20, 0x00, 0x00, 0x00,
|
||||
0x0b, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00,
|
||||
0x93, 0xb9, 0x25, 0x00
|
||||
};
|
||||
|
||||
struct param *
|
||||
unpack(const uint8_t *ptr, size_t len)
|
||||
{
|
||||
cbor_item_t *item = NULL, **v;
|
||||
struct cbor_load_result cbor;
|
||||
struct param *p;
|
||||
int ok = -1;
|
||||
|
||||
if ((p = calloc(1, sizeof(*p))) == NULL ||
|
||||
(item = cbor_load(ptr, len, &cbor)) == NULL ||
|
||||
cbor.read != len ||
|
||||
cbor_isa_array(item) == false ||
|
||||
cbor_array_is_definite(item) == false ||
|
||||
cbor_array_size(item) != 3 ||
|
||||
(v = cbor_array_handle(item)) == NULL)
|
||||
goto fail;
|
||||
|
||||
if (unpack_int(v[0], &p->seed) < 0 ||
|
||||
unpack_int(v[1], &p->dev) < 0 ||
|
||||
unpack_blob(v[2], &p->wiredata) < 0)
|
||||
goto fail;
|
||||
|
||||
ok = 0;
|
||||
fail:
|
||||
if (ok < 0) {
|
||||
free(p);
|
||||
p = NULL;
|
||||
}
|
||||
|
||||
if (item)
|
||||
cbor_decref(&item);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
size_t
|
||||
pack(uint8_t *ptr, size_t len, const struct param *p)
|
||||
{
|
||||
cbor_item_t *argv[3], *array = NULL;
|
||||
size_t cbor_alloc_len, cbor_len = 0;
|
||||
unsigned char *cbor = NULL;
|
||||
|
||||
memset(argv, 0, sizeof(argv));
|
||||
|
||||
if ((array = cbor_new_definite_array(3)) == NULL ||
|
||||
(argv[0] = pack_int(p->seed)) == NULL ||
|
||||
(argv[1] = pack_int(p->dev)) == NULL ||
|
||||
(argv[2] = pack_blob(&p->wiredata)) == NULL)
|
||||
goto fail;
|
||||
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
if (cbor_array_push(array, argv[i]) == false)
|
||||
goto fail;
|
||||
|
||||
if ((cbor_len = cbor_serialize_alloc(array, &cbor,
|
||||
&cbor_alloc_len)) > len) {
|
||||
cbor_len = 0;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(ptr, cbor, cbor_len);
|
||||
fail:
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
if (argv[i])
|
||||
cbor_decref(&argv[i]);
|
||||
|
||||
if (array)
|
||||
cbor_decref(&array);
|
||||
|
||||
free(cbor);
|
||||
|
||||
return cbor_len;
|
||||
}
|
||||
|
||||
size_t
|
||||
pack_dummy(uint8_t *ptr, size_t len)
|
||||
{
|
||||
struct param dummy;
|
||||
uint8_t blob[4096];
|
||||
size_t blob_len;
|
||||
|
||||
memset(&dummy, 0, sizeof(dummy));
|
||||
|
||||
dummy.wiredata.len = sizeof(sample_netlink_wiredata);
|
||||
memcpy(&dummy.wiredata.body, &sample_netlink_wiredata,
|
||||
dummy.wiredata.len);
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
|
@ -116,13 +116,16 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
|
|||
{
|
||||
struct param *p;
|
||||
|
||||
if (size > 4096)
|
||||
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 (size > 4096 || (p = unpack(data, size)) == NULL)
|
||||
if ((p = unpack(data, size)) == NULL)
|
||||
test_fail++;
|
||||
else {
|
||||
test(p);
|
||||
|
|
|
@ -6,15 +6,20 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <cbor.h>
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fido.h"
|
||||
#include "mutator_aux.h"
|
||||
|
||||
#define HID_DEV_HANDLE 0x68696421
|
||||
#define NFC_DEV_HANDLE 0x6e666321
|
||||
|
||||
int fido_nfc_rx(fido_dev_t *, uint8_t, unsigned char *, size_t, int);
|
||||
int fido_nfc_tx(fido_dev_t *, uint8_t, const unsigned char *, size_t);
|
||||
size_t LLVMFuzzerMutate(uint8_t *, size_t, size_t);
|
||||
|
||||
static const uint8_t *wire_data_ptr = NULL;
|
||||
|
@ -161,30 +166,14 @@ mutate_string(char *s)
|
|||
s[n] = '\0';
|
||||
}
|
||||
|
||||
void *
|
||||
dev_open(const char *path)
|
||||
{
|
||||
(void)path;
|
||||
|
||||
return (void *)0xdeadbeef;
|
||||
}
|
||||
|
||||
void
|
||||
dev_close(void *handle)
|
||||
{
|
||||
assert(handle == (void *)0xdeadbeef);
|
||||
}
|
||||
|
||||
int
|
||||
dev_read(void *handle, unsigned char *ptr, size_t len, int ms)
|
||||
/* XXX should fail, but doesn't */
|
||||
static int
|
||||
buf_read(unsigned char *ptr, size_t len, int ms)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
(void)ms;
|
||||
|
||||
assert(handle == (void *)0xdeadbeef);
|
||||
assert(len >= CTAP_MIN_REPORT_LEN && len <= CTAP_MAX_REPORT_LEN);
|
||||
|
||||
if (wire_data_len < len)
|
||||
n = wire_data_len;
|
||||
else
|
||||
|
@ -198,19 +187,143 @@ dev_read(void *handle, unsigned char *ptr, size_t len, int ms)
|
|||
return (int)n;
|
||||
}
|
||||
|
||||
int
|
||||
dev_write(void *handle, const unsigned char *ptr, size_t len)
|
||||
static int
|
||||
buf_write(const unsigned char *ptr, size_t len)
|
||||
{
|
||||
assert(handle == (void *)0xdeadbeef);
|
||||
consume(ptr, len);
|
||||
|
||||
if (uniform_random(400) < 1) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
static void *
|
||||
hid_open(const char *path)
|
||||
{
|
||||
(void)path;
|
||||
|
||||
return (void *)HID_DEV_HANDLE;
|
||||
}
|
||||
|
||||
static void
|
||||
hid_close(void *handle)
|
||||
{
|
||||
assert(handle == (void *)HID_DEV_HANDLE);
|
||||
}
|
||||
|
||||
static int
|
||||
hid_read(void *handle, unsigned char *ptr, size_t len, int ms)
|
||||
{
|
||||
assert(handle == (void *)HID_DEV_HANDLE);
|
||||
assert(len >= CTAP_MIN_REPORT_LEN && len <= CTAP_MAX_REPORT_LEN);
|
||||
|
||||
return buf_read(ptr, len, ms);
|
||||
}
|
||||
|
||||
static int
|
||||
hid_write(void *handle, const unsigned char *ptr, size_t len)
|
||||
{
|
||||
assert(handle == (void *)HID_DEV_HANDLE);
|
||||
assert(len >= CTAP_MIN_REPORT_LEN + 1 &&
|
||||
len <= CTAP_MAX_REPORT_LEN + 1);
|
||||
|
||||
consume(ptr, len);
|
||||
return buf_write(ptr, len);
|
||||
}
|
||||
|
||||
if (uniform_random(400) < 1)
|
||||
return -1;
|
||||
static void *
|
||||
nfc_open(const char *path)
|
||||
{
|
||||
(void)path;
|
||||
|
||||
return (int)len;
|
||||
return (void *)NFC_DEV_HANDLE;
|
||||
}
|
||||
|
||||
static void
|
||||
nfc_close(void *handle)
|
||||
{
|
||||
assert(handle == (void *)NFC_DEV_HANDLE);
|
||||
}
|
||||
|
||||
static int
|
||||
nfc_read(void *handle, unsigned char *ptr, size_t len, int ms)
|
||||
{
|
||||
assert(handle == (void *)NFC_DEV_HANDLE);
|
||||
assert(len > 0 && len <= 256 + 2);
|
||||
|
||||
return buf_read(ptr, len, ms);
|
||||
}
|
||||
|
||||
static int
|
||||
nfc_write(void *handle, const unsigned char *ptr, size_t len)
|
||||
{
|
||||
assert(handle == (void *)NFC_DEV_HANDLE);
|
||||
assert(len > 0 && len <= 256 + 2);
|
||||
|
||||
return buf_write(ptr, len);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
fd_read(int fd, void *ptr, size_t len)
|
||||
{
|
||||
assert(fd != -1);
|
||||
|
||||
return buf_read(ptr, len, -1);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
fd_write(int fd, const void *ptr, size_t len)
|
||||
{
|
||||
assert(fd != -1);
|
||||
|
||||
return buf_write(ptr, len);
|
||||
}
|
||||
|
||||
fido_dev_t *
|
||||
open_dev(int nfc)
|
||||
{
|
||||
fido_dev_t *dev;
|
||||
fido_dev_io_t io;
|
||||
fido_dev_transport_t t;
|
||||
|
||||
memset(&io, 0, sizeof(io));
|
||||
memset(&t, 0, sizeof(t));
|
||||
|
||||
if ((dev = fido_dev_new()) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (nfc) {
|
||||
io.open = nfc_open;
|
||||
io.close = nfc_close;
|
||||
io.read = nfc_read;
|
||||
io.write = nfc_write;
|
||||
} else {
|
||||
io.open = hid_open;
|
||||
io.close = hid_close;
|
||||
io.read = hid_read;
|
||||
io.write = hid_write;
|
||||
}
|
||||
|
||||
if (fido_dev_set_io_functions(dev, &io) != FIDO_OK)
|
||||
goto fail;
|
||||
|
||||
if (nfc) {
|
||||
t.rx = fido_nfc_rx;
|
||||
t.tx = fido_nfc_tx;
|
||||
if (fido_dev_set_transport_functions(dev, &t) != FIDO_OK)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (fido_dev_open(dev, "nodev") != FIDO_OK)
|
||||
goto fail;
|
||||
|
||||
return dev;
|
||||
fail:
|
||||
fido_dev_free(&dev);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -11,6 +11,16 @@
|
|||
#include <stdint.h>
|
||||
#include <cbor.h>
|
||||
|
||||
#include "../src/fido.h"
|
||||
#include "../src/fido/bio.h"
|
||||
#include "../src/fido/config.h"
|
||||
#include "../src/fido/credman.h"
|
||||
#include "../src/fido/eddsa.h"
|
||||
#include "../src/fido/es256.h"
|
||||
#include "../src/fido/es256.h"
|
||||
#include "../src/fido/rs256.h"
|
||||
#include "../src/netlink.h"
|
||||
|
||||
/*
|
||||
* As of LLVM 10.0.0, MSAN support in libFuzzer was still experimental.
|
||||
* We therefore have to be careful when using our custom mutator, or
|
||||
|
@ -73,11 +83,11 @@ void mutate_int(int *);
|
|||
void mutate_blob(struct blob *);
|
||||
void mutate_string(char *);
|
||||
|
||||
void *dev_open(const char *);
|
||||
void dev_close(void *);
|
||||
ssize_t fd_read(int, void *, size_t);
|
||||
ssize_t fd_write(int, const void *, size_t);
|
||||
|
||||
fido_dev_t *open_dev(int);
|
||||
void set_wire_data(const uint8_t *, size_t);
|
||||
int dev_read(void *, unsigned char *, size_t, int);
|
||||
int dev_write(void *, const unsigned char *, size_t);
|
||||
|
||||
void prng_init(unsigned long);
|
||||
unsigned long prng_uint32(void);
|
||||
|
|
Binary file not shown.
|
@ -3,40 +3,48 @@ Filename Regions Missed Regions Cover Funct
|
|||
fuzz/prng.c 31 0 100.00% 2 0 100.00% 49 0 100.00%
|
||||
fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 23 1 95.65%
|
||||
fuzz/wrap.c 6 0 100.00% 1 0 100.00% 7 0 100.00%
|
||||
openbsd-compat/explicit_bzero.c 4 0 100.00% 1 0 100.00% 12 0 100.00%
|
||||
openbsd-compat/explicit_bzero.c 4 0 100.00% 1 0 100.00% 13 0 100.00%
|
||||
openbsd-compat/freezero.c 4 0 100.00% 1 0 100.00% 6 0 100.00%
|
||||
openbsd-compat/recallocarray.c 41 7 82.93% 1 0 100.00% 49 7 85.71%
|
||||
openbsd-compat/strlcat.c 12 1 91.67% 1 0 100.00% 25 1 96.00%
|
||||
openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 8 0 100.00%
|
||||
src/aes256.c 56 0 100.00% 2 0 100.00% 82 0 100.00%
|
||||
src/assert.c 566 24 95.76% 53 1 98.11% 900 50 94.44%
|
||||
src/aes256.c 115 4 96.52% 8 0 100.00% 175 14 92.00%
|
||||
src/assert.c 593 34 94.27% 58 2 96.55% 914 52 94.31%
|
||||
src/authkey.c 44 0 100.00% 5 0 100.00% 75 0 100.00%
|
||||
src/bio.c 418 20 95.22% 49 2 95.92% 661 22 96.67%
|
||||
src/blob.c 39 0 100.00% 7 0 100.00% 73 0 100.00%
|
||||
src/bio.c 419 20 95.23% 49 2 95.92% 663 22 96.68%
|
||||
src/blob.c 53 3 94.34% 10 0 100.00% 96 7 92.71%
|
||||
src/buf.c 8 1 87.50% 2 0 100.00% 20 1 95.00%
|
||||
src/cbor.c 883 6 99.32% 52 0 100.00% 1364 17 98.75%
|
||||
src/cred.c 536 23 95.71% 57 1 98.25% 836 29 96.53%
|
||||
src/credman.c 385 18 95.32% 38 0 100.00% 595 16 97.31%
|
||||
src/dev.c 334 90 73.05% 33 8 75.76% 466 140 69.96%
|
||||
src/ecdh.c 68 0 100.00% 2 0 100.00% 104 0 100.00%
|
||||
src/eddsa.c 54 0 100.00% 8 0 100.00% 79 0 100.00%
|
||||
src/err.c 112 8 92.86% 1 0 100.00% 116 8 93.10%
|
||||
src/es256.c 280 0 100.00% 16 0 100.00% 398 0 100.00%
|
||||
src/hid.c 16 16 0.00% 8 8 0.00% 38 38 0.00%
|
||||
src/hid_linux.c 235 235 0.00% 19 19 0.00% 416 416 0.00%
|
||||
src/info.c 152 0 100.00% 34 0 100.00% 319 0 100.00%
|
||||
src/io.c 156 9 94.23% 10 0 100.00% 236 11 95.34%
|
||||
src/iso7816.c 18 1 94.44% 5 0 100.00% 47 0 100.00%
|
||||
src/log.c 34 2 94.12% 5 1 80.00% 50 3 94.00%
|
||||
src/pin.c 248 0 100.00% 16 0 100.00% 365 0 100.00%
|
||||
src/reset.c 19 0 100.00% 3 0 100.00% 22 0 100.00%
|
||||
src/rs256.c 102 6 94.12% 8 0 100.00% 140 13 90.71%
|
||||
src/u2f.c 491 9 98.17% 15 0 100.00% 774 18 97.67%
|
||||
src/cbor.c 984 34 96.54% 53 0 100.00% 1425 49 96.56%
|
||||
src/compress.c 34 4 88.24% 3 0 100.00% 30 3 90.00%
|
||||
src/config.c 93 2 97.85% 10 0 100.00% 148 3 97.97%
|
||||
src/cred.c 563 23 95.91% 63 1 98.41% 880 26 97.05%
|
||||
src/credman.c 370 10 97.30% 38 0 100.00% 596 16 97.32%
|
||||
src/dev.c 421 112 73.40% 42 8 80.95% 561 162 71.12%
|
||||
src/ecdh.c 117 2 98.29% 4 0 100.00% 161 5 96.89%
|
||||
src/eddsa.c 54 0 100.00% 8 0 100.00% 77 0 100.00%
|
||||
src/err.c 122 10 91.80% 1 0 100.00% 126 10 92.06%
|
||||
src/es256.c 280 0 100.00% 16 0 100.00% 394 0 100.00%
|
||||
src/hid.c 60 16 73.33% 12 8 33.33% 133 38 71.43%
|
||||
src/hid_linux.c 159 159 0.00% 14 14 0.00% 281 281 0.00%
|
||||
src/hid_unix.c 30 27 10.00% 2 1 50.00% 52 40 23.08%
|
||||
src/info.c 154 0 100.00% 35 0 100.00% 324 0 100.00%
|
||||
src/io.c 156 7 95.51% 10 0 100.00% 228 11 95.18%
|
||||
src/iso7816.c 18 1 94.44% 5 0 100.00% 42 0 100.00%
|
||||
src/largeblob.c 511 23 95.50% 30 0 100.00% 759 51 93.28%
|
||||
src/log.c 39 5 87.18% 7 1 85.71% 73 4 94.52%
|
||||
src/netlink.c 327 15 95.41% 40 0 100.00% 565 35 93.81%
|
||||
src/nfc_linux.c 304 187 38.49% 23 14 39.13% 520 309 40.58%
|
||||
src/pin.c 406 3 99.26% 27 0 100.00% 583 3 99.49%
|
||||
src/random.c 6 1 83.33% 1 0 100.00% 8 1 87.50%
|
||||
src/reset.c 24 0 100.00% 3 0 100.00% 27 0 100.00%
|
||||
src/rs256.c 102 4 96.08% 8 0 100.00% 138 6 95.65%
|
||||
src/u2f.c 473 6 98.73% 15 0 100.00% 745 9 98.79%
|
||||
|
||||
Files which contain no functions:
|
||||
openbsd-compat/time.h 0 0 - 0 0 - 0 0 -
|
||||
openbsd-compat/openbsd-compat.h 0 0 - 0 0 - 0 0 -
|
||||
src/extern.h 0 0 - 0 0 - 0 0 -
|
||||
src/fido.h 0 0 - 0 0 - 0 0 -
|
||||
src/fido/err.h 0 0 - 0 0 - 0 0 -
|
||||
src/fido/param.h 0 0 - 0 0 - 0 0 -
|
||||
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
TOTAL 5359 477 91.10% 456 40 91.23% 8349 791 90.53%
|
||||
TOTAL 7148 722 89.90% 611 51 91.65% 10999 1167 89.39%
|
||||
|
|
|
@ -61,16 +61,6 @@
|
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
|
||||
#define WIREDATA_CTAP_CBOR_RESET \
|
||||
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_AUTHKEY \
|
||||
0x00, 0x22, 0x00, 0x02, 0x90, 0x00, 0x51, 0x00, \
|
||||
0xa1, 0x01, 0xa5, 0x01, 0x02, 0x03, 0x38, 0x18, \
|
||||
|
@ -80,7 +70,7 @@
|
|||
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, 0x03, 0x00, 0x3f, 0xf1, 0x60, \
|
||||
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, \
|
||||
|
@ -566,4 +556,78 @@
|
|||
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
|
||||
|
||||
#endif /* _WIREDATA_FIDO2_H */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Yubico AB. All rights reserved.
|
||||
* Copyright (c) 2019-2021 Yubico AB. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
@ -9,8 +9,6 @@
|
|||
#include <openssl/sha.h>
|
||||
|
||||
#include <cbor.h>
|
||||
#include <fido.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
@ -60,6 +58,23 @@ WRAP(char *,
|
|||
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),
|
||||
|
@ -68,7 +83,8 @@ WRAP(EVP_CIPHER_CTX *,
|
|||
1
|
||||
)
|
||||
|
||||
WRAP(int, EVP_EncryptInit_ex,
|
||||
WRAP(int,
|
||||
EVP_EncryptInit_ex,
|
||||
(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl,
|
||||
const unsigned char *key, const unsigned char *iv),
|
||||
0,
|
||||
|
@ -93,6 +109,15 @@ WRAP(int,
|
|||
1
|
||||
)
|
||||
|
||||
WRAP(int,
|
||||
EVP_CipherInit,
|
||||
(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
|
||||
const unsigned char *key, const unsigned char *iv, int enc),
|
||||
0,
|
||||
(ctx, cipher, key, iv, enc),
|
||||
1
|
||||
)
|
||||
|
||||
WRAP(int,
|
||||
EVP_DecryptInit_ex,
|
||||
(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl,
|
||||
|
@ -336,6 +361,14 @@ WRAP(EVP_PKEY_CTX *,
|
|||
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),
|
||||
|
|
|
@ -24,8 +24,11 @@ EC_KEY_get0_private_key
|
|||
EC_KEY_new_by_curve_name
|
||||
EC_POINT_get_affine_coordinates_GFp
|
||||
EC_POINT_new
|
||||
EVP_Cipher
|
||||
EVP_CIPHER_CTX_ctrl
|
||||
EVP_CIPHER_CTX_new
|
||||
EVP_CIPHER_CTX_set_padding
|
||||
EVP_CipherInit
|
||||
EVP_DecryptInit_ex
|
||||
EVP_DecryptUpdate
|
||||
EVP_DigestVerifyInit
|
||||
|
@ -35,6 +38,7 @@ EVP_MD_CTX_new
|
|||
EVP_PKEY_assign
|
||||
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
|
||||
|
|
|
@ -29,9 +29,11 @@ list(APPEND MAN_SOURCES
|
|||
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
|
||||
|
@ -50,6 +52,8 @@ list(APPEND MAN_ALIAS
|
|||
es256_pk_new es256_pk_to_EVP_PKEY
|
||||
fido_assert_new fido_assert_authdata_len
|
||||
fido_assert_new fido_assert_authdata_ptr
|
||||
fido_assert_new fido_assert_blob_len
|
||||
fido_assert_new fido_assert_blob_ptr
|
||||
fido_assert_new fido_assert_clientdata_hash_len
|
||||
fido_assert_new fido_assert_clientdata_hash_ptr
|
||||
fido_assert_new fido_assert_count
|
||||
|
@ -59,6 +63,8 @@ list(APPEND MAN_ALIAS
|
|||
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
|
||||
|
@ -72,6 +78,7 @@ list(APPEND MAN_ALIAS
|
|||
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
|
||||
|
@ -104,6 +111,7 @@ list(APPEND MAN_ALIAS
|
|||
fido_cbor_info_new fido_cbor_info_extensions_ptr
|
||||
fido_cbor_info_new fido_cbor_info_free
|
||||
fido_cbor_info_new fido_cbor_info_maxmsgsiz
|
||||
fido_cbor_info_new fido_cbor_info_maxcredbloblen
|
||||
fido_cbor_info_new fido_cbor_info_maxcredcntlst;
|
||||
fido_cbor_info_new fido_cbor_info_maxcredidlen;
|
||||
fido_cbor_info_new fido_cbor_info_fwversion
|
||||
|
@ -117,16 +125,21 @@ list(APPEND MAN_ALIAS
|
|||
fido_cbor_info_new fido_dev_get_cbor_info
|
||||
fido_cred_new fido_cred_authdata_len
|
||||
fido_cred_new fido_cred_authdata_ptr
|
||||
fido_cred_new fido_cred_authdata_raw_len
|
||||
fido_cred_new fido_cred_authdata_raw_ptr
|
||||
fido_cred_new fido_cred_clientdata_hash_len
|
||||
fido_cred_new fido_cred_clientdata_hash_ptr
|
||||
fido_cred_new fido_cred_display_name
|
||||
fido_cred_new fido_cred_flags
|
||||
fido_cred_new fido_cred_sigcount
|
||||
fido_cred_new fido_cred_fmt
|
||||
fido_cred_new fido_cred_free
|
||||
fido_cred_new fido_cred_id_len
|
||||
fido_cred_new fido_cred_id_ptr
|
||||
fido_cred_new fido_cred_aaguid_len
|
||||
fido_cred_new fido_cred_aaguid_ptr
|
||||
fido_cred_new fido_cred_largeblob_key_len
|
||||
fido_cred_new fido_cred_largeblob_key_ptr
|
||||
fido_cred_new fido_cred_prot
|
||||
fido_cred_new fido_cred_pubkey_len
|
||||
fido_cred_new fido_cred_pubkey_ptr
|
||||
|
@ -159,6 +172,7 @@ list(APPEND MAN_ALIAS
|
|||
fido_credman_metadata_new fido_credman_rp_name
|
||||
fido_credman_metadata_new fido_credman_rp_new
|
||||
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_hash
|
||||
fido_cred_set_authdata fido_cred_set_extensions
|
||||
fido_cred_set_authdata fido_cred_set_fmt
|
||||
|
@ -170,6 +184,10 @@ list(APPEND MAN_ALIAS
|
|||
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_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
|
||||
|
@ -186,14 +204,23 @@ list(APPEND MAN_ALIAS
|
|||
fido_dev_open fido_dev_force_u2f
|
||||
fido_dev_open fido_dev_free
|
||||
fido_dev_open fido_dev_is_fido2
|
||||
fido_dev_open fido_dev_supports_cred_prot
|
||||
fido_dev_open fido_dev_supports_pin
|
||||
fido_dev_open fido_dev_major
|
||||
fido_dev_open fido_dev_minor
|
||||
fido_dev_open fido_dev_new
|
||||
fido_dev_open fido_dev_protocol
|
||||
fido_dev_open fido_dev_supports_cred_prot
|
||||
fido_dev_open fido_dev_supports_credman
|
||||
fido_dev_open fido_dev_supports_pin
|
||||
fido_dev_open fido_dev_supports_uv
|
||||
fido_dev_open fido_dev_has_uv
|
||||
fido_dev_set_pin fido_dev_get_retry_count
|
||||
fido_dev_set_pin fido_dev_get_uv_retry_count
|
||||
fido_dev_set_pin fido_dev_reset
|
||||
fido_dev_set_io_functions fido_dev_set_sigmask
|
||||
fido_dev_largeblob_get fido_dev_largeblob_set
|
||||
fido_dev_largeblob_get fido_dev_largeblob_remove
|
||||
fido_dev_largeblob_get fido_dev_largeblob_get_array
|
||||
fido_dev_largeblob_get fido_dev_largeblob_set_array
|
||||
rs256_pk_new rs256_pk_free
|
||||
rs256_pk_new rs256_pk_from_ptr
|
||||
rs256_pk_new rs256_pk_from_RSA
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Fl G
|
||||
.Op Fl dhpruv
|
||||
.Op Fl bdhpruv
|
||||
.Op Fl t Ar option
|
||||
.Op Fl i Ar input_file
|
||||
.Op Fl o Ar output_file
|
||||
|
@ -75,6 +75,10 @@ If
|
|||
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.
|
||||
|
@ -111,6 +115,9 @@ 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 FIDO2.1.
|
||||
.It Fl t Ar option
|
||||
Toggles a key/value
|
||||
.Ar option ,
|
||||
|
@ -219,6 +226,10 @@ 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,
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Fl M
|
||||
.Op Fl dhqruv
|
||||
.Op Fl bdhqruv
|
||||
.Op Fl c Ar cred_protect
|
||||
.Op Fl i Ar input_file
|
||||
.Op Fl o Ar output_file
|
||||
|
@ -91,9 +91,19 @@ to make a new credential on
|
|||
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 .
|
||||
.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 .
|
||||
|
@ -131,6 +141,9 @@ is specified,
|
|||
will fail.
|
||||
.It Fl r
|
||||
Create a resident credential.
|
||||
Resident credentials are called
|
||||
.Dq discoverable credentials
|
||||
in FIDO2.1.
|
||||
.It Fl u
|
||||
Create a U2F credential.
|
||||
By default,
|
||||
|
@ -212,6 +225,10 @@ credential id (base64 blob);
|
|||
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,
|
||||
|
@ -244,3 +261,7 @@ verify it, and save the id and the public key of the credential in
|
|||
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.
|
||||
|
|
|
@ -10,14 +10,49 @@
|
|||
.Nd find and manage a FIDO 2 authenticator
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl CR
|
||||
.Fl C
|
||||
.Op Fl d
|
||||
.Ar device
|
||||
.Nm
|
||||
.Fl D
|
||||
.Op Fl de
|
||||
.Op Fl d
|
||||
.Fl i
|
||||
.Ar id
|
||||
.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 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
|
||||
|
@ -26,13 +61,41 @@
|
|||
.Ar device
|
||||
.Nm
|
||||
.Fl L
|
||||
.Op Fl der
|
||||
.Op Fl bder
|
||||
.Op Fl k Ar rp_id
|
||||
.Op device
|
||||
.Nm
|
||||
.Fl R
|
||||
.Op Fl d
|
||||
.Ar device
|
||||
.Nm
|
||||
.Fl S
|
||||
.Op Fl de
|
||||
.Op Fl i Ar template_id Fl n Ar template_name
|
||||
.Op Fl adeu
|
||||
.Ar device
|
||||
.Nm
|
||||
.Fl S
|
||||
.Op Fl d
|
||||
.Fl i Ar template_id
|
||||
.Fl n Ar template_name
|
||||
.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 V
|
||||
|
@ -55,6 +118,34 @@ where
|
|||
.Ar id
|
||||
is the credential's base64-encoded id.
|
||||
The user will be prompted for the PIN.
|
||||
.It Fl D Fl b Fl k Ar key_path Ar device
|
||||
Deletes a
|
||||
.Dq largeBlob
|
||||
encrypted with
|
||||
.Ar key_path
|
||||
from
|
||||
.Ar device ,
|
||||
where
|
||||
.Ar key_path
|
||||
must hold the blob's base64-encoded encryption key.
|
||||
A PIN or equivalent user-verification gesture is required.
|
||||
.It Fl D Fl b Fl n Ar rp_id Oo Fl i Ar cred_id Oc Ar device
|
||||
Deletes a
|
||||
.Dq largeBlob
|
||||
corresponding to
|
||||
.Ar rp_id
|
||||
from
|
||||
.Ar device .
|
||||
If
|
||||
.Ar rp_id
|
||||
has multiple credentials enrolled on
|
||||
.Ar device ,
|
||||
the credential ID must be specified using
|
||||
.Fl i Ar cred_id ,
|
||||
where
|
||||
.Ar cred_id
|
||||
is a base64-encoded blob.
|
||||
A PIN or equivalent user-verification gesture is required.
|
||||
.It Fl D Fl e Fl i Ar id Ar device
|
||||
Deletes the biometric enrollment specified by
|
||||
.Ar id
|
||||
|
@ -64,6 +155,43 @@ where
|
|||
.Ar id
|
||||
is the enrollment's template base64-encoded id.
|
||||
The user will be prompted for the PIN.
|
||||
.It Fl D Fl u Ar device
|
||||
Disables the FIDO 2.1
|
||||
.Dq user verification always
|
||||
feature on
|
||||
.Ar device .
|
||||
.It Fl G Fl b Fl k Ar key_path Ar blob_path Ar device
|
||||
Gets a FIDO 2.1
|
||||
.Dq largeBlob
|
||||
encrypted with
|
||||
.Ar key_path
|
||||
from
|
||||
.Ar device ,
|
||||
where
|
||||
.Ar key_path
|
||||
must hold the blob's base64-encoded encryption key.
|
||||
The blob is written to
|
||||
.Ar blob_path .
|
||||
A PIN or equivalent user-verification gesture is required.
|
||||
.It Fl G Fl b Fl n Ar rp_id Oo Fl i Ar cred_id Oc Ar blob_path Ar device
|
||||
Gets a FIDO 2.1
|
||||
.Dq largeBlob
|
||||
associated with
|
||||
.Ar rp_id
|
||||
from
|
||||
.Ar device .
|
||||
If
|
||||
.Ar rp_id
|
||||
has multiple credentials enrolled on
|
||||
.Ar device ,
|
||||
the credential ID must be specified using
|
||||
.Fl i Ar cred_id ,
|
||||
where
|
||||
.Ar cred_id
|
||||
is a base64-encoded blob.
|
||||
The blob is written to
|
||||
.Ar blob_path .
|
||||
A PIN or equivalent user-verification gesture is required.
|
||||
.It Fl I Ar device
|
||||
Retrieves information on
|
||||
.Ar device .
|
||||
|
@ -85,6 +213,12 @@ is a base64-encoded credential id.
|
|||
The user will be prompted for the PIN.
|
||||
.It Fl L
|
||||
Produces a list of authenticators found by the operating system.
|
||||
.It Fl L Fl b Ar device
|
||||
Produces a list of FIDO 2.1
|
||||
.Dq largeBlobs
|
||||
on
|
||||
.Ar device .
|
||||
A PIN or equivalent user-verification gesture is required.
|
||||
.It Fl L Fl e Ar device
|
||||
Produces a list of biometric enrollments on
|
||||
.Ar device .
|
||||
|
@ -109,6 +243,43 @@ will NOT prompt for confirmation.
|
|||
Sets the PIN of
|
||||
.Ar device .
|
||||
The user will be prompted for the PIN.
|
||||
.It Fl S Fl a Ar device
|
||||
Enables FIDO 2.1 Enterprise Attestation on
|
||||
.Ar device .
|
||||
.It Fl S Fl b Fl k Ar key_path Ar blob_path Ar device
|
||||
Sets
|
||||
.Ar blob_path
|
||||
as a FIDO 2.1
|
||||
.Dq largeBlob
|
||||
encrypted with
|
||||
.Ar key_path
|
||||
on
|
||||
.Ar device ,
|
||||
where
|
||||
.Ar blob_path
|
||||
holds the blob's plaintext, and
|
||||
.Ar key_path
|
||||
the blob's base64-encoded encryption.
|
||||
A PIN or equivalent user-verification gesture is required.
|
||||
.It Fl S Fl b Fl n Ar rp_id Oo Fl i Ar cred_id Oc Ar blob_path Ar device
|
||||
Sets
|
||||
.Ar blob_path
|
||||
as a FIDO 2.1
|
||||
.Dq largeBlob
|
||||
associated with
|
||||
.Ar rp_id
|
||||
on
|
||||
.Ar device .
|
||||
If
|
||||
.Ar rp_id
|
||||
has multiple credentials enrolled on
|
||||
.Ar device ,
|
||||
the credential ID must be specified using
|
||||
.Fl i Ar cred_id ,
|
||||
where
|
||||
.Ar cred_id
|
||||
is a base64-encoded blob.
|
||||
A PIN or equivalent user-verification gesture is required.
|
||||
.It Fl S Fl e Ar device
|
||||
Performs a new biometric enrollment on
|
||||
.Ar device .
|
||||
|
@ -126,6 +297,21 @@ 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 u Ar device
|
||||
Enables the FIDO 2.1
|
||||
.Dq user verification always
|
||||
feature on
|
||||
.Ar device .
|
||||
.It Fl V
|
||||
Prints version information.
|
||||
.It Fl d
|
||||
|
@ -158,3 +344,12 @@ 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 FIDO2.1.
|
||||
.Pp
|
||||
Whether the FIDO 2.1
|
||||
.Dq user verification always
|
||||
feature is activated or deactivated after an authenticator reset
|
||||
is vendor-specific.
|
||||
|
|
|
@ -14,14 +14,18 @@
|
|||
.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 ,
|
||||
|
@ -49,8 +53,12 @@
|
|||
.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"
|
||||
.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"
|
||||
|
@ -61,8 +69,12 @@
|
|||
.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"
|
||||
.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"
|
||||
|
@ -143,19 +155,26 @@ NUL-terminated UTF-8 strings.
|
|||
The
|
||||
.Fn fido_assert_user_id_ptr ,
|
||||
.Fn fido_assert_authdata_ptr ,
|
||||
.Fn fido_assert_blob_ptr ,
|
||||
.Fn fido_assert_hmac_secret_ptr ,
|
||||
.Fn fido_assert_largeblob_key_ptr ,
|
||||
.Fn fido_assert_sig_ptr ,
|
||||
and
|
||||
.Fn fido_assert_id_ptr
|
||||
functions return pointers to the user ID, authenticator data,
|
||||
hmac-secret, signature, and credential ID attributes of statement
|
||||
functions return pointers to the user ID, CBOR-encoded
|
||||
authenticator data, cred blob, hmac-secret,
|
||||
.Dq largeBlobKey ,
|
||||
signature, and credential ID attributes of statement
|
||||
.Fa idx
|
||||
in
|
||||
.Fa assert .
|
||||
.Pp
|
||||
The
|
||||
.Fn fido_assert_user_id_len ,
|
||||
.Fn fido_assert_authdata_len ,
|
||||
.Fn fido_assert_blob_len ,
|
||||
.Fn fido_assert_hmac_secret_len ,
|
||||
.Fn fido_assert_largeblob_key_len ,
|
||||
.Fn fido_assert_sig_len ,
|
||||
and
|
||||
.Fn fido_assert_id_len
|
||||
|
@ -192,12 +211,18 @@ function returns a pointer to the client data hash of
|
|||
The corresponding length can be obtained by
|
||||
.Fn fido_assert_clientdata_hash_len .
|
||||
.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_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_hmac_secret_ptr ,
|
||||
.Fn fido_assert_largeblob_key_ptr ,
|
||||
.Fn fido_assert_user_id_ptr ,
|
||||
and
|
||||
.Fn fido_assert_sig_ptr
|
||||
|
@ -214,4 +239,5 @@ qualifier is invoked.
|
|||
.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_get_assert 3 ,
|
||||
.Xr fido_dev_largeblob_get 3
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
.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 ,
|
||||
|
@ -39,6 +40,8 @@ typedef enum {
|
|||
.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" "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"
|
||||
|
@ -100,9 +103,10 @@ Alternatively, a raw binary blob may be passed to
|
|||
.Fn fido_assert_set_authdata_raw .
|
||||
.Pp
|
||||
The
|
||||
.Fn fido_assert_set_clientdata_hash
|
||||
.Fn fido_assert_set_clientdata_hash ,
|
||||
.Fn fido_assert_set_hmac_salt ,
|
||||
and
|
||||
.Fn fido_assert_set_hmac_salt
|
||||
.Fn fido_assert_set_hmac_secret
|
||||
functions set the client data hash and hmac-salt parts of
|
||||
.Fa assert
|
||||
to
|
||||
|
@ -136,8 +140,11 @@ function sets the extensions of
|
|||
to the bitmask
|
||||
.Fa flags .
|
||||
At the moment, only the
|
||||
.Dv FIDO_EXT_HMAC_SECRET
|
||||
extension is supported.
|
||||
.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
|
||||
|
@ -178,6 +185,11 @@ set of functions can be found in the
|
|||
.Pa examples/assert.c
|
||||
file shipped with
|
||||
.Em libfido2 .
|
||||
.Pp
|
||||
.Fn fido_assert_set_hmac_secret
|
||||
is not normally useful in a FIDO client or server \(em it is provided
|
||||
to enable testing other functionality that relies on retrieving the
|
||||
HMAC secret from an assertion obtained from an authenticator.
|
||||
.Sh RETURN VALUES
|
||||
The
|
||||
.Nm
|
||||
|
|
|
@ -58,6 +58,8 @@
|
|||
.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"
|
||||
|
@ -137,6 +139,13 @@ 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
|
||||
|
|
|
@ -15,23 +15,28 @@
|
|||
.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_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_type ,
|
||||
.Nm fido_cred_flags
|
||||
.Nm fido_cred_flags ,
|
||||
.Nm fido_cred_sigcount
|
||||
.Nd FIDO 2 credential API
|
||||
.Sh SYNOPSIS
|
||||
.In fido.h
|
||||
|
@ -54,12 +59,16 @@
|
|||
.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"
|
||||
|
@ -70,12 +79,16 @@
|
|||
.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"
|
||||
|
@ -87,6 +100,8 @@
|
|||
.Fn fido_cred_type "const fido_cred_t *cred"
|
||||
.Ft uint8_t
|
||||
.Fn fido_cred_flags "const fido_cred_t *cred"
|
||||
.Ft uint32_t
|
||||
.Fn fido_cred_sigcount "const fido_cred_t *cred"
|
||||
.Sh DESCRIPTION
|
||||
FIDO 2 credentials are abstracted in
|
||||
.Em libfido2
|
||||
|
@ -163,25 +178,30 @@ 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 ,
|
||||
and
|
||||
.Fn fido_cred_x5c_ptr
|
||||
functions return pointers to the authenticator data, client data
|
||||
hash, ID, authenticator attestation GUID, public key, signature,
|
||||
user ID, and x509 certificate parts of
|
||||
functions return pointers to the CBOR-encoded and raw authenticator
|
||||
data, client data hash, ID, authenticator attestation GUID,
|
||||
.Dq largeBlobKey ,
|
||||
public key, signature, user ID, and x509 certificate parts of
|
||||
.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 ,
|
||||
|
@ -200,10 +220,17 @@ 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 ,
|
||||
|
@ -211,6 +238,7 @@ If not NULL, pointers returned by
|
|||
.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
|
||||
|
@ -225,4 +253,5 @@ qualifier is invoked.
|
|||
.Xr fido_cred_set_authdata 3 ,
|
||||
.Xr fido_cred_verify 3 ,
|
||||
.Xr fido_credman_metadata_new 3 ,
|
||||
.Xr fido_dev_largeblob_get 3 ,
|
||||
.Xr fido_dev_make_cred 3
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
.Nm fido_cred_set_rp ,
|
||||
.Nm fido_cred_set_user ,
|
||||
.Nm fido_cred_set_extensions ,
|
||||
.Nm fido_cred_set_blob ,
|
||||
.Nm fido_cred_set_prot ,
|
||||
.Nm fido_cred_set_rk ,
|
||||
.Nm fido_cred_set_uv ,
|
||||
|
@ -46,6 +47,8 @@ typedef enum {
|
|||
.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_prot "fido_cred_t *cred" "int prot"
|
||||
.Ft int
|
||||
.Fn fido_cred_set_rk "fido_cred_t *cred" "fido_opt_t rk"
|
||||
|
@ -151,9 +154,11 @@ function sets the extensions of
|
|||
to the bitmask
|
||||
.Fa flags .
|
||||
At the moment, only the
|
||||
.Dv FIDO_EXT_HMAC_SECRET
|
||||
.Dv FIDO_EXT_CRED_BLOB ,
|
||||
.Dv FIDO_EXT_CRED_PROTECT ,
|
||||
.Dv FIDO_EXT_HMAC_SECRET ,
|
||||
and
|
||||
.Dv FIDO_EXT_CRED_PROTECT
|
||||
.Dv FIDO_EXT_LARGEBLOB_KEY
|
||||
extensions are supported.
|
||||
If
|
||||
.Fa flags
|
||||
|
@ -162,6 +167,18 @@ is zero, the extensions of
|
|||
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_prot
|
||||
function sets the protection of
|
||||
.Fa cred
|
||||
|
@ -185,10 +202,10 @@ and
|
|||
.Fn fido_cred_set_uv
|
||||
functions set the
|
||||
.Em rk
|
||||
(resident key)
|
||||
.Pq resident/discoverable key
|
||||
and
|
||||
.Em uv
|
||||
(user verification)
|
||||
.Pq user verification
|
||||
attributes of
|
||||
.Fa cred .
|
||||
Both are
|
||||
|
@ -205,10 +222,10 @@ where
|
|||
.Fa fmt
|
||||
must be either
|
||||
.Vt "packed"
|
||||
(the format used in FIDO 2)
|
||||
.Pq the format used in FIDO2
|
||||
or
|
||||
.Vt "fido-u2f"
|
||||
(the format used by U2F).
|
||||
.Pq the format used by U2F .
|
||||
A copy of
|
||||
.Fa fmt
|
||||
is made, and no references to the passed pointer are kept.
|
||||
|
|
|
@ -29,7 +29,7 @@ A brief description follows:
|
|||
The
|
||||
.Fn fido_cred_verify
|
||||
function verifies whether the client data hash, relying party ID,
|
||||
credential ID, type, and resident key and user verification
|
||||
credential ID, type, and resident/discoverable key and user verification
|
||||
attributes of
|
||||
.Fa cred
|
||||
have been attested by the holder of the private counterpart of
|
||||
|
|
|
@ -306,3 +306,7 @@ Applications using credential management should ensure it is
|
|||
supported by the authenticator prior to using the API.
|
||||
Since FIDO 2.1 hasn't been finalised, there is a chance the
|
||||
functionality and associated data structures may change.
|
||||
.Pp
|
||||
Resident credentials are called
|
||||
.Dq discoverable credentials
|
||||
in FIDO2.1.
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
.\" Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||
.\" Use of this source code is governed by a BSD-style
|
||||
.\" license that can be found in the LICENSE file.
|
||||
.\"
|
||||
.Dd $Mdocdate: September 22 2020 $
|
||||
.Dt FIDO_DEV_ENABLE_ENTATTEST 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm fido_dev_enable_entattest ,
|
||||
.Nm fido_dev_toggle_always_uv ,
|
||||
.Nm fido_dev_force_pin_change ,
|
||||
.Nm fido_dev_set_pin_minlen
|
||||
.Nd FIDO 2.1 configuration authenticator API
|
||||
.Sh SYNOPSIS
|
||||
.In fido.h
|
||||
.In fido/config.h
|
||||
.Ft int
|
||||
.Fn fido_dev_enable_entattest "fido_dev_t *dev" "const char *pin"
|
||||
.Ft int
|
||||
.Fn fido_dev_toggle_always_uv "fido_dev_t *dev" "const char *pin"
|
||||
.Ft int
|
||||
.Fn fido_dev_force_pin_change "fido_dev_t *dev" "const char *pin"
|
||||
.Ft int
|
||||
.Fn fido_dev_set_pin_minlen "fido_dev_t *dev" "size_t len" "const char *pin"
|
||||
.Sh DESCRIPTION
|
||||
The functions described in this page allow configuration of a
|
||||
FIDO 2.1 authenticator.
|
||||
.Pp
|
||||
The
|
||||
.Fn fido_dev_enable_entattest
|
||||
function enables the
|
||||
.Em Enterprise Attestation
|
||||
feature on
|
||||
.Fa dev .
|
||||
.Em Enterprise Attestation
|
||||
instructs the authenticator to include uniquely identifying
|
||||
information in subsequent attestation statements.
|
||||
The
|
||||
.Fa pin
|
||||
parameter may be NULL if
|
||||
.Fa dev
|
||||
does not have a PIN set.
|
||||
.Pp
|
||||
The
|
||||
.Fn fido_dev_toggle_always_uv
|
||||
function toggles the
|
||||
.Dq user verification always
|
||||
feature on
|
||||
.Fa dev .
|
||||
When set, this toggle enforces user verification at the
|
||||
authenticator level for all known credentials.
|
||||
If
|
||||
.Fa dev
|
||||
supports U2F (CTAP1) and the user verification methods supported by
|
||||
the authenticator do not allow protection of U2F credentials, the
|
||||
U2F subsystem will be disabled by the authenticator.
|
||||
The
|
||||
.Fa pin
|
||||
parameter may be NULL if
|
||||
.Fa dev
|
||||
does not have a PIN set.
|
||||
.Pp
|
||||
The
|
||||
.Fn fido_dev_force_pin_change
|
||||
instructs
|
||||
.Fa dev
|
||||
to require a PIN change.
|
||||
Subsequent PIN authentication attempts against
|
||||
.Fa dev
|
||||
will fail until its PIN is changed.
|
||||
.Pp
|
||||
The
|
||||
.Fn fido_dev_set_pin_minlen
|
||||
function sets the minimum PIN length of
|
||||
.Fa dev
|
||||
to
|
||||
.Fa len .
|
||||
Minimum PIN lengths may only be increased.
|
||||
.Pp
|
||||
Configuration settings are reflected in the payload returned by the
|
||||
authenticator in response to a
|
||||
.Xr fido_dev_get_cbor_info 3
|
||||
call.
|
||||
.Sh SEE ALSO
|
||||
.Xr fido_dev_get_cbor_info 3 ,
|
||||
.Xr fido_dev_reset 3
|
||||
.Sh CAVEATS
|
||||
Authenticator configuration is a tentative feature of FIDO 2.1.
|
||||
Applications willing to strictly abide by FIDO 2.0 should refrain
|
||||
from using authenticator configuration.
|
||||
Applications using authenticator configuration should ensure the
|
||||
feature is supported by the authenticator prior to using the
|
||||
corresponding API.
|
||||
Since FIDO 2.1 hasn't been finalised, there is a chance the
|
||||
functionality and associated data structures may change.
|
|
@ -0,0 +1,194 @@
|
|||
.\" Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||
.\" Use of this source code is governed by a BSD-style
|
||||
.\" license that can be found in the LICENSE file.
|
||||
.\"
|
||||
.Dd $Mdocdate: 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 FIDO 2 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 FIDO 2.1 authenticator to be
|
||||
read, written, and inspected.
|
||||
.Dq largeBlobs
|
||||
is a FIDO 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 FIDO 2.1's
|
||||
.Dq largeBlobs
|
||||
extension, please refer to the FIDO 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
|
||||
.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_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.
|
|
@ -33,7 +33,7 @@ defined in
|
|||
.It
|
||||
.Nm list of excluded credential IDs ;
|
||||
.It
|
||||
.Nm resident key and user verification attributes .
|
||||
.Nm resident/discoverable key and user verification attributes .
|
||||
.El
|
||||
.Pp
|
||||
See
|
||||
|
|
|
@ -14,9 +14,12 @@
|
|||
.Nm fido_dev_force_fido2 ,
|
||||
.Nm fido_dev_force_u2f ,
|
||||
.Nm fido_dev_is_fido2 ,
|
||||
.Nm fido_dev_supports_credman ,
|
||||
.Nm fido_dev_supports_cred_prot ,
|
||||
.Nm fido_dev_supports_pin ,
|
||||
.Nm fido_dev_has_pin ,
|
||||
.Nm fido_dev_supports_uv ,
|
||||
.Nm fido_dev_has_uv ,
|
||||
.Nm fido_dev_protocol ,
|
||||
.Nm fido_dev_build ,
|
||||
.Nm fido_dev_flags ,
|
||||
|
@ -42,11 +45,17 @@
|
|||
.Ft bool
|
||||
.Fn fido_dev_is_fido2 "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_pin "const fido_dev_t *dev"
|
||||
.Ft bool
|
||||
.Fn fido_dev_has_pin "const fido_dev_t *dev"
|
||||
.Ft bool
|
||||
.Fn fido_dev_supports_uv "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
|
||||
|
@ -66,6 +75,18 @@ 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_close
|
||||
|
@ -126,6 +147,14 @@ if
|
|||
is a FIDO 2 device.
|
||||
.Pp
|
||||
The
|
||||
.Fn fido_dev_supports_credman
|
||||
function returns
|
||||
.Dv true
|
||||
if
|
||||
.Fa dev
|
||||
supports FIDO 2.1 Credential Management.
|
||||
.Pp
|
||||
The
|
||||
.Fn fido_dev_supports_cred_prot
|
||||
function returns
|
||||
.Dv true
|
||||
|
@ -150,6 +179,23 @@ if
|
|||
has a FIDO 2.0 Client PIN set.
|
||||
.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_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 .
|
||||
|
@ -189,4 +235,5 @@ On error, a different error code defined in
|
|||
is returned.
|
||||
.Sh SEE ALSO
|
||||
.Xr fido_dev_info_manifest 3 ,
|
||||
.Xr fido_dev_set_io_functions 3
|
||||
.Xr fido_dev_set_io_functions 3 ,
|
||||
.Xr fido_init 3
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
.Dt FIDO_DEV_SET_IO_FUNCTIONS 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm fido_dev_set_io_functions
|
||||
.Nm fido_dev_set_io_functions ,
|
||||
.Nm fido_dev_set_sigmask
|
||||
.Nd FIDO 2 device I/O interface
|
||||
.Sh SYNOPSIS
|
||||
.In fido.h
|
||||
|
@ -15,137 +16,118 @@ 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_io_rx_t(struct fido_dev *, uint8_t, unsigned char *, size_t, int);
|
||||
typedef int fido_dev_io_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_rx_t *rx;
|
||||
fido_dev_io_tx_t *tx;
|
||||
} fido_dev_io_t;
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef int fido_sigset_t;
|
||||
#else
|
||||
typedef sigset_t fido_sigset_t;
|
||||
#endif
|
||||
.Ed
|
||||
.Ft int
|
||||
.Fn fido_dev_set_io_functions "fido_dev_t *dev" "const fido_dev_io_t *io"
|
||||
.Ft int
|
||||
.Fn fido_dev_set_sigmask "fido_dev_t *dev" "const fido_sigset_t *sigmask"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
interface defines the I/O and transmission handlers used to talk to
|
||||
.Fa dev .
|
||||
Its usage is optional.
|
||||
By default,
|
||||
.Fn fido_dev_set_io_functions
|
||||
function sets the I/O handlers used by
|
||||
.Em libfido2
|
||||
will use the operating system's native HID interface to talk CTAP2 to
|
||||
a FIDO device.
|
||||
.Pp
|
||||
A
|
||||
.Vt fido_dev_io_open_t
|
||||
function is expected to return a non-NULL opaque pointer on success,
|
||||
and NULL on error.
|
||||
The returned opaque pointer is never dereferenced by
|
||||
.Em libfido2 .
|
||||
.Pp
|
||||
A
|
||||
.Vt fido_dev_io_close_t
|
||||
function receives the opaque handle obtained from
|
||||
.Vt fido_dev_io_open_t .
|
||||
It is not expected to be idempotent.
|
||||
.Pp
|
||||
A
|
||||
.Vt fido_dev_io_read_t
|
||||
function reads a single HID report from
|
||||
to talk to
|
||||
.Fa dev .
|
||||
The first parameter taken is the opaque handle obtained from
|
||||
.Vt fido_dev_io_open_t .
|
||||
The read buffer is pointed to by the second parameter, and the
|
||||
third parameter holds its size.
|
||||
The last argument passed to
|
||||
.Vt fido_dev_io_read_t
|
||||
is the number of milliseconds the caller is willing to sleep,
|
||||
should the call need to block.
|
||||
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_io_read_t
|
||||
.Vt fido_dev_read_t
|
||||
may block indefinitely.
|
||||
The number of bytes read is returned.
|
||||
On success, the number of bytes read is returned.
|
||||
On error, -1 is returned.
|
||||
.Pp
|
||||
A
|
||||
.Vt fido_dev_io_write_t
|
||||
function writes a single HID report to
|
||||
.It Vt fido_dev_write_t
|
||||
Writes a single transmission unit (HID report, APDU) to
|
||||
.Fa dev .
|
||||
The first parameter taken is the opaque handle returned by
|
||||
.Vt fido_dev_io_open_t .
|
||||
The write buffer is pointed to by the second parameter, and the
|
||||
third parameter holds its size.
|
||||
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_io_write_t
|
||||
function may block.
|
||||
The number of bytes written is returned.
|
||||
On error, -1 is returned.
|
||||
.Pp
|
||||
A
|
||||
.Vt fido_dev_io_rx_t
|
||||
function receives a complete CTAP2 message from
|
||||
.Fa dev .
|
||||
The first parameter taken is a pointer to
|
||||
.Fa dev .
|
||||
The second parameter holds the expected CTAP2 command byte.
|
||||
The read buffer is pointed to by the third parameter, and the
|
||||
fourth parameter holds its size.
|
||||
The last argument passed to
|
||||
.Vt fido_dev_io_rx_t
|
||||
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_io_rx_t
|
||||
may block indefinitely.
|
||||
The number of bytes read is returned.
|
||||
On error, -1 is returned.
|
||||
.Pp
|
||||
A
|
||||
.Vt fido_dev_io_tx_t
|
||||
function transmits a complete CTAP2 message to
|
||||
.Fa dev .
|
||||
The first parameter taken is a pointer to
|
||||
.Fa dev .
|
||||
The second parameter holds the CTAP2 command byte.
|
||||
The write buffer is pointed to by the third parameter, and the
|
||||
fourth parameter holds its size.
|
||||
A
|
||||
.Vt fido_dev_io_tx_t
|
||||
function may block.
|
||||
On success, 0 is returned.
|
||||
.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
|
||||
.Fa read ,
|
||||
and
|
||||
.Fa write
|
||||
fields of
|
||||
.Fa io
|
||||
may not be NULL.
|
||||
Either
|
||||
.Fa rx
|
||||
or
|
||||
.Fa tx
|
||||
may be NULL, in which case
|
||||
.Em libfido2
|
||||
uses its corresponding CTAP2 HID transport method.
|
||||
.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 .
|
||||
.Sh RETURN VALUES
|
||||
On success,
|
||||
.Fn fido_dev_set_io_functions
|
||||
returns
|
||||
and
|
||||
.Fn fido_dev_set_sigmask
|
||||
return
|
||||
.Dv FIDO_OK .
|
||||
On error, a different error code defined in
|
||||
.In fido/err.h
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
.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 FIDO 2 device management functions
|
||||
.Sh SYNOPSIS
|
||||
|
@ -17,6 +18,8 @@
|
|||
.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
|
||||
|
@ -51,6 +54,16 @@ before lock-out, where
|
|||
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 ,
|
||||
|
@ -60,6 +73,7 @@ device.
|
|||
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.
|
||||
|
@ -67,6 +81,7 @@ are synchronous and will block if necessary.
|
|||
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
|
||||
|
|
|
@ -20,7 +20,8 @@ function initialises the
|
|||
library.
|
||||
Its invocation must precede that of any other
|
||||
.Em libfido2
|
||||
function.
|
||||
function in the context of the executing thread.
|
||||
.Pp
|
||||
If
|
||||
.Dv FIDO_DEBUG
|
||||
is set in
|
||||
|
@ -33,6 +34,17 @@ on
|
|||
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 be FIDO2 but fails to respond to a
|
||||
FIDO2 command.
|
||||
.Sh SEE ALSO
|
||||
.Xr fido_assert_new 3 ,
|
||||
.Xr fido_cred_new 3 ,
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "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 */
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2010, 2011, 2016 Otto Moerbeek <otto@drijf.net>
|
||||
*
|
||||
* 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_FREEZERO
|
||||
|
||||
void
|
||||
freezero(void *ptr, size_t sz)
|
||||
{
|
||||
if (ptr == NULL)
|
||||
return;
|
||||
explicit_bzero(ptr, sz);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
#endif /* HAVE_FREEZERO */
|
|
@ -0,0 +1,124 @@
|
|||
/* $OpenBSD: hkdf.c,v 1.4 2019/11/21 20:02:20 tim Exp $ */
|
||||
/* Copyright (c) 2014, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "openbsd-compat.h"
|
||||
#include "fido.h"
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
#define CRYPTOerror(r) CRYPTOerr(ERR_LIB_CRYPTO, (r))
|
||||
|
||||
/* https://tools.ietf.org/html/rfc5869#section-2 */
|
||||
int
|
||||
HKDF(uint8_t *out_key, size_t out_len, const EVP_MD *digest,
|
||||
const uint8_t *secret, size_t secret_len, const uint8_t *salt,
|
||||
size_t salt_len, const uint8_t *info, size_t info_len)
|
||||
{
|
||||
uint8_t prk[EVP_MAX_MD_SIZE];
|
||||
size_t prk_len;
|
||||
|
||||
if (!HKDF_extract(prk, &prk_len, digest, secret, secret_len, salt,
|
||||
salt_len))
|
||||
return 0;
|
||||
if (!HKDF_expand(out_key, out_len, digest, prk, prk_len, info,
|
||||
info_len))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* https://tools.ietf.org/html/rfc5869#section-2.2 */
|
||||
int
|
||||
HKDF_extract(uint8_t *out_key, size_t *out_len,
|
||||
const EVP_MD *digest, const uint8_t *secret, size_t secret_len,
|
||||
const uint8_t *salt, size_t salt_len)
|
||||
{
|
||||
unsigned int len;
|
||||
|
||||
/*
|
||||
* If salt is not given, HashLength zeros are used. However, HMAC does
|
||||
* that internally already so we can ignore it.
|
||||
*/
|
||||
if (salt_len > INT_MAX || HMAC(digest, salt, (int)salt_len, secret,
|
||||
secret_len, out_key, &len) == NULL) {
|
||||
CRYPTOerror(ERR_R_CRYPTO_LIB);
|
||||
return 0;
|
||||
}
|
||||
*out_len = len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* https://tools.ietf.org/html/rfc5869#section-2.3 */
|
||||
int
|
||||
HKDF_expand(uint8_t *out_key, size_t out_len,
|
||||
const EVP_MD *digest, const uint8_t *prk, size_t prk_len,
|
||||
const uint8_t *info, size_t info_len)
|
||||
{
|
||||
const size_t digest_len = EVP_MD_size(digest);
|
||||
uint8_t previous[EVP_MAX_MD_SIZE];
|
||||
size_t n, done = 0;
|
||||
unsigned int i;
|
||||
int ret = 0;
|
||||
HMAC_CTX hmac;
|
||||
|
||||
/* Expand key material to desired length. */
|
||||
n = (out_len + digest_len - 1) / digest_len;
|
||||
if (out_len + digest_len < out_len || n > 255 || prk_len > INT_MAX) {
|
||||
CRYPTOerror(EVP_R_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
HMAC_CTX_init(&hmac);
|
||||
if (!HMAC_Init_ex(&hmac, prk, (int)prk_len, digest, NULL))
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
uint8_t ctr = i + 1;
|
||||
size_t todo;
|
||||
|
||||
if (i != 0 && (!HMAC_Init_ex(&hmac, NULL, 0, NULL, NULL) ||
|
||||
!HMAC_Update(&hmac, previous, digest_len)))
|
||||
goto out;
|
||||
|
||||
if (!HMAC_Update(&hmac, info, info_len) ||
|
||||
!HMAC_Update(&hmac, &ctr, 1) ||
|
||||
!HMAC_Final(&hmac, previous, NULL))
|
||||
goto out;
|
||||
|
||||
todo = digest_len;
|
||||
if (done + todo > out_len)
|
||||
todo = out_len - done;
|
||||
|
||||
memcpy(out_key + done, previous, todo);
|
||||
done += todo;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
out:
|
||||
HMAC_CTX_cleanup(&hmac);
|
||||
explicit_bzero(previous, sizeof(previous));
|
||||
if (ret != 1)
|
||||
CRYPTOerror(ERR_R_CRYPTO_LIB);
|
||||
return ret;
|
||||
}
|
||||
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
|
|
@ -0,0 +1,65 @@
|
|||
/* $OpenBSD: hkdf.h,v 1.2 2018/04/03 13:33:53 tb Exp $ */
|
||||
/* Copyright (c) 2014, Google Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
|
||||
|
||||
#ifndef OPENSSL_HEADER_HKDF_H
|
||||
#define OPENSSL_HEADER_HKDF_H
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* HKDF computes HKDF (as specified by RFC 5869) of initial keying
|
||||
* material |secret| with |salt| and |info| using |digest|, and
|
||||
* outputs |out_len| bytes to |out_key|. It returns one on success and
|
||||
* zero on error.
|
||||
*
|
||||
* HKDF is an Extract-and-Expand algorithm. It does not do any key
|
||||
* stretching, and as such, is not suited to be used alone to generate
|
||||
* a key from a password.
|
||||
*/
|
||||
|
||||
int HKDF(uint8_t *out_key, size_t out_len, const struct env_md_st *digest,
|
||||
const uint8_t *secret, size_t secret_len, const uint8_t *salt,
|
||||
size_t salt_len, const uint8_t *info, size_t info_len);
|
||||
|
||||
/*
|
||||
* HKDF_extract computes a HKDF PRK (as specified by RFC 5869) from
|
||||
* initial keying material |secret| and salt |salt| using |digest|,
|
||||
* and outputs |out_len| bytes to |out_key|. The maximum output size
|
||||
* is |EVP_MAX_MD_SIZE|. It returns one on success and zero on error.
|
||||
*/
|
||||
int HKDF_extract(uint8_t *out_key, size_t *out_len,
|
||||
const struct env_md_st *digest, const uint8_t *secret,
|
||||
size_t secret_len, const uint8_t *salt, size_t salt_len);
|
||||
|
||||
/*
|
||||
* HKDF_expand computes a HKDF OKM (as specified by RFC 5869) of
|
||||
* length |out_len| from the PRK |prk| and info |info| using |digest|,
|
||||
* and outputs the result to |out_key|. It returns one on success and
|
||||
* zero on error.
|
||||
*/
|
||||
int HKDF_expand(uint8_t *out_key, size_t out_len,
|
||||
const EVP_MD *digest, const uint8_t *prk, size_t prk_len,
|
||||
const uint8_t *info, size_t info_len);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} /* extern C */
|
||||
#endif
|
||||
|
||||
#endif /* OPENSSL_HEADER_HKDF_H */
|
|
@ -20,9 +20,12 @@
|
|||
#define be16toh(x) OSSwapBigToHostInt16((x))
|
||||
#define htobe16(x) OSSwapHostToBigInt16((x))
|
||||
#define be32toh(x) OSSwapBigToHostInt32((x))
|
||||
#define htole32(x) OSSwapHostToLittleInt32((x))
|
||||
#define htole64(x) OSSwapHostToLittleInt64((x))
|
||||
#endif /* __APPLE__ && !HAVE_ENDIAN_H */
|
||||
|
||||
#if defined(_WIN32) && !defined(HAVE_ENDIAN_H)
|
||||
#include <stdint.h>
|
||||
#include <winsock2.h>
|
||||
#if !defined(_MSC_VER)
|
||||
#include <sys/param.h>
|
||||
|
@ -30,6 +33,8 @@
|
|||
#define be16toh(x) ntohs((x))
|
||||
#define htobe16(x) htons((x))
|
||||
#define be32toh(x) ntohl((x))
|
||||
uint32_t htole32(uint32_t);
|
||||
uint64_t htole64(uint64_t);
|
||||
#endif /* _WIN32 && !HAVE_ENDIAN_H */
|
||||
|
||||
#if defined(__FreeBSD__) && !defined(HAVE_ENDIAN_H)
|
||||
|
@ -37,6 +42,7 @@
|
|||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(HAVE_STRLCAT)
|
||||
size_t strlcat(char *, const char *, size_t);
|
||||
|
@ -54,6 +60,10 @@ void *recallocarray(void *, size_t, size_t, size_t);
|
|||
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
|
||||
|
@ -68,7 +78,11 @@ int timingsafe_bcmp(const void *, const void *, size_t);
|
|||
#include <readpassphrase.h>
|
||||
#endif
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
#include <stdint.h>
|
||||
#include "hkdf.h"
|
||||
#define EVP_PKEY_get0_EC_KEY(x) ((x)->pkey.ec)
|
||||
#define EVP_PKEY_get0_RSA(x) ((x)->pkey.rsa)
|
||||
#endif
|
||||
|
@ -90,6 +104,16 @@ int timingsafe_bcmp(const void *, const void *, size_t);
|
|||
ssize_t getline(char **, size_t *, FILE *);
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define strerror_r(e, b, l) strerror_s((b), (l), (e))
|
||||
#endif
|
||||
|
||||
#include "time.h"
|
||||
|
||||
#if !defined(HAVE_POSIX_IOCTL)
|
||||
#define IOCTL_REQ(x) (x)
|
||||
#else
|
||||
#define IOCTL_REQ(x) ((int)(x))
|
||||
#endif
|
||||
|
||||
#endif /* !_OPENBSD_COMPAT_H */
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#include <sys/ioctl.h>
|
||||
|
||||
int
|
||||
posix_ioctl_check(int fd)
|
||||
{
|
||||
return ioctl(fd, -1, 0);
|
||||
}
|
|
@ -32,15 +32,30 @@ int clock_gettime(clockid_t, struct timespec *);
|
|||
#endif
|
||||
|
||||
#ifndef HAVE_TIMESPECSUB
|
||||
#define timespecsub(tsp, usp, vsp) \
|
||||
do { \
|
||||
(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
|
||||
(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
|
||||
if ((vsp)->tv_nsec < 0) { \
|
||||
(vsp)->tv_sec--; \
|
||||
(vsp)->tv_nsec += 1000000000L; \
|
||||
} \
|
||||
} while (0)
|
||||
#define timespecadd(tsp, usp, vsp) \
|
||||
do { \
|
||||
(vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \
|
||||
(vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \
|
||||
if ((vsp)->tv_nsec >= 1000000000L) { \
|
||||
(vsp)->tv_sec++; \
|
||||
(vsp)->tv_nsec -= 1000000000L; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define timespecsub(tsp, usp, vsp) \
|
||||
do { \
|
||||
(vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
|
||||
(vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
|
||||
if ((vsp)->tv_nsec < 0) { \
|
||||
(vsp)->tv_sec--; \
|
||||
(vsp)->tv_nsec += 1000000000L; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define timespeccmp(tsp, usp, cmp) \
|
||||
(((tsp)->tv_sec == (usp)->tv_sec) ? \
|
||||
((tsp)->tv_nsec cmp (usp)->tv_nsec) : \
|
||||
((tsp)->tv_sec cmp (usp)->tv_sec))
|
||||
#endif
|
||||
|
||||
#endif /* _COMPAT_TIME_H */
|
||||
|
|
|
@ -23,6 +23,11 @@ typedef uint32_t uid_t;
|
|||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned char u_char;
|
||||
typedef unsigned short u_short;
|
||||
typedef unsigned int u_int;
|
||||
typedef unsigned long u_long;
|
||||
|
||||
#include <basetsd.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <fido.h>
|
||||
#include <fido/es256.h>
|
||||
#include <fido/rs256.h>
|
||||
#include <fido/eddsa.h>
|
||||
#include <string.h>
|
||||
|
||||
#define FAKE_DEV_HANDLE ((void *)0xdeadbeef)
|
||||
|
@ -159,11 +160,30 @@ free_rs256_pk(rs256_pk_t *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);
|
||||
|
@ -183,6 +203,7 @@ empty_assert(fido_dev_t *d, fido_assert_t *a, size_t idx)
|
|||
|
||||
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);
|
||||
|
@ -191,8 +212,12 @@ empty_assert(fido_dev_t *d, fido_assert_t *a, size_t idx)
|
|||
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);
|
||||
|
@ -201,11 +226,16 @@ empty_assert(fido_dev_t *d, fido_assert_t *a, size_t idx)
|
|||
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
|
||||
|
@ -244,11 +274,15 @@ static void
|
|||
valid_assert(void)
|
||||
{
|
||||
fido_assert_t *a;
|
||||
es256_pk_t *pk;
|
||||
es256_pk_t *es256;
|
||||
rs256_pk_t *rs256;
|
||||
eddsa_pk_t *eddsa;
|
||||
|
||||
a = alloc_assert();
|
||||
pk = alloc_es256_pk();
|
||||
assert(es256_pk_from_ptr(pk, es256_pk, sizeof(es256_pk)) == FIDO_OK);
|
||||
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);
|
||||
|
@ -257,9 +291,13 @@ valid_assert(void)
|
|||
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_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(pk);
|
||||
free_es256_pk(es256);
|
||||
free_rs256_pk(rs256);
|
||||
free_eddsa_pk(eddsa);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <cbor.h>
|
||||
#include <fido.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -327,6 +328,8 @@ empty_cred(void)
|
|||
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);
|
||||
|
@ -696,6 +699,8 @@ junk_authdata(void)
|
|||
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);
|
||||
|
@ -866,6 +871,46 @@ wrong_credprot(void)
|
|||
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);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
|
@ -892,6 +937,7 @@ main(void)
|
|||
duplicate_keys();
|
||||
unsorted_keys();
|
||||
wrong_credprot();
|
||||
raw_authdata();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
@ -8,9 +8,16 @@
|
|||
#include <fido.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../fuzz/wiredata_fido2.h"
|
||||
|
||||
#define FAKE_DEV_HANDLE ((void *)0xdeadbeef)
|
||||
#define REPORT_LEN (64 + 1)
|
||||
|
||||
static uint8_t ctap_nonce[8];
|
||||
static uint8_t *wiredata_ptr;
|
||||
static size_t wiredata_len;
|
||||
static int initialised;
|
||||
|
||||
static void *
|
||||
dummy_open(const char *path)
|
||||
{
|
||||
|
@ -28,13 +35,33 @@ dummy_close(void *handle)
|
|||
static int
|
||||
dummy_read(void *handle, unsigned char *ptr, size_t len, int ms)
|
||||
{
|
||||
(void)ptr;
|
||||
(void)len;
|
||||
size_t n;
|
||||
|
||||
(void)ms;
|
||||
|
||||
assert(handle == FAKE_DEV_HANDLE);
|
||||
assert(ptr != NULL);
|
||||
assert(len == REPORT_LEN - 1);
|
||||
|
||||
return (-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 (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
|
||||
|
@ -44,9 +71,41 @@ dummy_write(void *handle, const unsigned char *ptr, size_t len)
|
|||
assert(ptr != NULL);
|
||||
assert(len == REPORT_LEN);
|
||||
|
||||
if (!initialised)
|
||||
memcpy(&ctap_nonce, &ptr[8], sizeof(ctap_nonce));
|
||||
|
||||
return ((int)len);
|
||||
}
|
||||
|
||||
static uint8_t *
|
||||
wiredata_setup(const uint8_t *data, size_t len)
|
||||
{
|
||||
const uint8_t ctap_init_data[] = { WIREDATA_CTAP_INIT };
|
||||
|
||||
assert(wiredata_ptr == NULL);
|
||||
assert(SIZE_MAX - len > sizeof(ctap_init_data));
|
||||
assert((wiredata_ptr = malloc(sizeof(ctap_init_data) + len)) != NULL);
|
||||
|
||||
memcpy(wiredata_ptr, ctap_init_data, sizeof(ctap_init_data));
|
||||
|
||||
if (len)
|
||||
memcpy(wiredata_ptr + sizeof(ctap_init_data), data, len);
|
||||
|
||||
wiredata_len = sizeof(ctap_init_data) + len;
|
||||
|
||||
return (wiredata_ptr);
|
||||
}
|
||||
|
||||
static void
|
||||
wiredata_clear(uint8_t **wiredata)
|
||||
{
|
||||
free(*wiredata);
|
||||
*wiredata = NULL;
|
||||
wiredata_ptr = NULL;
|
||||
wiredata_len = 0;
|
||||
initialised = 0;
|
||||
}
|
||||
|
||||
/* gh#56 */
|
||||
static void
|
||||
open_iff_ok(void)
|
||||
|
@ -69,12 +128,139 @@ open_iff_ok(void)
|
|||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
wiredata_clear(&wiredata);
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
fido_init(0);
|
||||
|
||||
open_iff_ok();
|
||||
reopen();
|
||||
double_open();
|
||||
is_fido2();
|
||||
has_pin();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ list(APPEND FIDO_SOURCES
|
|||
blob.c
|
||||
buf.c
|
||||
cbor.c
|
||||
compress.c
|
||||
config.c
|
||||
cred.c
|
||||
credman.c
|
||||
dev.c
|
||||
|
@ -23,8 +25,10 @@ list(APPEND FIDO_SOURCES
|
|||
info.c
|
||||
io.c
|
||||
iso7816.c
|
||||
largeblob.c
|
||||
log.c
|
||||
pin.c
|
||||
random.c
|
||||
reset.c
|
||||
rs256.c
|
||||
u2f.c
|
||||
|
@ -35,6 +39,9 @@ if(FUZZ)
|
|||
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)
|
||||
endif()
|
||||
|
||||
if(USE_HIDAPI)
|
||||
list(APPEND FIDO_SOURCES hid_hidapi.c)
|
||||
|
@ -43,9 +50,13 @@ elseif(WIN32)
|
|||
elseif(APPLE)
|
||||
list(APPEND FIDO_SOURCES hid_osx.c)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
list(APPEND FIDO_SOURCES hid_linux.c)
|
||||
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)
|
||||
list(APPEND FIDO_SOURCES hid_openbsd.c hid_unix.c)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
|
||||
list(APPEND FIDO_SOURCES hid_freebsd.c hid_unix.c)
|
||||
else()
|
||||
message(FATAL_ERROR "please define a hid backend for your platform")
|
||||
endif()
|
||||
|
@ -57,53 +68,60 @@ endif()
|
|||
|
||||
list(APPEND COMPAT_SOURCES
|
||||
../openbsd-compat/bsd-getpagesize.c
|
||||
../openbsd-compat/endian_win32.c
|
||||
../openbsd-compat/explicit_bzero.c
|
||||
../openbsd-compat/explicit_bzero_win32.c
|
||||
../openbsd-compat/freezero.c
|
||||
../openbsd-compat/hkdf.c
|
||||
../openbsd-compat/recallocarray.c
|
||||
../openbsd-compat/strlcat.c
|
||||
../openbsd-compat/timingsafe_bcmp.c
|
||||
)
|
||||
|
||||
# static library
|
||||
add_library(fido2 STATIC ${FIDO_SOURCES} ${COMPAT_SOURCES})
|
||||
target_link_libraries(fido2 ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES}
|
||||
${UDEV_LIBRARIES} ${BASE_LIBRARIES} ${HIDAPI_LIBRARIES})
|
||||
if(WIN32)
|
||||
if (MINGW)
|
||||
target_link_libraries(fido2 wsock32 ws2_32 bcrypt setupapi hid)
|
||||
else()
|
||||
target_link_libraries(fido2 wsock32 ws2_32 bcrypt SetupAPI hid)
|
||||
set_target_properties(fido2 PROPERTIES OUTPUT_NAME fido2_static)
|
||||
if(BUILD_STATIC_LIBS)
|
||||
add_library(fido2 STATIC ${FIDO_SOURCES} ${COMPAT_SOURCES})
|
||||
target_link_libraries(fido2 ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES}
|
||||
${UDEV_LIBRARIES} ${BASE_LIBRARIES} ${HIDAPI_LIBRARIES} ${ZLIB_LIBRARIES})
|
||||
if(WIN32)
|
||||
if (MINGW)
|
||||
target_link_libraries(fido2 wsock32 ws2_32 bcrypt setupapi hid)
|
||||
else()
|
||||
target_link_libraries(fido2 wsock32 ws2_32 bcrypt SetupAPI hid)
|
||||
set_target_properties(fido2 PROPERTIES OUTPUT_NAME fido2_static)
|
||||
endif()
|
||||
elseif(APPLE)
|
||||
target_link_libraries(fido2 "-framework CoreFoundation"
|
||||
"-framework IOKit")
|
||||
endif()
|
||||
elseif(APPLE)
|
||||
target_link_libraries(fido2 "-framework CoreFoundation"
|
||||
"-framework IOKit")
|
||||
install(TARGETS fido2 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
install(TARGETS fido2 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
# dynamic library
|
||||
add_library(fido2_shared SHARED ${FIDO_SOURCES} ${COMPAT_SOURCES})
|
||||
target_link_libraries(fido2_shared ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES}
|
||||
${UDEV_LIBRARIES} ${BASE_LIBRARIES} ${HIDAPI_LIBRARIES})
|
||||
if(WIN32)
|
||||
if (MINGW)
|
||||
target_link_libraries(fido2_shared wsock32 ws2_32 bcrypt
|
||||
setupapi hid)
|
||||
else()
|
||||
target_link_libraries(fido2_shared wsock32 ws2_32 bcrypt
|
||||
SetupAPI hid)
|
||||
if(BUILD_SHARED_LIBS)
|
||||
add_library(fido2_shared SHARED ${FIDO_SOURCES} ${COMPAT_SOURCES})
|
||||
target_link_libraries(fido2_shared ${CBOR_LIBRARIES} ${CRYPTO_LIBRARIES}
|
||||
${UDEV_LIBRARIES} ${BASE_LIBRARIES} ${HIDAPI_LIBRARIES} ${ZLIB_LIBRARIES})
|
||||
if(WIN32)
|
||||
if (MINGW)
|
||||
target_link_libraries(fido2_shared wsock32 ws2_32 bcrypt
|
||||
setupapi hid)
|
||||
else()
|
||||
target_link_libraries(fido2_shared wsock32 ws2_32 bcrypt
|
||||
SetupAPI hid)
|
||||
endif()
|
||||
elseif(APPLE)
|
||||
target_link_libraries(fido2_shared "-framework CoreFoundation"
|
||||
"-framework IOKit")
|
||||
endif()
|
||||
elseif(APPLE)
|
||||
target_link_libraries(fido2_shared "-framework CoreFoundation"
|
||||
"-framework IOKit")
|
||||
set_target_properties(fido2_shared PROPERTIES OUTPUT_NAME fido2
|
||||
VERSION ${FIDO_VERSION} SOVERSION ${FIDO_MAJOR})
|
||||
install(TARGETS fido2_shared
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
set_target_properties(fido2_shared PROPERTIES OUTPUT_NAME fido2
|
||||
VERSION ${FIDO_VERSION} SOVERSION ${FIDO_MAJOR})
|
||||
install(TARGETS fido2_shared
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
install(FILES fido.h DESTINATION include)
|
||||
install(DIRECTORY fido DESTINATION include)
|
||||
|
|
|
@ -1,98 +1,215 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Yubico AB. All rights reserved.
|
||||
* Copyright (c) 2021 Yubico AB. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fido.h"
|
||||
|
||||
int
|
||||
aes256_cbc_enc(const fido_blob_t *key, const fido_blob_t *in, fido_blob_t *out)
|
||||
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;
|
||||
unsigned char iv[32];
|
||||
int len;
|
||||
int ok = -1;
|
||||
EVP_CIPHER_CTX *ctx = NULL;
|
||||
const EVP_CIPHER *cipher;
|
||||
int ok = -1;
|
||||
|
||||
memset(iv, 0, sizeof(iv));
|
||||
out->ptr = NULL;
|
||||
out->len = 0;
|
||||
memset(out, 0, sizeof(*out));
|
||||
|
||||
/* sanity check */
|
||||
if (in->len > INT_MAX || (in->len % 16) != 0 ||
|
||||
(out->ptr = calloc(1, in->len)) == NULL) {
|
||||
fido_log_debug("%s: in->len=%zu", __func__, in->len);
|
||||
if (key->len != 32) {
|
||||
fido_log_debug("%s: invalid key len %zu", __func__, key->len);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((ctx = EVP_CIPHER_CTX_new()) == NULL || key->len != 32 ||
|
||||
!EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key->ptr, iv) ||
|
||||
!EVP_CIPHER_CTX_set_padding(ctx, 0) ||
|
||||
!EVP_EncryptUpdate(ctx, out->ptr, &len, in->ptr, (int)in->len) ||
|
||||
len < 0 || (size_t)len != in->len) {
|
||||
fido_log_debug("%s: EVP_Encrypt", __func__);
|
||||
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;
|
||||
}
|
||||
|
||||
out->len = (size_t)len;
|
||||
|
||||
ok = 0;
|
||||
fail:
|
||||
if (ctx != NULL)
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
if (ok < 0)
|
||||
fido_blob_reset(out);
|
||||
|
||||
if (ok < 0) {
|
||||
free(out->ptr);
|
||||
out->ptr = NULL;
|
||||
out->len = 0;
|
||||
}
|
||||
|
||||
return (ok);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int
|
||||
aes256_cbc_dec(const fido_blob_t *key, const fido_blob_t *in, fido_blob_t *out)
|
||||
static int
|
||||
aes256_cbc_proto1(const fido_blob_t *key, const fido_blob_t *in,
|
||||
fido_blob_t *out, int encrypt)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx = NULL;
|
||||
unsigned char iv[32];
|
||||
int len;
|
||||
int ok = -1;
|
||||
u_char iv[16];
|
||||
|
||||
memset(iv, 0, sizeof(iv));
|
||||
out->ptr = NULL;
|
||||
out->len = 0;
|
||||
memset(&iv, 0, sizeof(iv));
|
||||
|
||||
/* sanity check */
|
||||
if (in->len > INT_MAX || (in->len % 16) != 0 ||
|
||||
(out->ptr = calloc(1, in->len)) == NULL) {
|
||||
fido_log_debug("%s: in->len=%zu", __func__, in->len);
|
||||
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 ((ctx = EVP_CIPHER_CTX_new()) == NULL || key->len != 32 ||
|
||||
!EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key->ptr, iv) ||
|
||||
!EVP_CIPHER_CTX_set_padding(ctx, 0) ||
|
||||
!EVP_DecryptUpdate(ctx, out->ptr, &len, in->ptr, (int)in->len) ||
|
||||
len < 0 || (size_t)len > in->len + 32) {
|
||||
fido_log_debug("%s: EVP_Decrypt", __func__);
|
||||
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;
|
||||
}
|
||||
|
||||
out->len = (size_t)len;
|
||||
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);
|
||||
|
||||
if (ok < 0) {
|
||||
free(out->ptr);
|
||||
out->ptr = NULL;
|
||||
out->len = 0;
|
||||
}
|
||||
|
||||
return (ok);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Yubico AB. All rights reserved.
|
||||
* Copyright (c) 2018-2021 Yubico AB. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include <string.h>
|
||||
#include "fido.h"
|
||||
#include "fido/es256.h"
|
||||
#include "fido/rs256.h"
|
||||
|
@ -67,12 +64,13 @@ parse_assert_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
|
|||
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,
|
||||
&stmt->hmac_secret_enc));
|
||||
&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);
|
||||
|
@ -85,6 +83,7 @@ fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert,
|
|||
{
|
||||
fido_blob_t f;
|
||||
cbor_item_t *argv[7];
|
||||
const uint8_t cmd = CTAP_CBOR_ASSERT;
|
||||
int r;
|
||||
|
||||
memset(argv, 0, sizeof(argv));
|
||||
|
@ -115,44 +114,33 @@ fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert,
|
|||
}
|
||||
}
|
||||
|
||||
/* hmac-secret extension */
|
||||
if (assert->ext & FIDO_EXT_HMAC_SECRET)
|
||||
if ((argv[3] = cbor_encode_hmac_secret_param(ecdh, pk,
|
||||
&assert->hmac_salt)) == NULL) {
|
||||
fido_log_debug("%s: cbor_encode_hmac_secret_param",
|
||||
__func__);
|
||||
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;
|
||||
}
|
||||
|
||||
/* options */
|
||||
if (assert->up != FIDO_OPT_OMIT || assert->uv != FIDO_OPT_OMIT)
|
||||
if ((argv[4] = cbor_encode_assert_options(assert->up,
|
||||
if ((argv[4] = cbor_encode_assert_opt(assert->up,
|
||||
assert->uv)) == NULL) {
|
||||
fido_log_debug("%s: cbor_encode_assert_options",
|
||||
__func__);
|
||||
fido_log_debug("%s: cbor_encode_assert_opt", __func__);
|
||||
r = FIDO_ERR_INTERNAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* pin authentication */
|
||||
if (pin) {
|
||||
if (pk == NULL || ecdh == NULL) {
|
||||
fido_log_debug("%s: pin=%p, pk=%p, ecdh=%p", __func__,
|
||||
(const void *)pin, (const void *)pk,
|
||||
(const void *)ecdh);
|
||||
r = FIDO_ERR_INVALID_ARGUMENT;
|
||||
/* user verification */
|
||||
if (fido_dev_can_get_uv_token(dev, pin, assert->uv))
|
||||
if ((r = cbor_add_uv_params(dev, cmd, &assert->cdh, pk, ecdh,
|
||||
pin, assert->rp_id, &argv[5], &argv[6])) != FIDO_OK) {
|
||||
fido_log_debug("%s: cbor_add_uv_params", __func__);
|
||||
goto fail;
|
||||
}
|
||||
if ((r = cbor_add_pin_params(dev, &assert->cdh, pk, ecdh, pin,
|
||||
&argv[5], &argv[6])) != FIDO_OK) {
|
||||
fido_log_debug("%s: cbor_add_pin_params", __func__);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* frame and transmit */
|
||||
if (cbor_build_frame(CTAP_CBOR_ASSERT, argv, nitems(argv), &f) < 0 ||
|
||||
if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
|
||||
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
|
||||
fido_log_debug("%s: fido_tx", __func__);
|
||||
r = FIDO_ERR_TX;
|
||||
|
@ -271,12 +259,14 @@ fido_dev_get_assert_wait(fido_dev_t *dev, fido_assert_t *assert,
|
|||
}
|
||||
|
||||
static int
|
||||
decrypt_hmac_secrets(fido_assert_t *assert, const fido_blob_t *key)
|
||||
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->hmac_secret_enc.ptr != NULL) {
|
||||
if (aes256_cbc_dec(key, &stmt->hmac_secret_enc,
|
||||
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);
|
||||
|
@ -302,12 +292,13 @@ fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin)
|
|||
}
|
||||
|
||||
if (fido_dev_is_fido2(dev) == false) {
|
||||
if (pin != NULL || assert->ext != 0)
|
||||
if (pin != NULL || assert->ext.mask != 0)
|
||||
return (FIDO_ERR_UNSUPPORTED_OPTION);
|
||||
return (u2f_authenticate(dev, assert, -1));
|
||||
}
|
||||
|
||||
if (pin != NULL || assert->ext != 0) {
|
||||
if (fido_dev_can_get_uv_token(dev, pin, assert->uv) ||
|
||||
(assert->ext.mask & FIDO_EXT_HMAC_SECRET)) {
|
||||
if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
|
||||
fido_log_debug("%s: fido_do_ecdh", __func__);
|
||||
goto fail;
|
||||
|
@ -315,8 +306,8 @@ fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin)
|
|||
}
|
||||
|
||||
r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, -1);
|
||||
if (r == FIDO_OK && assert->ext & FIDO_EXT_HMAC_SECRET)
|
||||
if (decrypt_hmac_secrets(assert, ecdh) < 0) {
|
||||
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;
|
||||
|
@ -353,6 +344,8 @@ fido_check_flags(uint8_t flags, fido_opt_t up, fido_opt_t uv)
|
|||
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);
|
||||
|
@ -363,8 +356,8 @@ check_extensions(int authdata_ext, int ext)
|
|||
}
|
||||
|
||||
int
|
||||
fido_get_signed_hash(int cose_alg, fido_blob_t *dgst, const fido_blob_t *clientdata,
|
||||
const fido_blob_t *authdata_cbor)
|
||||
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;
|
||||
|
@ -566,7 +559,7 @@ fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (check_extensions(stmt->authdata_ext, assert->ext) < 0) {
|
||||
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;
|
||||
|
@ -627,7 +620,19 @@ 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->hmac_salt, salt, salt_len) < 0)
|
||||
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);
|
||||
|
@ -686,10 +691,13 @@ fail:
|
|||
int
|
||||
fido_assert_set_extensions(fido_assert_t *assert, int ext)
|
||||
{
|
||||
if (ext != 0 && ext != FIDO_EXT_HMAC_SECRET)
|
||||
return (FIDO_ERR_INVALID_ARGUMENT);
|
||||
|
||||
assert->ext = 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);
|
||||
}
|
||||
|
@ -741,42 +749,40 @@ void
|
|||
fido_assert_reset_tx(fido_assert_t *assert)
|
||||
{
|
||||
free(assert->rp_id);
|
||||
free(assert->cdh.ptr);
|
||||
free(assert->hmac_salt.ptr);
|
||||
fido_blob_reset(&assert->cdh);
|
||||
fido_blob_reset(&assert->ext.hmac_salt);
|
||||
fido_free_blob_array(&assert->allow_list);
|
||||
|
||||
memset(&assert->cdh, 0, sizeof(assert->cdh));
|
||||
memset(&assert->hmac_salt, 0, sizeof(assert->hmac_salt));
|
||||
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;
|
||||
assert->ext = 0;
|
||||
}
|
||||
|
||||
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.id.ptr);
|
||||
free(assert->stmt[i].user.icon);
|
||||
free(assert->stmt[i].user.name);
|
||||
free(assert->stmt[i].user.display_name);
|
||||
free(assert->stmt[i].id.ptr);
|
||||
if (assert->stmt[i].hmac_secret.ptr != NULL) {
|
||||
explicit_bzero(assert->stmt[i].hmac_secret.ptr,
|
||||
assert->stmt[i].hmac_secret.len);
|
||||
}
|
||||
free(assert->stmt[i].hmac_secret.ptr);
|
||||
free(assert->stmt[i].hmac_secret_enc.ptr);
|
||||
free(assert->stmt[i].authdata_cbor.ptr);
|
||||
free(assert->stmt[i].sig.ptr);
|
||||
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;
|
||||
|
@ -789,12 +795,9 @@ fido_assert_free(fido_assert_t **assert_p)
|
|||
|
||||
if (assert_p == NULL || (assert = *assert_p) == NULL)
|
||||
return;
|
||||
|
||||
fido_assert_reset_tx(assert);
|
||||
fido_assert_reset_rx(assert);
|
||||
|
||||
free(assert);
|
||||
|
||||
*assert_p = NULL;
|
||||
}
|
||||
|
||||
|
@ -945,16 +948,48 @@ fido_assert_hmac_secret_len(const fido_assert_t *assert, size_t idx)
|
|||
return (assert->stmt[idx].hmac_secret.len);
|
||||
}
|
||||
|
||||
static void
|
||||
fido_assert_clean_authdata(fido_assert_stmt *as)
|
||||
const unsigned char *
|
||||
fido_assert_largeblob_key_ptr(const fido_assert_t *assert, size_t idx)
|
||||
{
|
||||
free(as->authdata_cbor.ptr);
|
||||
free(as->hmac_secret_enc.ptr);
|
||||
if (idx >= assert->stmt_len)
|
||||
return (NULL);
|
||||
|
||||
memset(&as->authdata_ext, 0, sizeof(as->authdata_ext));
|
||||
memset(&as->authdata_cbor, 0, sizeof(as->authdata_cbor));
|
||||
memset(&as->authdata, 0, sizeof(as->authdata));
|
||||
memset(&as->hmac_secret_enc, 0, sizeof(as->hmac_secret_enc));
|
||||
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
|
||||
|
@ -979,7 +1014,7 @@ fido_assert_set_authdata(fido_assert_t *assert, size_t idx,
|
|||
}
|
||||
|
||||
if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor,
|
||||
&stmt->authdata, &stmt->authdata_ext, &stmt->hmac_secret_enc) < 0) {
|
||||
&stmt->authdata, &stmt->authdata_ext) < 0) {
|
||||
fido_log_debug("%s: cbor_decode_assert_authdata", __func__);
|
||||
r = FIDO_ERR_INVALID_ARGUMENT;
|
||||
goto fail;
|
||||
|
@ -1017,7 +1052,7 @@ fido_assert_set_authdata_raw(fido_assert_t *assert, size_t idx,
|
|||
}
|
||||
|
||||
if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor,
|
||||
&stmt->authdata, &stmt->authdata_ext, &stmt->hmac_secret_enc) < 0) {
|
||||
&stmt->authdata, &stmt->authdata_ext) < 0) {
|
||||
fido_log_debug("%s: cbor_decode_assert_authdata", __func__);
|
||||
r = FIDO_ERR_INVALID_ARGUMENT;
|
||||
goto fail;
|
||||
|
@ -1034,14 +1069,6 @@ fail:
|
|||
return (r);
|
||||
}
|
||||
|
||||
static void
|
||||
fido_assert_clean_sig(fido_assert_stmt *as)
|
||||
{
|
||||
free(as->sig.ptr);
|
||||
as->sig.ptr = NULL;
|
||||
as->sig.len = 0;
|
||||
}
|
||||
|
||||
int
|
||||
fido_assert_set_sig(fido_assert_t *a, size_t idx, const unsigned char *ptr,
|
||||
size_t len)
|
||||
|
@ -1051,7 +1078,7 @@ fido_assert_set_sig(fido_assert_t *a, size_t idx, const unsigned char *ptr,
|
|||
if (idx >= a->stmt_len || ptr == NULL || len == 0)
|
||||
return (FIDO_ERR_INVALID_ARGUMENT);
|
||||
|
||||
fido_assert_clean_sig(&a->stmt[idx]);
|
||||
fido_blob_reset(&a->stmt[idx].sig);
|
||||
|
||||
if ((sig = malloc(len)) == NULL)
|
||||
return (FIDO_ERR_INTERNAL);
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "fido.h"
|
||||
|
||||
static int
|
||||
|
@ -35,7 +34,7 @@ fido_dev_authkey_tx(fido_dev_t *dev)
|
|||
memset(argv, 0, sizeof(argv));
|
||||
|
||||
/* add command parameters */
|
||||
if ((argv[0] = cbor_build_uint8(1)) == NULL ||
|
||||
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;
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "fido.h"
|
||||
#include "fido/bio.h"
|
||||
#include "fido/es256.h"
|
||||
|
@ -59,7 +57,7 @@ fail:
|
|||
}
|
||||
|
||||
static int
|
||||
bio_tx(fido_dev_t *dev, uint8_t cmd, cbor_item_t **sub_argv, size_t sub_argc,
|
||||
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)
|
||||
{
|
||||
cbor_item_t *argv[5];
|
||||
|
@ -67,6 +65,7 @@ bio_tx(fido_dev_t *dev, uint8_t cmd, cbor_item_t **sub_argv, size_t sub_argc,
|
|||
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));
|
||||
|
@ -75,14 +74,14 @@ bio_tx(fido_dev_t *dev, uint8_t cmd, cbor_item_t **sub_argv, size_t sub_argc,
|
|||
|
||||
/* modality, subCommand */
|
||||
if ((argv[0] = cbor_build_uint8(1)) == NULL ||
|
||||
(argv[1] = cbor_build_uint8(cmd)) == 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(cmd, sub_argv, sub_argc, &argv[2],
|
||||
if (bio_prepare_hmac(subcmd, sub_argv, sub_argc, &argv[2],
|
||||
&hmac) < 0) {
|
||||
fido_log_debug("%s: bio_prepare_hmac", __func__);
|
||||
goto fail;
|
||||
|
@ -95,22 +94,22 @@ bio_tx(fido_dev_t *dev, uint8_t cmd, cbor_item_t **sub_argv, size_t sub_argc,
|
|||
fido_log_debug("%s: fido_do_ecdh", __func__);
|
||||
goto fail;
|
||||
}
|
||||
if ((r = cbor_add_pin_params(dev, &hmac, pk, ecdh, pin,
|
||||
&argv[4], &argv[3])) != FIDO_OK) {
|
||||
fido_log_debug("%s: cbor_add_pin_params", __func__);
|
||||
if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin,
|
||||
NULL, &argv[4], &argv[3])) != FIDO_OK) {
|
||||
fido_log_debug("%s: cbor_add_uv_params", __func__);
|
||||
goto fail;
|
||||
}
|
||||
} else if (token) {
|
||||
if ((argv[3] = cbor_encode_pin_opt()) == NULL ||
|
||||
(argv[4] = cbor_encode_pin_auth(token, &hmac)) == NULL) {
|
||||
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(CTAP_CBOR_BIO_ENROLL_PRE, argv, nitems(argv),
|
||||
&f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
|
||||
if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
|
||||
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
|
||||
fido_log_debug("%s: fido_tx", __func__);
|
||||
r = FIDO_ERR_TX;
|
||||
goto fail;
|
||||
|
@ -461,8 +460,9 @@ fido_bio_dev_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if ((r = fido_dev_get_pin_token(dev, pin, ecdh, pk, token)) != FIDO_OK) {
|
||||
fido_log_debug("%s: fido_dev_get_pin_token", __func__);
|
||||
if ((r = fido_dev_get_uv_token(dev, CTAP_CBOR_BIO_ENROLL_PRE, pin, ecdh,
|
||||
pk, NULL, token)) != FIDO_OK) {
|
||||
fido_log_debug("%s: fido_dev_get_uv_token", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,41 +4,66 @@
|
|||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "fido.h"
|
||||
|
||||
fido_blob_t *
|
||||
fido_blob_new(void)
|
||||
{
|
||||
return (calloc(1, sizeof(fido_blob_t)));
|
||||
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 unsigned char *ptr, size_t len)
|
||||
fido_blob_set(fido_blob_t *b, const u_char *ptr, size_t len)
|
||||
{
|
||||
if (b->ptr != NULL) {
|
||||
explicit_bzero(b->ptr, b->len);
|
||||
free(b->ptr);
|
||||
b->ptr = NULL;
|
||||
}
|
||||
|
||||
b->len = 0;
|
||||
fido_blob_reset(b);
|
||||
|
||||
if (ptr == NULL || len == 0) {
|
||||
fido_log_debug("%s: ptr=%p, len=%zu", __func__,
|
||||
(const void *)ptr, len);
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((b->ptr = malloc(len)) == NULL) {
|
||||
fido_log_debug("%s: malloc", __func__);
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(b->ptr, ptr, len);
|
||||
b->len = len;
|
||||
|
||||
return (0);
|
||||
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
|
||||
|
@ -49,14 +74,8 @@ fido_blob_free(fido_blob_t **bp)
|
|||
if (bp == NULL || (b = *bp) == NULL)
|
||||
return;
|
||||
|
||||
if (b->ptr) {
|
||||
explicit_bzero(b->ptr, b->len);
|
||||
free(b->ptr);
|
||||
}
|
||||
|
||||
explicit_bzero(b, sizeof(*b));
|
||||
fido_blob_reset(b);
|
||||
free(b);
|
||||
|
||||
*bp = NULL;
|
||||
}
|
||||
|
||||
|
@ -68,11 +87,8 @@ fido_free_blob_array(fido_blob_array_t *array)
|
|||
|
||||
for (size_t i = 0; i < array->len; i++) {
|
||||
fido_blob_t *b = &array->ptr[i];
|
||||
if (b->ptr != NULL) {
|
||||
explicit_bzero(b->ptr, b->len);
|
||||
free(b->ptr);
|
||||
b->ptr = NULL;
|
||||
}
|
||||
freezero(b->ptr, b->len);
|
||||
b->ptr = NULL;
|
||||
}
|
||||
|
||||
free(array->ptr);
|
||||
|
@ -84,19 +100,34 @@ cbor_item_t *
|
|||
fido_blob_encode(const fido_blob_t *b)
|
||||
{
|
||||
if (b == NULL || b->ptr == NULL)
|
||||
return (NULL);
|
||||
return NULL;
|
||||
|
||||
return (cbor_build_bytestring(b->ptr, b->len));
|
||||
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));
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -28,8 +28,10 @@ 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 unsigned char *, size_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
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "fido.h"
|
||||
|
||||
int
|
||||
|
|
|
@ -4,11 +4,8 @@
|
|||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include <string.h>
|
||||
#include "fido.h"
|
||||
|
||||
static int
|
||||
|
@ -563,21 +560,37 @@ fail:
|
|||
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_extensions(const fido_cred_ext_t *ext)
|
||||
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 (size == 0 || (item = cbor_new_definite_map(size)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (ext->mask & FIDO_EXT_HMAC_SECRET) {
|
||||
if (cbor_add_bool(item, "hmac-secret", FIDO_OPT_TRUE) < 0) {
|
||||
if (ext->mask & FIDO_EXT_CRED_BLOB) {
|
||||
if (cbor_add_bytestring(item, "credBlob", blob->ptr,
|
||||
blob->len) < 0) {
|
||||
cbor_decref(&item);
|
||||
return (NULL);
|
||||
}
|
||||
|
@ -590,18 +603,29 @@ cbor_encode_extensions(const fido_cred_ext_t *ext)
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return (item);
|
||||
}
|
||||
|
||||
cbor_item_t *
|
||||
cbor_encode_options(fido_opt_t rk, fido_opt_t uv)
|
||||
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);
|
||||
|
@ -612,13 +636,12 @@ cbor_encode_options(fido_opt_t rk, fido_opt_t uv)
|
|||
}
|
||||
|
||||
cbor_item_t *
|
||||
cbor_encode_assert_options(fido_opt_t up, fido_opt_t uv)
|
||||
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);
|
||||
|
@ -629,62 +652,55 @@ cbor_encode_assert_options(fido_opt_t up, fido_opt_t uv)
|
|||
}
|
||||
|
||||
cbor_item_t *
|
||||
cbor_encode_pin_auth(const fido_blob_t *hmac_key, const fido_blob_t *data)
|
||||
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;
|
||||
|
||||
if ((md = EVP_sha256()) == NULL || HMAC(md, hmac_key->ptr,
|
||||
(int)hmac_key->len, data->ptr, data->len, dgst,
|
||||
|
||||
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);
|
||||
|
||||
return (cbor_build_bytestring(dgst, 16));
|
||||
outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len;
|
||||
|
||||
return (cbor_build_bytestring(dgst, outlen));
|
||||
}
|
||||
|
||||
cbor_item_t *
|
||||
cbor_encode_pin_opt(void)
|
||||
cbor_encode_pin_opt(const fido_dev_t *dev)
|
||||
{
|
||||
return (cbor_build_uint8(1));
|
||||
}
|
||||
uint8_t prot;
|
||||
|
||||
cbor_item_t *
|
||||
cbor_encode_pin_enc(const fido_blob_t *key, const fido_blob_t *pin)
|
||||
{
|
||||
fido_blob_t pe;
|
||||
cbor_item_t *item = NULL;
|
||||
|
||||
if (aes256_cbc_enc(key, pin, &pe) < 0)
|
||||
if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
|
||||
fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
|
||||
return (NULL);
|
||||
|
||||
item = cbor_build_bytestring(pe.ptr, pe.len);
|
||||
free(pe.ptr);
|
||||
|
||||
return (item);
|
||||
}
|
||||
|
||||
static int
|
||||
sha256(const unsigned char *data, size_t data_len, fido_blob_t *digest)
|
||||
{
|
||||
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) {
|
||||
free(digest->ptr);
|
||||
digest->ptr = NULL;
|
||||
digest->len = 0;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
return (cbor_build_uint8(prot));
|
||||
}
|
||||
|
||||
cbor_item_t *
|
||||
cbor_encode_change_pin_auth(const fido_blob_t *key, const fido_blob_t *new_pin,
|
||||
const fido_blob_t *pin)
|
||||
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;
|
||||
|
@ -695,65 +711,54 @@ cbor_encode_change_pin_auth(const fido_blob_t *key, const fido_blob_t *new_pin,
|
|||
#else
|
||||
HMAC_CTX *ctx = NULL;
|
||||
#endif
|
||||
fido_blob_t *npe = NULL; /* new pin, encrypted */
|
||||
fido_blob_t *ph = NULL; /* pin hash */
|
||||
fido_blob_t *phe = NULL; /* pin hash, encrypted */
|
||||
fido_blob_t key;
|
||||
uint8_t prot;
|
||||
size_t outlen;
|
||||
|
||||
if ((npe = fido_blob_new()) == NULL ||
|
||||
(ph = fido_blob_new()) == NULL ||
|
||||
(phe = fido_blob_new()) == NULL)
|
||||
goto fail;
|
||||
key.ptr = secret->ptr;
|
||||
key.len = secret->len;
|
||||
|
||||
if (aes256_cbc_enc(key, new_pin, npe) < 0) {
|
||||
fido_log_debug("%s: aes256_cbc_enc 1", __func__);
|
||||
if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
|
||||
fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (sha256(pin->ptr, pin->len, ph) < 0 || ph->len < 16) {
|
||||
fido_log_debug("%s: sha256", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ph->len = 16; /* first 16 bytes */
|
||||
|
||||
if (aes256_cbc_enc(key, ph, phe) < 0) {
|
||||
fido_log_debug("%s: aes256_cbc_enc 2", __func__);
|
||||
goto fail;
|
||||
}
|
||||
if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32)
|
||||
key.len = 32;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
HMAC_CTX_init(&ctx);
|
||||
|
||||
if ((md = EVP_sha256()) == NULL ||
|
||||
HMAC_Init_ex(&ctx, key->ptr, (int)key->len, md, NULL) == 0 ||
|
||||
HMAC_Update(&ctx, npe->ptr, (int)npe->len) == 0 ||
|
||||
HMAC_Update(&ctx, phe->ptr, (int)phe->len) == 0 ||
|
||||
HMAC_Final(&ctx, dgst, &dgst_len) == 0 || dgst_len != 32) {
|
||||
HMAC_Init_ex(&ctx, key.ptr, (int)key.len, md, NULL) == 0 ||
|
||||
HMAC_Update(&ctx, new_pin_enc->ptr, new_pin_enc->len) == 0 ||
|
||||
HMAC_Update(&ctx, pin_hash_enc->ptr, pin_hash_enc->len) == 0 ||
|
||||
HMAC_Final(&ctx, dgst, &dgst_len) == 0 ||
|
||||
dgst_len != SHA256_DIGEST_LENGTH) {
|
||||
fido_log_debug("%s: HMAC", __func__);
|
||||
goto fail;
|
||||
}
|
||||
#else
|
||||
if ((ctx = HMAC_CTX_new()) == NULL ||
|
||||
(md = EVP_sha256()) == NULL ||
|
||||
HMAC_Init_ex(ctx, key->ptr, (int)key->len, md, NULL) == 0 ||
|
||||
HMAC_Update(ctx, npe->ptr, npe->len) == 0 ||
|
||||
HMAC_Update(ctx, phe->ptr, phe->len) == 0 ||
|
||||
HMAC_Final(ctx, dgst, &dgst_len) == 0 || dgst_len != 32) {
|
||||
HMAC_Init_ex(ctx, key.ptr, (int)key.len, md, NULL) == 0 ||
|
||||
HMAC_Update(ctx, new_pin_enc->ptr, new_pin_enc->len) == 0 ||
|
||||
HMAC_Update(ctx, pin_hash_enc->ptr, pin_hash_enc->len) == 0 ||
|
||||
HMAC_Final(ctx, dgst, &dgst_len) == 0 ||
|
||||
dgst_len != SHA256_DIGEST_LENGTH) {
|
||||
fido_log_debug("%s: HMAC", __func__);
|
||||
goto fail;
|
||||
}
|
||||
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
|
||||
|
||||
if ((item = cbor_build_bytestring(dgst, 16)) == NULL) {
|
||||
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:
|
||||
fido_blob_free(&npe);
|
||||
fido_blob_free(&ph);
|
||||
fido_blob_free(&phe);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
if (ctx != NULL)
|
||||
HMAC_CTX_free(ctx);
|
||||
|
@ -762,112 +767,59 @@ fail:
|
|||
return (item);
|
||||
}
|
||||
|
||||
cbor_item_t *
|
||||
cbor_encode_set_pin_auth(const fido_blob_t *key, const fido_blob_t *pin)
|
||||
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)
|
||||
{
|
||||
const EVP_MD *md = NULL;
|
||||
unsigned char dgst[SHA256_DIGEST_LENGTH];
|
||||
unsigned int dgst_len;
|
||||
cbor_item_t *item = NULL;
|
||||
fido_blob_t *pe = NULL;
|
||||
|
||||
if ((pe = fido_blob_new()) == NULL)
|
||||
goto fail;
|
||||
|
||||
if (aes256_cbc_enc(key, pin, pe) < 0) {
|
||||
fido_log_debug("%s: aes256_cbc_enc", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((md = EVP_sha256()) == NULL || key->len != 32 || HMAC(md, key->ptr,
|
||||
(int)key->len, pe->ptr, pe->len, dgst, &dgst_len) == NULL ||
|
||||
dgst_len != SHA256_DIGEST_LENGTH) {
|
||||
fido_log_debug("%s: HMAC", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
item = cbor_build_bytestring(dgst, 16);
|
||||
fail:
|
||||
fido_blob_free(&pe);
|
||||
|
||||
return (item);
|
||||
}
|
||||
|
||||
cbor_item_t *
|
||||
cbor_encode_pin_hash_enc(const fido_blob_t *shared, const fido_blob_t *pin)
|
||||
{
|
||||
cbor_item_t *item = NULL;
|
||||
fido_blob_t *ph = NULL;
|
||||
fido_blob_t *phe = NULL;
|
||||
|
||||
if ((ph = fido_blob_new()) == NULL || (phe = fido_blob_new()) == NULL)
|
||||
goto fail;
|
||||
|
||||
if (sha256(pin->ptr, pin->len, ph) < 0 || ph->len < 16) {
|
||||
fido_log_debug("%s: SHA256", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ph->len = 16; /* first 16 bytes */
|
||||
|
||||
if (aes256_cbc_enc(shared, ph, phe) < 0) {
|
||||
fido_log_debug("%s: aes256_cbc_enc", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
item = cbor_build_bytestring(phe->ptr, phe->len);
|
||||
fail:
|
||||
fido_blob_free(&ph);
|
||||
fido_blob_free(&phe);
|
||||
|
||||
return (item);
|
||||
}
|
||||
|
||||
cbor_item_t *
|
||||
cbor_encode_hmac_secret_param(const fido_blob_t *ecdh, const es256_pk_t *pk,
|
||||
const fido_blob_t *hmac_salt)
|
||||
{
|
||||
cbor_item_t *item = NULL;
|
||||
cbor_item_t *param = NULL;
|
||||
cbor_item_t *argv[3];
|
||||
cbor_item_t *argv[4];
|
||||
struct cbor_pair pair;
|
||||
fido_blob_t *enc = NULL;
|
||||
int r;
|
||||
|
||||
memset(argv, 0, sizeof(argv));
|
||||
memset(&pair, 0, sizeof(pair));
|
||||
|
||||
if (ecdh == NULL || pk == NULL || hmac_salt->ptr == NULL) {
|
||||
fido_log_debug("%s: ecdh=%p, pk=%p, hmac_salt->ptr=%p",
|
||||
__func__, (const void *)ecdh, (const void *)pk,
|
||||
(const void *)hmac_salt->ptr);
|
||||
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 (hmac_salt->len != 32 && hmac_salt->len != 64) {
|
||||
fido_log_debug("%s: hmac_salt->len=%zu", __func__,
|
||||
hmac_salt->len);
|
||||
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;
|
||||
}
|
||||
|
||||
/* XXX not pin, but salt */
|
||||
if ((argv[0] = es256_pk_encode(pk, 1)) == NULL ||
|
||||
(argv[1] = cbor_encode_pin_enc(ecdh, hmac_salt)) == NULL ||
|
||||
(argv[2] = cbor_encode_set_pin_auth(ecdh, hmac_salt)) == NULL) {
|
||||
(argv[1] = fido_blob_encode(enc)) == NULL ||
|
||||
(argv[2] = cbor_encode_pin_auth(dev, ecdh, enc)) == NULL ||
|
||||
(argv[3] = cbor_encode_pin_opt(dev)) == NULL) {
|
||||
fido_log_debug("%s: cbor encode", __func__);
|
||||
r = FIDO_ERR_INTERNAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((param = cbor_flatten_vector(argv, 3)) == NULL) {
|
||||
if ((param = cbor_flatten_vector(argv, nitems(argv))) == NULL) {
|
||||
fido_log_debug("%s: cbor_flatten_vector", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((item = cbor_new_definite_map(1)) == NULL) {
|
||||
fido_log_debug("%s: cbor_new_definite_map", __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;
|
||||
}
|
||||
|
||||
|
@ -875,21 +827,61 @@ cbor_encode_hmac_secret_param(const fido_blob_t *ecdh, const es256_pk_t *pk,
|
|||
|
||||
if (!cbor_map_add(item, pair)) {
|
||||
fido_log_debug("%s: cbor_map_add", __func__);
|
||||
cbor_decref(&item);
|
||||
item = NULL;
|
||||
r = FIDO_ERR_INTERNAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = FIDO_OK;
|
||||
|
||||
fail:
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
if (argv[i] != NULL)
|
||||
cbor_decref(&argv[i]);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1058,8 +1050,7 @@ decode_attcred(const unsigned char **buf, size_t *len, int cose_alg,
|
|||
uint16_t id_len;
|
||||
int ok = -1;
|
||||
|
||||
fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf,
|
||||
*len);
|
||||
fido_log_xxd(*buf, *len, "%s", __func__);
|
||||
|
||||
if (fido_buf_read(buf, len, &attcred->aaguid,
|
||||
sizeof(attcred->aaguid)) < 0) {
|
||||
|
@ -1085,7 +1076,6 @@ decode_attcred(const unsigned char **buf, size_t *len, int cose_alg,
|
|||
|
||||
if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
|
||||
fido_log_debug("%s: cbor_load", __func__);
|
||||
fido_log_xxd(*buf, *len);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -1112,7 +1102,7 @@ fail:
|
|||
}
|
||||
|
||||
static int
|
||||
decode_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg)
|
||||
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;
|
||||
|
@ -1141,6 +1131,15 @@ decode_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg)
|
|||
}
|
||||
authdata_ext->mask |= FIDO_EXT_CRED_PROTECT;
|
||||
authdata_ext->prot = cbor_get_uint8(val);
|
||||
} else if (strcmp(type, "credBlob") == 0) {
|
||||
if (cbor_isa_float_ctrl(val) == false ||
|
||||
cbor_float_get_width(val) != CBOR_FLOAT_0 ||
|
||||
cbor_is_bool(val) == false) {
|
||||
fido_log_debug("%s: cbor type", __func__);
|
||||
goto out;
|
||||
}
|
||||
if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE)
|
||||
authdata_ext->mask |= FIDO_EXT_CRED_BLOB;
|
||||
}
|
||||
|
||||
ok = 0;
|
||||
|
@ -1151,28 +1150,25 @@ out:
|
|||
}
|
||||
|
||||
static int
|
||||
decode_extensions(const unsigned char **buf, size_t *len,
|
||||
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;
|
||||
|
||||
fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf,
|
||||
*len);
|
||||
fido_log_xxd(*buf, *len);
|
||||
|
||||
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__);
|
||||
fido_log_xxd(*buf, *len);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (cbor_isa_map(item) == false ||
|
||||
cbor_map_is_definite(item) == false ||
|
||||
cbor_map_iter(item, authdata_ext, decode_extension) < 0) {
|
||||
cbor_map_iter(item, authdata_ext, decode_cred_extension) < 0) {
|
||||
fido_log_debug("%s: cbor type", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
@ -1189,19 +1185,34 @@ fail:
|
|||
}
|
||||
|
||||
static int
|
||||
decode_hmac_secret_aux(const cbor_item_t *key, const cbor_item_t *val, void *arg)
|
||||
decode_assert_extension(const cbor_item_t *key, const cbor_item_t *val,
|
||||
void *arg)
|
||||
{
|
||||
fido_blob_t *out = arg;
|
||||
char *type = NULL;
|
||||
int ok = -1;
|
||||
fido_assert_extattr_t *authdata_ext = arg;
|
||||
char *type = NULL;
|
||||
int ok = -1;
|
||||
|
||||
if (cbor_string_copy(key, &type) < 0 || strcmp(type, "hmac-secret")) {
|
||||
if (cbor_string_copy(key, &type) < 0) {
|
||||
fido_log_debug("%s: cbor type", __func__);
|
||||
ok = 0; /* ignore */
|
||||
goto out;
|
||||
}
|
||||
|
||||
ok = cbor_bytestring_copy(val, &out->ptr, &out->len);
|
||||
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);
|
||||
|
||||
|
@ -1209,25 +1220,23 @@ out:
|
|||
}
|
||||
|
||||
static int
|
||||
decode_hmac_secret(const unsigned char **buf, size_t *len, fido_blob_t *out)
|
||||
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_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf,
|
||||
*len);
|
||||
fido_log_xxd(*buf, *len, "%s", __func__);
|
||||
|
||||
if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
|
||||
fido_log_debug("%s: cbor_load", __func__);
|
||||
fido_log_xxd(*buf, *len);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (cbor_isa_map(item) == false ||
|
||||
cbor_map_is_definite(item) == false ||
|
||||
cbor_map_size(item) != 1 ||
|
||||
cbor_map_iter(item, out, decode_hmac_secret_aux) < 0) {
|
||||
cbor_map_iter(item, authdata_ext, decode_assert_extension) < 0) {
|
||||
fido_log_debug("%s: cbor type", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
@ -1267,9 +1276,7 @@ cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg,
|
|||
|
||||
buf = cbor_bytestring_handle(item);
|
||||
len = cbor_bytestring_length(item);
|
||||
|
||||
fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len);
|
||||
fido_log_xxd(buf, len);
|
||||
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__);
|
||||
|
@ -1286,7 +1293,7 @@ cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg,
|
|||
|
||||
if (authdata_ext != NULL) {
|
||||
if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 &&
|
||||
decode_extensions(&buf, &len, authdata_ext) < 0)
|
||||
decode_cred_extensions(&buf, &len, authdata_ext) < 0)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
@ -1297,7 +1304,7 @@ cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg,
|
|||
|
||||
int
|
||||
cbor_decode_assert_authdata(const cbor_item_t *item, fido_blob_t *authdata_cbor,
|
||||
fido_authdata_t *authdata, int *authdata_ext, fido_blob_t *hmac_secret_enc)
|
||||
fido_authdata_t *authdata, fido_assert_extattr_t *authdata_ext)
|
||||
{
|
||||
const unsigned char *buf = NULL;
|
||||
size_t len;
|
||||
|
@ -1328,14 +1335,12 @@ cbor_decode_assert_authdata(const cbor_item_t *item, fido_blob_t *authdata_cbor,
|
|||
|
||||
authdata->sigcount = be32toh(authdata->sigcount);
|
||||
|
||||
*authdata_ext = 0;
|
||||
if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0) {
|
||||
/* XXX semantic leap: extensions -> hmac_secret */
|
||||
if (decode_hmac_secret(&buf, &len, hmac_secret_enc) < 0) {
|
||||
fido_log_debug("%s: decode_hmac_secret", __func__);
|
||||
if (decode_assert_extensions(&buf, &len, authdata_ext) < 0) {
|
||||
fido_log_debug("%s: decode_assert_extensions",
|
||||
__func__);
|
||||
return (-1);
|
||||
}
|
||||
*authdata_ext = FIDO_EXT_HMAC_SECRET;
|
||||
}
|
||||
|
||||
/* XXX we should probably ensure that len == 0 at this point */
|
||||
|
@ -1351,7 +1356,7 @@ decode_x5c(const cbor_item_t *item, void *arg)
|
|||
if (x5c->len)
|
||||
return (0); /* ignore */
|
||||
|
||||
return (cbor_bytestring_copy(item, &x5c->ptr, &x5c->len));
|
||||
return (fido_blob_decode(item, x5c));
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1381,8 +1386,7 @@ decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
|
|||
goto out;
|
||||
}
|
||||
} else if (!strcmp(name, "sig")) {
|
||||
if (cbor_bytestring_copy(val, &attstmt->sig.ptr,
|
||||
&attstmt->sig.len) < 0) {
|
||||
if (fido_blob_decode(val, &attstmt->sig) < 0) {
|
||||
fido_log_debug("%s: sig", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
@ -1442,7 +1446,7 @@ decode_cred_id_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
|
|||
}
|
||||
|
||||
if (!strcmp(name, "id"))
|
||||
if (cbor_bytestring_copy(val, &id->ptr, &id->len) < 0) {
|
||||
if (fido_blob_decode(val, id) < 0) {
|
||||
fido_log_debug("%s: cbor_bytestring_copy", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
@ -1496,7 +1500,7 @@ decode_user_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
|
|||
goto out;
|
||||
}
|
||||
} else if (!strcmp(name, "id")) {
|
||||
if (cbor_bytestring_copy(val, &user->id.ptr, &user->id.len) < 0) {
|
||||
if (fido_blob_decode(val, &user->id) < 0) {
|
||||
fido_log_debug("%s: id", __func__);
|
||||
goto out;
|
||||
}
|
||||
|
@ -1567,3 +1571,64 @@ cbor_decode_rp_entity(const cbor_item_t *item, fido_rp_t *rp)
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <zlib.h>
|
||||
#include "fido.h"
|
||||
|
||||
#define BOUND (1024UL * 1024UL)
|
||||
|
||||
static int
|
||||
do_compress(fido_blob_t *out, const fido_blob_t *in, size_t origsiz, int decomp)
|
||||
{
|
||||
u_long ilen, olen;
|
||||
int r;
|
||||
|
||||
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)
|
||||
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) {
|
||||
fido_blob_reset(out);
|
||||
return FIDO_ERR_COMPRESS;
|
||||
}
|
||||
out->len = olen;
|
||||
|
||||
return FIDO_OK;
|
||||
}
|
||||
|
||||
int
|
||||
fido_compress(fido_blob_t *out, const fido_blob_t *in)
|
||||
{
|
||||
return do_compress(out, in, 0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
fido_uncompress(fido_blob_t *out, const fido_blob_t *in, size_t origsiz)
|
||||
{
|
||||
return do_compress(out, in, origsiz, 1);
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "fido.h"
|
||||
#include "fido/config.h"
|
||||
#include "fido/es256.h"
|
||||
|
||||
#define CMD_ENABLE_ENTATTEST 0x01
|
||||
#define CMD_TOGGLE_ALWAYS_UV 0x02
|
||||
#define CMD_SET_PIN_MINLEN 0x03
|
||||
|
||||
static int
|
||||
config_prepare_hmac(uint8_t subcmd, const cbor_item_t *item, fido_blob_t *hmac)
|
||||
{
|
||||
uint8_t prefix[32 + 2 * sizeof(uint8_t)], cbor[128];
|
||||
size_t cbor_len;
|
||||
|
||||
memset(prefix, 0xff, sizeof(prefix));
|
||||
prefix[sizeof(prefix) - 2] = CTAP_CBOR_CONFIG;
|
||||
prefix[sizeof(prefix) - 1] = subcmd;
|
||||
|
||||
if (item == NULL)
|
||||
return fido_blob_set(hmac, prefix, sizeof(prefix));
|
||||
|
||||
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)
|
||||
{
|
||||
cbor_item_t *argv[4];
|
||||
es256_pk_t *pk = NULL;
|
||||
fido_blob_t *ecdh = NULL, f, hmac;
|
||||
const uint8_t cmd = CTAP_CBOR_CONFIG;
|
||||
int r = FIDO_ERR_INTERNAL;
|
||||
|
||||
memset(&f, 0, sizeof(f));
|
||||
memset(&hmac, 0, sizeof(hmac));
|
||||
memset(&argv, 0, sizeof(argv));
|
||||
|
||||
/* subCommand */
|
||||
if ((argv[0] = cbor_build_uint8(subcmd)) == NULL) {
|
||||
fido_log_debug("%s: cbor encode", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* pinProtocol, pinAuth */
|
||||
if (fido_dev_can_get_uv_token(dev, pin, FIDO_OPT_OMIT)) {
|
||||
if ((argv[1] = cbor_flatten_vector(paramv, paramc)) == NULL) {
|
||||
fido_log_debug("%s: cbor_flatten_vector", __func__);
|
||||
goto fail;
|
||||
}
|
||||
if (config_prepare_hmac(subcmd, argv[1], &hmac) < 0) {
|
||||
fido_log_debug("%s: config_prepare_hmac", __func__);
|
||||
goto fail;
|
||||
}
|
||||
if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
|
||||
fido_log_debug("%s: fido_do_ecdh", __func__);
|
||||
goto fail;
|
||||
}
|
||||
if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin,
|
||||
NULL, &argv[3], &argv[2])) != FIDO_OK) {
|
||||
fido_log_debug("%s: cbor_add_uv_params", __func__);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* framing and transmission */
|
||||
if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
|
||||
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
|
||||
fido_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)) != FIDO_OK)
|
||||
return r;
|
||||
|
||||
return fido_rx_cbor_status(dev, ms);
|
||||
}
|
||||
|
||||
int
|
||||
fido_dev_enable_entattest(fido_dev_t *dev, const char *pin)
|
||||
{
|
||||
return (config_enable_entattest_wait(dev, pin, -1));
|
||||
}
|
||||
|
||||
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)) != FIDO_OK)
|
||||
return r;
|
||||
|
||||
return (fido_rx_cbor_status(dev, ms));
|
||||
}
|
||||
|
||||
int
|
||||
fido_dev_toggle_always_uv(fido_dev_t *dev, const char *pin)
|
||||
{
|
||||
return config_toggle_always_uv_wait(dev, pin, -1);
|
||||
}
|
||||
|
||||
static int
|
||||
config_pin_minlen_tx(fido_dev_t *dev, size_t len, bool force, const char *pin)
|
||||
{
|
||||
cbor_item_t *argv[3];
|
||||
int r;
|
||||
|
||||
memset(argv, 0, sizeof(argv));
|
||||
|
||||
if ((!len && !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 (force && (argv[2] = cbor_build_bool(true)) == NULL) {
|
||||
fido_log_debug("%s: cbor_build_bool", __func__);
|
||||
r = FIDO_ERR_INTERNAL;
|
||||
goto fail;
|
||||
}
|
||||
if ((r = config_tx(dev, CMD_SET_PIN_MINLEN, argv, nitems(argv),
|
||||
pin)) != FIDO_OK) {
|
||||
fido_log_debug("%s: config_tx", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
cbor_vector_free(argv, nitems(argv));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
config_pin_minlen(fido_dev_t *dev, size_t len, bool force, const char *pin,
|
||||
int ms)
|
||||
{
|
||||
int r;
|
||||
|
||||
if ((r = config_pin_minlen_tx(dev, len, force, pin)) != FIDO_OK)
|
||||
return r;
|
||||
|
||||
return fido_rx_cbor_status(dev, ms);
|
||||
}
|
||||
|
||||
int
|
||||
fido_dev_set_pin_minlen(fido_dev_t *dev, size_t len, const char *pin)
|
||||
{
|
||||
return config_pin_minlen(dev, len, false, pin, -1);
|
||||
}
|
||||
|
||||
int
|
||||
fido_dev_force_pin_change(fido_dev_t *dev, const char *pin)
|
||||
{
|
||||
return config_pin_minlen(dev, 0, true, pin, -1);
|
||||
}
|
|
@ -4,12 +4,9 @@
|
|||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include <string.h>
|
||||
#include "fido.h"
|
||||
#include "fido/es256.h"
|
||||
|
||||
|
@ -28,11 +25,17 @@ parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
|
|||
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);
|
||||
|
@ -46,6 +49,7 @@ fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
|
|||
fido_blob_t *ecdh = NULL;
|
||||
es256_pk_t *pk = NULL;
|
||||
cbor_item_t *argv[9];
|
||||
const uint8_t cmd = CTAP_CBOR_MAKECRED;
|
||||
int r;
|
||||
|
||||
memset(&f, 0, sizeof(f));
|
||||
|
@ -77,36 +81,37 @@ fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
|
|||
|
||||
/* extensions */
|
||||
if (cred->ext.mask)
|
||||
if ((argv[5] = cbor_encode_extensions(&cred->ext)) == NULL) {
|
||||
fido_log_debug("%s: cbor_encode_extensions", __func__);
|
||||
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;
|
||||
}
|
||||
|
||||
/* options */
|
||||
if (cred->rk != FIDO_OPT_OMIT || cred->uv != FIDO_OPT_OMIT)
|
||||
if ((argv[6] = cbor_encode_options(cred->rk,
|
||||
if ((argv[6] = cbor_encode_cred_opt(cred->rk,
|
||||
cred->uv)) == NULL) {
|
||||
fido_log_debug("%s: cbor_encode_options", __func__);
|
||||
fido_log_debug("%s: cbor_encode_cred_opt", __func__);
|
||||
r = FIDO_ERR_INTERNAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* pin authentication */
|
||||
if (pin) {
|
||||
/* user verification */
|
||||
if (fido_dev_can_get_uv_token(dev, pin, cred->uv)) {
|
||||
if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
|
||||
fido_log_debug("%s: fido_do_ecdh", __func__);
|
||||
goto fail;
|
||||
}
|
||||
if ((r = cbor_add_pin_params(dev, &cred->cdh, pk, ecdh, pin,
|
||||
&argv[7], &argv[8])) != FIDO_OK) {
|
||||
fido_log_debug("%s: cbor_add_pin_params", __func__);
|
||||
if ((r = cbor_add_uv_params(dev, cmd, &cred->cdh, pk, ecdh,
|
||||
pin, cred->rp.id, &argv[7], &argv[8])) != FIDO_OK) {
|
||||
fido_log_debug("%s: cbor_add_uv_params", __func__);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* framing and transmission */
|
||||
if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, nitems(argv), &f) < 0 ||
|
||||
if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
|
||||
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
|
||||
fido_log_debug("%s: fido_tx", __func__);
|
||||
r = FIDO_ERR_TX;
|
||||
|
@ -155,7 +160,8 @@ fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int ms)
|
|||
}
|
||||
|
||||
static int
|
||||
fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin, int ms)
|
||||
fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
|
||||
int ms)
|
||||
{
|
||||
int r;
|
||||
|
||||
|
@ -180,9 +186,16 @@ fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
|
|||
}
|
||||
|
||||
static int
|
||||
check_extensions(const fido_cred_ext_t *authdata_ext, const fido_cred_ext_t *ext)
|
||||
check_extensions(const fido_cred_ext_t *authdata_ext,
|
||||
const fido_cred_ext_t *ext)
|
||||
{
|
||||
return (timingsafe_bcmp(authdata_ext, ext, sizeof(*authdata_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
|
||||
|
@ -448,10 +461,12 @@ static void
|
|||
fido_cred_clean_authdata(fido_cred_t *cred)
|
||||
{
|
||||
free(cred->authdata_cbor.ptr);
|
||||
free(cred->authdata_raw.ptr);
|
||||
free(cred->attcred.id.ptr);
|
||||
|
||||
memset(&cred->authdata_ext, 0, sizeof(cred->authdata_ext));
|
||||
memset(&cred->authdata_cbor, 0, sizeof(cred->authdata_cbor));
|
||||
memset(&cred->authdata_raw, 0, sizeof(cred->authdata_raw));
|
||||
memset(&cred->authdata, 0, sizeof(cred->authdata));
|
||||
memset(&cred->attcred, 0, sizeof(cred->attcred));
|
||||
}
|
||||
|
@ -472,6 +487,9 @@ fido_cred_reset_tx(fido_cred_t *cred)
|
|||
memset(&cred->rp, 0, sizeof(cred->rp));
|
||||
memset(&cred->user, 0, sizeof(cred->user));
|
||||
memset(&cred->excl, 0, sizeof(cred->excl));
|
||||
|
||||
fido_blob_reset(&cred->blob);
|
||||
|
||||
memset(&cred->ext, 0, sizeof(cred->ext));
|
||||
|
||||
cred->type = 0;
|
||||
|
@ -500,10 +518,10 @@ fido_cred_reset_rx(fido_cred_t *cred)
|
|||
{
|
||||
free(cred->fmt);
|
||||
cred->fmt = NULL;
|
||||
|
||||
fido_cred_clean_authdata(cred);
|
||||
fido_cred_clean_x509(cred);
|
||||
fido_cred_clean_sig(cred);
|
||||
fido_blob_reset(&cred->largeblob_key);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -513,12 +531,9 @@ fido_cred_free(fido_cred_t **cred_p)
|
|||
|
||||
if (cred_p == NULL || (cred = *cred_p) == NULL)
|
||||
return;
|
||||
|
||||
fido_cred_reset_tx(cred);
|
||||
fido_cred_reset_rx(cred);
|
||||
|
||||
free(cred);
|
||||
|
||||
*cred_p = NULL;
|
||||
}
|
||||
|
||||
|
@ -527,25 +542,26 @@ 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;
|
||||
int r = FIDO_ERR_INVALID_ARGUMENT;
|
||||
|
||||
fido_cred_clean_authdata(cred);
|
||||
|
||||
if (ptr == NULL || len == 0) {
|
||||
r = FIDO_ERR_INVALID_ARGUMENT;
|
||||
if (ptr == NULL || len == 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
|
||||
fido_log_debug("%s: cbor_load", __func__);
|
||||
r = FIDO_ERR_INVALID_ARGUMENT;
|
||||
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__);
|
||||
r = FIDO_ERR_INVALID_ARGUMENT;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -565,13 +581,17 @@ int
|
|||
fido_cred_set_authdata_raw(fido_cred_t *cred, const unsigned char *ptr,
|
||||
size_t len)
|
||||
{
|
||||
cbor_item_t *item = NULL;
|
||||
int r;
|
||||
cbor_item_t *item = NULL;
|
||||
int r = FIDO_ERR_INVALID_ARGUMENT;
|
||||
|
||||
fido_cred_clean_authdata(cred);
|
||||
|
||||
if (ptr == NULL || len == 0) {
|
||||
r = FIDO_ERR_INVALID_ARGUMENT;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -584,7 +604,6 @@ fido_cred_set_authdata_raw(fido_cred_t *cred, const unsigned char *ptr,
|
|||
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__);
|
||||
r = FIDO_ERR_INVALID_ARGUMENT;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -766,8 +785,7 @@ fido_cred_set_extensions(fido_cred_t *cred, int ext)
|
|||
if (ext == 0)
|
||||
cred->ext.mask = 0;
|
||||
else {
|
||||
if (ext != FIDO_EXT_HMAC_SECRET &&
|
||||
ext != FIDO_EXT_CRED_PROTECT)
|
||||
if ((ext & FIDO_EXT_CRED_MASK) != ext)
|
||||
return (FIDO_ERR_INVALID_ARGUMENT);
|
||||
cred->ext.mask |= ext;
|
||||
}
|
||||
|
@ -819,6 +837,19 @@ fido_cred_set_prot(fido_cred_t *cred, int prot)
|
|||
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)
|
||||
{
|
||||
|
@ -861,6 +892,12 @@ 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)
|
||||
{
|
||||
|
@ -909,6 +946,18 @@ 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_pubkey_ptr(const fido_cred_t *cred)
|
||||
{
|
||||
|
@ -1026,3 +1075,15 @@ 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);
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "fido.h"
|
||||
#include "fido/credman.h"
|
||||
#include "fido/es256.h"
|
||||
|
@ -99,14 +97,15 @@ fail:
|
|||
}
|
||||
|
||||
static int
|
||||
credman_tx(fido_dev_t *dev, uint8_t cmd, const fido_blob_t *param,
|
||||
const char *pin)
|
||||
credman_tx(fido_dev_t *dev, uint8_t subcmd, const fido_blob_t *param,
|
||||
const char *pin, const char *rp_id, fido_opt_t uv)
|
||||
{
|
||||
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));
|
||||
|
@ -114,14 +113,14 @@ credman_tx(fido_dev_t *dev, uint8_t cmd, const fido_blob_t *param,
|
|||
memset(&argv, 0, sizeof(argv));
|
||||
|
||||
/* subCommand */
|
||||
if ((argv[0] = cbor_build_uint8(cmd)) == NULL) {
|
||||
if ((argv[0] = cbor_build_uint8(subcmd)) == NULL) {
|
||||
fido_log_debug("%s: cbor encode", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* pinProtocol, pinAuth */
|
||||
if (pin != NULL) {
|
||||
if (credman_prepare_hmac(cmd, param, &argv[1], &hmac) < 0) {
|
||||
if (fido_dev_can_get_uv_token(dev, pin, uv)) {
|
||||
if (credman_prepare_hmac(subcmd, param, &argv[1], &hmac) < 0) {
|
||||
fido_log_debug("%s: credman_prepare_hmac", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
@ -129,16 +128,16 @@ credman_tx(fido_dev_t *dev, uint8_t cmd, const fido_blob_t *param,
|
|||
fido_log_debug("%s: fido_do_ecdh", __func__);
|
||||
goto fail;
|
||||
}
|
||||
if ((r = cbor_add_pin_params(dev, &hmac, pk, ecdh, pin,
|
||||
&argv[3], &argv[2])) != FIDO_OK) {
|
||||
fido_log_debug("%s: cbor_add_pin_params", __func__);
|
||||
if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin,
|
||||
rp_id, &argv[3], &argv[2])) != FIDO_OK) {
|
||||
fido_log_debug("%s: cbor_add_uv_params", __func__);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* framing and transmission */
|
||||
if (cbor_build_frame(CTAP_CBOR_CRED_MGMT_PRE, argv, nitems(argv),
|
||||
&f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
|
||||
if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
|
||||
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
|
||||
fido_log_debug("%s: fido_tx", __func__);
|
||||
r = FIDO_ERR_TX;
|
||||
goto fail;
|
||||
|
@ -208,7 +207,8 @@ credman_get_metadata_wait(fido_dev_t *dev, fido_credman_metadata_t *metadata,
|
|||
{
|
||||
int r;
|
||||
|
||||
if ((r = credman_tx(dev, CMD_CRED_METADATA, NULL, pin)) != FIDO_OK ||
|
||||
if ((r = credman_tx(dev, CMD_CRED_METADATA, NULL, pin, NULL,
|
||||
FIDO_OPT_OMIT)) != FIDO_OK ||
|
||||
(r = credman_rx_metadata(dev, metadata, ms)) != FIDO_OK)
|
||||
return (r);
|
||||
|
||||
|
@ -221,8 +221,6 @@ fido_credman_get_dev_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata
|
|||
{
|
||||
if (fido_dev_is_fido2(dev) == false)
|
||||
return (FIDO_ERR_INVALID_COMMAND);
|
||||
if (pin == NULL)
|
||||
return (FIDO_ERR_INVALID_ARGUMENT);
|
||||
|
||||
return (credman_get_metadata_wait(dev, metadata, pin, -1));
|
||||
}
|
||||
|
@ -240,7 +238,7 @@ credman_parse_rk(const cbor_item_t *key, const cbor_item_t *val, void *arg)
|
|||
}
|
||||
|
||||
switch (cbor_get_uint8(key)) {
|
||||
case 6: /* user entity */
|
||||
case 6:
|
||||
return (cbor_decode_user(val, &cred->user));
|
||||
case 7:
|
||||
return (cbor_decode_cred_id(val, &cred->attcred.id));
|
||||
|
@ -255,6 +253,8 @@ credman_parse_rk(const cbor_item_t *key, const cbor_item_t *val, void *arg)
|
|||
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 */
|
||||
|
@ -387,12 +387,14 @@ credman_get_rk_wait(fido_dev_t *dev, const char *rp_id, fido_credman_rk_t *rk,
|
|||
rp_dgst.ptr = dgst;
|
||||
rp_dgst.len = sizeof(dgst);
|
||||
|
||||
if ((r = credman_tx(dev, CMD_RK_BEGIN, &rp_dgst, pin)) != FIDO_OK ||
|
||||
if ((r = credman_tx(dev, CMD_RK_BEGIN, &rp_dgst, pin, rp_id,
|
||||
FIDO_OPT_OMIT)) != 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)) != FIDO_OK ||
|
||||
if ((r = credman_tx(dev, CMD_RK_NEXT, NULL, NULL, NULL,
|
||||
FIDO_OPT_FALSE)) != FIDO_OK ||
|
||||
(r = credman_rx_next_rk(dev, rk, ms)) != FIDO_OK)
|
||||
return (r);
|
||||
rk->n_rx++;
|
||||
|
@ -407,8 +409,6 @@ fido_credman_get_dev_rk(fido_dev_t *dev, const char *rp_id,
|
|||
{
|
||||
if (fido_dev_is_fido2(dev) == false)
|
||||
return (FIDO_ERR_INVALID_COMMAND);
|
||||
if (pin == NULL)
|
||||
return (FIDO_ERR_INVALID_ARGUMENT);
|
||||
|
||||
return (credman_get_rk_wait(dev, rp_id, rk, pin, -1));
|
||||
}
|
||||
|
@ -425,7 +425,8 @@ credman_del_rk_wait(fido_dev_t *dev, const unsigned char *cred_id,
|
|||
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)) != FIDO_OK ||
|
||||
if ((r = credman_tx(dev, CMD_DELETE_CRED, &cred, pin, NULL,
|
||||
FIDO_OPT_OMIT)) != FIDO_OK ||
|
||||
(r = fido_rx_cbor_status(dev, ms)) != FIDO_OK)
|
||||
goto fail;
|
||||
|
||||
|
@ -442,8 +443,6 @@ fido_credman_del_dev_rk(fido_dev_t *dev, const unsigned char *cred_id,
|
|||
{
|
||||
if (fido_dev_is_fido2(dev) == false)
|
||||
return (FIDO_ERR_INVALID_COMMAND);
|
||||
if (pin == NULL)
|
||||
return (FIDO_ERR_INVALID_ARGUMENT);
|
||||
|
||||
return (credman_del_rk_wait(dev, cred_id, cred_id_len, pin, -1));
|
||||
}
|
||||
|
@ -591,12 +590,14 @@ credman_get_rp_wait(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin,
|
|||
{
|
||||
int r;
|
||||
|
||||
if ((r = credman_tx(dev, CMD_RP_BEGIN, NULL, pin)) != FIDO_OK ||
|
||||
if ((r = credman_tx(dev, CMD_RP_BEGIN, NULL, pin, NULL,
|
||||
FIDO_OPT_OMIT)) != 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)) != FIDO_OK ||
|
||||
if ((r = credman_tx(dev, CMD_RP_NEXT, NULL, NULL, NULL,
|
||||
FIDO_OPT_FALSE)) != FIDO_OK ||
|
||||
(r = credman_rx_next_rp(dev, rp, ms)) != FIDO_OK)
|
||||
return (r);
|
||||
rp->n_rx++;
|
||||
|
@ -610,8 +611,6 @@ fido_credman_get_dev_rp(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin)
|
|||
{
|
||||
if (fido_dev_is_fido2(dev) == false)
|
||||
return (FIDO_ERR_INVALID_COMMAND);
|
||||
if (pin == NULL)
|
||||
return (FIDO_ERR_INVALID_ARGUMENT);
|
||||
|
||||
return (credman_get_rp_wait(dev, rp, pin, -1));
|
||||
}
|
||||
|
|
|
@ -4,86 +4,9 @@
|
|||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef HAVE_SYS_RANDOM_H
|
||||
#include <sys/random.h>
|
||||
#endif
|
||||
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "fido.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
|
||||
#include <winternl.h>
|
||||
#include <winerror.h>
|
||||
#include <stdio.h>
|
||||
#include <bcrypt.h>
|
||||
#include <sal.h>
|
||||
|
||||
static int
|
||||
obtain_nonce(uint64_t *nonce)
|
||||
{
|
||||
NTSTATUS status;
|
||||
|
||||
status = BCryptGenRandom(NULL, (unsigned char *)nonce, sizeof(*nonce),
|
||||
BCRYPT_USE_SYSTEM_PREFERRED_RNG);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
#elif defined(HAVE_ARC4RANDOM_BUF)
|
||||
static int
|
||||
obtain_nonce(uint64_t *nonce)
|
||||
{
|
||||
arc4random_buf(nonce, sizeof(*nonce));
|
||||
return (0);
|
||||
}
|
||||
#elif defined(HAVE_GETRANDOM)
|
||||
static int
|
||||
obtain_nonce(uint64_t *nonce)
|
||||
{
|
||||
if (getrandom(nonce, sizeof(*nonce), 0) < 0)
|
||||
return (-1);
|
||||
return (0);
|
||||
}
|
||||
#elif defined(HAVE_DEV_URANDOM)
|
||||
static int
|
||||
obtain_nonce(uint64_t *nonce)
|
||||
{
|
||||
int fd = -1;
|
||||
int ok = -1;
|
||||
ssize_t r;
|
||||
|
||||
if ((fd = open(FIDO_RANDOM_DEV, O_RDONLY)) < 0)
|
||||
goto fail;
|
||||
if ((r = read(fd, nonce, sizeof(*nonce))) < 0 ||
|
||||
(size_t)r != sizeof(*nonce))
|
||||
goto fail;
|
||||
|
||||
ok = 0;
|
||||
fail:
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
|
||||
return (ok);
|
||||
}
|
||||
#else
|
||||
#error "please provide an implementation of obtain_nonce() for your platform"
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#ifndef TLS
|
||||
#define TLS
|
||||
#endif
|
||||
|
@ -94,6 +17,7 @@ typedef struct dev_manifest_func_node {
|
|||
} 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,
|
||||
|
@ -120,32 +44,67 @@ set_random_report_len(fido_dev_t *dev)
|
|||
#endif
|
||||
|
||||
static void
|
||||
fido_dev_set_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
|
||||
fido_dev_set_extension_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
|
||||
{
|
||||
char * const *ptr;
|
||||
const bool *val;
|
||||
size_t len;
|
||||
|
||||
ptr = fido_cbor_info_extensions_ptr(info);
|
||||
len = fido_cbor_info_extensions_len(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;
|
||||
}
|
||||
|
||||
ptr = fido_cbor_info_options_name_ptr(info);
|
||||
val = fido_cbor_info_options_value_ptr(info);
|
||||
len = fido_cbor_info_options_len(info);
|
||||
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) {
|
||||
if (val[i] == true)
|
||||
dev->flags |= FIDO_DEV_PIN_SET;
|
||||
else
|
||||
dev->flags |= 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;
|
||||
} 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)
|
||||
{
|
||||
|
@ -162,8 +121,13 @@ fido_dev_open_tx(fido_dev_t *dev, const char *path)
|
|||
return (FIDO_ERR_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
if (obtain_nonce(&dev->nonce) < 0) {
|
||||
fido_log_debug("%s: obtain_nonce", __func__);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -246,7 +210,12 @@ fido_dev_open_rx(fido_dev_t *dev, int ms)
|
|||
r = FIDO_ERR_INTERNAL;
|
||||
goto fail;
|
||||
}
|
||||
if (fido_dev_get_cbor_info_wait(dev, info, ms) != FIDO_OK) {
|
||||
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 {
|
||||
|
@ -255,8 +224,9 @@ fido_dev_open_rx(fido_dev_t *dev, int ms)
|
|||
}
|
||||
|
||||
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)fido_cbor_info_maxmsgsiz(info));
|
||||
FIDO_MAXMSG, (unsigned long)dev->maxmsgsize);
|
||||
}
|
||||
|
||||
r = FIDO_OK;
|
||||
|
@ -333,6 +303,11 @@ fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
|
|||
if (fido_dev_register_manifest_func(fido_hid_manifest) != FIDO_OK)
|
||||
return (FIDO_ERR_INTERNAL);
|
||||
|
||||
#ifdef NFC_LINUX
|
||||
if (fido_dev_register_manifest_func(fido_nfc_manifest) != FIDO_OK)
|
||||
return (FIDO_ERR_INTERNAL);
|
||||
#endif
|
||||
|
||||
for (curr = manifest_funcs; curr != NULL; curr = curr->next) {
|
||||
curr_olen = 0;
|
||||
m_func = curr->manifest_func;
|
||||
|
@ -359,6 +334,28 @@ fido_dev_open_with_info(fido_dev_t *dev)
|
|||
int
|
||||
fido_dev_open(fido_dev_t *dev, const char *path)
|
||||
{
|
||||
#ifdef NFC_LINUX
|
||||
/*
|
||||
* this is a hack to get existing applications up and running with nfc;
|
||||
* it will *NOT* be part of a libfido2 release. to support nfc in your
|
||||
* application, please change it to use fido_dev_open_with_info().
|
||||
*/
|
||||
if (strncmp(path, "/sys", strlen("/sys")) == 0 && strlen(path) > 4 &&
|
||||
path[strlen(path) - 4] == 'n' && path[strlen(path) - 3] == 'f' &&
|
||||
path[strlen(path) - 2] == 'c') {
|
||||
dev->io_own = true;
|
||||
dev->io = (fido_dev_io_t) {
|
||||
fido_nfc_open,
|
||||
fido_nfc_close,
|
||||
fido_nfc_read,
|
||||
fido_nfc_write,
|
||||
};
|
||||
dev->transport = (fido_dev_transport_t) {
|
||||
fido_nfc_rx,
|
||||
fido_nfc_tx,
|
||||
};
|
||||
}
|
||||
#endif
|
||||
return (fido_dev_open_wait(dev, path, -1));
|
||||
}
|
||||
|
||||
|
@ -370,10 +367,24 @@ fido_dev_close(fido_dev_t *dev)
|
|||
|
||||
dev->io.close(dev->io_handle);
|
||||
dev->io_handle = NULL;
|
||||
dev->cid = CTAP_CID_BROADCAST;
|
||||
|
||||
return (FIDO_OK);
|
||||
}
|
||||
|
||||
int
|
||||
fido_dev_set_sigmask(fido_dev_t *dev, const fido_sigset_t *sigmask)
|
||||
{
|
||||
if (dev->io_own || dev->io_handle == NULL || sigmask == NULL)
|
||||
return (FIDO_ERR_INVALID_ARGUMENT);
|
||||
|
||||
#ifdef NFC_LINUX
|
||||
if (dev->transport.rx == fido_nfc_rx)
|
||||
return (fido_nfc_set_sigmask(dev->io_handle, sigmask));
|
||||
#endif
|
||||
return (fido_hid_set_sigmask(dev->io_handle, sigmask));
|
||||
}
|
||||
|
||||
int
|
||||
fido_dev_cancel(fido_dev_t *dev)
|
||||
{
|
||||
|
@ -433,7 +444,7 @@ fido_dev_get_touch_begin(fido_dev_t *dev)
|
|||
|
||||
if (fido_dev_supports_pin(dev)) {
|
||||
if ((argv[7] = cbor_new_definite_bytestring()) == NULL ||
|
||||
(argv[8] = cbor_encode_pin_opt()) == NULL) {
|
||||
(argv[8] = cbor_encode_pin_opt(dev)) == NULL) {
|
||||
fido_log_debug("%s: cbor encode", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
@ -524,6 +535,8 @@ 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 *
|
||||
|
@ -553,8 +566,6 @@ fido_dev_new_with_info(const fido_dev_info_t *di)
|
|||
if ((dev = calloc(1, sizeof(*dev))) == NULL)
|
||||
return (NULL);
|
||||
|
||||
dev->cid = CTAP_CID_BROADCAST;
|
||||
|
||||
if (di->io.open == NULL || di->io.close == NULL ||
|
||||
di->io.read == NULL || di->io.write == NULL) {
|
||||
fido_log_debug("%s: NULL function", __func__);
|
||||
|
@ -563,7 +574,9 @@ fido_dev_new_with_info(const fido_dev_info_t *di)
|
|||
}
|
||||
|
||||
dev->io = di->io;
|
||||
dev->io_own = di->transport.tx != NULL || di->transport.rx != NULL;
|
||||
dev->transport = di->transport;
|
||||
dev->cid = CTAP_CID_BROADCAST;
|
||||
|
||||
if ((dev->path = strdup(di->path)) == NULL) {
|
||||
fido_log_debug("%s: strdup", __func__);
|
||||
|
@ -642,6 +655,30 @@ 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)
|
||||
{
|
||||
|
@ -654,3 +691,20 @@ 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);
|
||||
}
|
||||
|
|
|
@ -1,59 +1,149 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Yubico AB. All rights reserved.
|
||||
* Copyright (c) 2018-2021 Yubico AB. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/sha.h>
|
||||
#if defined(LIBRESSL_VERSION_NUMBER)
|
||||
#include <openssl/hkdf.h>
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
#include <openssl/kdf.h>
|
||||
#endif
|
||||
|
||||
#include "fido.h"
|
||||
#include "fido/es256.h"
|
||||
|
||||
#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
static int
|
||||
do_ecdh(const es256_sk_t *sk, const es256_pk_t *pk, fido_blob_t **ecdh)
|
||||
hkdf_sha256(uint8_t *key, const char *info, const fido_blob_t *secret)
|
||||
{
|
||||
EVP_PKEY *pk_evp = NULL;
|
||||
EVP_PKEY *sk_evp = NULL;
|
||||
EVP_PKEY_CTX *ctx = NULL;
|
||||
fido_blob_t *secret = NULL;
|
||||
int ok = -1;
|
||||
const EVP_MD *md;
|
||||
uint8_t salt[32];
|
||||
|
||||
memset(salt, 0, sizeof(salt));
|
||||
if ((md = EVP_sha256()) == NULL ||
|
||||
HKDF(key, SHA256_DIGEST_LENGTH, md, secret->ptr, secret->len, salt,
|
||||
sizeof(salt), (const uint8_t *)info, strlen(info)) != 1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int
|
||||
hkdf_sha256(uint8_t *key, char *info, fido_blob_t *secret)
|
||||
{
|
||||
const EVP_MD *const_md;
|
||||
EVP_MD *md = NULL;
|
||||
EVP_PKEY_CTX *ctx = NULL;
|
||||
size_t keylen = SHA256_DIGEST_LENGTH;
|
||||
uint8_t salt[32];
|
||||
int ok = -1;
|
||||
|
||||
memset(salt, 0, sizeof(salt));
|
||||
if (secret->len > INT_MAX || strlen(info) > INT_MAX) {
|
||||
fido_log_debug("%s: invalid param", __func__);
|
||||
goto fail;
|
||||
}
|
||||
if ((const_md = EVP_sha256()) == NULL ||
|
||||
(md = EVP_MD_meth_dup(const_md)) == NULL ||
|
||||
(ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL)) == NULL) {
|
||||
fido_log_debug("%s: init", __func__);
|
||||
goto fail;
|
||||
}
|
||||
if (EVP_PKEY_derive_init(ctx) < 1 ||
|
||||
EVP_PKEY_CTX_set_hkdf_md(ctx, md) < 1 ||
|
||||
EVP_PKEY_CTX_set1_hkdf_salt(ctx, salt, sizeof(salt)) < 1 ||
|
||||
EVP_PKEY_CTX_set1_hkdf_key(ctx, secret->ptr, (int)secret->len) < 1 ||
|
||||
EVP_PKEY_CTX_add1_hkdf_info(ctx, info, (int)strlen(info)) < 1) {
|
||||
fido_log_debug("%s: EVP_PKEY_CTX", __func__);
|
||||
goto fail;
|
||||
}
|
||||
if (EVP_PKEY_derive(ctx, key, &keylen) < 1) {
|
||||
fido_log_debug("%s: EVP_PKEY_derive", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ok = 0;
|
||||
fail:
|
||||
if (md != NULL)
|
||||
EVP_MD_meth_free(md);
|
||||
if (ctx != NULL)
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
|
||||
return ok;
|
||||
}
|
||||
#endif /* defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L */
|
||||
|
||||
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;
|
||||
|
||||
/* allocate blobs for secret & ecdh */
|
||||
if ((secret = fido_blob_new()) == NULL ||
|
||||
(*ecdh = fido_blob_new()) == NULL)
|
||||
goto fail;
|
||||
|
||||
/* wrap the keys as openssl objects */
|
||||
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;
|
||||
}
|
||||
|
||||
/* set ecdh parameters */
|
||||
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;
|
||||
}
|
||||
|
||||
/* perform ecdh */
|
||||
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;
|
||||
}
|
||||
|
||||
/* use sha256 as a kdf on the resulting secret */
|
||||
(*ecdh)->len = SHA256_DIGEST_LENGTH;
|
||||
if (((*ecdh)->ptr = calloc(1, (*ecdh)->len)) == NULL ||
|
||||
SHA256(secret->ptr, secret->len, (*ecdh)->ptr) != (*ecdh)->ptr) {
|
||||
fido_log_debug("%s: sha256", __func__);
|
||||
if (kdf(fido_dev_get_pin_protocol(dev), *ecdh, secret) < 0) {
|
||||
fido_log_debug("%s: kdf", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -70,38 +160,34 @@ fail:
|
|||
|
||||
fido_blob_free(&secret);
|
||||
|
||||
return (ok);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int
|
||||
fido_do_ecdh(fido_dev_t *dev, es256_pk_t **pk, fido_blob_t **ecdh)
|
||||
{
|
||||
es256_sk_t *sk = NULL; /* our private key */
|
||||
es256_pk_t *ak = NULL; /* authenticator's public key */
|
||||
int r;
|
||||
|
||||
*pk = NULL; /* our public key; returned */
|
||||
*ecdh = NULL; /* shared ecdh secret; returned */
|
||||
es256_sk_t *sk = NULL; /* our private key */
|
||||
es256_pk_t *ak = NULL; /* authenticator's public key */
|
||||
int r;
|
||||
|
||||
*pk = NULL;
|
||||
*ecdh = NULL;
|
||||
if ((sk = es256_sk_new()) == NULL || (*pk = es256_pk_new()) == NULL) {
|
||||
r = FIDO_ERR_INTERNAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (es256_sk_create(sk) < 0 || es256_derive_pk(sk, *pk) < 0) {
|
||||
fido_log_debug("%s: es256_derive_pk", __func__);
|
||||
r = FIDO_ERR_INTERNAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((ak = es256_pk_new()) == NULL ||
|
||||
fido_dev_authkey(dev, ak) != FIDO_OK) {
|
||||
fido_log_debug("%s: fido_dev_authkey", __func__);
|
||||
r = FIDO_ERR_INTERNAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (do_ecdh(sk, ak, ecdh) < 0) {
|
||||
if (do_ecdh(dev, sk, ak, ecdh) < 0) {
|
||||
fido_log_debug("%s: do_ecdh", __func__);
|
||||
r = FIDO_ERR_INTERNAL;
|
||||
goto fail;
|
||||
|
@ -117,5 +203,5 @@ fail:
|
|||
fido_blob_free(ecdh);
|
||||
}
|
||||
|
||||
return (r);
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -5,11 +5,8 @@
|
|||
*/
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/obj_mac.h>
|
||||
|
||||
#include <string.h>
|
||||
#include "fido.h"
|
||||
#include "fido/eddsa.h"
|
||||
|
||||
|
@ -132,9 +129,7 @@ eddsa_pk_free(eddsa_pk_t **pkp)
|
|||
if (pkp == NULL || (pk = *pkp) == NULL)
|
||||
return;
|
||||
|
||||
explicit_bzero(pk, sizeof(*pk));
|
||||
free(pk);
|
||||
|
||||
freezero(pk, sizeof(*pk));
|
||||
*pkp = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,8 @@ fido_strerr(int n)
|
|||
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:
|
||||
|
@ -98,6 +100,10 @@ fido_strerr(int n)
|
|||
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:
|
||||
|
@ -118,6 +124,10 @@ fido_strerr(int n)
|
|||
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:
|
||||
|
|
|
@ -5,11 +5,8 @@
|
|||
*/
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/obj_mac.h>
|
||||
|
||||
#include <string.h>
|
||||
#include "fido.h"
|
||||
#include "fido/es256.h"
|
||||
|
||||
|
@ -147,9 +144,7 @@ es256_sk_free(es256_sk_t **skp)
|
|||
if (skp == NULL || (sk = *skp) == NULL)
|
||||
return;
|
||||
|
||||
explicit_bzero(sk, sizeof(*sk));
|
||||
free(sk);
|
||||
|
||||
freezero(sk, sizeof(*sk));
|
||||
*skp = NULL;
|
||||
}
|
||||
|
||||
|
@ -167,9 +162,7 @@ es256_pk_free(es256_pk_t **pkp)
|
|||
if (pkp == NULL || (pk = *pkp) == NULL)
|
||||
return;
|
||||
|
||||
explicit_bzero(pk, sizeof(*pk));
|
||||
free(pk);
|
||||
|
||||
freezero(pk, sizeof(*pk));
|
||||
*pkp = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
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;
|
||||
|
@ -22,6 +24,8 @@
|
|||
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;
|
||||
|
@ -30,6 +34,7 @@
|
|||
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;
|
||||
|
@ -76,6 +81,7 @@
|
|||
fido_cbor_info_extensions_ptr;
|
||||
fido_cbor_info_free;
|
||||
fido_cbor_info_maxmsgsiz;
|
||||
fido_cbor_info_maxcredbloblen;
|
||||
fido_cbor_info_maxcredcntlst;
|
||||
fido_cbor_info_maxcredidlen;
|
||||
fido_cbor_info_fwversion;
|
||||
|
@ -89,11 +95,16 @@
|
|||
fido_cbor_info_versions_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;
|
||||
|
@ -127,6 +138,7 @@
|
|||
fido_cred_rp_name;
|
||||
fido_cred_set_authdata;
|
||||
fido_cred_set_authdata_raw;
|
||||
fido_cred_set_blob;
|
||||
fido_cred_set_clientdata_hash;
|
||||
fido_cred_set_extensions;
|
||||
fido_cred_set_fmt;
|
||||
|
@ -152,16 +164,20 @@
|
|||
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;
|
||||
|
@ -181,9 +197,20 @@
|
|||
fido_dev_reset;
|
||||
fido_dev_set_io_functions;
|
||||
fido_dev_set_pin;
|
||||
fido_dev_set_pin_minlen;
|
||||
fido_dev_set_sigmask;
|
||||
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;
|
||||
|
|
|
@ -11,6 +11,8 @@ _es256_pk_to_EVP_PKEY
|
|||
_fido_assert_allow_cred
|
||||
_fido_assert_authdata_len
|
||||
_fido_assert_authdata_ptr
|
||||
_fido_assert_blob_len
|
||||
_fido_assert_blob_ptr
|
||||
_fido_assert_clientdata_hash_len
|
||||
_fido_assert_clientdata_hash_ptr
|
||||
_fido_assert_count
|
||||
|
@ -20,6 +22,8 @@ _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
|
||||
|
@ -28,6 +32,7 @@ _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
|
||||
|
@ -74,6 +79,7 @@ _fido_cbor_info_extensions_len
|
|||
_fido_cbor_info_extensions_ptr
|
||||
_fido_cbor_info_free
|
||||
_fido_cbor_info_maxmsgsiz
|
||||
_fido_cbor_info_maxcredbloblen
|
||||
_fido_cbor_info_maxcredcntlst
|
||||
_fido_cbor_info_maxcredidlen
|
||||
_fido_cbor_info_fwversion
|
||||
|
@ -87,11 +93,16 @@ _fido_cbor_info_versions_len
|
|||
_fido_cbor_info_versions_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
|
||||
|
@ -125,6 +136,7 @@ _fido_cred_rp_id
|
|||
_fido_cred_rp_name
|
||||
_fido_cred_set_authdata
|
||||
_fido_cred_set_authdata_raw
|
||||
_fido_cred_set_blob
|
||||
_fido_cred_set_clientdata_hash
|
||||
_fido_cred_set_extensions
|
||||
_fido_cred_set_fmt
|
||||
|
@ -150,16 +162,20 @@ _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
|
||||
|
@ -179,9 +195,20 @@ _fido_dev_protocol
|
|||
_fido_dev_reset
|
||||
_fido_dev_set_io_functions
|
||||
_fido_dev_set_pin
|
||||
_fido_dev_set_pin_minlen
|
||||
_fido_dev_set_sigmask
|
||||
_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
|
||||
|
|
|
@ -12,6 +12,8 @@ es256_pk_to_EVP_PKEY
|
|||
fido_assert_allow_cred
|
||||
fido_assert_authdata_len
|
||||
fido_assert_authdata_ptr
|
||||
fido_assert_blob_len
|
||||
fido_assert_blob_ptr
|
||||
fido_assert_clientdata_hash_len
|
||||
fido_assert_clientdata_hash_ptr
|
||||
fido_assert_count
|
||||
|
@ -21,6 +23,8 @@ 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
|
||||
|
@ -29,6 +33,7 @@ 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
|
||||
|
@ -75,6 +80,7 @@ fido_cbor_info_extensions_len
|
|||
fido_cbor_info_extensions_ptr
|
||||
fido_cbor_info_free
|
||||
fido_cbor_info_maxmsgsiz
|
||||
fido_cbor_info_maxcredbloblen
|
||||
fido_cbor_info_maxcredcntlst
|
||||
fido_cbor_info_maxcredidlen
|
||||
fido_cbor_info_fwversion
|
||||
|
@ -88,11 +94,16 @@ fido_cbor_info_versions_len
|
|||
fido_cbor_info_versions_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
|
||||
|
@ -126,6 +137,7 @@ fido_cred_rp_id
|
|||
fido_cred_rp_name
|
||||
fido_cred_set_authdata
|
||||
fido_cred_set_authdata_raw
|
||||
fido_cred_set_blob
|
||||
fido_cred_set_clientdata_hash
|
||||
fido_cred_set_extensions
|
||||
fido_cred_set_fmt
|
||||
|
@ -151,16 +163,20 @@ 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
|
||||
|
@ -180,9 +196,20 @@ fido_dev_protocol
|
|||
fido_dev_reset
|
||||
fido_dev_set_io_functions
|
||||
fido_dev_set_pin
|
||||
fido_dev_set_pin_minlen
|
||||
fido_dev_set_sigmask
|
||||
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
|
||||
|
|
|
@ -7,6 +7,14 @@
|
|||
#ifndef _EXTERN_H
|
||||
#define _EXTERN_H
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "fido/types.h"
|
||||
|
@ -17,27 +25,32 @@ extern "C" {
|
|||
#endif /* __cplusplus */
|
||||
|
||||
/* aes256 */
|
||||
int aes256_cbc_dec(const fido_blob_t *, const fido_blob_t *, fido_blob_t *);
|
||||
int aes256_cbc_enc(const fido_blob_t *, const fido_blob_t *, fido_blob_t *);
|
||||
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_options(fido_opt_t, fido_opt_t);
|
||||
cbor_item_t *cbor_encode_change_pin_auth(const fido_blob_t *,
|
||||
const fido_blob_t *, const fido_blob_t *);
|
||||
cbor_item_t *cbor_encode_extensions(const fido_cred_ext_t *);
|
||||
cbor_item_t *cbor_encode_hmac_secret_param(const fido_blob_t *,
|
||||
const es256_pk_t *, const fido_blob_t *);
|
||||
cbor_item_t *cbor_encode_options(fido_opt_t, fido_opt_t);
|
||||
cbor_item_t *cbor_encode_pin_auth(const fido_blob_t *, const fido_blob_t *);
|
||||
cbor_item_t *cbor_encode_pin_enc(const fido_blob_t *, const fido_blob_t *);
|
||||
cbor_item_t *cbor_encode_pin_hash_enc(const fido_blob_t *, const fido_blob_t *);
|
||||
cbor_item_t *cbor_encode_pin_opt(void);
|
||||
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_set_pin_auth(const fido_blob_t *, const fido_blob_t *);
|
||||
cbor_item_t *cbor_encode_user_entity(const fido_user_t *);
|
||||
cbor_item_t *es256_pk_encode(const es256_pk_t *, int);
|
||||
|
||||
|
@ -46,7 +59,7 @@ int cbor_decode_attstmt(const cbor_item_t *, fido_attstmt_t *);
|
|||
int cbor_decode_cred_authdata(const cbor_item_t *, int, fido_blob_t *,
|
||||
fido_authdata_t *, fido_attcred_t *, fido_cred_ext_t *);
|
||||
int cbor_decode_assert_authdata(const cbor_item_t *, fido_blob_t *,
|
||||
fido_authdata_t *, int *, 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 *);
|
||||
|
@ -71,9 +84,16 @@ int cbor_map_iter(const cbor_item_t *, void *, int(*)(const cbor_item_t *,
|
|||
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_pin_params(fido_dev_t *, const fido_blob_t *, const es256_pk_t *,
|
||||
const fido_blob_t *,const char *, cbor_item_t **, cbor_item_t **);
|
||||
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 **);
|
||||
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]))
|
||||
|
@ -88,9 +108,23 @@ void *fido_hid_open(const char *);
|
|||
void fido_hid_close(void *);
|
||||
int fido_hid_read(void *, unsigned char *, size_t, int);
|
||||
int fido_hid_write(void *, const unsigned char *, size_t);
|
||||
int fido_hid_get_usage(const uint8_t *, size_t, uint32_t *);
|
||||
int fido_hid_get_report_len(const uint8_t *, size_t, size_t *, size_t *);
|
||||
int fido_hid_unix_open(const char *);
|
||||
int fido_hid_unix_wait(int, int, const fido_sigset_t *);
|
||||
int fido_hid_set_sigmask(void *, const fido_sigset_t *);
|
||||
size_t fido_hid_report_in_len(void *);
|
||||
size_t fido_hid_report_out_len(void *);
|
||||
|
||||
/* nfc i/o */
|
||||
void *fido_nfc_open(const char *);
|
||||
void fido_nfc_close(void *);
|
||||
int fido_nfc_read(void *, unsigned char *, size_t, int);
|
||||
int fido_nfc_write(void *, const unsigned char *, size_t);
|
||||
int fido_nfc_rx(fido_dev_t *, uint8_t, unsigned char *, size_t, int);
|
||||
int fido_nfc_tx(fido_dev_t *, uint8_t, const unsigned char *, size_t);
|
||||
int fido_nfc_set_sigmask(void *, const fido_sigset_t *);
|
||||
|
||||
/* generic i/o */
|
||||
int fido_rx_cbor_status(fido_dev_t *, int);
|
||||
int fido_rx(fido_dev_t *, uint8_t, void *, size_t, int);
|
||||
|
@ -101,16 +135,21 @@ int fido_tx(fido_dev_t *, uint8_t, const void *, size_t);
|
|||
#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);
|
||||
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);
|
||||
void fido_log_xxd(const void *, size_t, const char *, ...);
|
||||
void fido_log_error(int, const char *, ...);
|
||||
#endif /* __GNUC__ */
|
||||
#endif /* FIDO_NO_DIAGNOSTIC */
|
||||
|
||||
|
@ -121,11 +160,15 @@ int u2f_get_touch_begin(fido_dev_t *);
|
|||
int u2f_get_touch_status(fido_dev_t *, int *, int);
|
||||
|
||||
/* unexposed fido ops */
|
||||
uint8_t fido_dev_get_pin_protocol(const fido_dev_t *);
|
||||
int fido_dev_authkey(fido_dev_t *, es256_pk_t *);
|
||||
int fido_dev_get_cbor_info_wait(fido_dev_t *, fido_cbor_info_t *, int);
|
||||
int fido_dev_get_pin_token(fido_dev_t *, const char *, const fido_blob_t *,
|
||||
const es256_pk_t *, fido_blob_t *);
|
||||
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 *);
|
||||
uint64_t fido_dev_maxmsgsize(const fido_dev_t *);
|
||||
int fido_do_ecdh(fido_dev_t *, es256_pk_t **, fido_blob_t **);
|
||||
bool fido_dev_supports_permissions(const fido_dev_t *);
|
||||
bool fido_dev_can_get_uv_token(const fido_dev_t *, const char *, fido_opt_t);
|
||||
|
||||
/* misc */
|
||||
void fido_assert_reset_rx(fido_assert_t *);
|
||||
|
@ -134,6 +177,8 @@ void fido_cred_reset_rx(fido_cred_t *);
|
|||
void fido_cred_reset_tx(fido_cred_t *);
|
||||
int fido_check_rp_id(const char *, const unsigned char *);
|
||||
int fido_check_flags(uint8_t, fido_opt_t, fido_opt_t);
|
||||
int fido_get_random(void *, size_t);
|
||||
int fido_blob_serialise(fido_blob_t *, const cbor_item_t *);
|
||||
|
||||
/* crypto */
|
||||
int fido_verify_sig_es256(const fido_blob_t *, const es256_pk_t *,
|
||||
|
@ -145,8 +190,9 @@ int fido_verify_sig_eddsa(const fido_blob_t *, const eddsa_pk_t *,
|
|||
int fido_get_signed_hash(int, fido_blob_t *, const fido_blob_t *,
|
||||
const fido_blob_t *);
|
||||
|
||||
/* hid device manifest */
|
||||
/* 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 *);
|
||||
|
@ -159,9 +205,15 @@ uint32_t uniform_random(uint32_t);
|
|||
#endif
|
||||
|
||||
/* internal device capability flags */
|
||||
#define FIDO_DEV_PIN_SET 0x01
|
||||
#define FIDO_DEV_PIN_UNSET 0x02
|
||||
#define FIDO_DEV_CRED_PROT 0x04
|
||||
#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
|
||||
|
||||
/* miscellanea */
|
||||
#define FIDO_DUMMY_CLIENTDATA ""
|
||||
|
|
|
@ -15,11 +15,13 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#ifdef _FIDO_INTERNAL
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <cbor.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "blob.h"
|
||||
#include "../openbsd-compat/openbsd-compat.h"
|
||||
#include "blob.h"
|
||||
#include "iso7816.h"
|
||||
#include "extern.h"
|
||||
#endif
|
||||
|
@ -32,12 +34,6 @@
|
|||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define FIDO_DEPRECATED(reason) __declspec(deprecated(reason))
|
||||
#else
|
||||
#define FIDO_DEPRECATED(reason) __attribute__((__deprecated__(reason)))
|
||||
#endif
|
||||
|
||||
fido_assert_t *fido_assert_new(void);
|
||||
fido_cred_t *fido_cred_new(void);
|
||||
fido_dev_t *fido_dev_new(void);
|
||||
|
@ -55,6 +51,7 @@ 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 *);
|
||||
|
@ -63,8 +60,10 @@ const unsigned char *fido_assert_authdata_ptr(const fido_assert_t *, size_t);
|
|||
const unsigned char *fido_assert_clientdata_hash_ptr(const fido_assert_t *);
|
||||
const unsigned char *fido_assert_hmac_secret_ptr(const fido_assert_t *, size_t);
|
||||
const unsigned char *fido_assert_id_ptr(const fido_assert_t *, size_t);
|
||||
const unsigned char *fido_assert_largeblob_key_ptr(const fido_assert_t *, size_t);
|
||||
const unsigned char *fido_assert_sig_ptr(const fido_assert_t *, size_t);
|
||||
const unsigned char *fido_assert_user_id_ptr(const fido_assert_t *, size_t);
|
||||
const unsigned char *fido_assert_blob_ptr(const fido_assert_t *, size_t);
|
||||
|
||||
char **fido_cbor_info_extensions_ptr(const fido_cbor_info_t *);
|
||||
char **fido_cbor_info_options_name_ptr(const fido_cbor_info_t *);
|
||||
|
@ -86,6 +85,7 @@ const fido_dev_info_t *fido_dev_info_ptr(const fido_dev_info_t *, size_t);
|
|||
const uint8_t *fido_cbor_info_protocols_ptr(const fido_cbor_info_t *);
|
||||
const unsigned char *fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *);
|
||||
const unsigned char *fido_cred_authdata_ptr(const fido_cred_t *);
|
||||
const unsigned char *fido_cred_authdata_raw_ptr(const fido_cred_t *);
|
||||
const unsigned char *fido_cred_clientdata_hash_ptr(const fido_cred_t *);
|
||||
const unsigned char *fido_cred_id_ptr(const fido_cred_t *);
|
||||
const unsigned char *fido_cred_aaguid_ptr(const fido_cred_t *);
|
||||
|
@ -93,6 +93,7 @@ const unsigned char *fido_cred_user_id_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_x5c_ptr(const fido_cred_t *);
|
||||
const unsigned char *fido_cred_largeblob_key_ptr(const fido_cred_t *);
|
||||
|
||||
int fido_assert_allow_cred(fido_assert_t *, const unsigned char *, size_t);
|
||||
int fido_assert_set_authdata(fido_assert_t *, size_t, const unsigned char *,
|
||||
|
@ -104,7 +105,8 @@ int fido_assert_set_clientdata_hash(fido_assert_t *, const unsigned char *,
|
|||
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);
|
||||
FIDO_DEPRECATED("use fido_assert_set_up/fido_assert_set_uv")
|
||||
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);
|
||||
|
@ -115,10 +117,10 @@ int fido_cred_exclude(fido_cred_t *, const unsigned char *, size_t);
|
|||
int fido_cred_prot(const fido_cred_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_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 *);
|
||||
FIDO_DEPRECATED("use fido_cred_set_rk/fido_cred_set_uv")
|
||||
int fido_cred_set_options(fido_cred_t *, bool, bool);
|
||||
int fido_cred_set_prot(fido_cred_t *, int);
|
||||
int fido_cred_set_rk(fido_cred_t *, fido_opt_t);
|
||||
|
@ -132,11 +134,13 @@ int fido_cred_set_user(fido_cred_t *, const unsigned char *, size_t,
|
|||
int fido_cred_set_x509(fido_cred_t *, const unsigned char *, size_t);
|
||||
int fido_cred_verify(const fido_cred_t *);
|
||||
int fido_cred_verify_self(const fido_cred_t *);
|
||||
int fido_dev_set_sigmask(fido_dev_t *, const fido_sigset_t *);
|
||||
int fido_dev_cancel(fido_dev_t *);
|
||||
int fido_dev_close(fido_dev_t *);
|
||||
int fido_dev_get_assert(fido_dev_t *, fido_assert_t *, const char *);
|
||||
int fido_dev_get_cbor_info(fido_dev_t *, fido_cbor_info_t *);
|
||||
int fido_dev_get_retry_count(fido_dev_t *, int *);
|
||||
int fido_dev_get_uv_retry_count(fido_dev_t *, int *);
|
||||
int fido_dev_get_touch_begin(fido_dev_t *);
|
||||
int fido_dev_get_touch_status(fido_dev_t *, int *, int);
|
||||
int fido_dev_info_manifest(fido_dev_info_t *, size_t, size_t *);
|
||||
|
@ -153,14 +157,17 @@ 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_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_versions_len(const fido_cbor_info_t *);
|
||||
size_t fido_cred_authdata_len(const fido_cred_t *);
|
||||
size_t fido_cred_authdata_raw_len(const fido_cred_t *);
|
||||
size_t fido_cred_clientdata_hash_len(const fido_cred_t *);
|
||||
size_t fido_cred_id_len(const fido_cred_t *);
|
||||
size_t fido_cred_aaguid_len(const fido_cred_t *);
|
||||
|
@ -168,10 +175,12 @@ size_t fido_cred_user_id_len(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_x5c_len(const fido_cred_t *);
|
||||
size_t fido_cred_largeblob_key_len(const fido_cred_t *);
|
||||
|
||||
uint8_t fido_assert_flags(const fido_assert_t *, size_t);
|
||||
uint32_t fido_assert_sigcount(const fido_assert_t *, size_t);
|
||||
uint8_t fido_cred_flags(const fido_cred_t *);
|
||||
uint32_t fido_cred_sigcount(const fido_cred_t *);
|
||||
uint8_t fido_dev_protocol(const fido_dev_t *);
|
||||
uint8_t fido_dev_major(const fido_dev_t *);
|
||||
uint8_t fido_dev_minor(const fido_dev_t *);
|
||||
|
@ -180,14 +189,28 @@ uint8_t fido_dev_flags(const fido_dev_t *);
|
|||
int16_t fido_dev_info_vendor(const fido_dev_info_t *);
|
||||
int16_t fido_dev_info_product(const fido_dev_info_t *);
|
||||
uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *);
|
||||
uint64_t fido_cbor_info_maxcredbloblen(const fido_cbor_info_t *);
|
||||
uint64_t fido_cbor_info_maxcredcntlst(const fido_cbor_info_t *);
|
||||
uint64_t fido_cbor_info_maxcredidlen(const fido_cbor_info_t *);
|
||||
uint64_t fido_cbor_info_fwversion(const fido_cbor_info_t *);
|
||||
|
||||
bool fido_dev_has_pin(const fido_dev_t *);
|
||||
bool fido_dev_has_uv(const fido_dev_t *);
|
||||
bool fido_dev_is_fido2(const fido_dev_t *);
|
||||
bool fido_dev_supports_pin(const fido_dev_t *);
|
||||
bool fido_dev_supports_cred_prot(const fido_dev_t *);
|
||||
bool fido_dev_supports_credman(const fido_dev_t *);
|
||||
bool fido_dev_supports_uv(const fido_dev_t *);
|
||||
|
||||
int fido_dev_largeblob_get(fido_dev_t *, const unsigned char *, size_t,
|
||||
unsigned char **, size_t *);
|
||||
int fido_dev_largeblob_set(fido_dev_t *, const unsigned char *, size_t,
|
||||
const unsigned char *, size_t, const char *);
|
||||
int fido_dev_largeblob_remove(fido_dev_t *, const unsigned char *, size_t,
|
||||
const char *);
|
||||
int fido_dev_largeblob_get_array(fido_dev_t *, unsigned char **, size_t *);
|
||||
int fido_dev_largeblob_set_array(fido_dev_t *, const unsigned char *, size_t,
|
||||
const char *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _FIDO_CONFIG_H
|
||||
#define _FIDO_CONFIG_H
|
||||
|
||||
#ifdef _FIDO_INTERNAL
|
||||
#include "blob.h"
|
||||
#include "fido/err.h"
|
||||
#include "fido/param.h"
|
||||
#include "fido/types.h"
|
||||
#else
|
||||
#include <fido.h>
|
||||
#include <fido/err.h>
|
||||
#include <fido/param.h>
|
||||
#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 *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* !_FIDO_CONFIG_H */
|
|
@ -7,7 +7,7 @@
|
|||
#ifndef _FIDO_ERR_H
|
||||
#define _FIDO_ERR_H
|
||||
|
||||
#define FIDO_ERR_SUCCESS 0x00
|
||||
#define FIDO_ERR_SUCCESS 0x00
|
||||
#define FIDO_ERR_INVALID_COMMAND 0x01
|
||||
#define FIDO_ERR_INVALID_PARAMETER 0x02
|
||||
#define FIDO_ERR_INVALID_LENGTH 0x03
|
||||
|
@ -22,6 +22,7 @@
|
|||
#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
|
||||
|
@ -51,6 +52,8 @@
|
|||
#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
|
||||
|
||||
|
@ -65,6 +68,8 @@
|
|||
#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" {
|
||||
|
|
|
@ -31,9 +31,15 @@
|
|||
#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
|
||||
|
@ -43,6 +49,7 @@
|
|||
#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
|
||||
|
@ -92,10 +99,19 @@
|
|||
/* 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
|
||||
|
||||
/* 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)
|
||||
#endif /* _FIDO_INTERNAL */
|
||||
|
||||
#endif /* !_FIDO_PARAM_H */
|
||||
|
|
|
@ -7,6 +7,11 @@
|
|||
#ifndef _FIDO_TYPES_H
|
||||
#define _FIDO_TYPES_H
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
@ -43,6 +48,12 @@ typedef enum {
|
|||
|
||||
typedef void fido_log_handler_t(const char *);
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef int fido_sigset_t;
|
||||
#else
|
||||
typedef sigset_t fido_sigset_t;
|
||||
#endif
|
||||
|
||||
#ifdef _FIDO_INTERNAL
|
||||
#include "packed.h"
|
||||
#include "blob.h"
|
||||
|
@ -128,31 +139,44 @@ typedef struct fido_cred {
|
|||
int type; /* cose algorithm */
|
||||
char *fmt; /* credential format */
|
||||
fido_cred_ext_t authdata_ext; /* decoded extensions */
|
||||
fido_blob_t authdata_cbor; /* raw cbor payload */
|
||||
fido_blob_t authdata_cbor; /* cbor-encoded payload */
|
||||
fido_blob_t authdata_raw; /* cbor-decoded payload */
|
||||
fido_authdata_t authdata; /* decoded authdata payload */
|
||||
fido_attcred_t attcred; /* returned credential (key + id) */
|
||||
fido_attstmt_t attstmt; /* attestation statement (x509 + sig) */
|
||||
fido_blob_t largeblob_key; /* decoded large blob key */
|
||||
fido_blob_t blob; /* FIDO 2.1 credBlob */
|
||||
} fido_cred_t;
|
||||
|
||||
typedef struct fido_assert_extattr {
|
||||
int mask; /* decoded extensions */
|
||||
fido_blob_t hmac_secret_enc; /* hmac secret, encrypted */
|
||||
fido_blob_t blob; /* decoded FIDO 2.1 credBlob */
|
||||
} fido_assert_extattr_t;
|
||||
|
||||
typedef struct _fido_assert_stmt {
|
||||
fido_blob_t id; /* credential id */
|
||||
fido_user_t user; /* user attributes */
|
||||
fido_blob_t hmac_secret_enc; /* hmac secret, encrypted */
|
||||
fido_blob_t hmac_secret; /* hmac secret */
|
||||
int 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 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 cdh; /* client data hash */
|
||||
fido_blob_t hmac_salt; /* optional hmac-secret salt */
|
||||
fido_blob_array_t allow_list; /* list of allowed credentials */
|
||||
fido_opt_t up; /* user presence */
|
||||
fido_opt_t uv; /* user verification */
|
||||
int ext; /* enabled extensions */
|
||||
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 */
|
||||
|
@ -184,6 +208,7 @@ typedef struct fido_cbor_info {
|
|||
uint64_t maxcredcntlst; /* max number of credentials in list */
|
||||
uint64_t maxcredidlen; /* max credential ID length */
|
||||
uint64_t fwversion; /* firmware version */
|
||||
uint64_t maxcredbloblen; /* max credBlob length */
|
||||
} fido_cbor_info_t;
|
||||
|
||||
typedef struct fido_dev_info {
|
||||
|
@ -209,17 +234,18 @@ struct fido_ctap_info {
|
|||
})
|
||||
|
||||
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 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 */
|
||||
} fido_dev_t;
|
||||
|
||||
#else
|
||||
|
|
|
@ -4,9 +4,117 @@
|
|||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#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)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Yubico AB. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <dev/usb/usb_ioctl.h>
|
||||
#include <dev/usb/usbhid.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "fido.h"
|
||||
|
||||
#define MAX_UHID 64
|
||||
|
||||
struct hid_freebsd {
|
||||
int fd;
|
||||
size_t report_in_len;
|
||||
size_t report_out_len;
|
||||
sigset_t sigmask;
|
||||
const sigset_t *sigmaskp;
|
||||
};
|
||||
|
||||
static bool
|
||||
is_fido(int fd)
|
||||
{
|
||||
char buf[64];
|
||||
struct usb_gen_descriptor ugd;
|
||||
uint32_t usage_page = 0;
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
memset(&ugd, 0, sizeof(ugd));
|
||||
|
||||
ugd.ugd_report_type = UHID_FEATURE_REPORT;
|
||||
ugd.ugd_data = buf;
|
||||
ugd.ugd_maxlen = sizeof(buf);
|
||||
|
||||
if (ioctl(fd, IOCTL_REQ(USB_GET_REPORT_DESC), &ugd) == -1) {
|
||||
fido_log_error(errno, "%s: ioctl", __func__);
|
||||
return (false);
|
||||
}
|
||||
if (ugd.ugd_actlen > sizeof(buf) || fido_hid_get_usage(ugd.ugd_data,
|
||||
ugd.ugd_actlen, &usage_page) < 0) {
|
||||
fido_log_debug("%s: fido_hid_get_usage", __func__);
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (usage_page == 0xf1d0);
|
||||
}
|
||||
|
||||
static int
|
||||
copy_info(fido_dev_info_t *di, const char *path)
|
||||
{
|
||||
int fd = -1;
|
||||
int ok = -1;
|
||||
struct usb_device_info udi;
|
||||
|
||||
memset(di, 0, sizeof(*di));
|
||||
memset(&udi, 0, sizeof(udi));
|
||||
|
||||
if ((fd = fido_hid_unix_open(path)) == -1 || is_fido(fd) == 0)
|
||||
goto fail;
|
||||
|
||||
if (ioctl(fd, IOCTL_REQ(USB_GET_DEVICEINFO), &udi) == -1) {
|
||||
fido_log_error(errno, "%s: ioctl", __func__);
|
||||
strlcpy(udi.udi_vendor, "FreeBSD", sizeof(udi.udi_vendor));
|
||||
strlcpy(udi.udi_product, "uhid(4)", sizeof(udi.udi_product));
|
||||
udi.udi_vendorNo = 0x0b5d; /* stolen from PCI_VENDOR_OPENBSD */
|
||||
}
|
||||
|
||||
if ((di->path = strdup(path)) == NULL ||
|
||||
(di->manufacturer = strdup(udi.udi_vendor)) == NULL ||
|
||||
(di->product = strdup(udi.udi_product)) == NULL)
|
||||
goto fail;
|
||||
|
||||
di->vendor_id = (int16_t)udi.udi_vendorNo;
|
||||
di->product_id = (int16_t)udi.udi_productNo;
|
||||
|
||||
ok = 0;
|
||||
fail:
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
|
||||
if (ok < 0) {
|
||||
free(di->path);
|
||||
free(di->manufacturer);
|
||||
free(di->product);
|
||||
explicit_bzero(di, sizeof(*di));
|
||||
}
|
||||
|
||||
return (ok);
|
||||
}
|
||||
|
||||
int
|
||||
fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
|
||||
{
|
||||
char path[64];
|
||||
size_t i;
|
||||
|
||||
*olen = 0;
|
||||
|
||||
if (ilen == 0)
|
||||
return (FIDO_OK); /* nothing to do */
|
||||
|
||||
if (devlist == NULL || olen == NULL)
|
||||
return (FIDO_ERR_INVALID_ARGUMENT);
|
||||
|
||||
for (i = *olen = 0; i < MAX_UHID && *olen < ilen; i++) {
|
||||
snprintf(path, sizeof(path), "/dev/uhid%zu", i);
|
||||
if (copy_info(&devlist[*olen], path) == 0) {
|
||||
devlist[*olen].io = (fido_dev_io_t) {
|
||||
fido_hid_open,
|
||||
fido_hid_close,
|
||||
fido_hid_read,
|
||||
fido_hid_write,
|
||||
};
|
||||
++(*olen);
|
||||
}
|
||||
}
|
||||
|
||||
return (FIDO_OK);
|
||||
}
|
||||
|
||||
void *
|
||||
fido_hid_open(const char *path)
|
||||
{
|
||||
char buf[64];
|
||||
struct hid_freebsd *ctx;
|
||||
struct usb_gen_descriptor ugd;
|
||||
int r;
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
memset(&ugd, 0, sizeof(ugd));
|
||||
|
||||
if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
|
||||
return (NULL);
|
||||
|
||||
if ((ctx->fd = fido_hid_unix_open(path)) == -1) {
|
||||
free(ctx);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
ugd.ugd_report_type = UHID_FEATURE_REPORT;
|
||||
ugd.ugd_data = buf;
|
||||
ugd.ugd_maxlen = sizeof(buf);
|
||||
|
||||
if ((r = ioctl(ctx->fd, IOCTL_REQ(USB_GET_REPORT_DESC), &ugd) == -1) ||
|
||||
ugd.ugd_actlen > sizeof(buf) ||
|
||||
fido_hid_get_report_len(ugd.ugd_data, ugd.ugd_actlen,
|
||||
&ctx->report_in_len, &ctx->report_out_len) < 0) {
|
||||
if (r == -1)
|
||||
fido_log_error(errno, "%s: ioctl", __func__);
|
||||
fido_log_debug("%s: using default report sizes", __func__);
|
||||
ctx->report_in_len = CTAP_MAX_REPORT_LEN;
|
||||
ctx->report_out_len = CTAP_MAX_REPORT_LEN;
|
||||
}
|
||||
|
||||
return (ctx);
|
||||
}
|
||||
|
||||
void
|
||||
fido_hid_close(void *handle)
|
||||
{
|
||||
struct hid_freebsd *ctx = handle;
|
||||
|
||||
if (close(ctx->fd) == -1)
|
||||
fido_log_error(errno, "%s: close", __func__);
|
||||
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int
|
||||
fido_hid_set_sigmask(void *handle, const fido_sigset_t *sigmask)
|
||||
{
|
||||
struct hid_freebsd *ctx = handle;
|
||||
|
||||
ctx->sigmask = *sigmask;
|
||||
ctx->sigmaskp = &ctx->sigmask;
|
||||
|
||||
return (FIDO_OK);
|
||||
}
|
||||
|
||||
int
|
||||
fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
|
||||
{
|
||||
struct hid_freebsd *ctx = handle;
|
||||
ssize_t r;
|
||||
|
||||
if (len != ctx->report_in_len) {
|
||||
fido_log_debug("%s: len %zu", __func__, len);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (fido_hid_unix_wait(ctx->fd, ms, ctx->sigmaskp) < 0) {
|
||||
fido_log_debug("%s: fd not ready", __func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((r = read(ctx->fd, buf, len)) == -1) {
|
||||
fido_log_error(errno, "%s: read", __func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (r < 0 || (size_t)r != len) {
|
||||
fido_log_debug("%s: %zd != %zu", __func__, r, len);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return ((int)r);
|
||||
}
|
||||
|
||||
int
|
||||
fido_hid_write(void *handle, const unsigned char *buf, size_t len)
|
||||
{
|
||||
struct hid_freebsd *ctx = handle;
|
||||
ssize_t r;
|
||||
|
||||
if (len != ctx->report_out_len + 1) {
|
||||
fido_log_debug("%s: len %zu", __func__, len);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((r = write(ctx->fd, buf + 1, len - 1)) == -1) {
|
||||
fido_log_error(errno, "%s: write", __func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (r < 0 || (size_t)r != len - 1) {
|
||||
fido_log_debug("%s: %zd != %zu", __func__, r, len - 1);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return ((int)len);
|
||||
}
|
||||
|
||||
size_t
|
||||
fido_hid_report_in_len(void *handle)
|
||||
{
|
||||
struct hid_freebsd *ctx = handle;
|
||||
|
||||
return (ctx->report_in_len);
|
||||
}
|
||||
|
||||
size_t
|
||||
fido_hid_report_out_len(void *handle)
|
||||
{
|
||||
struct hid_freebsd *ctx = handle;
|
||||
|
||||
return (ctx->report_out_len);
|
||||
}
|
|
@ -11,9 +11,8 @@
|
|||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
#include <hidapi.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "fido.h"
|
||||
|
@ -97,81 +96,6 @@ copy_info(fido_dev_info_t *di, const struct hid_device_info *d)
|
|||
}
|
||||
|
||||
#ifdef __linux__
|
||||
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;
|
||||
}
|
||||
|
||||
static int
|
||||
get_usage_info(const struct hidraw_report_descriptor *hrd, uint32_t *usage_page,
|
||||
uint32_t *usage)
|
||||
{
|
||||
const uint8_t *ptr = hrd->value;
|
||||
size_t len = hrd->size;
|
||||
|
||||
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;
|
||||
} else if (key == 0x8) {
|
||||
*usage = key_val;
|
||||
}
|
||||
|
||||
ptr += key_len;
|
||||
len -= key_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd)
|
||||
{
|
||||
|
@ -179,21 +103,21 @@ get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd)
|
|||
int s = -1;
|
||||
int ok = -1;
|
||||
|
||||
if ((fd = open(path, O_RDONLY)) < 0) {
|
||||
fido_log_debug("%s: open", __func__);
|
||||
if ((fd = fido_hid_unix_open(path)) == -1) {
|
||||
fido_log_debug("%s: fido_hid_unix_open", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl(fd, HIDIOCGRDESCSIZE, &s) < 0 || s < 0 ||
|
||||
if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESCSIZE), &s) < 0 || s < 0 ||
|
||||
(unsigned)s > HID_MAX_DESCRIPTOR_SIZE) {
|
||||
fido_log_debug("%s: ioctl HIDIOCGRDESCSIZE", __func__);
|
||||
fido_log_error(errno, "%s: ioctl HIDIOCGRDESCSIZE", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
hrd->size = (unsigned)s;
|
||||
|
||||
if (ioctl(fd, HIDIOCGRDESC, hrd) < 0) {
|
||||
fido_log_debug("%s: ioctl HIDIOCGRDESC", __func__);
|
||||
if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESC), hrd) < 0) {
|
||||
fido_log_error(errno, "%s: ioctl HIDIOCGRDESC", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
@ -208,14 +132,13 @@ fail:
|
|||
static bool
|
||||
is_fido(const struct hid_device_info *hdi)
|
||||
{
|
||||
uint32_t usage = 0;
|
||||
uint32_t usage_page = 0;
|
||||
struct hidraw_report_descriptor hrd;
|
||||
|
||||
memset(&hrd, 0, sizeof(hrd));
|
||||
|
||||
if (get_report_descriptor(hdi->path, &hrd) < 0 ||
|
||||
get_usage_info(&hrd, &usage_page, &usage) < 0) {
|
||||
fido_hid_get_usage(hrd.value, hrd.size, &usage_page) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -265,6 +188,15 @@ fido_hid_close(void *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)
|
||||
{
|
||||
|
|
|
@ -11,146 +11,38 @@
|
|||
#include <linux/input.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libudev.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "fido.h"
|
||||
|
||||
struct hid_linux {
|
||||
int fd;
|
||||
size_t report_in_len;
|
||||
size_t report_out_len;
|
||||
int fd;
|
||||
size_t report_in_len;
|
||||
size_t report_out_len;
|
||||
sigset_t sigmask;
|
||||
const sigset_t *sigmaskp;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int
|
||||
get_usage_info(const struct hidraw_report_descriptor *hrd, uint32_t *usage_page,
|
||||
uint32_t *usage)
|
||||
{
|
||||
const uint8_t *ptr = hrd->value;
|
||||
size_t len = hrd->size;
|
||||
|
||||
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;
|
||||
} else if (key == 0x8) {
|
||||
*usage = key_val;
|
||||
}
|
||||
|
||||
ptr += key_len;
|
||||
len -= key_len;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
get_report_sizes(const struct hidraw_report_descriptor *hrd,
|
||||
size_t *report_in_len, size_t *report_out_len)
|
||||
{
|
||||
const uint8_t *ptr = hrd->value;
|
||||
size_t len = hrd->size;
|
||||
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);
|
||||
}
|
||||
|
||||
static int
|
||||
get_report_descriptor(int fd, struct hidraw_report_descriptor *hrd)
|
||||
{
|
||||
int s = -1;
|
||||
|
||||
if (ioctl(fd, HIDIOCGRDESCSIZE, &s) < 0 || s < 0 ||
|
||||
(unsigned)s > HID_MAX_DESCRIPTOR_SIZE) {
|
||||
fido_log_debug("%s: ioctl HIDIOCGRDESCSIZE", __func__);
|
||||
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, HIDIOCGRDESC, hrd) < 0) {
|
||||
fido_log_debug("%s: ioctl HIDIOCGRDESC", __func__);
|
||||
if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESC), hrd) == -1) {
|
||||
fido_log_error(errno, "%s: ioctl HIDIOCGRDESC", __func__);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
@ -161,24 +53,20 @@ static bool
|
|||
is_fido(const char *path)
|
||||
{
|
||||
int fd;
|
||||
uint32_t usage = 0;
|
||||
uint32_t usage_page = 0;
|
||||
struct hidraw_report_descriptor hrd;
|
||||
|
||||
memset(&hrd, 0, sizeof(hrd));
|
||||
|
||||
if ((fd = open(path, O_RDONLY)) == -1) {
|
||||
fido_log_debug("%s: open", __func__);
|
||||
if ((fd = fido_hid_unix_open(path)) == -1)
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (get_report_descriptor(fd, &hrd) < 0 ||
|
||||
get_usage_info(&hrd, &usage_page, &usage) < 0) {
|
||||
close(fd);
|
||||
return (false);
|
||||
}
|
||||
fido_hid_get_usage(hrd.value, hrd.size, &usage_page) < 0)
|
||||
usage_page = 0;
|
||||
|
||||
close(fd);
|
||||
if (close(fd) == -1)
|
||||
fido_log_error(errno, "%s: close", __func__);
|
||||
|
||||
return (usage_page == 0xf1d0);
|
||||
}
|
||||
|
@ -354,14 +242,15 @@ fido_hid_open(const char *path)
|
|||
if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
|
||||
return (NULL);
|
||||
|
||||
if ((ctx->fd = open(path, O_RDWR)) < 0) {
|
||||
if ((ctx->fd = fido_hid_unix_open(path)) == -1) {
|
||||
free(ctx);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (get_report_descriptor(ctx->fd, &hrd) < 0 || get_report_sizes(&hrd,
|
||||
&ctx->report_in_len, &ctx->report_out_len) < 0 ||
|
||||
ctx->report_in_len == 0 || ctx->report_out_len == 0) {
|
||||
if (get_report_descriptor(ctx->fd, &hrd) < 0 ||
|
||||
fido_hid_get_report_len(hrd.value, hrd.size, &ctx->report_in_len,
|
||||
&ctx->report_out_len) < 0 || ctx->report_in_len == 0 ||
|
||||
ctx->report_out_len == 0) {
|
||||
fido_log_debug("%s: using default report sizes", __func__);
|
||||
ctx->report_in_len = CTAP_MAX_REPORT_LEN;
|
||||
ctx->report_out_len = CTAP_MAX_REPORT_LEN;
|
||||
|
@ -375,73 +264,21 @@ fido_hid_close(void *handle)
|
|||
{
|
||||
struct hid_linux *ctx = handle;
|
||||
|
||||
close(ctx->fd);
|
||||
if (close(ctx->fd) == -1)
|
||||
fido_log_error(errno, "%s: close", __func__);
|
||||
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static int
|
||||
timespec_to_ms(const struct timespec *ts, int upper_bound)
|
||||
int
|
||||
fido_hid_set_sigmask(void *handle, const fido_sigset_t *sigmask)
|
||||
{
|
||||
int64_t x;
|
||||
int64_t y;
|
||||
struct hid_linux *ctx = handle;
|
||||
|
||||
if (ts->tv_sec < 0 || ts->tv_sec > INT64_MAX / 1000LL ||
|
||||
ts->tv_nsec < 0 || ts->tv_nsec / 1000000LL > INT64_MAX)
|
||||
return (upper_bound);
|
||||
ctx->sigmask = *sigmask;
|
||||
ctx->sigmaskp = &ctx->sigmask;
|
||||
|
||||
x = ts->tv_sec * 1000LL;
|
||||
y = ts->tv_nsec / 1000000LL;
|
||||
|
||||
if (INT64_MAX - x < y || x + y > upper_bound)
|
||||
return (upper_bound);
|
||||
|
||||
return (int)(x + y);
|
||||
}
|
||||
|
||||
static int
|
||||
waitfd(int fd, int ms)
|
||||
{
|
||||
struct timespec ts_start;
|
||||
struct timespec ts_now;
|
||||
struct timespec ts_delta;
|
||||
struct pollfd pfd;
|
||||
int ms_remain;
|
||||
int r;
|
||||
|
||||
if (ms < 0)
|
||||
return (0);
|
||||
|
||||
memset(&pfd, 0, sizeof(pfd));
|
||||
pfd.events = POLLIN;
|
||||
pfd.fd = fd;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts_start) != 0) {
|
||||
fido_log_debug("%s: clock_gettime: %s", __func__,
|
||||
strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
for (ms_remain = ms; ms_remain > 0;) {
|
||||
if ((r = poll(&pfd, 1, ms_remain)) > 0)
|
||||
return (0);
|
||||
else if (r == 0)
|
||||
break;
|
||||
else if (errno != EINTR) {
|
||||
fido_log_debug("%s: poll: %s", __func__,
|
||||
strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
/* poll interrupted - subtract time already waited */
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts_now) != 0) {
|
||||
fido_log_debug("%s: clock_gettime: %s", __func__,
|
||||
strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
timespecsub(&ts_now, &ts_start, &ts_delta);
|
||||
ms_remain = ms - timespec_to_ms(&ts_delta, ms);
|
||||
}
|
||||
|
||||
return (-1);
|
||||
return (FIDO_OK);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -455,13 +292,18 @@ fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
|
|||
return (-1);
|
||||
}
|
||||
|
||||
if (waitfd(ctx->fd, ms) < 0) {
|
||||
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)) < 0 || (size_t)r != len) {
|
||||
fido_log_debug("%s: read", __func__);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -479,8 +321,13 @@ fido_hid_write(void *handle, const unsigned char *buf, size_t len)
|
|||
return (-1);
|
||||
}
|
||||
|
||||
if ((r = write(ctx->fd, buf, len)) < 0 || (size_t)r != len) {
|
||||
fido_log_debug("%s: write", __func__);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,23 +11,24 @@
|
|||
#include <dev/usb/usbhid.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <usbhid.h>
|
||||
|
||||
#include "fido.h"
|
||||
|
||||
#define MAX_UHID 64
|
||||
|
||||
struct hid_netbsd {
|
||||
int fd;
|
||||
size_t report_in_len;
|
||||
size_t report_out_len;
|
||||
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. */
|
||||
|
@ -39,47 +40,39 @@ struct hid_netbsd {
|
|||
static bool
|
||||
is_fido(int fd)
|
||||
{
|
||||
report_desc_t rdesc;
|
||||
hid_data_t hdata;
|
||||
hid_item_t hitem;
|
||||
bool isfido;
|
||||
struct usb_ctl_report_desc ucrd;
|
||||
uint32_t usage_page = 0;
|
||||
int raw = 1;
|
||||
|
||||
if ((rdesc = hid_get_report_desc(fd)) == NULL) {
|
||||
fido_log_debug("%s: failed to get report descriptor",
|
||||
__func__);
|
||||
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 ((hdata = hid_start_parse(rdesc, 1 << hid_collection, -1))
|
||||
== NULL) {
|
||||
fido_log_debug("%s: failed to parse report descriptor",
|
||||
__func__);
|
||||
hid_dispose_report_desc(rdesc);
|
||||
|
||||
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);
|
||||
}
|
||||
isfido = false;
|
||||
while ((hid_get_item(hdata, &hitem)) > 0) {
|
||||
if (HID_PAGE(hitem.usage) == 0xf1d0) {
|
||||
isfido = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
hid_end_parse(hdata);
|
||||
hid_dispose_report_desc(rdesc);
|
||||
if (!isfido)
|
||||
|
||||
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.
|
||||
* 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, USB_HID_SET_RAW, &raw) == -1) {
|
||||
fido_log_debug("%s: unable to set raw", __func__);
|
||||
if (ioctl(fd, IOCTL_REQ(USB_HID_SET_RAW), &raw) == -1) {
|
||||
fido_log_error(errno, "%s: unable to set raw", __func__);
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
@ -96,17 +89,13 @@ copy_info(fido_dev_info_t *di, const char *path)
|
|||
memset(di, 0, sizeof(*di));
|
||||
memset(&udi, 0, sizeof(udi));
|
||||
|
||||
if ((fd = open(path, O_RDWR)) == -1) {
|
||||
if (errno != EBUSY && errno != ENOENT)
|
||||
fido_log_debug("%s: open %s: %s", __func__, path,
|
||||
strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
if (!is_fido(fd))
|
||||
if ((fd = fido_hid_unix_open(path)) == -1 || is_fido(fd) == 0)
|
||||
goto fail;
|
||||
|
||||
if (ioctl(fd, USB_GET_DEVICEINFO, &udi) == -1)
|
||||
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 ||
|
||||
|
@ -118,8 +107,8 @@ copy_info(fido_dev_info_t *di, const char *path)
|
|||
|
||||
ok = 0;
|
||||
fail:
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
if (fd != -1 && close(fd) == -1)
|
||||
fido_log_error(errno, "%s: close", __func__);
|
||||
|
||||
if (ok < 0) {
|
||||
free(di->path);
|
||||
|
@ -196,7 +185,7 @@ terrible_ping_kludge(struct hid_netbsd *ctx)
|
|||
pfd.fd = ctx->fd;
|
||||
pfd.events = POLLIN;
|
||||
if ((n = poll(&pfd, 1, 100)) == -1) {
|
||||
fido_log_debug("%s: poll: %d", __func__, errno);
|
||||
fido_log_error(errno, "%s: poll", __func__);
|
||||
return -1;
|
||||
} else if (n == 0) {
|
||||
fido_log_debug("%s: timed out", __func__);
|
||||
|
@ -209,8 +198,8 @@ terrible_ping_kludge(struct hid_netbsd *ctx)
|
|||
* so we might get an error, but we don't care - we're
|
||||
* synched now.
|
||||
*/
|
||||
fido_log_debug("%s: got reply", __func__);
|
||||
fido_log_xxd(data, ctx->report_out_len);
|
||||
fido_log_xxd(data, ctx->report_out_len, "%s: got reply",
|
||||
__func__);
|
||||
return 0;
|
||||
}
|
||||
fido_log_debug("%s: no response", __func__);
|
||||
|
@ -221,58 +210,40 @@ void *
|
|||
fido_hid_open(const char *path)
|
||||
{
|
||||
struct hid_netbsd *ctx;
|
||||
report_desc_t rdesc = NULL;
|
||||
hid_data_t hdata;
|
||||
int len, report_id = 0;
|
||||
struct usb_ctl_report_desc ucrd;
|
||||
int r;
|
||||
|
||||
if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
|
||||
goto fail0;
|
||||
if ((ctx->fd = open(path, O_RDWR)) == -1)
|
||||
goto fail1;
|
||||
if (ioctl(ctx->fd, USB_GET_REPORT_ID, &report_id) == -1) {
|
||||
fido_log_debug("%s: failed to get report ID: %s", __func__,
|
||||
strerror(errno));
|
||||
goto fail2;
|
||||
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 ((rdesc = hid_get_report_desc(ctx->fd)) == NULL) {
|
||||
fido_log_debug("%s: failed to get report descriptor",
|
||||
__func__);
|
||||
goto fail2;
|
||||
|
||||
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;
|
||||
}
|
||||
if ((hdata = hid_start_parse(rdesc, 1 << hid_collection, -1))
|
||||
== NULL) {
|
||||
fido_log_debug("%s: failed to parse report descriptor",
|
||||
__func__);
|
||||
goto fail3;
|
||||
}
|
||||
if ((len = hid_report_size(rdesc, hid_input, report_id)) <= 0 ||
|
||||
(size_t)len > CTAP_MAX_REPORT_LEN) {
|
||||
fido_log_debug("%s: bad input report size %d", __func__, len);
|
||||
goto fail3;
|
||||
}
|
||||
ctx->report_in_len = (size_t)len;
|
||||
if ((len = hid_report_size(rdesc, hid_output, report_id)) <= 0 ||
|
||||
(size_t)len > CTAP_MAX_REPORT_LEN) {
|
||||
fido_log_debug("%s: bad output report size %d", __func__, len);
|
||||
goto fail3;
|
||||
}
|
||||
ctx->report_out_len = (size_t)len;
|
||||
hid_dispose_report_desc(rdesc);
|
||||
|
||||
/*
|
||||
* 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)
|
||||
goto fail2;
|
||||
if (!is_fido(ctx->fd) || terrible_ping_kludge(ctx) != 0) {
|
||||
fido_hid_close(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (ctx);
|
||||
|
||||
fail3: hid_dispose_report_desc(rdesc);
|
||||
fail2: close(ctx->fd);
|
||||
fail1: free(ctx);
|
||||
fail0: return (NULL);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -280,86 +251,21 @@ fido_hid_close(void *handle)
|
|||
{
|
||||
struct hid_netbsd *ctx = handle;
|
||||
|
||||
close(ctx->fd);
|
||||
if (close(ctx->fd) == -1)
|
||||
fido_log_error(errno, "%s: close", __func__);
|
||||
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
xstrerror(int errnum, char *buf, size_t len)
|
||||
int
|
||||
fido_hid_set_sigmask(void *handle, const fido_sigset_t *sigmask)
|
||||
{
|
||||
if (len < 1)
|
||||
return;
|
||||
struct hid_netbsd *ctx = handle;
|
||||
|
||||
memset(buf, 0, len);
|
||||
ctx->sigmask = *sigmask;
|
||||
ctx->sigmaskp = &ctx->sigmask;
|
||||
|
||||
if (strerror_r(errnum, buf, len - 1) != 0)
|
||||
snprintf(buf, len - 1, "error %d", errnum);
|
||||
}
|
||||
|
||||
static int
|
||||
timespec_to_ms(const struct timespec *ts, int upper_bound)
|
||||
{
|
||||
int64_t x;
|
||||
int64_t y;
|
||||
|
||||
if (ts->tv_sec < 0 || (uint64_t)ts->tv_sec > INT64_MAX / 1000LL ||
|
||||
ts->tv_nsec < 0 || (uint64_t)ts->tv_nsec / 1000000LL > INT64_MAX)
|
||||
return (upper_bound);
|
||||
|
||||
x = ts->tv_sec * 1000LL;
|
||||
y = ts->tv_nsec / 1000000LL;
|
||||
|
||||
if (INT64_MAX - x < y || x + y > upper_bound)
|
||||
return (upper_bound);
|
||||
|
||||
return (int)(x + y);
|
||||
}
|
||||
|
||||
static int
|
||||
fido_hid_unix_wait(int fd, int ms)
|
||||
{
|
||||
char ebuf[128];
|
||||
struct timespec ts_start;
|
||||
struct timespec ts_now;
|
||||
struct timespec ts_delta;
|
||||
struct pollfd pfd;
|
||||
int ms_remain;
|
||||
int r;
|
||||
|
||||
if (ms < 0)
|
||||
return (0);
|
||||
|
||||
memset(&pfd, 0, sizeof(pfd));
|
||||
pfd.events = POLLIN;
|
||||
pfd.fd = fd;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts_start) != 0) {
|
||||
xstrerror(errno, ebuf, sizeof(ebuf));
|
||||
fido_log_debug("%s: clock_gettime: %s", __func__, ebuf);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
for (ms_remain = ms; ms_remain > 0;) {
|
||||
if ((r = poll(&pfd, 1, ms_remain)) > 0)
|
||||
return (0);
|
||||
else if (r == 0)
|
||||
break;
|
||||
else if (errno != EINTR) {
|
||||
xstrerror(errno, ebuf, sizeof(ebuf));
|
||||
fido_log_debug("%s: poll: %s", __func__, ebuf);
|
||||
return (-1);
|
||||
}
|
||||
/* poll interrupted - subtract time already waited */
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts_now) != 0) {
|
||||
xstrerror(errno, ebuf, sizeof(ebuf));
|
||||
fido_log_debug("%s: clock_gettime: %s", __func__, ebuf);
|
||||
return (-1);
|
||||
}
|
||||
timespecsub(&ts_now, &ts_start, &ts_delta);
|
||||
ms_remain = ms - timespec_to_ms(&ts_delta, ms);
|
||||
}
|
||||
|
||||
return (-1);
|
||||
return (FIDO_OK);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -373,13 +279,18 @@ fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
|
|||
return (-1);
|
||||
}
|
||||
|
||||
if (fido_hid_unix_wait(ctx->fd, ms) < 0) {
|
||||
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 || (size_t)r != len) {
|
||||
fido_log_debug("%s: read", __func__);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -397,9 +308,13 @@ fido_hid_write(void *handle, const unsigned char *buf, size_t len)
|
|||
return (-1);
|
||||
}
|
||||
|
||||
if ((r = write(ctx->fd, buf + 1, len - 1)) == -1 ||
|
||||
(size_t)r != len - 1) {
|
||||
fido_log_debug("%s: write", __func__);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "fido.h"
|
||||
|
||||
|
@ -42,22 +42,18 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
|
|||
|
||||
for (i = *olen = 0; i < MAX_UHID && *olen < ilen; i++) {
|
||||
snprintf(path, sizeof(path), "/dev/fido/%zu", i);
|
||||
if ((fd = open(path, O_RDWR)) == -1) {
|
||||
if (errno != ENOENT && errno != ENXIO) {
|
||||
fido_log_debug("%s: open %s: %s", __func__,
|
||||
path, strerror(errno));
|
||||
}
|
||||
if ((fd = fido_hid_unix_open(path)) == -1)
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(&udi, 0, sizeof(udi));
|
||||
if (ioctl(fd, USB_GET_DEVICEINFO, &udi) != 0) {
|
||||
fido_log_debug("%s: get device info %s: %s", __func__,
|
||||
path, strerror(errno));
|
||||
close(fd);
|
||||
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;
|
||||
}
|
||||
close(fd);
|
||||
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);
|
||||
|
@ -127,7 +123,7 @@ terrible_ping_kludge(struct hid_openbsd *ctx)
|
|||
pfd.fd = ctx->fd;
|
||||
pfd.events = POLLIN;
|
||||
if ((n = poll(&pfd, 1, 100)) == -1) {
|
||||
fido_log_debug("%s: poll: %s", __func__, strerror(errno));
|
||||
fido_log_error(errno, "%s: poll", __func__);
|
||||
return -1;
|
||||
} else if (n == 0) {
|
||||
fido_log_debug("%s: timed out", __func__);
|
||||
|
@ -140,8 +136,8 @@ terrible_ping_kludge(struct hid_openbsd *ctx)
|
|||
* so we might get an error, but we don't care - we're
|
||||
* synched now.
|
||||
*/
|
||||
fido_log_debug("%s: got reply", __func__);
|
||||
fido_log_xxd(data, ctx->report_out_len);
|
||||
fido_log_xxd(data, ctx->report_out_len, "%s: got reply",
|
||||
__func__);
|
||||
return 0;
|
||||
}
|
||||
fido_log_debug("%s: no response", __func__);
|
||||
|
@ -154,7 +150,7 @@ fido_hid_open(const char *path)
|
|||
struct hid_openbsd *ret = NULL;
|
||||
|
||||
if ((ret = calloc(1, sizeof(*ret))) == NULL ||
|
||||
(ret->fd = open(path, O_RDWR)) < 0) {
|
||||
(ret->fd = fido_hid_unix_open(path)) == -1) {
|
||||
free(ret);
|
||||
return (NULL);
|
||||
}
|
||||
|
@ -180,10 +176,21 @@ fido_hid_close(void *handle)
|
|||
{
|
||||
struct hid_openbsd *ctx = (struct hid_openbsd *)handle;
|
||||
|
||||
close(ctx->fd);
|
||||
if (close(ctx->fd) == -1)
|
||||
fido_log_error(errno, "%s: close", __func__);
|
||||
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int
|
||||
fido_hid_set_sigmask(void *handle, const fido_sigset_t *sigmask)
|
||||
{
|
||||
(void)handle;
|
||||
(void)sigmask;
|
||||
|
||||
return (FIDO_ERR_INTERNAL);
|
||||
}
|
||||
|
||||
int
|
||||
fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
|
||||
{
|
||||
|
@ -197,10 +204,17 @@ fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
|
|||
len, ctx->report_in_len);
|
||||
return (-1);
|
||||
}
|
||||
if ((r = read(ctx->fd, buf, len)) == -1 || (size_t)r != len) {
|
||||
fido_log_debug("%s: read: %s", __func__, strerror(errno));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -215,11 +229,17 @@ fido_hid_write(void *handle, const unsigned char *buf, size_t len)
|
|||
len, ctx->report_out_len);
|
||||
return (-1);
|
||||
}
|
||||
if ((r = write(ctx->fd, buf + 1, len - 1)) == -1 ||
|
||||
(size_t)r != len - 1) {
|
||||
fido_log_debug("%s: write: %s", __func__, strerror(errno));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue