Add files via upload

This commit is contained in:
Token2
2024-05-24 11:40:07 +02:00
committed by GitHub
commit df1b66988f
9 changed files with 1482 additions and 0 deletions

498
CMakeLists.txt Normal file
View File

@@ -0,0 +1,498 @@
# Copyright (c) 2018-2022 Yubico AB. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# SPDX-License-Identifier: BSD-2-Clause
cmake_minimum_required(VERSION 3.7)
# detect AppleClang; needs to come before project()
cmake_policy(SET CMP0025 NEW)
project(libfido2 C)
# Set PIE flags for POSITION_INDEPENDENT_CODE targets, added in CMake 3.14.
if(POLICY CMP0083)
cmake_policy(SET CMP0083 NEW)
endif()
include(CheckCCompilerFlag)
include(CheckFunctionExists)
include(CheckLibraryExists)
include(CheckSymbolExists)
include(CheckIncludeFiles)
include(CheckTypeSize)
include(GNUInstallDirs)
include(CheckPIESupported OPTIONAL RESULT_VARIABLE CHECK_PIE_SUPPORTED)
if(CHECK_PIE_SUPPORTED)
check_pie_supported(LANGUAGES C)
endif()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_COLOR_MAKEFILE OFF)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(FIDO_MAJOR "1")
set(FIDO_MINOR "15")
set(FIDO_PATCH "0")
set(FIDO_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}.${FIDO_PATCH})
option(BUILD_TESTS "Build the regress tests" ON)
option(BUILD_EXAMPLES "Build example programs" ON)
option(BUILD_MANPAGES "Build man pages" ON)
option(BUILD_SHARED_LIBS "Build a shared library" ON)
option(BUILD_STATIC_LIBS "Build a static library" ON)
option(BUILD_TOOLS "Build tool programs" ON)
option(FUZZ "Enable fuzzing instrumentation" OFF)
option(USE_HIDAPI "Use hidapi as the HID backend" OFF)
option(USE_PCSC "Enable experimental PCSC support" ON)
option(USE_WINHELLO "Abstract Windows Hello as a FIDO device" ON)
option(NFC_LINUX "Enable NFC support on Linux" ON)
add_definitions(-D_FIDO_MAJOR=${FIDO_MAJOR})
add_definitions(-D_FIDO_MINOR=${FIDO_MINOR})
add_definitions(-D_FIDO_PATCH=${FIDO_PATCH})
if(BUILD_SHARED_LIBS)
set(_FIDO2_LIBRARY fido2_shared)
elseif(BUILD_STATIC_LIBS)
set(_FIDO2_LIBRARY fido2)
else()
message(FATAL_ERROR "Nothing to build (BUILD_*_LIBS=OFF)")
endif()
if(CYGWIN OR MSYS OR MINGW)
set(WIN32 1)
endif()
if(WIN32)
add_definitions(-DWIN32_LEAN_AND_MEAN -D_WIN32_WINNT=0x0600)
endif()
if(APPLE)
set(CMAKE_INSTALL_NAME_DIR
"${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
endif()
if(NOT MSVC)
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_POSIX_C_SOURCE=200809L")
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_BSD_SOURCE")
if(APPLE)
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_DARWIN_C_SOURCE")
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D__STDC_WANT_LIB_EXT1__=1")
elseif((CMAKE_SYSTEM_NAME STREQUAL "Linux") OR MINGW OR CYGWIN)
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_GNU_SOURCE")
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_DEFAULT_SOURCE")
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD")
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D__BSD_VISIBLE=1")
elseif(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_NETBSD_SOURCE")
endif()
set(FIDO_CFLAGS "${FIDO_CFLAGS} -std=c99")
set(CMAKE_C_FLAGS "${FIDO_CFLAGS} ${CMAKE_C_FLAGS}")
endif()
check_c_compiler_flag("-Wshorten-64-to-32" HAVE_SHORTEN_64_TO_32)
check_c_compiler_flag("-Werror -fstack-protector-all" HAVE_STACK_PROTECTOR_ALL)
check_include_files(cbor.h HAVE_CBOR_H)
check_include_files(endian.h HAVE_ENDIAN_H)
check_include_files(err.h HAVE_ERR_H)
check_include_files(openssl/opensslv.h HAVE_OPENSSLV_H)
check_include_files(signal.h HAVE_SIGNAL_H)
check_include_files(sys/random.h HAVE_SYS_RANDOM_H)
check_include_files(unistd.h HAVE_UNISTD_H)
check_symbol_exists(arc4random_buf stdlib.h HAVE_ARC4RANDOM_BUF)
check_symbol_exists(asprintf stdio.h HAVE_ASPRINTF)
check_symbol_exists(clock_gettime time.h HAVE_CLOCK_GETTIME)
check_symbol_exists(explicit_bzero string.h HAVE_EXPLICIT_BZERO)
check_symbol_exists(freezero stdlib.h HAVE_FREEZERO)
check_symbol_exists(getline stdio.h HAVE_GETLINE)
check_symbol_exists(getopt unistd.h HAVE_GETOPT)
check_symbol_exists(getpagesize unistd.h HAVE_GETPAGESIZE)
check_symbol_exists(getrandom sys/random.h HAVE_GETRANDOM)
check_symbol_exists(memset_s string.h HAVE_MEMSET_S)
check_symbol_exists(readpassphrase readpassphrase.h HAVE_READPASSPHRASE)
check_symbol_exists(recallocarray stdlib.h HAVE_RECALLOCARRAY)
check_symbol_exists(strlcat string.h HAVE_STRLCAT)
check_symbol_exists(strlcpy string.h HAVE_STRLCPY)
check_symbol_exists(strsep string.h HAVE_STRSEP)
check_symbol_exists(sysconf unistd.h HAVE_SYSCONF)
check_symbol_exists(timespecsub sys/time.h HAVE_TIMESPECSUB)
check_symbol_exists(timingsafe_bcmp string.h HAVE_TIMINGSAFE_BCMP)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
try_compile(HAVE_POSIX_IOCTL
"${CMAKE_CURRENT_BINARY_DIR}/posix_ioctl_check.o"
"${CMAKE_CURRENT_SOURCE_DIR}/openbsd-compat/posix_ioctl_check.c"
COMPILE_DEFINITIONS "-Werror -Woverflow -Wsign-conversion")
list(APPEND CHECK_VARIABLES
HAVE_ARC4RANDOM_BUF
HAVE_ASPRINTF
HAVE_CBOR_H
HAVE_CLOCK_GETTIME
HAVE_ENDIAN_H
HAVE_ERR_H
HAVE_FREEZERO
HAVE_GETLINE
HAVE_GETOPT
HAVE_GETPAGESIZE
HAVE_GETRANDOM
HAVE_MEMSET_S
HAVE_OPENSSLV_H
HAVE_POSIX_IOCTL
HAVE_READPASSPHRASE
HAVE_RECALLOCARRAY
HAVE_SIGNAL_H
HAVE_STRLCAT
HAVE_STRLCPY
HAVE_STRSEP
HAVE_SYSCONF
HAVE_SYS_RANDOM_H
HAVE_TIMESPECSUB
HAVE_TIMINGSAFE_BCMP
HAVE_UNISTD_H
)
foreach(v ${CHECK_VARIABLES})
if (${v})
add_definitions(-D${v})
endif()
endforeach()
if(HAVE_EXPLICIT_BZERO AND NOT FUZZ)
add_definitions(-DHAVE_EXPLICIT_BZERO)
endif()
if(UNIX)
add_definitions(-DHAVE_DEV_URANDOM)
endif()
if(MSVC)
if((NOT CBOR_INCLUDE_DIRS) OR (NOT CBOR_LIBRARY_DIRS) OR
(NOT CRYPTO_INCLUDE_DIRS) OR (NOT CRYPTO_LIBRARY_DIRS) OR
(NOT ZLIB_INCLUDE_DIRS) OR (NOT ZLIB_LIBRARY_DIRS))
message(FATAL_ERROR "please define "
"{CBOR,CRYPTO,ZLIB}_{INCLUDE,LIBRARY}_DIRS when "
"building under msvc")
endif()
if(BUILD_TESTS AND BUILD_SHARED_LIBS AND
((NOT CBOR_BIN_DIRS) OR (NOT ZLIB_BIN_DIRS) OR (NOT CRYPTO_BIN_DIRS)))
message(FATAL_ERROR "please define {CBOR,CRYPTO,ZLIB}_BIN_DIRS "
"when building tests")
endif()
if(NOT CBOR_LIBRARIES)
set(CBOR_LIBRARIES cbor)
endif()
if(NOT ZLIB_LIBRARIES)
set(ZLIB_LIBRARIES zlib1)
endif()
if(NOT CRYPTO_LIBRARIES)
set(CRYPTO_LIBRARIES crypto)
endif()
set(MSVC_DISABLED_WARNINGS_LIST
"C4152" # nonstandard extension used: function/data pointer
# conversion in expression;
"C4200" # nonstandard extension used: zero-sized array in
# struct/union;
"C4201" # nonstandard extension used: nameless struct/union;
"C4204" # nonstandard extension used: non-constant aggregate
# initializer;
"C4706" # assignment within conditional expression;
"C4996" # The POSIX name for this item is deprecated. Instead,
# use the ISO C and C++ conformant name;
"C6287" # redundant code: the left and right subexpressions are identical
)
# The construction in the following 3 lines was taken from LibreSSL's
# CMakeLists.txt.
string(REPLACE "C" " -wd" MSVC_DISABLED_WARNINGS_STR
${MSVC_DISABLED_WARNINGS_LIST})
string(REGEX REPLACE "[/-]W[1234][ ]?" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MP -W4 -WX ${MSVC_DISABLED_WARNINGS_STR}")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Od /Z7 /guard:cf /sdl /RTCcsu")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi /guard:cf /sdl")
if(USE_WINHELLO)
add_definitions(-DUSE_WINHELLO)
endif()
set(NFC_LINUX OFF)
else()
include(FindPkgConfig)
pkg_search_module(CBOR libcbor)
pkg_search_module(CRYPTO libcrypto)
pkg_search_module(ZLIB zlib)
if(NOT CBOR_FOUND AND NOT HAVE_CBOR_H)
message(FATAL_ERROR "could not find libcbor")
endif()
if(NOT CRYPTO_FOUND AND NOT HAVE_OPENSSLV_H)
message(FATAL_ERROR "could not find libcrypto")
endif()
if(NOT ZLIB_FOUND)
message(FATAL_ERROR "could not find zlib")
endif()
if(NOT CBOR_LIBRARIES)
set(CBOR_LIBRARIES "cbor")
endif()
if(NOT CRYPTO_LIBRARIES)
set(CRYPTO_LIBRARIES "crypto")
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
pkg_search_module(UDEV libudev REQUIRED)
set(UDEV_NAME "udev")
# If using hidapi, use hidapi-hidraw.
set(HIDAPI_SUFFIX -hidraw)
if(NOT HAVE_CLOCK_GETTIME)
# Look for clock_gettime in librt.
check_library_exists(rt clock_gettime "time.h"
HAVE_CLOCK_GETTIME)
if (HAVE_CLOCK_GETTIME)
add_definitions(-DHAVE_CLOCK_GETTIME)
set(BASE_LIBRARIES ${BASE_LIBRARIES} rt)
endif()
endif()
else()
set(NFC_LINUX OFF)
endif()
if(MINGW)
# MinGW is stuck with a flavour of C89.
add_definitions(-DFIDO_NO_DIAGNOSTIC)
add_definitions(-DWC_ERR_INVALID_CHARS=0x80)
add_compile_options(-Wno-unused-parameter)
endif()
if(FUZZ)
set(USE_PCSC ON)
add_definitions(-DFIDO_FUZZ)
endif()
# If building with PCSC, look for pcsc-lite.
if(USE_PCSC AND NOT (APPLE OR CYGWIN OR MSYS OR MINGW))
pkg_search_module(PCSC libpcsclite REQUIRED)
set(PCSC_LIBRARIES pcsclite)
endif()
if(USE_HIDAPI)
add_definitions(-DUSE_HIDAPI)
pkg_search_module(HIDAPI hidapi${HIDAPI_SUFFIX} REQUIRED)
set(HIDAPI_LIBRARIES hidapi${HIDAPI_SUFFIX})
endif()
if(NFC_LINUX)
add_definitions(-DUSE_NFC)
endif()
if(WIN32)
if(USE_WINHELLO)
add_definitions(-DUSE_WINHELLO)
endif()
else()
set(USE_WINHELLO OFF)
endif()
add_compile_options(-Wall)
add_compile_options(-Wextra)
add_compile_options(-Werror)
add_compile_options(-Wshadow)
add_compile_options(-Wcast-qual)
add_compile_options(-Wwrite-strings)
add_compile_options(-Wmissing-prototypes)
add_compile_options(-Wbad-function-cast)
add_compile_options(-Wimplicit-fallthrough)
add_compile_options(-pedantic)
add_compile_options(-pedantic-errors)
set(EXTRA_CFLAGS "-Wconversion -Wsign-conversion")
if(WIN32)
add_compile_options(-Wno-type-limits)
add_compile_options(-Wno-cast-function-type)
endif()
if(HAVE_SHORTEN_64_TO_32)
add_compile_options(-Wshorten-64-to-32)
endif()
if(HAVE_STACK_PROTECTOR_ALL)
add_compile_options(-fstack-protector-all)
endif()
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g2")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -D_FORTIFY_SOURCE=2")
if(CRYPTO_VERSION VERSION_GREATER_EQUAL 3.0)
add_definitions(-DOPENSSL_API_COMPAT=0x10100000L)
endif()
if(NOT FUZZ)
set(EXTRA_CFLAGS "${EXTRA_CFLAGS} -Wframe-larger-than=2047")
endif()
endif()
# Avoid https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425
if(CMAKE_COMPILER_IS_GNUCC)
add_compile_options(-Wno-unused-result)
endif()
# Decide which keyword to use for thread-local storage.
if(CMAKE_COMPILER_IS_GNUCC OR
CMAKE_C_COMPILER_ID STREQUAL "Clang" OR
CMAKE_C_COMPILER_ID STREQUAL "AppleClang")
set(TLS "__thread")
elseif(WIN32)
set(TLS "__declspec(thread)")
endif()
add_definitions(-DTLS=${TLS})
if(USE_PCSC)
add_definitions(-DUSE_PCSC)
endif()
# export list
if(APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR
CMAKE_C_COMPILER_ID STREQUAL "AppleClang"))
# clang + lld
string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}
" -exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/src/export.llvm")
elseif(NOT MSVC)
# clang/gcc + gnu ld
if(FUZZ)
string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}
" -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/fuzz/export.gnu")
else()
string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}
" -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/export.gnu")
endif()
if(NOT WIN32)
string(CONCAT CMAKE_SHARED_LINKER_FLAGS
${CMAKE_SHARED_LINKER_FLAGS}
" -Wl,-z,noexecstack -Wl,-z,relro,-z,now")
string(CONCAT CMAKE_EXE_LINKER_FLAGS
${CMAKE_EXE_LINKER_FLAGS}
" -Wl,-z,noexecstack -Wl,-z,relro,-z,now")
if(FUZZ)
file(STRINGS fuzz/wrapped.sym WRAPPED_SYMBOLS)
foreach(s ${WRAPPED_SYMBOLS})
string(CONCAT CMAKE_SHARED_LINKER_FLAGS
${CMAKE_SHARED_LINKER_FLAGS}
" -Wl,--wrap=${s}")
endforeach()
endif()
endif()
else()
string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}
" /def:\"${CMAKE_CURRENT_SOURCE_DIR}/src/export.msvc\"")
endif()
include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${CBOR_INCLUDE_DIRS})
include_directories(${CRYPTO_INCLUDE_DIRS})
include_directories(${HIDAPI_INCLUDE_DIRS})
include_directories(${PCSC_INCLUDE_DIRS})
include_directories(${UDEV_INCLUDE_DIRS})
include_directories(${ZLIB_INCLUDE_DIRS})
link_directories(${CBOR_LIBRARY_DIRS})
link_directories(${CRYPTO_LIBRARY_DIRS})
link_directories(${HIDAPI_LIBRARY_DIRS})
link_directories(${PCSC_LIBRARY_DIRS})
link_directories(${UDEV_LIBRARY_DIRS})
link_directories(${ZLIB_LIBRARY_DIRS})
message(STATUS "BASE_LIBRARIES: ${BASE_LIBRARIES}")
message(STATUS "BUILD_EXAMPLES: ${BUILD_EXAMPLES}")
message(STATUS "BUILD_MANPAGES: ${BUILD_MANPAGES}")
message(STATUS "BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}")
message(STATUS "BUILD_STATIC_LIBS: ${BUILD_STATIC_LIBS}")
message(STATUS "BUILD_TOOLS: ${BUILD_TOOLS}")
message(STATUS "CBOR_INCLUDE_DIRS: ${CBOR_INCLUDE_DIRS}")
message(STATUS "CBOR_LIBRARIES: ${CBOR_LIBRARIES}")
message(STATUS "CBOR_LIBRARY_DIRS: ${CBOR_LIBRARY_DIRS}")
if(BUILD_TESTS)
message(STATUS "CBOR_BIN_DIRS: ${CBOR_BIN_DIRS}")
endif()
message(STATUS "CBOR_VERSION: ${CBOR_VERSION}")
message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}")
message(STATUS "CMAKE_C_COMPILER_ID: ${CMAKE_C_COMPILER_ID}")
message(STATUS "CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}")
message(STATUS "CMAKE_CROSSCOMPILING: ${CMAKE_CROSSCOMPILING}")
message(STATUS "CMAKE_GENERATOR_PLATFORM: ${CMAKE_GENERATOR_PLATFORM}")
message(STATUS "CMAKE_HOST_SYSTEM_NAME: ${CMAKE_HOST_SYSTEM_NAME}")
message(STATUS "CMAKE_HOST_SYSTEM_PROCESSOR: ${CMAKE_HOST_SYSTEM_PROCESSOR}")
message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}")
message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
message(STATUS "CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
message(STATUS "CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}")
message(STATUS "CMAKE_SYSTEM_VERSION: ${CMAKE_SYSTEM_VERSION}")
message(STATUS "CRYPTO_INCLUDE_DIRS: ${CRYPTO_INCLUDE_DIRS}")
message(STATUS "CRYPTO_LIBRARIES: ${CRYPTO_LIBRARIES}")
message(STATUS "CRYPTO_LIBRARY_DIRS: ${CRYPTO_LIBRARY_DIRS}")
if(BUILD_TESTS)
message(STATUS "CRYPTO_BIN_DIRS: ${CRYPTO_BIN_DIRS}")
endif()
message(STATUS "CRYPTO_VERSION: ${CRYPTO_VERSION}")
message(STATUS "FIDO_VERSION: ${FIDO_VERSION}")
message(STATUS "FUZZ: ${FUZZ}")
if(FUZZ)
message(STATUS "FUZZ_LDFLAGS: ${FUZZ_LDFLAGS}")
endif()
message(STATUS "ZLIB_INCLUDE_DIRS: ${ZLIB_INCLUDE_DIRS}")
message(STATUS "ZLIB_LIBRARIES: ${ZLIB_LIBRARIES}")
message(STATUS "ZLIB_LIBRARY_DIRS: ${ZLIB_LIBRARY_DIRS}")
if(BUILD_TESTS)
message(STATUS "ZLIB_BIN_DIRS: ${ZLIB_BIN_DIRS}")
endif()
message(STATUS "ZLIB_VERSION: ${ZLIB_VERSION}")
if(USE_HIDAPI)
message(STATUS "HIDAPI_INCLUDE_DIRS: ${HIDAPI_INCLUDE_DIRS}")
message(STATUS "HIDAPI_LIBRARIES: ${HIDAPI_LIBRARIES}")
message(STATUS "HIDAPI_LIBRARY_DIRS: ${HIDAPI_LIBRARY_DIRS}")
message(STATUS "HIDAPI_VERSION: ${HIDAPI_VERSION}")
endif()
message(STATUS "PCSC_INCLUDE_DIRS: ${PCSC_INCLUDE_DIRS}")
message(STATUS "PCSC_LIBRARIES: ${PCSC_LIBRARIES}")
message(STATUS "PCSC_LIBRARY_DIRS: ${PCSC_LIBRARY_DIRS}")
message(STATUS "PCSC_VERSION: ${PCSC_VERSION}")
message(STATUS "TLS: ${TLS}")
message(STATUS "UDEV_INCLUDE_DIRS: ${UDEV_INCLUDE_DIRS}")
message(STATUS "UDEV_LIBRARIES: ${UDEV_LIBRARIES}")
message(STATUS "UDEV_LIBRARY_DIRS: ${UDEV_LIBRARY_DIRS}")
message(STATUS "UDEV_RULES_DIR: ${UDEV_RULES_DIR}")
message(STATUS "UDEV_VERSION: ${UDEV_VERSION}")
message(STATUS "USE_HIDAPI: ${USE_HIDAPI}")
message(STATUS "USE_PCSC: ${USE_PCSC}")
message(STATUS "USE_WINHELLO: ${USE_WINHELLO}")
message(STATUS "NFC_LINUX: ${NFC_LINUX}")
if(BUILD_TESTS)
enable_testing()
endif()
add_subdirectory(src)
if(BUILD_TESTS)
add_subdirectory(regress)
endif()
if(BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
if(BUILD_TOOLS)
add_subdirectory(tools)
endif()
if(BUILD_MANPAGES AND NOT MSVC)
add_subdirectory(man)
endif()
if(NOT WIN32)
if(FUZZ)
add_subdirectory(fuzz)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_subdirectory(udev)
endif()
endif()

26
LICENSE Normal file
View File

@@ -0,0 +1,26 @@
Copyright (c) 2018-2024 Yubico AB. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
SPDX-License-Identifier: BSD-2-Clause

269
NEWS Normal file
View File

@@ -0,0 +1,269 @@
* Version 1.15.0 (unreleased)
** 1.15.0 will be the last release to support OpenSSL 1.1.
* Version 1.14.0 (2023-11-13)
** fido2-cred -M, fido2-token -G: support raw client data via -w flag.
** winhello: support U2F AppID extension for assertions.
** winhello: fix restrictive parsing of the hmac-secret on assertions.
** winhello: translate NTE_USER_CANCELLED to FIDO_ERR_OPERATION_DENIED; gh#685.
** New API calls:
- fido_assert_authdata_raw_len;
- fido_assert_authdata_raw_ptr;
- fido_assert_set_winhello_appid.
* Version 1.13.0 (2023-02-20)
** Support for linking against OpenSSL on Windows; gh#668.
** New API calls:
- fido_assert_empty_allow_list;
- fido_cred_empty_exclude_list.
** fido2-token: fix issue when listing large blobs.
** Improved support for different fuzzing engines.
* Version 1.12.0 (2022-09-22)
** Support for COSE_ES384.
** Support for hidraw(4) on FreeBSD; gh#597.
** Improved support for FIDO 2.1 authenticators.
** New API calls:
- es384_pk_free;
- es384_pk_from_EC_KEY;
- es384_pk_from_EVP_PKEY;
- es384_pk_from_ptr;
- es384_pk_new;
- es384_pk_to_EVP_PKEY;
- fido_cbor_info_certs_len;
- fido_cbor_info_certs_name_ptr;
- fido_cbor_info_certs_value_ptr;
- fido_cbor_info_maxrpid_minpinlen;
- fido_cbor_info_minpinlen;
- fido_cbor_info_new_pin_required;
- fido_cbor_info_rk_remaining;
- fido_cbor_info_uv_attempts;
- fido_cbor_info_uv_modality.
** Documentation and reliability fixes.
* Version 1.11.0 (2022-05-03)
** Experimental PCSC support; enable with -DUSE_PCSC.
** Improved OpenSSL 3.0 compatibility.
** Use RFC1951 raw deflate to compress CTAP 2.1 largeBlobs.
** winhello: advertise "uv" instead of "clientPin".
** winhello: support hmac-secret in fido_dev_get_assert().
** New API calls:
- fido_cbor_info_maxlargeblob.
** Documentation and reliability fixes.
** Separate build and regress targets.
* Version 1.10.0 (2022-01-17)
** hid_osx: handle devices with paths > 511 bytes; gh#462.
** bio: fix CTAP2 canonical CBOR encoding in fido_bio_dev_enroll_*(); gh#480.
** winhello: fallback to GetTopWindow() if GetForegroundWindow() fails.
** winhello: fallback to hid_win.c if webauthn.dll isn't available.
** New API calls:
- fido_dev_info_set;
- fido_dev_io_handle;
- fido_dev_new_with_info;
- fido_dev_open_with_info.
** Cygwin and NetBSD build fixes.
** Documentation and reliability fixes.
** Support for TPM 2.0 attestation of COSE_ES256 credentials.
* Version 1.9.0 (2021-10-27)
** Enabled NFC support on Linux.
** Added OpenSSL 3.0 compatibility.
** Removed OpenSSL 1.0 compatibility.
** Support for FIDO 2.1 "minPinLength" extension.
** Support for COSE_EDDSA, COSE_ES256, and COSE_RS1 attestation.
** Support for TPM 2.0 attestation.
** Support for device timeouts; see fido_dev_set_timeout().
** New API calls:
- es256_pk_from_EVP_PKEY;
- fido_cred_attstmt_len;
- fido_cred_attstmt_ptr;
- fido_cred_pin_minlen;
- fido_cred_set_attstmt;
- fido_cred_set_pin_minlen;
- fido_dev_set_pin_minlen_rpid;
- fido_dev_set_timeout;
- rs256_pk_from_EVP_PKEY.
** Reliability and portability fixes.
** Better handling of HID devices without identification strings; gh#381.
** Fixed detection of Windows's native webauthn API; gh#382.
* Version 1.8.0 (2021-07-22)
** Dropped 'Requires.private' entry from pkg-config file.
** Better support for FIDO 2.1 authenticators.
** Support for Windows's native webauthn API.
** Support for attestation format 'none'.
** New API calls:
- fido_assert_set_clientdata;
- fido_cbor_info_algorithm_cose;
- fido_cbor_info_algorithm_count;
- fido_cbor_info_algorithm_type;
- fido_cbor_info_transports_len;
- fido_cbor_info_transports_ptr;
- fido_cred_set_clientdata;
- fido_cred_set_id;
- fido_credman_set_dev_rk;
- fido_dev_is_winhello.
** fido2-token: new -Sc option to update a resident credential.
** Documentation and reliability fixes.
** HID access serialisation on Linux.
* Version 1.7.0 (2021-03-29)
** New dependency on zlib.
** Fixed musl build; gh#259.
** hid_win: detect devices with vendor or product IDs > 0x7fff; gh#264.
** Support for FIDO 2.1 authenticator configuration.
** Support for FIDO 2.1 UV token permissions.
** Support for FIDO 2.1 "credBlobs" and "largeBlobs" extensions.
** New API calls:
- fido_assert_blob_len;
- fido_assert_blob_ptr;
- fido_assert_largeblob_key_len;
- fido_assert_largeblob_key_ptr;
- fido_assert_set_hmac_secret;
- fido_cbor_info_maxcredbloblen;
- fido_cred_largeblob_key_len;
- fido_cred_largeblob_key_ptr;
- fido_cred_set_blob;
- fido_dev_enable_entattest;
- fido_dev_force_pin_change;
- fido_dev_has_uv;
- fido_dev_largeblob_get;
- fido_dev_largeblob_get_array;
- fido_dev_largeblob_remove;
- fido_dev_largeblob_set;
- fido_dev_largeblob_set_array;
- fido_dev_set_pin_minlen;
- fido_dev_set_sigmask;
- fido_dev_supports_credman;
- fido_dev_supports_permissions;
- fido_dev_supports_uv;
- fido_dev_toggle_always_uv.
** New fido_init flag to disable fido_dev_open's U2F fallback; gh#282.
** Experimental NFC support on Linux; enable with -DNFC_LINUX.
* Version 1.6.0 (2020-12-22)
** Fix OpenSSL 1.0 and Cygwin builds.
** hid_linux: fix build on 32-bit systems.
** hid_osx: allow reads from spawned threads.
** Documentation and reliability fixes.
** New API calls:
- fido_cred_authdata_raw_len;
- fido_cred_authdata_raw_ptr;
- fido_cred_sigcount;
- fido_dev_get_uv_retry_count;
- fido_dev_supports_credman.
** Hardened Windows build.
** Native FreeBSD and NetBSD support.
** Use CTAP2 canonical CBOR when combining hmac-secret and credProtect.
* Version 1.5.0 (2020-09-01)
** hid_linux: return FIDO_OK if no devices are found.
** hid_osx:
- repair communication with U2F tokens, gh#166;
- reliability fixes.
** fido2-{assert,cred}: new options to explicitly toggle UP, UV.
** Support for configurable report lengths.
** New API calls:
- fido_cbor_info_maxcredcntlst;
- fido_cbor_info_maxcredidlen;
- fido_cred_aaguid_len;
- fido_cred_aaguid_ptr;
- fido_dev_get_touch_begin;
- fido_dev_get_touch_status.
** Use COSE_ECDH_ES256 with CTAP_CBOR_CLIENT_PIN; gh#154.
** Allow CTAP messages up to 2048 bytes; gh#171.
** Ensure we only list USB devices by default.
* Version 1.4.0 (2020-04-15)
** hid_hidapi: hidapi backend; enable with -DUSE_HIDAPI=1.
** Fall back to U2F if the key claims to, but does not support FIDO2.
** FIDO2 credential protection (credprot) support.
** New API calls:
- fido_cbor_info_fwversion;
- fido_cred_prot;
- fido_cred_set_prot;
- fido_dev_set_transport_functions;
- fido_set_log_handler.
** Support for FreeBSD.
** Support for C++.
** Support for MSYS.
** Fixed EdDSA and RSA self-attestation.
* Version 1.3.1 (2020-02-19)
** fix zero-ing of le1 and le2 when talking to a U2F device.
** dropping sk-libfido2 middleware, please find it in the openssh tree.
* Version 1.3.0 (2019-11-28)
** assert/hmac: encode public key as per spec, gh#60.
** fido2-cred: fix creation of resident keys.
** fido2-{assert,cred}: support for hmac-secret extension.
** hid_osx: detect device removal, gh#56.
** hid_osx: fix device detection in MacOS Catalina.
** New API calls:
- fido_assert_set_authdata_raw;
- fido_assert_sigcount;
- fido_cred_set_authdata_raw;
- fido_dev_cancel.
** Middleware library for use by OpenSSH.
** Support for biometric enrollment.
** Support for OpenBSD.
** Support for self-attestation.
* Version 1.2.0 (released 2019-07-26)
** Credential management support.
** New API reflecting FIDO's 3-state booleans (true, false, absent):
- fido_assert_set_up;
- fido_assert_set_uv;
- fido_cred_set_rk;
- fido_cred_set_uv.
** Command-line tools for Windows.
** Documentation and reliability fixes.
** fido_{assert,cred}_set_options() are now marked as deprecated.
* Version 1.1.0 (released 2019-05-08)
** MacOS: fix IOKit crash on HID read.
** Windows: fix contents of release file.
** EdDSA (Ed25519) support.
** fido_dev_make_cred: fix order of CBOR map keys.
** fido_dev_get_assert: plug memory leak when operating on U2F devices.
* Version 1.0.0 (released 2019-03-21)
** Native HID support on Linux, MacOS, and Windows.
** fido2-{assert,cred}: new -u option to force U2F on dual authenticators.
** fido2-assert: support for multiple resident keys with the same RP.
** Strict checks for CTAP2 compliance on received CBOR payloads.
** Better fuzzing harnesses.
** Documentation and reliability fixes.
* Version 0.4.0 (released 2019-01-07)
** fido2-assert: print the user id for resident credentials.
** Fix encoding of COSE algorithms when making a credential.
** Rework purpose of fido_cred_set_type; no ABI change.
** Minor documentation and code fixes.
* Version 0.3.0 (released 2018-09-11)
** Various reliability fixes.
** Merged fuzzing instrumentation.
** Added regress tests.
** Added support for FIDO 2's hmac-secret extension.
** New API calls:
- fido_assert_hmac_secret_len;
- fido_assert_hmac_secret_ptr;
- fido_assert_set_extensions;
- fido_assert_set_hmac_salt;
- fido_cred_set_extensions;
- fido_dev_force_fido2.
** Support for native builds with Microsoft Visual Studio 17.
* Version 0.2.0 (released 2018-06-20)
** Added command-line tools.
** Added a couple of missing get functions.
* Version 0.1.1 (released 2018-06-05)
** Added documentation.
** Added OpenSSL 1.0 support.
** Minor fixes.
* Version 0.1.0 (released 2018-05-18)
** First beta release.

78
README.md Normal file
View File

@@ -0,0 +1,78 @@
# fido2-manage
*fido2-manage* is a tool allowing to manage FIDO2.1 devices over USB or NFC, including Passkey (resident keys) management
![image](https://repository-images.githubusercontent.com/803272315/648a5edf-2324-4f45-ba40-089f830a919b)
# License
*fido2-manage* is licensed under the BSD 2-clause license. See the LICENSE
file for the full license text.
# Supported Platforms
*fido2-manage* should work on any Linux distribution, but we develop and test using Ubuntu. This library is partially forked from [libfido2](https://github.com/Yubico/libfido2) to provide a FIDO2.1 key management tool under the Linux platform (we already have a solution for Windows).
# Supported devices
FIDO2.1 (PRE or FINAL) keys from any brand can be used. However, with FIDO2.0 keys, no passkey management is possible. As a result, only basic information will be shown with 2.0 devices.
# Installation
If you haven't installed Git yet, please do so (`sudo apt install git`)
```bash
git clone https://github.com/Token2/fido2-manage.git
cd fido2-manage
sudo apt install -y zlib1g-dev pkg-config
sudo apt install -y cmake libcbor-dev libpcsclite-dev libssl-dev libudev-dev
rm -rf build && mkdir build && cd build && cmake -USE_PCSC=ON ..
cd ..
make -C build
sudo make -C build install
sudo ldconfig
chmod 755 fido2-manage.sh
```
### Test the shell script
`./fido2-manage.sh -list`
### GUI
The GUI wrapper (`gui.py`) created with Python3 is included in the package and should be ready for use on the latest Ubuntu releases. The only requirement is the tkinter module that can be installed as follows:
`sudo apt install -y python3-tk`
To run the script, execute it using Python from the same folder:
`python3 gui.py`
## Automated installation script
You can download the installer bash script to run all commands in one go
```bash
wget https://raw.githubusercontent.com/token2/fido2-manage/main/install-fido2-manage.sh
```
```bash
chmod +x ./install-fido2-manage.sh & ./install-fido2-manage.sh
```
If no errors are shown, then you can launch the GUI:
```bash
cd fido2-manage
```
```bash
python2 gui.py
```

5
SECURITY.md Normal file
View File

@@ -0,0 +1,5 @@
# Reporting libfido2 Security Issues
To report security issues in libfido2, please contact security@yubico.com.
A PGP public key can be found at
https://www.yubico.com/support/issue-rating-system/.

3
TODO.md Normal file
View File

@@ -0,0 +1,3 @@
add Linux-style aliases for arguments (i.e. `--device` in addition to `-device`)
rename output tool (instead of `fido2-token` , `fido2-token2` or similar)

220
fido2-manage.sh Normal file
View File

@@ -0,0 +1,220 @@
#!/bin/bash
FIDO2_TOKEN_CMD="/usr/local/bin/fido2-token"
list=false
info=false
device=""
pin=""
storage=false
residentKeys=false
domain=""
delete=false
credential=""
changePIN=false
setPIN=false
reset=false
uvs=false
uvd=false
help=false
show_message() {
local message=$1
local type=${2:-"Info"}
echo "[$type] $message"
}
while [[ "$#" -gt 0 ]]; do
case $1 in
-list) list=true ;;
-info) info=true ;;
-device) device="$2"; shift ;;
-pin) pin="$2"; shift ;;
-storage) storage=true ;;
-residentKeys) residentKeys=true ;;
-domain) domain="$2"; shift ;;
-delete) delete=true ;;
-credential) credential="$2"; shift ;;
-changePIN) changePIN=true ;;
-setPIN) setPIN=true ;;
-reset) reset=true ;;
-uvs) uvs=true ;;
-uvd) uvd=true ;;
-help) help=true ;;
*) show_message "Unknown parameter: $1" "Error"; exit 1 ;;
esac
shift
done
show_help() {
cat << EOF
FIDO2 Token Management Tool
v 0.2.2
This is a wrapper for libfido2 library
(c) Token2 Sarl
Usage: ./fido2-manage.sh [-list] [-info -device <number>] [-storage -device <number>] [-residentKeys -device <number> -domain <domain>] [-uvs] [-uvd] [-delete -device <number> -credential <credential>] [-help]
Examples:
- List available devices:
./fido2-manage.sh -list
- Retrieve information about a specific device:
./fido2-manage.sh -info -device 1
- Retrieve storage data for credentials (number of resident keys stored and available) on a specific device:
./fido2-manage.sh -storage -device 2
- Retrieve resident keys on a specific device for a domain:
./fido2-manage.sh -residentKeys -device 1 -domain login.microsoft.com
- Enforce user verification to be always requested on a specific device:
./fido2-manage.sh -uvs -device 1
- Disable enforcing user verification to be always requested on a specific device:
./fido2-manage.sh -uvd -device 1
- Sets PIN of a specific device:
./fido2-manage.sh -setPIN -device 1
- Perform a factory reset on a specific device:
./fido2-manage.sh -reset -device 1
- Change PIN of a specific device:
./fido2-manage.sh -changePIN -device 1
- Delete a credential on a specific device:
./fido2-manage.sh -delete -device 2 -credential Y+Dh/tSy/Q2IdZt6PW/G1A==
- Display script help information:
./fido2-manage.sh -help
EOF
}
# Display help if -help parameter is provided
if $help; then
show_help
exit 0
fi
# Check if no arguments are specified, then show help
if ! $list && ! $info && [[ -z $device ]] && ! $storage && ! $residentKeys && [[ -z $domain ]] && ! $delete && [[ -z $credential ]] && ! $changePIN && ! $setPIN && ! $reset && ! $uvs && ! $uvd && ! $help; then
show_help
exit 1
fi
if $list; then
command_output=$($FIDO2_TOKEN_CMD -L 2>&1)
if [ $? -ne 0 ]; then
show_message "Error executing $FIDO2_TOKEN_CMD -L: $command_output" "Error"
exit 1
fi
device_count=1
echo "$command_output" | while read -r line; do
if [[ $line =~ ^([^:]+) ]]; then
echo "Device [$device_count] : $(echo "${line}" | grep -oP '\(([^)]+)\)' | sed 's/(\(.*\))/\1/')"
device_count=$((device_count + 1))
fi
done
exit 0
fi
if [[ -n $device ]]; then
device_index=$((device - 1))
command_output=$($FIDO2_TOKEN_CMD -L 2>&1)
if [ $? -ne 0 ]; then
show_message "Error executing $FIDO2_TOKEN_CMD -L: $command_output" "Error"
exit 1
fi
if [[ $command_output =~ pcsc://slot0: ]]; then
device_string="pcsc://slot0"
else
device_string=$(echo "$command_output" | sed -n "$((device_index + 1))p" | cut -d ':' -f 1)
fi
if $reset; then
show_message "WARNING: Factory reset will remove all data and settings of the device, including its PIN, fingerprints, and passkeys stored. The factory reset process is irreversible. Are you sure you want to proceed? (Y/N)"
read -r confirmation
if [[ $confirmation =~ [Yy] ]]; then
show_message "Touch or press the security key button when it starts blinking."
output=$($FIDO2_TOKEN_CMD -R "$device_string" 2>&1)
if [[ $output == *"FIDO_ERR_NOT_ALLOWED"* ]]; then
show_message "Error: Factory reset not allowed. Factory reset is only allowed within 10 seconds of powering up of the security key. Please unplug and plug the device back in and retry within 10 seconds after plugging in."
else
show_message "Factory reset completed."
fi
else
show_message "Factory reset canceled."
fi
exit 0
fi
if $changePIN; then
show_message "Enter the old and new PIN below."
$FIDO2_TOKEN_CMD -C "$device_string"
exit 0
fi
if $uvs; then
show_message "Enforcing user verification."
$FIDO2_TOKEN_CMD -Su "$device_string"
exit 0
fi
if $uvd; then
show_message "Disabling user verification."
$FIDO2_TOKEN_CMD -Du "$device_string"
exit 0
fi
if $setPIN; then
show_message "Enter and confirm the PIN as prompted below."
$FIDO2_TOKEN_CMD -S "$device_string"
exit 0
fi
if $delete && [[ -n $credential ]]; then
show_message "WARNING: Deleting a credential is irreversible. Are you sure you want to proceed? (Y/N)"
read -r confirmation
if [[ $confirmation =~ [Yy] ]]; then
$FIDO2_TOKEN_CMD -D -i "$credential" "$device_string"
show_message "Credential deleted successfully."
else
show_message "Deletion canceled."
fi
exit 0
fi
if $storage; then
$FIDO2_TOKEN_CMD -I -c "$device_string" $([[ -n $pin ]] && echo "-w $pin ")
exit 0
elif $residentKeys; then
if [[ -n $domain ]]; then
output=$($FIDO2_TOKEN_CMD -L -k "$domain" "$device_string" $([[ -n $pin ]] && echo "-w $pin"))
echo "$output" | grep -oP '(\d+): (\S+) (.+)' | while read -r line; do
key_id=$(echo "$line" | awk '{print $1}')
credential_id=$(echo "$line" | awk '{print $2}')
user=$(echo "$line" | grep -oP '(\S+\s+\S+).+ es256' | head -1)
show_message "Credential ID: $credential_id, User: $user"
done
else
$FIDO2_TOKEN_CMD -L -r "$device_string" $(if [[ -n $pin ]]; then echo "-w $pin"; fi)
fi
exit 0
fi
if $info; then
command_output=$($FIDO2_TOKEN_CMD -I "$device_string")
show_message "Device $device Information:"
echo "$command_output"
exit 0
fi
fi

372
gui.py Normal file
View File

@@ -0,0 +1,372 @@
import subprocess
import sys
import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
import re
# Define the command to execute
FIDO_COMMAND = './fido2-manage.sh'
#Command below for Windows
#FIDO_COMMAND = 'fido2-manage-ui.exe'
# Global variable to store the PIN
pin = None
# Function to get device list from fido2-manage-ui.exe
def get_device_list():
try:
# Execute the command with '-list' argument and capture the output
result = subprocess.run([FIDO_COMMAND, '-list'], capture_output=True, text=True)
# Split the output into lines and return as a list
device_list = result.stdout.strip().split('\n')
return device_list
except Exception as e:
# Handle exceptions (e.g., file not found or command error)
print(f"Error executing device list command: {e}")
return []
# Function to execute storage command and prepend its output to the grid
def execute_storage_command(device_digit):
global pin
command = [FIDO_COMMAND, '-storage', '-pin', pin, '-device', device_digit]
try:
result = subprocess.run(command, capture_output=True, text=True)
# Check if the subprocess was executed successfully
#print (result)
if result.returncode == 0:
# Parse the output and insert into the treeview
for line in reversed(result.stdout.splitlines()): # Insert in reversed order to prepend
if ": " in line:
key, value = line.split(": ", 1)
tree.insert("", 0, values=(key, value)) # Insert at the top of the grid
else:
raise subprocess.CalledProcessError(result.returncode, command)
except Exception as e:
messagebox.showerror("Error", f"Command execution failed: {e}\nOutput: {result.stderr}")
# Function to execute info command and append its output to the grid
def execute_info_command(device_digit):
global pin
tree.delete(*tree.get_children())
command = [FIDO_COMMAND, '-storage', '-pin', pin, '-device', device_digit]
try:
result = subprocess.run(command, capture_output=True, text=True)
if result.stderr.find("FIDO_ERR_PIN_INVALID")!= -1:
#exit
messagebox.showerror("Error", f"Invalid PIN provided")
return
# Check FIDO_ERR_PIN_AUTH_BLOCKED
if result.stderr.find("FIDO_ERR_PIN_AUTH_BLOCKED")!= -1:
#exit
messagebox.showerror("Error", f"Wrong PIN provided to many times. Reinsert the key")
return
# Check FIDO_ERR_PIN_REQUIRED
if result.stderr.find("FIDO_ERR_PIN_REQUIRED")!= -1:
#exit
messagebox.showerror("Error", f"No PIN set for this key. Passkeys can be managed only with a PIN set. You will be prompted to create a PIN on the next window")
command = [FIDO_COMMAND, '-setPIN', '-device', device_digit]
if sys.platform.startswith('win'):
subprocess.Popen(['start', 'cmd', '/c'] + command, shell=True)
elif sys.platform.startswith('linux'):
subprocess.Popen(['x-terminal-emulator', '-e'] + command)
return
# Check FIDO version
if result.stderr.find("FIDO_ERR_INVALID_CBOR")!= -1:
#exit
messagebox.showerror("Error", f"This is an older key (probably FIDO2.0). No passkey management is possible with this key. Only basic information will be shown.")
# Check if the subprocess was executed successfully
if result.returncode == 0:
# Parse the output and insert into the treeview
for line in result.stdout.splitlines():
if ": " in line:
key, value = line.split(": ", 1)
tree.insert("", tk.END, values=(key, value)) # Append to the end of the grid
else:
raise subprocess.CalledProcessError(result.returncode, command)
except Exception as e:
messagebox.showerror("Error", f"Command execution failed: {e}\nOutput: {result.stderr}")
command = [FIDO_COMMAND, '-info', '-pin', pin, '-device', device_digit]
try:
result = subprocess.run(command, capture_output=True, text=True)
# Check if the subprocess was executed successfully
if result.returncode == 0:
# Parse the output and insert into the treeview
for line in result.stdout.splitlines():
if ": " in line:
key, value = line.split(": ", 1)
tree.insert("", tk.END, values=(key, value)) # Append to the end of the grid
else:
raise subprocess.CalledProcessError(result.returncode, command)
except Exception as e:
messagebox.showerror("Error", f"Command execution failed: {e}\nOutput: {result.stderr}")
# Function to set the PIN
def set_pin():
global pin
pin = simpledialog.askstring("PIN Code", "Enter PIN code (enter 0000 if no PIN is set/known):", show='*')
# Function to handle selection event
def on_device_selected(event):
global pin
selected_device = device_var.get()
# Extract the digit inside the first pair of square brackets
match = re.search(r'\[(\d+)\]', selected_device)
pin = None
set_pin()
#print (pin)
if match:
device_digit = match.group(1)
if pin is not None:
execute_info_command(device_digit)
check_passkeys_button_state()
check_changepin_button_state()
else:
messagebox.showinfo("Device Selected", "No digit found in the selected device")
# Function to check if the "passkeys" button should be enabled
def check_passkeys_button_state():
passkeys_button_state = tk.DISABLED
for child in tree.get_children():
values = tree.item(child, 'values')
if values and len(values) == 2 and values[0] == 'existing rk(s)':
try:
rk_count = int(values[1])
if rk_count > 0:
passkeys_button_state = tk.NORMAL
break
except ValueError:
pass
passkeys_button.config(state=passkeys_button_state)
# Function to check if the "passkeys" button should be enabled
def check_changepin_button_state():
passkeys_button_state = tk.DISABLED
for child in tree.get_children():
values = tree.item(child, 'values')
if values and len(values) == 2 and values[0] == 'remaining rk(s)':
try:
rk_count = int(values[1])
if rk_count > 0:
passkeys_button_state = tk.NORMAL
break
except ValueError:
pass
change_pin_button.config(state=passkeys_button_state)
# Function to handle "passkeys" button click
def on_passkeys_button_click():
global pin
# Get the selected device and PIN
selected_device = device_var.get()
match = re.search(r'\[(\d+)\]', selected_device)
if match:
device_digit = match.group(1)
#pin = simpledialog.askstring("PIN Code", "Enter PIN code (enter 0000 if no PIN is set/known):", show='*')
if pin is not None:
# Execute the command to get resident keys
command = [FIDO_COMMAND, '-residentKeys', '-pin', pin, '-device', device_digit]
try:
result = subprocess.run(command, capture_output=True, text=True)
if result.returncode == 0:
# Parse the domains from the output
domains = []
for line in result.stdout.splitlines():
match = re.search(r'= (.+)$', line)
if match:
domains.append(match.group(1))
# Execute the command for each domain
cumulated_output = ""
for domain in domains:
domain_command = [FIDO_COMMAND, '-residentKeys', '-domain', domain, '-pin', pin, '-device', device_digit]
domain_result = subprocess.run(domain_command, capture_output=True, text=True)
if domain_result.returncode == 0:
cumulated_output += domain_result.stdout
else:
raise subprocess.CalledProcessError(domain_result.returncode, domain_command)
# Show the cumulated output in a new window
show_output_in_new_window(cumulated_output, device_digit)
else:
raise subprocess.CalledProcessError(result.returncode, command)
except Exception as e:
messagebox.showerror("Error", f"Command execution failed: {e}\nOutput: {result.stderr}")
else:
messagebox.showinfo("Device Selected", "No digit found in the selected device")
def change_pin():
# Get the selected device and PIN
selected_device = device_var.get()
# Extract the digit inside the first pair of square brackets
match = re.search(r'\[(\d+)\]', selected_device)
if match:
device_digit = match.group(1)
command = [FIDO_COMMAND, '-changePIN', '-device', device_digit]
if sys.platform.startswith('win'):
subprocess.Popen(['start', 'cmd', '/c'] + command, shell=True)
elif sys.platform.startswith('linux'):
subprocess.Popen(['x-terminal-emulator', '-e'] + command)
pass
def refresh_combobox():
# Implement your refresh logic here
# For example, you can update the values in the combobox
# based on some external data source or trigger a refresh action.
device_combobox.set("") # Clear the selected value
tree.delete(*tree.get_children())
passkeys_button.config(state=tk.DISABLED)
change_pin_button.config(state=tk.DISABLED)
device_list = get_device_list() # Assuming you have a function to get the device list
if not device_list:
print("No devices found.")
device_combobox['values'] = device_list # Update the combobox values
# Function to show the output in a new window
def show_output_in_new_window(output,device_digit):
# Create a new window
new_window = tk.Toplevel(root)
new_window.geometry("500x450")
new_window.title("Resident Keys / Passkeys")
# Create a Treeview widget for displaying output
tree_new_window = ttk.Treeview(new_window, columns=("Credential ID", "User"), show="headings")
# Set column headings
tree_new_window.heading("Credential ID", text="Credential ID")
tree_new_window.heading("User", text="User")
tree_new_window.pack(expand=True, fill=tk.BOTH, padx=10, pady=10)
# Add scrollbars to the Treeview
tree_scrollbar_y = ttk.Scrollbar(new_window, orient="vertical", command=tree_new_window.yview)
tree_scrollbar_y.pack(side="right", fill="y")
tree_new_window.configure(yscrollcommand=tree_scrollbar_y.set)
tree_scrollbar_x = ttk.Scrollbar(new_window, orient="horizontal", command=tree_new_window.xview)
tree_scrollbar_x.pack(side="bottom", fill="x")
tree_new_window.configure(xscrollcommand=tree_scrollbar_x.set)
# Parse the output and insert into the Treeview
for line in output.splitlines():
if "Credential ID: " in line and "User: " in line:
credential_id = line.split("Credential ID: ")[1].split(",")[0].strip()
user = line.split("User: ")[1].strip()
tree_new_window.insert("", tk.END, values=(credential_id, user))
# Function to handle show value button click
def show_selected_value():
selected_item = tree_new_window.selection()
if selected_item:
value = tree_new_window.item(selected_item, 'values')[0] # Get the value of the selected item
new_window.destroy()
command = [FIDO_COMMAND, '-delete', '-device', device_digit, '-credential', value]
if sys.platform.startswith('win'):
subprocess.Popen(['start', 'cmd', '/c'] + command, shell=True)
elif sys.platform.startswith('linux'):
subprocess.Popen(['x-terminal-emulator', '-e'] + command)
# Create the "Show Value" button
show_value_button = tk.Button(new_window, text="delete passkey", command=show_selected_value)
show_value_button.pack(pady=10)
def show_about_message():
messagebox.showinfo("About", "The FIDO2.1 Security Key Management Tool is a utility designed to manage and interact with FIDO2.1 security keys.\r\nIt provides functionalities to view information, manage relying parties, and perform various operations on connected FIDO2.1 devices.\r\n\r\n(c)TOKEN2 Sarl\r\nVersoix, Switzerland")
# Create the main application window
root = tk.Tk()
root.geometry("700x500") # Width x Height
root.title("FIDO2.1 Manager - Python version 0.1 - (c) Token2")
# Create a frame for the first three elements
top_frame = ttk.Frame(root)
top_frame.pack(side=tk.TOP, fill=tk.X)
# Create a label for the dropdown
label = tk.Label(top_frame, text="Select Device:")
label.pack(side=tk.LEFT, padx=10, pady=10)
# Create a ComboBox (dropdown) and populate it with device list
device_list = get_device_list()
if not device_list:
device_list = "No devices found."
device_var = tk.StringVar()
device_combobox = ttk.Combobox(top_frame, textvariable=device_var, values=device_list, width=60)
device_combobox.pack(side=tk.LEFT, padx=10, pady=10)
device_combobox.bind("<<ComboboxSelected>>", on_device_selected)
# Create the refresh button
refresh_button = tk.Button(top_frame, text="Refresh", command=refresh_combobox)
refresh_button.pack(side=tk.LEFT, padx=10, pady=10)
# Create a Treeview widget for displaying output with scrollbars
tree_frame = ttk.Frame(root)
tree_frame.pack(expand=True, fill=tk.BOTH, padx=10, pady=10)
tree_scrollbar_y = ttk.Scrollbar(tree_frame, orient="vertical")
tree_scrollbar_x = ttk.Scrollbar(tree_frame, orient="horizontal")
tree = ttk.Treeview(tree_frame, columns=("Key", "Value"), show="headings", yscrollcommand=tree_scrollbar_y.set, xscrollcommand=tree_scrollbar_x.set)
tree_scrollbar_y.config(command=tree.yview)
tree_scrollbar_x.config(command=tree.xview)
tree_scrollbar_y.pack(side="right", fill="y")
tree_scrollbar_x.pack(side="bottom", fill="x")
# Set column headings
tree.heading("Key", text="Key")
tree.heading("Value", text="Value")
tree.pack(expand=True, fill=tk.BOTH)
# Create the "passkeys" button
passkeys_button = ttk.Button(root, text="Passkeys", state=tk.DISABLED, command=on_passkeys_button_click)
passkeys_button.pack(side=tk.LEFT, padx=5, pady=10)
# Create the "Change PIN" button
change_pin_button = ttk.Button(root, text="Change PIN", state=tk.DISABLED, command=change_pin)
change_pin_button.pack(side=tk.LEFT, padx=5, pady=10)
about_button = ttk.Button(root, text="About", command=show_about_message)
about_button.pack(side=tk.RIGHT, padx=5, pady=10)
# Run the Tkinter main loop
root.mainloop()

11
install-fido2-manage.sh Normal file
View File

@@ -0,0 +1,11 @@
#!/bin/bash
git clone https://github.com/Token2/fido2-manage.git
cd fido2-manage
sudo apt install -y zlib1g-dev pkg-config cmake libcbor-dev libpcsclite-dev libssl-dev libudev-dev
rm -rf build && mkdir build && cd build && cmake -USE_PCSC=ON ..
cd ..
make -C build
sudo make -C build install
sudo ldconfig
chmod 755 fido2-manage.sh
sudo apt-get -y install python3-tk