Vendor import of libfido2 1.9.0

This commit is contained in:
Ed Maste 2023-04-26 12:37:20 -04:00
parent a58dee945a
commit 7248ec417c
100 changed files with 5620 additions and 2328 deletions

View File

@ -1,4 +1,4 @@
# 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.
@ -28,7 +28,7 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_COLOR_MAKEFILE OFF)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(FIDO_MAJOR "1")
set(FIDO_MINOR "8")
set(FIDO_MINOR "9")
set(FIDO_PATCH "0")
set(FIDO_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}.${FIDO_PATCH})
@ -68,10 +68,11 @@ if(NOT MSVC)
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_DARWIN_C_SOURCE")
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D__STDC_WANT_LIB_EXT1__=1")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(NFC_LINUX OFF)
set(NFC_LINUX ON)
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_GNU_SOURCE")
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D_DEFAULT_SOURCE")
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD")
set(FIDO_CFLAGS "${FIDO_CFLAGS} -D__BSD_VISIBLE=1")
endif()
set(FIDO_CFLAGS "${FIDO_CFLAGS} -std=c99")
@ -79,7 +80,7 @@ if(NOT MSVC)
endif()
check_c_compiler_flag("-Wshorten-64-to-32" HAVE_SHORTEN_64_TO_32)
check_c_compiler_flag("-fstack-protector-all" HAVE_STACK_PROTECTOR_ALL)
check_c_compiler_flag("-Werror -fstack-protector-all" HAVE_STACK_PROTECTOR_ALL)
check_include_files(cbor.h HAVE_CBOR_H)
check_include_files(endian.h HAVE_ENDIAN_H)
@ -88,7 +89,6 @@ check_include_files(openssl/opensslv.h HAVE_OPENSSLV_H)
check_include_files(signal.h HAVE_SIGNAL_H)
check_include_files(sys/random.h HAVE_SYS_RANDOM_H)
check_include_files(unistd.h HAVE_UNISTD_H)
check_include_files("windows.h;webauthn.h" HAVE_WEBAUTHN_H)
check_symbol_exists(arc4random_buf stdlib.h HAVE_ARC4RANDOM_BUF)
check_symbol_exists(clock_gettime time.h HAVE_CLOCK_GETTIME)
@ -101,17 +101,13 @@ check_symbol_exists(getrandom sys/random.h HAVE_GETRANDOM)
check_symbol_exists(memset_s string.h HAVE_MEMSET_S)
check_symbol_exists(readpassphrase readpassphrase.h HAVE_READPASSPHRASE)
check_symbol_exists(recallocarray stdlib.h HAVE_RECALLOCARRAY)
check_symbol_exists(sigaction signal.h HAVE_SIGACTION)
check_symbol_exists(strlcat string.h HAVE_STRLCAT)
check_symbol_exists(strlcpy string.h HAVE_STRLCPY)
check_symbol_exists(strsep string.h HAVE_STRSEP)
check_symbol_exists(sysconf unistd.h HAVE_SYSCONF)
check_symbol_exists(timespecsub sys/time.h HAVE_TIMESPECSUB)
check_symbol_exists(timingsafe_bcmp string.h HAVE_TIMINGSAFE_BCMP)
set(CMAKE_EXTRA_INCLUDE_FILES signal.h)
check_type_size("sig_atomic_t" HAVE_SIG_ATOMIC_T)
set(CMAKE_EXTRA_INCLUDE_FILES)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
try_compile(HAVE_POSIX_IOCTL
"${CMAKE_CURRENT_BINARY_DIR}/posix_ioctl_check.o"
@ -134,16 +130,15 @@ list(APPEND CHECK_VARIABLES
HAVE_POSIX_IOCTL
HAVE_READPASSPHRASE
HAVE_RECALLOCARRAY
HAVE_SIGACTION
HAVE_SIGNAL_H
HAVE_STRLCAT
HAVE_STRLCPY
HAVE_STRSEP
HAVE_SYSCONF
HAVE_SYS_RANDOM_H
HAVE_TIMESPECSUB
HAVE_TIMINGSAFE_BCMP
HAVE_UNISTD_H
HAVE_WEBAUTHN_H
)
foreach(v ${CHECK_VARIABLES})
@ -156,26 +151,26 @@ if(HAVE_EXPLICIT_BZERO AND NOT LIBFUZZER)
add_definitions(-DHAVE_EXPLICIT_BZERO)
endif()
if(HAVE_SIGACTION AND (NOT HAVE_SIG_ATOMIC_T STREQUAL ""))
add_definitions(-DSIGNAL_EXAMPLE)
endif()
if(UNIX)
add_definitions(-DHAVE_DEV_URANDOM)
endif()
if(MSVC)
if((NOT CBOR_INCLUDE_DIRS) OR (NOT CBOR_LIBRARY_DIRS) OR
(NOT CRYPTO_INCLUDE_DIRS) OR (NOT CRYPTO_LIBRARY_DIRS) OR
(NOT ZLIB_INCLUDE_DIRS) OR (NOT ZLIB_LIBRARY_DIRS))
message(FATAL_ERROR "please provide definitions for "
"{CBOR,CRYPTO,ZLIB}_{INCLUDE,LIBRARY}_DIRS when building "
"under msvc")
(NOT CBOR_BIN_DIRS) OR (NOT CRYPTO_INCLUDE_DIRS) OR
(NOT CRYPTO_LIBRARY_DIRS) OR (NOT CRYPTO_BIN_DIRS) OR
(NOT ZLIB_INCLUDE_DIRS) OR (NOT ZLIB_LIBRARY_DIRS) OR
(NOT ZLIB_BIN_DIRS))
message(FATAL_ERROR "please define "
"{CBOR,CRYPTO,ZLIB}_{INCLUDE,LIBRARY,BIN}_DIRS when "
"building under msvc")
endif()
set(CBOR_LIBRARIES cbor)
set(ZLIB_LIBRARIES zlib)
set(CRYPTO_LIBRARIES crypto-46)
set(MSVC_DISABLED_WARNINGS_LIST
"C4152" # nonstandard extension used: function/data pointer
# conversion in expression;
"C4200" # nonstandard extension used: zero-sized array in
# struct/union;
"C4204" # nonstandard extension used: non-constant aggregate
@ -191,12 +186,10 @@ 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 /guard:cf /sdl /RTCcsu")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Od /Z7 /guard:cf /sdl /RTCcsu")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi /guard:cf /sdl")
if (HAVE_WEBAUTHN_H)
add_definitions(-DUSE_WINHELLO)
set(USE_WINHELLO ON)
endif()
add_definitions(-DUSE_WINHELLO)
set(USE_WINHELLO ON)
else()
include(FindPkgConfig)
pkg_search_module(CBOR libcbor)
@ -275,9 +268,14 @@ else()
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fno-omit-frame-pointer")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -D_FORTIFY_SOURCE=2")
if(CRYPTO_VERSION VERSION_GREATER_EQUAL 3.0)
add_definitions(-DOPENSSL_API_COMPAT=0x10100000L)
endif()
if(FUZZ)
add_definitions(-DFIDO_FUZZ)
endif()
if(LIBFUZZER)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=fuzzer-no-link")
endif()
@ -404,10 +402,9 @@ if(BUILD_MANPAGES)
endif()
if(NOT WIN32)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
if(NOT LIBFUZZER AND NOT FUZZ)
subdirs(regress)
endif()
if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT FUZZ)
enable_testing()
subdirs(regress)
endif()
if(FUZZ)
subdirs(fuzz)

22
NEWS
View File

@ -1,3 +1,25 @@
* 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.

View File

@ -23,6 +23,8 @@ file for the full license text.
*libfido2* is known to work on Linux, macOS, Windows, OpenBSD, and FreeBSD.
NFC support is available on Linux and Windows.
=== Documentation
Documentation is available in troff and HTML formats. An
@ -40,7 +42,7 @@ is also available.
==== Releases
The current release of *libfido2* is 1.8.0. Please consult Yubico's
The current release of *libfido2* is 1.9.0. Please consult Yubico's
https://developers.yubico.com/libfido2/Releases[release page] for source
and binary releases.
@ -66,7 +68,7 @@ Follow the instructions for Ubuntu 18.04 (Bionic) below.
Or from source, on UNIX-like systems:
$ (rm -rf build && mkdir build && cd build && cmake ..)
$ cmake -B build
$ make -C build
$ sudo make -C build install
@ -75,7 +77,8 @@ https://www.freedesktop.org/wiki/Software/pkg-config/[pkg-config] may need to
be installed, or the PKG_CONFIG_PATH environment variable set.
*libfido2* depends on https://github.com/pjk/libcbor[libcbor],
https://www.openssl.org[OpenSSL], and https://zlib.net[zlib]. On Linux, libudev
https://www.openssl.org[OpenSSL] 1.1 or newer, and https://zlib.net[zlib].
On Linux, libudev
(part of https://www.freedesktop.org/wiki/Software/systemd[systemd]) is also
required.

View File

@ -1,5 +1,5 @@
/*
* 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.
*/
@ -20,7 +20,7 @@
#include "../openbsd-compat/openbsd-compat.h"
#include "extern.h"
static const unsigned char cdh[32] = {
static const unsigned char cd[32] = {
0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7,
0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56,
0x42, 0x1c, 0xb6, 0xf6, 0xb3, 0x00, 0x86, 0x52,
@ -106,10 +106,9 @@ verify_assert(int type, const unsigned char *authdata_ptr, size_t authdata_len,
errx(1, "fido_assert_new");
/* client data hash */
r = fido_assert_set_clientdata_hash(assert, cdh, sizeof(cdh));
r = fido_assert_set_clientdata(assert, cd, sizeof(cd));
if (r != FIDO_OK)
errx(1, "fido_assert_set_clientdata_hash: %s (0x%x)",
fido_strerr(r), r);
errx(1, "fido_assert_set_clientdata: %s (0x%x)", fido_strerr(r), r);
/* relying party */
r = fido_assert_set_rp(assert, "localhost");
@ -166,7 +165,7 @@ main(int argc, char **argv)
const char *blobkey_out = NULL;
const char *hmac_out = NULL;
unsigned char *body = NULL;
long long seconds = 0;
long long ms = 0;
size_t len;
int type = COSE_ES256;
int ext = 0;
@ -182,16 +181,12 @@ main(int argc, char **argv)
pin = optarg;
break;
case 'T':
#ifndef SIGNAL_EXAMPLE
(void)seconds;
errx(1, "-T not supported");
#else
if (base10(optarg, &seconds) < 0)
if (base10(optarg, &ms) < 0)
errx(1, "base10: %s", optarg);
if (seconds <= 0 || seconds > 30)
if (ms <= 0 || ms > 30)
errx(1, "-T: %s must be in (0,30]", optarg);
ms *= 1000; /* seconds to milliseconds */
break;
#endif
case 'a':
if (read_blob(optarg, &body, &len) < 0)
errx(1, "read_blob: %s", optarg);
@ -262,10 +257,9 @@ main(int argc, char **argv)
fido_dev_force_u2f(dev);
/* client data hash */
r = fido_assert_set_clientdata_hash(assert, cdh, sizeof(cdh));
r = fido_assert_set_clientdata(assert, cd, sizeof(cd));
if (r != FIDO_OK)
errx(1, "fido_assert_set_clientdata_hash: %s (0x%x)",
fido_strerr(r), r);
errx(1, "fido_assert_set_clientdata: %s (0x%x)", fido_strerr(r), r);
/* relying party */
r = fido_assert_set_rp(assert, "localhost");
@ -286,20 +280,12 @@ main(int argc, char **argv)
if (uv && (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK)
errx(1, "fido_assert_set_uv: %s (0x%x)", fido_strerr(r), r);
#ifdef SIGNAL_EXAMPLE
prepare_signal_handler(SIGINT);
if (seconds) {
prepare_signal_handler(SIGALRM);
alarm((unsigned)seconds);
}
#endif
/* timeout */
if (ms != 0 && (r = fido_dev_set_timeout(dev, (int)ms)) != FIDO_OK)
errx(1, "fido_dev_set_timeout: %s (0x%x)", fido_strerr(r), r);
r = fido_dev_get_assert(dev, assert, pin);
if (r != FIDO_OK) {
#ifdef SIGNAL_EXAMPLE
if (got_signal)
fido_dev_cancel(dev);
#endif
if ((r = fido_dev_get_assert(dev, assert, pin)) != FIDO_OK) {
fido_dev_cancel(dev);
errx(1, "fido_dev_get_assert: %s (0x%x)", fido_strerr(r), r);
}

View File

@ -1,5 +1,5 @@
/*
* 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.
*/
@ -17,7 +17,7 @@
#include "../openbsd-compat/openbsd-compat.h"
#include "extern.h"
static const unsigned char cdh[32] = {
static const unsigned char cd[32] = {
0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb,
0xdd, 0xd7, 0xfb, 0x06, 0x37, 0x62, 0xea, 0x26,
0x20, 0x44, 0x8e, 0x69, 0x7c, 0x03, 0xf2, 0x31,
@ -42,9 +42,8 @@ usage(void)
static void
verify_cred(int type, const char *fmt, const unsigned char *authdata_ptr,
size_t authdata_len, const unsigned char *x509_ptr, size_t x509_len,
const unsigned char *sig_ptr, size_t sig_len, bool rk, bool uv, int ext,
const char *key_out, const char *id_out)
size_t authdata_len, const unsigned char *attstmt_ptr, size_t attstmt_len,
bool rk, bool uv, int ext, const char *key_out, const char *id_out)
{
fido_cred_t *cred;
int r;
@ -57,11 +56,10 @@ verify_cred(int type, const char *fmt, const unsigned char *authdata_ptr,
if (r != FIDO_OK)
errx(1, "fido_cred_set_type: %s (0x%x)", fido_strerr(r), r);
/* client data hash */
r = fido_cred_set_clientdata_hash(cred, cdh, sizeof(cdh));
/* client data */
r = fido_cred_set_clientdata(cred, cd, sizeof(cd));
if (r != FIDO_OK)
errx(1, "fido_cred_set_clientdata_hash: %s (0x%x)",
fido_strerr(r), r);
errx(1, "fido_cred_set_clientdata: %s (0x%x)", fido_strerr(r), r);
/* relying party */
r = fido_cred_set_rp(cred, "localhost", "sweet home localhost");
@ -96,15 +94,10 @@ verify_cred(int type, const char *fmt, const unsigned char *authdata_ptr,
goto out;
}
/* x509 */
r = fido_cred_set_x509(cred, x509_ptr, x509_len);
/* attestation statement */
r = fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len);
if (r != FIDO_OK)
errx(1, "fido_cred_set_x509: %s (0x%x)", fido_strerr(r), r);
/* sig */
r = fido_cred_set_sig(cred, sig_ptr, sig_len);
if (r != FIDO_OK)
errx(1, "fido_cred_set_sig: %s (0x%x)", fido_strerr(r), r);
errx(1, "fido_cred_set_attstmt: %s (0x%x)", fido_strerr(r), r);
r = fido_cred_verify(cred);
if (r != FIDO_OK)
@ -138,27 +131,6 @@ verify_cred(int type, const char *fmt, const unsigned char *authdata_ptr,
fido_cred_free(&cred);
}
static fido_dev_t *
open_from_manifest(const fido_dev_info_t *dev_infos, size_t len,
const char *path)
{
size_t i;
fido_dev_t *dev;
for (i = 0; i < len; i++) {
const fido_dev_info_t *curr = fido_dev_info_ptr(dev_infos, i);
if (path == NULL ||
strcmp(path, fido_dev_info_path(curr)) == 0) {
dev = fido_dev_new_with_info(curr);
if (fido_dev_open_with_info(dev) == FIDO_OK)
return (dev);
fido_dev_free(&dev);
}
}
return (NULL);
}
int
main(int argc, char **argv)
{
@ -171,16 +143,13 @@ main(int argc, char **argv)
const char *blobkey_out = NULL;
const char *key_out = NULL;
const char *id_out = NULL;
const char *path = NULL;
unsigned char *body = NULL;
long long seconds = 0;
long long ms = 0;
size_t len;
int type = COSE_ES256;
int ext = 0;
int ch;
int r;
fido_dev_info_t *dev_infos = NULL;
size_t dev_infos_len = 0;
if ((cred = fido_cred_new()) == NULL)
errx(1, "fido_cred_new");
@ -191,16 +160,12 @@ main(int argc, char **argv)
pin = optarg;
break;
case 'T':
#ifndef SIGNAL_EXAMPLE
(void)seconds;
errx(1, "-T not supported");
#else
if (base10(optarg, &seconds) < 0)
if (base10(optarg, &ms) < 0)
errx(1, "base10: %s", optarg);
if (seconds <= 0 || seconds > 30)
if (ms <= 0 || ms > 30)
errx(1, "-T: %s must be in (0,30]", optarg);
ms *= 1000; /* seconds to milliseconds */
break;
#endif
case 'b':
ext |= FIDO_EXT_LARGEBLOB_KEY;
blobkey_out = optarg;
@ -248,21 +213,20 @@ main(int argc, char **argv)
}
}
fido_init(0);
argc -= optind;
argv += optind;
if (argc > 1)
if (argc != 1)
usage();
dev_infos = fido_dev_info_new(16);
fido_dev_info_manifest(dev_infos, 16, &dev_infos_len);
if (argc == 1)
path = argv[0];
if ((dev = open_from_manifest(dev_infos, dev_infos_len, path)) == NULL)
errx(1, "open_from_manifest");
fido_init(0);
if ((dev = fido_dev_new()) == NULL)
errx(1, "fido_dev_new");
r = fido_dev_open(dev, argv[0]);
if (r != FIDO_OK)
errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r);
if (u2f)
fido_dev_force_u2f(dev);
@ -271,11 +235,10 @@ main(int argc, char **argv)
if (r != FIDO_OK)
errx(1, "fido_cred_set_type: %s (0x%x)", fido_strerr(r), r);
/* client data hash */
r = fido_cred_set_clientdata_hash(cred, cdh, sizeof(cdh));
/* client data */
r = fido_cred_set_clientdata(cred, cd, sizeof(cd));
if (r != FIDO_OK)
errx(1, "fido_cred_set_clientdata_hash: %s (0x%x)",
fido_strerr(r), r);
errx(1, "fido_cred_set_clientdata: %s (0x%x)", fido_strerr(r), r);
/* relying party */
r = fido_cred_set_rp(cred, "localhost", "sweet home localhost");
@ -301,20 +264,12 @@ main(int argc, char **argv)
if (uv && (r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK)
errx(1, "fido_cred_set_uv: %s (0x%x)", fido_strerr(r), r);
#ifdef SIGNAL_EXAMPLE
prepare_signal_handler(SIGINT);
if (seconds) {
prepare_signal_handler(SIGALRM);
alarm((unsigned)seconds);
}
#endif
/* timeout */
if (ms != 0 && (r = fido_dev_set_timeout(dev, (int)ms)) != FIDO_OK)
errx(1, "fido_dev_set_timeout: %s (0x%x)", fido_strerr(r), r);
r = fido_dev_make_cred(dev, cred, pin);
if (r != FIDO_OK) {
#ifdef SIGNAL_EXAMPLE
if (got_signal)
fido_dev_cancel(dev);
#endif
if ((r = fido_dev_make_cred(dev, cred, pin)) != FIDO_OK) {
fido_dev_cancel(dev);
errx(1, "fido_makecred: %s (0x%x)", fido_strerr(r), r);
}
@ -329,9 +284,8 @@ main(int argc, char **argv)
uv = true;
verify_cred(type, fido_cred_fmt(cred), fido_cred_authdata_ptr(cred),
fido_cred_authdata_len(cred), fido_cred_x5c_ptr(cred),
fido_cred_x5c_len(cred), fido_cred_sig_ptr(cred),
fido_cred_sig_len(cred), rk, uv, ext, key_out, id_out);
fido_cred_authdata_len(cred), fido_cred_attstmt_ptr(cred),
fido_cred_attstmt_len(cred), rk, uv, ext, key_out, id_out);
if (blobkey_out != NULL) {
/* extract the "largeBlob" key */

View File

@ -11,10 +11,6 @@
#include <openssl/evp.h>
#include <openssl/rsa.h>
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
/* util.c */
EC_KEY *read_ec_pubkey(const char *);
RSA *read_rsa_pubkey(const char *);
@ -25,9 +21,5 @@ int write_blob(const char *, const unsigned char *, size_t);
int write_ec_pubkey(const char *, const void *, size_t);
int write_rsa_pubkey(const char *, const void *, size_t);
int write_eddsa_pubkey(const char *, const void *, size_t);
#ifdef SIGNAL_EXAMPLE
void prepare_signal_handler(int);
extern volatile sig_atomic_t got_signal;
#endif
#endif /* _EXTERN_H_ */

View File

@ -1,5 +1,5 @@
/*
* 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.
*/
@ -34,16 +34,9 @@ main(int argc, char **argv)
if ((r = fido_dev_open(dev, argv[1])) != FIDO_OK)
errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r);
#ifdef SIGNAL_EXAMPLE
prepare_signal_handler(SIGINT);
#endif
if ((r = fido_dev_reset(dev)) != FIDO_OK) {
#ifdef SIGNAL_EXAMPLE
if (got_signal)
fido_dev_cancel(dev);
#endif
errx(1, "fido_reset: %s (0x%x)", fido_strerr(r), r);
fido_dev_cancel(dev);
errx(1, "fido_dev_reset: %s (0x%x)", fido_strerr(r), r);
}
if ((r = fido_dev_close(dev)) != FIDO_OK)

View File

@ -21,9 +21,6 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@ -33,31 +30,6 @@
#include "../openbsd-compat/openbsd-compat.h"
#include "extern.h"
#ifdef SIGNAL_EXAMPLE
volatile sig_atomic_t got_signal = 0;
static void
signal_handler(int signo)
{
(void)signo;
got_signal = 1;
}
void
prepare_signal_handler(int signo)
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sigemptyset(&sa.sa_mask);
sa.sa_handler = signal_handler;
if (sigaction(signo, &sa, NULL) < 0)
err(1, "sigaction");
}
#endif
int
base10(const char *str, long long *ll)
{

View File

@ -1,12 +1,12 @@
# Copyright (c) 2019 Yubico AB. All rights reserved.
# Copyright (c) 2019-2021 Yubico AB. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
FROM ubuntu:focal
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update
RUN apt-get install -y clang-11 cmake git libssl-dev libudev-dev make pkg-config
RUN apt-get install -y clang-12 cmake git libssl-dev libudev-dev make pkg-config
RUN apt-get install -y zlib1g-dev
RUN git clone --branch v0.8.0 https://github.com/PJK/libcbor
RUN git clone https://github.com/yubico/libfido2
RUN CC=clang-11 CXX=clang++-11 /libfido2/fuzz/build-coverage /libcbor /libfido2
RUN CC=clang-12 CXX=clang++-12 /libfido2/fuzz/build-coverage /libcbor /libfido2

View File

@ -1,11 +1,11 @@
# Copyright (c) 2019 Yubico AB. All rights reserved.
# Copyright (c) 2019-2021 Yubico AB. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
IMAGE := libfido2-coverage:1.8.0
IMAGE := libfido2-coverage:1.9.1
RUNNER := libfido2-runner
PROFDATA := llvm-profdata-11
COV := llvm-cov-11
PROFDATA := llvm-profdata-12
COV := llvm-cov-12
TARGETS := fuzz_assert fuzz_bio fuzz_cred fuzz_credman fuzz_hid \
fuzz_largeblob fuzz_netlink fuzz_mgmt
CORPORA := $(foreach f,${TARGETS},${f}/corpus)
@ -50,16 +50,18 @@ profdata: run
report.tgz: profdata
docker exec ${RUNNER} /bin/sh -c 'rm -rf /report && mkdir /report && \
${COV} show -format=html -tab-size=8 -instr-profile=/$< \
-output-dir=/report /libfido2/build/src/libfido2.so'
--show-branch-summary=false -output-dir=/report \
/libfido2/build/src/libfido2.so'
docker exec -i ${RUNNER} tar Czcf / - report > $@
summary.txt: profdata
docker exec ${RUNNER} ${COV} report -use-color=false \
/libfido2/build/src/libfido2.so -instr-profile=/$< > $@
--show-branch-summary=false /libfido2/build/src/libfido2.so \
-instr-profile=/$< > $@
functions.txt: profdata
docker exec ${RUNNER} /bin/sh -c '${COV} report -use-color=false \
-show-functions -instr-profile=/$< \
-show-functions --show-branch-summary=false -instr-profile=/$< \
/libfido2/build/src/libfido2.so /libfido2/src/*.[ch]' > $@
clean: run

79
fuzz/clock.c Normal file
View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2021 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
#include <stdint.h>
#include <time.h>
#include "mutator_aux.h"
/*
* A pseudo-random monotonic clock with a probabilistic discontinuity to
* the end of time (as measured by struct timespec).
*/
extern int prng_up;
extern int __wrap_clock_gettime(clockid_t, struct timespec *);
extern int __real_clock_gettime(clockid_t, struct timespec *);
extern int __wrap_usleep(unsigned int);
static TLS struct timespec fuzz_clock;
static void
tick(unsigned int usec)
{
long long drift;
/*
* Simulate a jump to the end of time with 0.125% probability.
* This condition should be gracefully handled by callers of
* clock_gettime().
*/
if (uniform_random(800) < 1) {
fuzz_clock.tv_sec = LLONG_MAX;
fuzz_clock.tv_nsec = LONG_MAX;
return;
}
drift = usec * 1000LL + (long long)uniform_random(10000000); /* 10ms */
if (LLONG_MAX - drift < (long long)fuzz_clock.tv_nsec) {
fuzz_clock_reset(); /* Not much we can do here. */
} else if (drift + (long long)fuzz_clock.tv_nsec < 1000000000) {
fuzz_clock.tv_nsec += (long)(drift);
} else {
fuzz_clock.tv_sec += (long)(drift / 1000000000);
fuzz_clock.tv_nsec += (long)(drift % 1000000000);
}
}
int
__wrap_clock_gettime(clockid_t clk_id, struct timespec *tp)
{
if (!prng_up || clk_id != CLOCK_MONOTONIC)
return __real_clock_gettime(clk_id, tp);
if (uniform_random(400) < 1)
return -1;
tick(0);
*tp = fuzz_clock;
return 0;
}
int
__wrap_usleep(unsigned int usec)
{
if (uniform_random(400) < 1)
return -1;
tick(usec);
return 0;
}
void
fuzz_clock_reset(void)
{
memset(&fuzz_clock, 0, sizeof(fuzz_clock));
}

View File

@ -93,4 +93,87 @@ const uint8_t dummy_eddsa[] = {
0xe2, 0x39, 0xdf, 0x2f, 0x87, 0x19, 0xb3, 0x02,
};
const uint8_t dummy_netlink_wiredata[] = {
0xd8, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x9d, 0x2e, 0x00, 0x00,
0x01, 0x02, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
0x6e, 0x66, 0x63, 0x00, 0x06, 0x00, 0x01, 0x00,
0x1e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x03, 0x00,
0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x05, 0x00,
0x1f, 0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0x00,
0x14, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00,
0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00,
0x08, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x14, 0x00, 0x03, 0x00, 0x08, 0x00, 0x01, 0x00,
0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x04, 0x00,
0x08, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00,
0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x14, 0x00, 0x05, 0x00, 0x08, 0x00, 0x01, 0x00,
0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x06, 0x00,
0x08, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x14, 0x00, 0x07, 0x00, 0x08, 0x00, 0x01, 0x00,
0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x08, 0x00,
0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,
0x08, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x00, 0x00,
0x14, 0x00, 0x09, 0x00, 0x08, 0x00, 0x01, 0x00,
0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0a, 0x00,
0x08, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00,
0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x14, 0x00, 0x0b, 0x00, 0x08, 0x00, 0x01, 0x00,
0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0c, 0x00,
0x08, 0x00, 0x01, 0x00, 0x15, 0x00, 0x00, 0x00,
0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x14, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x01, 0x00,
0x11, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0e, 0x00,
0x08, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00,
0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x14, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x01, 0x00,
0x1a, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x14, 0x00, 0x10, 0x00,
0x08, 0x00, 0x01, 0x00, 0x1b, 0x00, 0x00, 0x00,
0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x14, 0x00, 0x11, 0x00, 0x08, 0x00, 0x01, 0x00,
0x1c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x12, 0x00,
0x08, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x00, 0x00,
0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x00,
0x14, 0x00, 0x13, 0x00, 0x08, 0x00, 0x01, 0x00,
0x1e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
0x0a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x07, 0x00,
0x18, 0x00, 0x01, 0x00, 0x08, 0x00, 0x02, 0x00,
0x05, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x01, 0x00,
0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x9d, 0x2e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
0x1e, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x9d, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x05, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x09, 0x01, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
0x1e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x9d, 0x2e, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00,
0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x03, 0x00, 0x10, 0x00, 0x00, 0x00,
0x06, 0x00, 0x05, 0x00, 0x44, 0x00, 0x00, 0x00,
0x05, 0x00, 0x06, 0x00, 0x20, 0x00, 0x00, 0x00,
0x0b, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00,
0x93, 0xb9, 0x25, 0x00
};
#endif /* !_DUMMY_H */

View File

@ -7,6 +7,7 @@
eddsa_pk_to_EVP_PKEY;
es256_pk_free;
es256_pk_from_EC_KEY;
es256_pk_from_EVP_PKEY;
es256_pk_from_ptr;
es256_pk_new;
es256_pk_to_EVP_PKEY;
@ -30,6 +31,7 @@
fido_assert_rp_id;
fido_assert_set_authdata;
fido_assert_set_authdata_raw;
fido_assert_set_clientdata;
fido_assert_set_clientdata_hash;
fido_assert_set_count;
fido_assert_set_extensions;
@ -98,6 +100,8 @@
fido_cbor_info_transports_ptr;
fido_cbor_info_versions_len;
fido_cbor_info_versions_ptr;
fido_cred_attstmt_len;
fido_cred_attstmt_ptr;
fido_cred_authdata_len;
fido_cred_authdata_ptr;
fido_cred_authdata_raw_len;
@ -137,19 +141,23 @@
fido_credman_rp_new;
fido_credman_set_dev_rk;
fido_cred_new;
fido_cred_pin_minlen;
fido_cred_prot;
fido_cred_pubkey_len;
fido_cred_pubkey_ptr;
fido_cred_rp_id;
fido_cred_rp_name;
fido_cred_set_attstmt;
fido_cred_set_authdata;
fido_cred_set_authdata_raw;
fido_cred_set_blob;
fido_cred_set_clientdata;
fido_cred_set_clientdata_hash;
fido_cred_set_extensions;
fido_cred_set_fmt;
fido_cred_set_id;
fido_cred_set_options;
fido_cred_set_pin_minlen;
fido_cred_set_prot;
fido_cred_set_rk;
fido_cred_set_rp;
@ -205,6 +213,8 @@
fido_dev_set_io_functions;
fido_dev_set_pin;
fido_dev_set_pin_minlen;
fido_dev_set_pin_minlen_rpid;
fido_dev_set_timeout;
fido_dev_set_transport_functions;
fido_dev_supports_cred_prot;
fido_dev_supports_credman;
@ -230,10 +240,12 @@
fido_strerr;
rs256_pk_free;
rs256_pk_from_ptr;
rs256_pk_from_EVP_PKEY;
rs256_pk_from_RSA;
rs256_pk_new;
rs256_pk_to_EVP_PKEY;
prng_init;
fuzz_clock_reset;
set_netlink_io_functions;
set_udev_parameters;
uniform_random;

File diff suppressed because it is too large Load Diff

View File

@ -255,6 +255,7 @@ verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len,
int ext, void *pk)
{
fido_assert_t *assert = NULL;
int r;
if ((assert = fido_assert_new()) == NULL)
return;
@ -285,33 +286,52 @@ verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len,
}
fido_assert_set_sig(assert, 0, sig_ptr, sig_len);
assert(fido_assert_verify(assert, 0, type, pk) != FIDO_OK);
r = fido_assert_verify(assert, 0, type, pk);
consume(&r, sizeof(r));
fido_assert_free(&assert);
}
/*
* Do a dummy conversion to exercise rs256_pk_from_RSA().
* Do a dummy conversion to exercise es256_pk_from_EVP_PKEY().
*/
static void
es256_convert(const es256_pk_t *k)
{
EVP_PKEY *pkey = NULL;
es256_pk_t *pk = NULL;
int r;
if ((pkey = es256_pk_to_EVP_PKEY(k)) == NULL ||
(pk = es256_pk_new()) == NULL)
goto out;
r = es256_pk_from_EVP_PKEY(pk, pkey);
consume(&r, sizeof(r));
out:
es256_pk_free(&pk);
EVP_PKEY_free(pkey);
}
/*
* Do a dummy conversion to exercise rs256_pk_from_EVP_PKEY().
*/
static void
rs256_convert(const rs256_pk_t *k)
{
EVP_PKEY *pkey = NULL;
rs256_pk_t *pk = NULL;
RSA *rsa = NULL;
volatile int r;
int r;
if ((pkey = rs256_pk_to_EVP_PKEY(k)) == NULL ||
(pk = rs256_pk_new()) == NULL ||
(rsa = EVP_PKEY_get0_RSA(pkey)) == NULL)
(pk = rs256_pk_new()) == NULL)
goto out;
r = rs256_pk_from_RSA(pk, rsa);
r = rs256_pk_from_EVP_PKEY(pk, pkey);
consume(&r, sizeof(r));
out:
if (pk)
rs256_pk_free(&pk);
if (pkey)
EVP_PKEY_free(pkey);
rs256_pk_free(&pk);
EVP_PKEY_free(pkey);
}
/*
@ -322,13 +342,14 @@ eddsa_convert(const eddsa_pk_t *k)
{
EVP_PKEY *pkey = NULL;
eddsa_pk_t *pk = NULL;
volatile int r;
int r;
if ((pkey = eddsa_pk_to_EVP_PKEY(k)) == NULL ||
(pk = eddsa_pk_new()) == NULL)
goto out;
r = eddsa_pk_from_EVP_PKEY(pk, pkey);
consume(&r, sizeof(r));
out:
if (pk)
eddsa_pk_free(&pk);
@ -349,6 +370,7 @@ test(const struct param *p)
void *pk;
prng_init((unsigned int)p->seed);
fuzz_clock_reset();
fido_init(FIDO_DEBUG);
fido_set_log_handler(consume_str);
@ -362,6 +384,8 @@ test(const struct param *p)
es256_pk_from_ptr(es256_pk, p->es256.body, p->es256.len);
pk = es256_pk;
es256_convert(pk);
break;
case 1:
cose_alg = COSE_RS256;

View File

@ -408,6 +408,7 @@ void
test(const struct param *p)
{
prng_init((unsigned int)p->seed);
fuzz_clock_reset();
fido_init(FIDO_DEBUG);
fido_set_log_handler(consume_str);

View File

@ -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.
*/
@ -231,12 +231,15 @@ make_cred(fido_cred_t *cred, uint8_t opt, 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);
if (ext & FIDO_EXT_HMAC_SECRET)
fido_cred_set_extensions(cred, FIDO_EXT_HMAC_SECRET);
if (ext & FIDO_EXT_CRED_BLOB)
fido_cred_set_blob(cred, user_id->body, user_id->len);
if (ext & FIDO_EXT_LARGEBLOB_KEY)
fido_cred_set_extensions(cred, FIDO_EXT_LARGEBLOB_KEY);
if (ext & FIDO_EXT_MINPINLEN)
fido_cred_set_pin_minlen(cred, strlen(pin));
if (rk & 1)
fido_cred_set_rk(cred, FIDO_OPT_TRUE);
@ -268,11 +271,13 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len,
size_t authdata_len, const unsigned char *authdata_raw_ptr,
size_t authdata_raw_len, int ext, uint8_t rk, uint8_t uv,
const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr,
size_t sig_len, const char *fmt, int prot)
size_t sig_len, const unsigned char *attstmt_ptr, size_t attstmt_len,
const char *fmt, int prot, size_t minpinlen)
{
fido_cred_t *cred;
uint8_t flags;
uint32_t sigcount;
int r;
if ((cred = fido_cred_new()) == NULL)
return;
@ -282,13 +287,19 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len,
fido_cred_set_rp(cred, rp_id, rp_name);
consume(authdata_ptr, authdata_len);
consume(authdata_raw_ptr, authdata_raw_len);
consume(x5c_ptr, x5c_len);
consume(sig_ptr, sig_len);
consume(attstmt_ptr, attstmt_len);
if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK)
fido_cred_set_authdata_raw(cred, authdata_raw_ptr,
authdata_raw_len);
fido_cred_set_extensions(cred, ext);
fido_cred_set_x509(cred, x5c_ptr, x5c_len);
fido_cred_set_sig(cred, sig_ptr, sig_len);
if (fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len) != FIDO_OK) {
fido_cred_set_x509(cred, x5c_ptr, x5c_len);
fido_cred_set_sig(cred, sig_ptr, sig_len);
}
fido_cred_set_prot(cred, prot);
fido_cred_set_pin_minlen(cred, minpinlen);
if (rk & 1)
fido_cred_set_rk(cred, FIDO_OPT_TRUE);
@ -299,12 +310,19 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len,
/* repeat memory operations to trigger reallocation paths */
if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK)
fido_cred_set_authdata_raw(cred, authdata_ptr, authdata_len);
fido_cred_set_authdata_raw(cred, authdata_raw_ptr,
authdata_raw_len);
if (fido_cred_set_attstmt(cred, attstmt_ptr, attstmt_len) != FIDO_OK) {
fido_cred_set_x509(cred, x5c_ptr, x5c_len);
fido_cred_set_sig(cred, sig_ptr, sig_len);
}
fido_cred_set_x509(cred, x5c_ptr, x5c_len);
fido_cred_set_sig(cred, sig_ptr, sig_len);
assert(fido_cred_verify(cred) != FIDO_OK);
assert(fido_cred_verify_self(cred) != FIDO_OK);
r = fido_cred_verify(cred);
consume(&r, sizeof(r));
r = fido_cred_verify_self(cred);
consume(&r, sizeof(r));
consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred));
consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred));
@ -321,6 +339,8 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len,
consume(&sigcount, sizeof(sigcount));
type = fido_cred_type(cred);
consume(&type, sizeof(type));
minpinlen = fido_cred_pin_minlen(cred);
consume(&minpinlen, sizeof(minpinlen));
fido_cred_free(&cred);
}
@ -360,7 +380,9 @@ test_cred(const struct param *p)
fido_cred_authdata_raw_len(cred), p->ext, p->rk, p->uv,
fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred),
fido_cred_sig_ptr(cred), fido_cred_sig_len(cred),
fido_cred_fmt(cred), fido_cred_prot(cred));
fido_cred_attstmt_ptr(cred), fido_cred_attstmt_len(cred),
fido_cred_fmt(cred), fido_cred_prot(cred),
fido_cred_pin_minlen(cred));
fido_cred_free(&cred);
}
@ -408,6 +430,7 @@ void
test(const struct param *p)
{
prng_init((unsigned int)p->seed);
fuzz_clock_reset();
fido_init(FIDO_DEBUG);
fido_set_log_handler(consume_str);

View File

@ -374,6 +374,7 @@ void
test(const struct param *p)
{
prng_init((unsigned int)p->seed);
fuzz_clock_reset();
fido_init(FIDO_DEBUG);
fido_set_log_handler(consume_str);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Yubico AB. All rights reserved.
* Copyright (c) 2020-2021 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
@ -12,6 +12,7 @@
#include "../openbsd-compat/openbsd-compat.h"
#include "mutator_aux.h"
#include "dummy.h"
extern int fido_hid_get_usage(const uint8_t *, size_t, uint32_t *);
extern int fido_hid_get_report_len(const uint8_t *, size_t, size_t *, size_t *);
@ -21,6 +22,7 @@ struct param {
int seed;
char uevent[MAXSTR];
struct blob report_descriptor;
struct blob netlink_wiredata;
};
/*
@ -58,13 +60,14 @@ 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) != 3 ||
cbor_array_size(item) != 4 ||
(v = cbor_array_handle(item)) == NULL)
goto fail;
if (unpack_int(v[0], &p->seed) < 0 ||
unpack_string(v[1], p->uevent) < 0 ||
unpack_blob(v[2], &p->report_descriptor) < 0)
unpack_blob(v[2], &p->report_descriptor) < 0 ||
unpack_blob(v[3], &p->netlink_wiredata) < 0)
goto fail;
ok = 0;
@ -83,19 +86,20 @@ unpack(const uint8_t *ptr, size_t len)
size_t
pack(uint8_t *ptr, size_t len, const struct param *p)
{
cbor_item_t *argv[3], *array = NULL;
cbor_item_t *argv[4], *array = NULL;
size_t cbor_alloc_len, cbor_len = 0;
unsigned char *cbor = NULL;
memset(argv, 0, sizeof(argv));
if ((array = cbor_new_definite_array(3)) == NULL ||
if ((array = cbor_new_definite_array(4)) == NULL ||
(argv[0] = pack_int(p->seed)) == NULL ||
(argv[1] = pack_string(p->uevent)) == NULL ||
(argv[2] = pack_blob(&p->report_descriptor)) == NULL)
(argv[2] = pack_blob(&p->report_descriptor)) == NULL ||
(argv[3] = pack_blob(&p->netlink_wiredata)) == NULL)
goto fail;
for (size_t i = 0; i < 3; i++)
for (size_t i = 0; i < 4; i++)
if (cbor_array_push(array, argv[i]) == false)
goto fail;
@ -107,7 +111,7 @@ pack(uint8_t *ptr, size_t len, const struct param *p)
memcpy(ptr, cbor, cbor_len);
fail:
for (size_t i = 0; i < 3; i++)
for (size_t i = 0; i < 4; i++)
if (argv[i])
cbor_decref(&argv[i]);
@ -132,6 +136,9 @@ pack_dummy(uint8_t *ptr, size_t len)
strlcpy(dummy.uevent, dummy_uevent, sizeof(dummy.uevent));
memcpy(&dummy.report_descriptor.body, &dummy_report_descriptor,
dummy.report_descriptor.len);
dummy.netlink_wiredata.len = sizeof(dummy_netlink_wiredata);
memcpy(&dummy.netlink_wiredata.body, &dummy_netlink_wiredata,
dummy.netlink_wiredata.len);
assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
if (blob_len > len)
@ -171,7 +178,10 @@ manifest(const struct param *p)
fido_dev_info_t *devlist;
int16_t vendor_id, product_id;
set_netlink_io_functions(fd_read, fd_write);
set_wire_data(p->netlink_wiredata.body, p->netlink_wiredata.len);
set_udev_parameters(p->uevent, &p->report_descriptor);
ndevs = uniform_random(64);
if ((devlist = fido_dev_info_new(ndevs)) == NULL ||
fido_dev_info_manifest(devlist, ndevs, &nfound) != FIDO_OK)
@ -194,6 +204,7 @@ void
test(const struct param *p)
{
prng_init((unsigned int)p->seed);
fuzz_clock_reset();
fido_init(FIDO_DEBUG);
fido_set_log_handler(consume_str);
@ -212,4 +223,7 @@ mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
mutate_blob(&p->report_descriptor);
mutate_string(p->uevent);
}
if (flags & MUTATE_WIREDATA)
mutate_blob(&p->netlink_wiredata);
}

View File

@ -242,6 +242,7 @@ void
test(const struct param *p)
{
prng_init((unsigned int)p->seed);
fuzz_clock_reset();
fido_init(FIDO_DEBUG);
fido_set_log_handler(consume_str);

View File

@ -16,6 +16,8 @@
#include "../openbsd-compat/openbsd-compat.h"
#define MAXRPID 64
struct param {
char pin1[MAXSTR];
char pin2[MAXSTR];
@ -440,10 +442,35 @@ dev_set_pin_minlen(const struct param *p)
fido_dev_free(&dev);
}
static void
dev_set_pin_minlen_rpid(const struct param *p)
{
fido_dev_t *dev;
const char *rpid[MAXRPID];
const char *pin;
size_t n;
int r;
set_wire_data(p->config_wire_data.body, p->config_wire_data.len);
if ((dev = open_dev(0)) == NULL)
return;
n = uniform_random(MAXRPID);
for (size_t i = 0; i < n; i++)
rpid[i] = dummy_rp_id;
pin = p->pin1;
if (strlen(pin) == 0)
pin = NULL;
r = fido_dev_set_pin_minlen_rpid(dev, rpid, n, pin);
consume_str(fido_strerr(r));
fido_dev_close(dev);
fido_dev_free(&dev);
}
void
test(const struct param *p)
{
prng_init((unsigned int)p->seed);
fuzz_clock_reset();
fido_init(FIDO_DEBUG);
fido_set_log_handler(consume_str);
@ -457,6 +484,7 @@ test(const struct param *p)
dev_toggle_always_uv(p);
dev_force_pin_change(p);
dev_set_pin_minlen(p);
dev_set_pin_minlen_rpid(p);
}
void

View File

@ -12,6 +12,7 @@
#include "../openbsd-compat/openbsd-compat.h"
#include "mutator_aux.h"
#include "dummy.h"
struct param {
int seed;
@ -19,94 +20,6 @@ struct param {
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)
{
@ -190,8 +103,8 @@ pack_dummy(uint8_t *ptr, size_t len)
memset(&dummy, 0, sizeof(dummy));
dummy.wiredata.len = sizeof(sample_netlink_wiredata);
memcpy(&dummy.wiredata.body, &sample_netlink_wiredata,
dummy.wiredata.len = sizeof(dummy_netlink_wiredata);
memcpy(&dummy.wiredata.body, &dummy_netlink_wiredata,
dummy.wiredata.len);
assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
@ -213,6 +126,7 @@ test(const struct param *p)
uint32_t target;
prng_init((unsigned int)p->seed);
fuzz_clock_reset();
fido_init(FIDO_DEBUG);
fido_set_log_handler(consume_str);

View File

@ -37,6 +37,8 @@ consume(const void *body, size_t len)
while (len--)
x ^= *ptr++;
(void)x;
}
void
@ -308,7 +310,8 @@ open_dev(int nfc)
goto fail;
}
if (fido_dev_open(dev, "nodev") != FIDO_OK)
if (fido_dev_set_timeout(dev, 300) != FIDO_OK ||
fido_dev_open(dev, "nodev") != FIDO_OK)
goto fail;
return dev;

View File

@ -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.
*/
@ -49,7 +49,7 @@
#define MUTATE_ALL (MUTATE_SEED | MUTATE_PARAM | MUTATE_WIREDATA)
#define MAXSTR 1024
#define MAXBLOB 3072
#define MAXBLOB 3600
struct blob {
uint8_t body[MAXBLOB];
@ -88,6 +88,7 @@ ssize_t fd_write(int, const void *, size_t);
fido_dev_t *open_dev(int);
void set_wire_data(const uint8_t *, size_t);
void fuzz_clock_reset(void);
void prng_init(unsigned long);
unsigned long prng_uint32(void);

Binary file not shown.

View File

@ -1,51 +1,57 @@
Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
fuzz/prng.c 31 0 100.00% 2 0 100.00% 49 0 100.00%
fuzz/udev.c 103 5 95.15% 17 1 94.12% 141 7 95.04%
fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 23 1 95.65%
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
fuzz/clock.c 24 1 95.83% 4 0 100.00% 35 0 100.00%
fuzz/prng.c 31 0 100.00% 2 0 100.00% 35 0 100.00%
fuzz/udev.c 103 1 99.03% 17 0 100.00% 126 3 97.62%
fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 12 1 91.67%
fuzz/wrap.c 6 0 100.00% 1 0 100.00% 7 0 100.00%
openbsd-compat/explicit_bzero.c 4 0 100.00% 1 0 100.00% 13 0 100.00%
openbsd-compat/explicit_bzero.c 4 0 100.00% 1 0 100.00% 7 0 100.00%
openbsd-compat/freezero.c 4 0 100.00% 1 0 100.00% 6 0 100.00%
openbsd-compat/recallocarray.c 41 7 82.93% 1 0 100.00% 49 7 85.71%
openbsd-compat/strlcat.c 12 1 91.67% 1 0 100.00% 25 1 96.00%
openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 8 0 100.00%
src/aes256.c 115 4 96.52% 8 0 100.00% 175 14 92.00%
src/assert.c 616 46 92.53% 59 3 94.92% 924 64 93.07%
src/authkey.c 44 0 100.00% 5 0 100.00% 75 0 100.00%
src/bio.c 419 20 95.23% 49 2 95.92% 660 22 96.67%
src/blob.c 53 3 94.34% 10 0 100.00% 96 7 92.71%
src/buf.c 8 1 87.50% 2 0 100.00% 20 1 95.00%
src/cbor.c 986 17 98.28% 53 0 100.00% 1426 37 97.41%
src/compress.c 34 4 88.24% 3 0 100.00% 30 3 90.00%
src/config.c 94 1 98.94% 10 0 100.00% 146 3 97.95%
src/cred.c 581 38 93.46% 63 2 96.83% 872 48 94.50%
src/credman.c 382 10 97.38% 40 0 100.00% 614 15 97.56%
src/dev.c 414 74 82.13% 43 6 86.05% 556 106 80.94%
src/ecdh.c 117 2 98.29% 4 0 100.00% 161 5 96.89%
src/eddsa.c 54 0 100.00% 8 0 100.00% 77 0 100.00%
openbsd-compat/recallocarray.c 41 7 82.93% 1 0 100.00% 36 7 80.56%
openbsd-compat/strlcat.c 12 1 91.67% 1 0 100.00% 21 1 95.24%
openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 7 0 100.00%
src/aes256.c 115 4 96.52% 8 0 100.00% 157 14 91.08%
src/assert.c 563 40 92.90% 56 3 94.64% 694 40 94.24%
src/authkey.c 44 0 100.00% 5 0 100.00% 59 0 100.00%
src/bio.c 419 20 95.23% 49 2 95.92% 559 21 96.24%
src/blob.c 53 2 96.23% 10 0 100.00% 83 4 95.18%
src/buf.c 8 1 87.50% 2 0 100.00% 16 1 93.75%
src/cbor.c 1047 28 97.33% 54 0 100.00% 1237 54 95.63%
src/compress.c 34 4 88.24% 3 0 100.00% 28 3 89.29%
src/config.c 108 0 100.00% 11 0 100.00% 151 0 100.00%
src/cred.c 632 34 94.62% 69 2 97.10% 830 36 95.66%
src/credman.c 382 10 97.38% 40 0 100.00% 518 15 97.10%
src/dev.c 420 78 81.43% 44 6 86.36% 488 102 79.10%
src/ecdh.c 117 2 98.29% 4 0 100.00% 146 5 96.58%
src/eddsa.c 80 3 96.25% 10 0 100.00% 106 8 92.45%
src/err.c 122 10 91.80% 1 0 100.00% 126 10 92.06%
src/es256.c 280 0 100.00% 16 0 100.00% 394 0 100.00%
src/hid.c 60 0 100.00% 12 0 100.00% 134 0 100.00%
src/hid_linux.c 173 68 60.69% 14 7 50.00% 303 123 59.41%
src/hid_unix.c 30 20 33.33% 2 0 100.00% 52 28 46.15%
src/info.c 198 0 100.00% 44 0 100.00% 405 0 100.00%
src/io.c 158 7 95.57% 10 0 100.00% 228 11 95.18%
src/iso7816.c 18 1 94.44% 5 0 100.00% 42 0 100.00%
src/largeblob.c 513 19 96.30% 30 0 100.00% 759 43 94.33%
src/log.c 39 5 87.18% 7 1 85.71% 73 4 94.52%
src/netlink.c 327 15 95.41% 40 0 100.00% 565 35 93.81%
src/nfc_linux.c 304 123 59.54% 23 10 56.52% 520 199 61.73%
src/pin.c 403 3 99.26% 26 0 100.00% 583 3 99.49%
src/random.c 6 1 83.33% 1 0 100.00% 8 1 87.50%
src/reset.c 24 0 100.00% 3 0 100.00% 27 0 100.00%
src/rs256.c 102 4 96.08% 8 0 100.00% 138 6 95.65%
src/u2f.c 473 6 98.73% 15 0 100.00% 742 9 98.79%
src/es256.c 306 5 98.37% 19 0 100.00% 358 7 98.04%
src/hid.c 60 0 100.00% 12 0 100.00% 114 0 100.00%
src/hid_linux.c 173 68 60.69% 14 7 50.00% 250 104 58.40%
src/hid_unix.c 28 20 28.57% 2 0 100.00% 43 24 44.19%
src/info.c 184 0 100.00% 39 0 100.00% 316 0 100.00%
src/io.c 182 7 96.15% 13 0 100.00% 221 11 95.02%
src/iso7816.c 18 1 94.44% 5 0 100.00% 38 0 100.00%
src/largeblob.c 513 21 95.91% 30 0 100.00% 684 47 93.13%
src/log.c 39 5 87.18% 7 1 85.71% 63 4 93.65%
src/netlink.c 328 14 95.73% 40 0 100.00% 498 32 93.57%
src/nfc_linux.c 327 73 77.68% 23 5 78.26% 458 124 72.93%
src/pin.c 403 3 99.26% 26 0 100.00% 495 3 99.39%
src/random.c 6 1 83.33% 1 0 100.00% 6 1 83.33%
src/reset.c 24 0 100.00% 3 0 100.00% 23 0 100.00%
src/rs1.c 25 1 96.00% 3 0 100.00% 39 3 92.31%
src/rs256.c 141 8 94.33% 13 0 100.00% 172 10 94.19%
src/time.c 43 3 93.02% 3 0 100.00% 43 1 97.67%
src/tpm.c 76 0 100.00% 7 0 100.00% 138 0 100.00%
src/types.c 25 0 100.00% 6 0 100.00% 46 0 100.00%
src/u2f.c 528 4 99.24% 17 0 100.00% 685 12 98.25%
Files which contain no functions:
openbsd-compat/openbsd-compat.h 0 0 - 0 0 - 0 0 -
openbsd-compat/time.h 0 0 - 0 0 - 0 0 -
src/extern.h 0 0 - 0 0 - 0 0 -
src/fido.h 0 0 - 0 0 - 0 0 -
src/fido/err.h 0 0 - 0 0 - 0 0 -
src/fido/param.h 0 0 - 0 0 - 0 0 -
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
TOTAL 7359 516 92.99% 640 32 95.00% 11252 813 92.77%
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
TOTAL 7809 481 93.84% 679 26 96.17% 10180 708 93.05%

View File

@ -4,6 +4,9 @@
* license that can be found in the LICENSE file.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
@ -50,6 +53,14 @@ WRAP(void *,
1
)
WRAP(void *,
realloc,
(void *ptr, size_t size),
NULL,
(ptr, size),
1
)
WRAP(char *,
strdup,
(const char *s),
@ -83,32 +94,6 @@ WRAP(EVP_CIPHER_CTX *,
1
)
WRAP(int,
EVP_EncryptInit_ex,
(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl,
const unsigned char *key, const unsigned char *iv),
0,
(ctx, type, impl, key, iv),
1
)
WRAP(int,
EVP_CIPHER_CTX_set_padding,
(EVP_CIPHER_CTX *x, int padding),
0,
(x, padding),
1
)
WRAP(int,
EVP_EncryptUpdate,
(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
const unsigned char *in, int inl),
0,
(ctx, out, outl, in, inl),
1
)
WRAP(int,
EVP_CipherInit,
(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
@ -118,48 +103,6 @@ WRAP(int,
1
)
WRAP(int,
EVP_DecryptInit_ex,
(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl,
const unsigned char *key, const unsigned char *iv),
0,
(ctx, type, impl, key, iv),
1
)
WRAP(int,
EVP_DecryptUpdate,
(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
const unsigned char *in, int inl),
0,
(ctx, out, outl, in, inl),
1
)
WRAP(int,
SHA256_Init,
(SHA256_CTX *c),
0,
(c),
1
)
WRAP(int,
SHA256_Update,
(SHA256_CTX *c, const void *data, size_t len),
0,
(c, data, len),
1
)
WRAP(int,
SHA256_Final,
(unsigned char *md, SHA256_CTX *c),
0,
(md, c),
1
)
WRAP(RSA *,
EVP_PKEY_get0_RSA,
(EVP_PKEY *pkey),
@ -201,6 +144,30 @@ WRAP(int,
1
)
WRAP(int,
EVP_DigestInit_ex,
(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl),
0,
(ctx, type, impl),
1
)
WRAP(int,
EVP_DigestUpdate,
(EVP_MD_CTX *ctx, const void *data, size_t count),
0,
(ctx, data, count),
1
)
WRAP(int,
EVP_DigestFinal_ex,
(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *isize),
0,
(ctx, md, isize),
1
)
WRAP(BIGNUM *,
BN_bin2bn,
(const unsigned char *s, int len, BIGNUM *ret),
@ -241,6 +208,14 @@ WRAP(BIGNUM *,
1
)
WRAP(RSA *,
RSA_new,
(void),
NULL,
(),
1
)
WRAP(int,
RSA_set0_key,
(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d),
@ -249,6 +224,14 @@ WRAP(int,
1
)
WRAP(int,
RSA_pkey_ctx_ctrl,
(EVP_PKEY_CTX *ctx, int optype, int cmd, int p1, void *p2),
-1,
(ctx, optype, cmd, p1, p2),
1
)
WRAP(EC_KEY *,
EC_KEY_new_by_curve_name,
(int nid),
@ -385,6 +368,30 @@ WRAP(int,
1
)
WRAP(int,
EVP_PKEY_verify_init,
(EVP_PKEY_CTX *ctx),
0,
(ctx),
1
)
WRAP(int,
EVP_PKEY_CTX_ctrl,
(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd, int p1, void *p2),
-1,
(ctx, keytype, optype, cmd, p1, p2),
1
)
WRAP(const EVP_MD *,
EVP_sha1,
(void),
NULL,
(),
1
)
WRAP(const EVP_MD *,
EVP_sha256,
(void),
@ -393,6 +400,22 @@ WRAP(const EVP_MD *,
1
)
WRAP(const EVP_CIPHER *,
EVP_aes_256_cbc,
(void),
NULL,
(),
1
)
WRAP(const EVP_CIPHER *,
EVP_aes_256_gcm,
(void),
NULL,
(),
1
)
WRAP(unsigned char *,
HMAC,
(const EVP_MD *evp_md, const void *key, int key_len,
@ -436,6 +459,14 @@ WRAP(int,
1
)
WRAP(unsigned char *,
SHA1,
(const unsigned char *d, size_t n, unsigned char *md),
NULL,
(d, n, md),
1
)
WRAP(unsigned char *,
SHA256,
(const unsigned char *d, size_t n, unsigned char *md),
@ -500,6 +531,14 @@ WRAP(cbor_item_t *,
1
)
WRAP(cbor_item_t *,
cbor_build_uint16,
(uint16_t value),
NULL,
(value),
1
)
WRAP(cbor_item_t *,
cbor_build_uint32,
(uint32_t value),
@ -508,6 +547,14 @@ WRAP(cbor_item_t *,
1
)
WRAP(cbor_item_t *,
cbor_build_uint64,
(uint64_t value),
NULL,
(value),
1
)
WRAP(struct cbor_pair *,
cbor_map_handle,
(const cbor_item_t *item),
@ -556,6 +603,14 @@ WRAP(cbor_item_t *,
1
)
WRAP(cbor_item_t *,
cbor_new_definite_bytestring,
(void),
NULL,
(),
1
)
WRAP(size_t,
cbor_serialize_alloc,
(const cbor_item_t *item, cbor_mutable_data *buffer,
@ -567,16 +622,16 @@ WRAP(size_t,
WRAP(int,
fido_tx,
(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count),
(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count, int *ms),
-1,
(d, cmd, buf, count),
(d, cmd, buf, count, ms),
1
)
WRAP(int,
usleep,
(unsigned int usec),
bind,
(int sockfd, const struct sockaddr *addr, socklen_t addrlen),
-1,
(usec),
(sockfd, addr, addrlen),
1
)

View File

@ -1,3 +1,4 @@
bind
BN_bin2bn
BN_bn2bin
BN_CTX_get
@ -11,31 +12,36 @@ cbor_build_bytestring
cbor_build_negint16
cbor_build_negint8
cbor_build_string
cbor_build_uint16
cbor_build_uint32
cbor_build_uint64
cbor_build_uint8
cbor_load
cbor_map_add
cbor_map_handle
cbor_new_definite_array
cbor_new_definite_bytestring
cbor_new_definite_map
cbor_serialize_alloc
clock_gettime
EC_KEY_get0_group
EC_KEY_get0_private_key
EC_KEY_new_by_curve_name
EC_POINT_get_affine_coordinates_GFp
EC_POINT_new
EVP_aes_256_cbc
EVP_aes_256_gcm
EVP_Cipher
EVP_CIPHER_CTX_ctrl
EVP_CIPHER_CTX_new
EVP_CIPHER_CTX_set_padding
EVP_CipherInit
EVP_DecryptInit_ex
EVP_DecryptUpdate
EVP_DigestFinal_ex
EVP_DigestInit_ex
EVP_DigestUpdate
EVP_DigestVerifyInit
EVP_EncryptInit_ex
EVP_EncryptUpdate
EVP_MD_CTX_new
EVP_PKEY_assign
EVP_PKEY_CTX_ctrl
EVP_PKEY_CTX_new
EVP_PKEY_CTX_new_id
EVP_PKEY_derive
@ -50,6 +56,8 @@ EVP_PKEY_new
EVP_PKEY_new_raw_public_key
EVP_PKEY_paramgen
EVP_PKEY_paramgen_init
EVP_PKEY_verify_init
EVP_sha1
EVP_sha256
fido_tx
HMAC
@ -59,11 +67,12 @@ HMAC_Init_ex
HMAC_Update
ioctl
malloc
realloc
RSA_new
RSA_pkey_ctx_ctrl
RSA_set0_key
SHA1
SHA256
SHA256_Final
SHA256_Init
SHA256_Update
strdup
udev_device_get_devnode
udev_device_get_parent_with_subsystem_devtype

View File

@ -48,6 +48,7 @@ list(APPEND MAN_ALIAS
eddsa_pk_new eddsa_pk_to_EVP_PKEY
es256_pk_new es256_pk_free
es256_pk_new es256_pk_from_EC_KEY
es256_pk_new es256_pk_from_EVP_PKEY
es256_pk_new es256_pk_from_ptr
es256_pk_new es256_pk_to_EVP_PKEY
fido_assert_new fido_assert_authdata_len
@ -129,6 +130,10 @@ list(APPEND MAN_ALIAS
fido_cbor_info_new fido_cbor_info_versions_len
fido_cbor_info_new fido_cbor_info_versions_ptr
fido_cbor_info_new fido_dev_get_cbor_info
fido_cred_new fido_cred_aaguid_len
fido_cred_new fido_cred_aaguid_ptr
fido_cred_new fido_cred_attstmt_len
fido_cred_new fido_cred_attstmt_ptr
fido_cred_new fido_cred_authdata_len
fido_cred_new fido_cred_authdata_ptr
fido_cred_new fido_cred_authdata_raw_len
@ -137,26 +142,25 @@ list(APPEND MAN_ALIAS
fido_cred_new fido_cred_clientdata_hash_ptr
fido_cred_new fido_cred_display_name
fido_cred_new fido_cred_flags
fido_cred_new fido_cred_sigcount
fido_cred_new fido_cred_fmt
fido_cred_new fido_cred_free
fido_cred_new fido_cred_id_len
fido_cred_new fido_cred_id_ptr
fido_cred_new fido_cred_aaguid_len
fido_cred_new fido_cred_aaguid_ptr
fido_cred_new fido_cred_largeblob_key_len
fido_cred_new fido_cred_largeblob_key_ptr
fido_cred_new fido_cred_pin_minlen
fido_cred_new fido_cred_prot
fido_cred_new fido_cred_pubkey_len
fido_cred_new fido_cred_pubkey_ptr
fido_cred_new fido_cred_rp_id
fido_cred_new fido_cred_rp_name
fido_cred_new fido_cred_sigcount
fido_cred_new fido_cred_sig_len
fido_cred_new fido_cred_sig_ptr
fido_cred_new fido_cred_type
fido_cred_new fido_cred_user_name
fido_cred_new fido_cred_user_id_len
fido_cred_new fido_cred_user_id_ptr
fido_cred_new fido_cred_user_name
fido_cred_new fido_cred_x5c_len
fido_cred_new fido_cred_x5c_ptr
fido_credman_metadata_new fido_credman_del_dev_rk
@ -178,6 +182,7 @@ list(APPEND MAN_ALIAS
fido_credman_metadata_new fido_credman_rp_name
fido_credman_metadata_new fido_credman_rp_new
fido_credman_metadata_new fido_credman_set_dev_rk
fido_cred_set_authdata fido_cred_set_attstmt
fido_cred_set_authdata fido_cred_set_authdata_raw
fido_cred_set_authdata fido_cred_set_blob
fido_cred_set_authdata fido_cred_set_clientdata
@ -185,6 +190,7 @@ list(APPEND MAN_ALIAS
fido_cred_set_authdata fido_cred_set_extensions
fido_cred_set_authdata fido_cred_set_fmt
fido_cred_set_authdata fido_cred_set_id
fido_cred_set_authdata fido_cred_set_pin_minlen
fido_cred_set_authdata fido_cred_set_prot
fido_cred_set_authdata fido_cred_set_rk
fido_cred_set_authdata fido_cred_set_rp
@ -196,6 +202,7 @@ list(APPEND MAN_ALIAS
fido_dev_enable_entattest fido_dev_toggle_always_uv
fido_dev_enable_entattest fido_dev_force_pin_change
fido_dev_enable_entattest fido_dev_set_pin_minlen
fido_dev_enable_entattest fido_dev_set_pin_minlen_rpid
fido_dev_get_touch_begin fido_dev_get_touch_status
fido_dev_info_manifest fido_dev_info_free
fido_dev_info_manifest fido_dev_info_manufacturer_string
@ -227,12 +234,14 @@ list(APPEND MAN_ALIAS
fido_dev_set_pin fido_dev_get_uv_retry_count
fido_dev_set_pin fido_dev_reset
fido_dev_set_io_functions fido_dev_set_sigmask
fido_dev_set_io_functions fido_dev_set_timeout
fido_dev_largeblob_get fido_dev_largeblob_set
fido_dev_largeblob_get fido_dev_largeblob_remove
fido_dev_largeblob_get fido_dev_largeblob_get_array
fido_dev_largeblob_get fido_dev_largeblob_set_array
rs256_pk_new rs256_pk_free
rs256_pk_new rs256_pk_from_ptr
rs256_pk_new rs256_pk_from_EVP_PKEY
rs256_pk_new rs256_pk_from_RSA
rs256_pk_new rs256_pk_to_EVP_PKEY
)

View File

@ -1,4 +1,4 @@
.\" 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.
.\"
@ -9,6 +9,7 @@
.Nm es256_pk_new ,
.Nm es256_pk_free ,
.Nm es256_pk_from_EC_KEY ,
.Nm es256_pk_from_EVP_KEY ,
.Nm es256_pk_from_ptr ,
.Nm es256_pk_to_EVP_PKEY
.Nd FIDO 2 COSE ES256 API
@ -22,6 +23,8 @@
.Ft int
.Fn es256_pk_from_EC_KEY "es256_pk_t *pk" "const EC_KEY *ec"
.Ft int
.Fn es256_pk_from_EVP_PKEY "es256_pk_t *pk" "const EVP_PKEY *pkey"
.Ft int
.Fn es256_pk_from_ptr "es256_pk_t *pk" "const void *ptr" "size_t len"
.Ft EVP_PKEY *
.Fn es256_pk_to_EVP_PKEY "const es256_pk_t *pk"
@ -79,6 +82,16 @@ No references to
are kept.
.Pp
The
.Fn es256_pk_from_EVP_KEY
function fills
.Fa pk
with the contents of
.Fa pkey .
No references to
.Fa pkey
are kept.
.Pp
The
.Fn es256_pk_from_ptr
function fills
.Fa pk
@ -110,7 +123,8 @@ If an error occurs,
returns NULL.
.Sh RETURN VALUES
The
.Fn es256_pk_from_EC_KEY
.Fn es256_pk_from_EC_KEY ,
.Fn es256_pk_from_EVP_KEY ,
and
.Fn es256_pk_from_ptr
functions return

View File

@ -82,6 +82,7 @@
.Op Fl d
.Fl i Ar template_id
.Fl n Ar template_name
.Ar device
.Nm
.Fl S
.Op Fl d
@ -112,6 +113,11 @@
.Fl p Ar display_name
.Ar device
.Nm
.Fl S
.Fl m
.Ar rp_id
.Ar device
.Nm
.Fl V
.Sh DESCRIPTION
.Nm
@ -340,6 +346,12 @@ Sets the minimum PIN length of
to
.Ar pin_length .
The user will be prompted for the PIN.
.It Fl S Fl m Ar rp_id Ar device
Sets the list of relying party IDs that are allowed to retrieve
the minimum PIN length of
.Ar device .
Multiple IDs may be specified, separated by commas.
The user will be prompted for the PIN.
.It Fl S Fl u Ar device
Enables the FIDO 2.1
.Dq user verification always

View File

@ -1,4 +1,4 @@
.\" 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.
.\"
@ -8,6 +8,7 @@
.Sh NAME
.Nm fido_cred_new ,
.Nm fido_cred_free ,
.Nm fido_cred_pin_minlen ,
.Nm fido_cred_prot ,
.Nm fido_cred_fmt ,
.Nm fido_cred_rp_id ,
@ -24,6 +25,7 @@
.Nm fido_cred_sig_ptr ,
.Nm fido_cred_user_id_ptr ,
.Nm fido_cred_x5c_ptr ,
.Nm fido_cred_attstmt_ptr ,
.Nm fido_cred_authdata_len ,
.Nm fido_cred_authdata_raw_len ,
.Nm fido_cred_clientdata_hash_len ,
@ -34,6 +36,7 @@
.Nm fido_cred_sig_len ,
.Nm fido_cred_user_id_len ,
.Nm fido_cred_x5c_len ,
.Nm fido_cred_attstmt_len ,
.Nm fido_cred_type ,
.Nm fido_cred_flags ,
.Nm fido_cred_sigcount
@ -44,8 +47,10 @@
.Fn fido_cred_new "void"
.Ft void
.Fn fido_cred_free "fido_cred_t **cred_p"
.Ft size_t
.Fn fido_cred_pin_minlen "const fido_cred_t *cred"
.Ft int
.Fn fido_cred_prot "fido_cred_t *cred"
.Fn fido_cred_prot "const fido_cred_t *cred"
.Ft const char *
.Fn fido_cred_fmt "const fido_cred_t *cred"
.Ft const char *
@ -76,6 +81,8 @@
.Fn fido_cred_user_id_ptr "const fido_cred_t *cred"
.Ft const unsigned char *
.Fn fido_cred_x5c_ptr "const fido_cred_t *cred"
.Ft const unsigned char *
.Fn fido_cred_attstmt_ptr "const fido_cred_t *cred"
.Ft size_t
.Fn fido_cred_authdata_len "const fido_cred_t *cred"
.Ft size_t
@ -96,6 +103,8 @@
.Fn fido_cred_user_id_len "const fido_cred_t *cred"
.Ft size_t
.Fn fido_cred_x5c_len "const fido_cred_t *cred"
.Ft size_t
.Fn fido_cred_attstmt_len "const fido_cred_t *cred"
.Ft int
.Fn fido_cred_type "const fido_cred_t *cred"
.Ft uint8_t
@ -146,13 +155,35 @@ may be NULL, in which case
.Fn fido_cred_free
is a NOP.
.Pp
The
If the FIDO 2.1
.Dv FIDO_EXT_MINPINLEN
extension is enabled on
.Fa cred ,
then the
.Fn fido_cred_pin_minlen
function returns the minimum PIN length of
.Fa cred .
Otherwise,
.Fn fido_cred_pin_minlen
returns zero.
See
.Xr fido_cred_set_pin_minlen 3
on how to enable this extension.
.Pp
If the FIDO 2.1
.Dv FIDO_EXT_CRED_PROTECT
extension is enabled on
.Fa cred ,
then the
.Fn fido_cred_prot
function returns the protection of
.Fa cred .
Otherwise,
.Fn fido_cred_prot
returns zero.
See
.Xr fido_cred_set_prot 3
for the values understood by
for the protection policies understood by
.Em libfido2 .
.Pp
The
@ -186,12 +217,14 @@ The
.Fn fido_cred_pubkey_ptr ,
.Fn fido_cred_sig_ptr ,
.Fn fido_cred_user_id_ptr ,
.Fn fido_cred_x5c_ptr ,
and
.Fn fido_cred_x5c_ptr
.Fn fido_cred_attstmt_ptr
functions return pointers to the CBOR-encoded and raw authenticator
data, client data hash, ID, authenticator attestation GUID,
.Dq largeBlobKey ,
public key, signature, user ID, and x509 certificate parts of
public key, signature, user ID, x509 certificate, and attestation
statement parts of
.Fa cred ,
or NULL if the respective entry is not set.
.Pp
@ -205,8 +238,9 @@ The corresponding length can be obtained by
.Fn fido_cred_pubkey_len ,
.Fn fido_cred_sig_len ,
.Fn fido_cred_user_id_len ,
.Fn fido_cred_x5c_len ,
and
.Fn fido_cred_x5c_len .
.Fn fido_cred_attstmt_len .
.Pp
The authenticator data, x509 certificate, and signature parts of a
credential are typically passed to a FIDO 2 server for verification.
@ -251,6 +285,8 @@ qualifier is invoked.
.Sh SEE ALSO
.Xr fido_cred_exclude 3 ,
.Xr fido_cred_set_authdata 3 ,
.Xr fido_cred_set_pin_minlen 3 ,
.Xr fido_cred_set_prot 3 ,
.Xr fido_cred_verify 3 ,
.Xr fido_credman_metadata_new 3 ,
.Xr fido_dev_largeblob_get 3 ,

View File

@ -1,4 +1,4 @@
.\" 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.
.\"
@ -8,6 +8,7 @@
.Sh NAME
.Nm fido_cred_set_authdata ,
.Nm fido_cred_set_authdata_raw ,
.Nm fido_cred_set_attstmt ,
.Nm fido_cred_set_x509 ,
.Nm fido_cred_set_sig ,
.Nm fido_cred_set_id ,
@ -17,6 +18,7 @@
.Nm fido_cred_set_user ,
.Nm fido_cred_set_extensions ,
.Nm fido_cred_set_blob ,
.Nm fido_cred_set_pin_minlen ,
.Nm fido_cred_set_prot ,
.Nm fido_cred_set_rk ,
.Nm fido_cred_set_uv ,
@ -37,6 +39,8 @@ typedef enum {
.Ft int
.Fn fido_cred_set_authdata_raw "fido_cred_t *cred" "const unsigned char *ptr" "size_t len"
.Ft int
.Fn fido_cred_set_attstmt "fido_cred_t *cred" "const unsigned char *ptr" "size_t len"
.Ft int
.Fn fido_cred_set_x509 "fido_cred_t *cred" "const unsigned char *ptr" "size_t len"
.Ft int
.Fn fido_cred_set_sig "fido_cred_t *cred" "const unsigned char *ptr" "size_t len"
@ -55,6 +59,8 @@ typedef enum {
.Ft int
.Fn fido_cred_set_blob "fido_cred_t *cred" "const unsigned char *ptr" "size_t len"
.Ft int
.Fn fido_cred_set_pin_minlen "fido_cred_t *cred" "size_t len"
.Ft int
.Fn fido_cred_set_prot "fido_cred_t *cred" "int prot"
.Ft int
.Fn fido_cred_set_rk "fido_cred_t *cred" "fido_opt_t rk"
@ -80,13 +86,15 @@ of its constituent parts, please refer to the Web Authentication
.Pp
The
.Fn fido_cred_set_authdata ,
.Fn fido_cred_set_attstmt ,
.Fn fido_cred_set_x509 ,
.Fn fido_cred_set_sig ,
.Fn fido_cred_set_id ,
and
.Fn fido_cred_set_clientdata_hash
functions set the authenticator data, attestation certificate,
signature, id, and client data hash parts of
functions set the authenticator data, attestation statement,
attestation certificate, attestation signature, id, and client
data hash parts of
.Fa cred
to
.Fa ptr ,
@ -98,13 +106,13 @@ bytes.
A copy of
.Fa ptr
is made, and no references to the passed pointer are kept.
.Pp
The authenticator data passed to
.Fn fido_cred_set_authdata
must be a CBOR-encoded byte string, as obtained from
.Fn fido_cred_authdata_ptr .
Alternatively, a raw binary blob may be passed to
.Fn fido_cred_set_authdata_raw .
.Pp
An application calling
.Fn fido_cred_set_authdata
does not need to call
@ -112,6 +120,20 @@ does not need to call
The latter is meant to be used in contexts where the
credential's authenticator data is not available.
.Pp
The attestation statement passed to
.Fn fido_cred_set_attstmt
must be a CBOR-encoded map, as obtained from
.Fn fido_cred_attstmt_ptr .
An application calling
.Fn fido_cred_set_attstmt
does not need to call
.Fn fido_cred_set_x509
or
.Fn fido_cred_set_sig .
The latter two are meant to be used in contexts where the
credential's complete attestation statement is not available or
required.
.Pp
The
.Fn fido_cred_set_clientdata
function allows an application to set the client data hash of
@ -183,6 +205,7 @@ At the moment, only the
.Dv FIDO_EXT_CRED_BLOB ,
.Dv FIDO_EXT_CRED_PROTECT ,
.Dv FIDO_EXT_HMAC_SECRET ,
.Dv FIDO_EXT_MINPINLEN ,
and
.Dv FIDO_EXT_LARGEBLOB_KEY
extensions are supported.
@ -205,8 +228,32 @@ which must be
bytes long.
.Pp
The
.Fn fido_cred_set_pin_minlen
function enables the FIDO 2.1
.Dv FIDO_EXT_MINPINLEN
extension on
.Fa cred
and sets the expected minimum PIN length of
.Fa cred
to
.Fa len ,
where
.Fa len
is greater than zero.
If
.Fa len
is zero, the
.Dv FIDO_EXT_MINPINLEN
extension is disabled on
.Fa cred .
.Pp
The
.Fn fido_cred_set_prot
function sets the protection of
function enables the FIDO 2.1
.Dv FIDO_EXT_CRED_PROTECT
extension on
.Fa cred
and sets the protection of
.Fa cred
to the scalar
.Fa prot .

View File

@ -1,4 +1,4 @@
.\" 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.
.\"
@ -29,8 +29,8 @@ A brief description follows:
The
.Fn fido_cred_verify
function verifies whether the client data hash, relying party ID,
credential ID, type, and resident/discoverable key and user verification
attributes of
credential ID, type, protection policy, minimum PIN length, and
resident/discoverable key and user verification attributes of
.Fa cred
have been attested by the holder of the private counterpart of
the public key contained in the credential's x509 certificate.
@ -40,14 +40,14 @@ Please note that the x509 certificate itself is not verified.
The attestation statement formats supported by
.Fn fido_cred_verify
are
.Em packed
.Em packed ,
.Em fido-u2f ,
and
.Em fido-u2f .
.Em tpm .
The attestation type implemented by
.Fn fido_cred_verify
is
.Em Basic Attestation .
The attestation key pair is assumed to be of the type ES256.
Other attestation formats and types are not supported.
.Sh RETURN VALUES
The error codes returned by

View File

@ -9,7 +9,8 @@
.Nm fido_dev_enable_entattest ,
.Nm fido_dev_toggle_always_uv ,
.Nm fido_dev_force_pin_change ,
.Nm fido_dev_set_pin_minlen
.Nm fido_dev_set_pin_minlen ,
.Nm fido_dev_set_pin_minlen_rpid
.Nd FIDO 2.1 configuration authenticator API
.Sh SYNOPSIS
.In fido.h
@ -22,6 +23,8 @@
.Fn fido_dev_force_pin_change "fido_dev_t *dev" "const char *pin"
.Ft int
.Fn fido_dev_set_pin_minlen "fido_dev_t *dev" "size_t len" "const char *pin"
.Ft int
.Fn fido_dev_set_pin_minlen_rpid "fido_dev_t *dev" "const char * const *rpid" "size_t n" "const char *pin"
.Sh DESCRIPTION
The functions described in this page allow configuration of a
FIDO 2.1 authenticator.
@ -77,6 +80,24 @@ to
.Fa len .
Minimum PIN lengths may only be increased.
.Pp
The
.Fn fido_dev_set_pin_minlen_rpid
function sets the list of relying party identifiers
.Pq RP IDs
that are allowed to obtain the minimum PIN length of
.Fa dev
through the FIDO 2.1
.Dv FIDO_EXT_MINPINLEN
extension.
The list of RP identifiers is denoted by
.Fa rpid ,
a vector of
.Fa n
NUL-terminated UTF-8 strings.
A copy of
.Fa rpid
is made, and no reference to it or its contents is kept.
.Pp
Configuration settings are reflected in the payload returned by the
authenticator in response to a
.Xr fido_dev_get_cbor_info 3
@ -86,13 +107,15 @@ The error codes returned by
.Fn fido_dev_enable_entattest ,
.Fn fido_dev_toggle_always_uv ,
.Fn fido_dev_force_pin_change ,
.Fn fido_dev_set_pin_minlen ,
and
.Fn fido_dev_set_pin_minlen
.Fn fido_dev_set_pin_minlen_rpid
are defined in
.In fido/err.h .
On success,
.Dv FIDO_OK
is returned.
.Sh SEE ALSO
.Xr fido_cred_pin_minlen 3 ,
.Xr fido_dev_get_cbor_info 3 ,
.Xr fido_dev_reset 3

View File

@ -112,11 +112,21 @@ The
.Fn fido_dev_info_manufacturer_string
function returns the manufacturer string of
.Fa di .
If
.Fa di
does not have an associated manufacturer string,
.Fn fido_dev_info_manufacturer_string
returns an empty string.
.Pp
The
.Fn fido_dev_info_product_string
function returns the product string of
.Fa di .
If
.Fa di
does not have an associated product string,
.Fn fido_dev_info_product_string
returns an empty string.
.Pp
An example of how to use the functions described in this document
can be found in the

View File

@ -1,4 +1,4 @@
.\" 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.
.\"
@ -7,7 +7,8 @@
.Os
.Sh NAME
.Nm fido_dev_set_io_functions ,
.Nm fido_dev_set_sigmask
.Nm fido_dev_set_sigmask ,
.Nm fido_dev_set_timeout
.Nd FIDO 2 device I/O interface
.Sh SYNOPSIS
.In fido.h
@ -34,6 +35,8 @@ typedef sigset_t fido_sigset_t;
.Fn fido_dev_set_io_functions "fido_dev_t *dev" "const fido_dev_io_t *io"
.Ft int
.Fn fido_dev_set_sigmask "fido_dev_t *dev" "const fido_sigset_t *sigmask"
.Ft int
.Fn fido_dev_set_timeout "fido_dev_t *dev" "int ms"
.Sh DESCRIPTION
The
.Fn fido_dev_set_io_functions
@ -122,11 +125,35 @@ No references to
.Fa sigmask
are held by
.Fn fido_dev_set_sigmask .
.Pp
The
.Fn fido_dev_set_timeout
function informs
.Em libfido2
not to block for more than
.Fa ms
milliseconds while communicating with
.Fa dev .
If a timeout occurs, the corresponding
.Em fido_dev_*
function will fail with
.Dv FIDO_ERR_RX .
If
.Fa ms
is -1,
then
.Em libfido2
may block indefinitely.
This is the default behaviour.
When using the Windows Hello backend,
.Fa ms
is used as a guidance and may be overwritten by the platform.
.Sh RETURN VALUES
On success,
.Fn fido_dev_set_io_functions
.Fn fido_dev_set_io_functions ,
.Fn fido_dev_set_sigmask ,
and
.Fn fido_dev_set_sigmask
.Fn fido_dev_set_timeout
return
.Dv FIDO_OK .
On error, a different error code defined in

View File

@ -1,4 +1,4 @@
.\" 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.
.\"
@ -8,6 +8,7 @@
.Sh NAME
.Nm rs256_pk_new ,
.Nm rs256_pk_free ,
.Nm rs256_pk_from_EVP_PKEY ,
.Nm rs256_pk_from_RSA ,
.Nm rs256_pk_from_ptr ,
.Nm rs256_pk_to_EVP_PKEY
@ -20,6 +21,8 @@
.Ft void
.Fn rs256_pk_free "rs256_pk_t **pkp"
.Ft int
.Fn rs256_pk_from_EVP_PKEY "rs256_pk_t *pk" "const EVP_PKEY *pkey"
.Ft int
.Fn rs256_pk_from_RSA "rs256_pk_t *pk" "const RSA *rsa"
.Ft int
.Fn rs256_pk_from_ptr "rs256_pk_t *pk" "const void *ptr" "size_t len"
@ -69,6 +72,16 @@ may be NULL, in which case
is a NOP.
.Pp
The
.Fn rs256_pk_from_EVP_PKEY
function fills
.Fa pk
with the contents of
.Fa pkey .
No references to
.Fa pkey
are kept.
.Pp
The
.Fn rs256_pk_from_RSA
function fills
.Fa pk
@ -106,7 +119,8 @@ If an error occurs,
returns NULL.
.Sh RETURN VALUES
The
.Fn rs256_pk_from_RSA
.Fn rs256_pk_from_EVP_PKEY ,
.Fn rs256_pk_from_RSA ,
and
.Fn rs256_pk_from_ptr
functions return

View File

@ -1,124 +0,0 @@
/* $OpenBSD: hkdf.c,v 1.4 2019/11/21 20:02:20 tim Exp $ */
/* Copyright (c) 2014, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "openbsd-compat.h"
#include "fido.h"
#if OPENSSL_VERSION_NUMBER < 0x10100000L
#include <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 */

View File

@ -1,65 +0,0 @@
/* $OpenBSD: hkdf.h,v 1.2 2018/04/03 13:33:53 tb Exp $ */
/* Copyright (c) 2014, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#ifndef OPENSSL_HEADER_HKDF_H
#define OPENSSL_HEADER_HKDF_H
#include <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 */

View File

@ -1,5 +1,5 @@
/*
* 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.
*/
@ -20,6 +20,7 @@
#define be16toh(x) OSSwapBigToHostInt16((x))
#define htobe16(x) OSSwapHostToBigInt16((x))
#define be32toh(x) OSSwapBigToHostInt32((x))
#define htobe32(x) OSSwapHostToBigInt32((x))
#define htole32(x) OSSwapHostToLittleInt32((x))
#define htole64(x) OSSwapHostToLittleInt64((x))
#endif /* __APPLE__ && !HAVE_ENDIAN_H */
@ -33,11 +34,12 @@
#define be16toh(x) ntohs((x))
#define htobe16(x) htons((x))
#define be32toh(x) ntohl((x))
#define htobe32(x) htonl((x))
uint32_t htole32(uint32_t);
uint64_t htole64(uint64_t);
#endif /* _WIN32 && !HAVE_ENDIAN_H */
#if defined(__FreeBSD__) && !defined(HAVE_ENDIAN_H)
#if (defined(__FreeBSD__) || defined(__MidnightBSD__)) && !defined(HAVE_ENDIAN_H)
#include <sys/endian.h>
#endif
@ -52,6 +54,10 @@ size_t strlcat(char *, const char *, size_t);
size_t strlcpy(char *, const char *, size_t);
#endif
#if !defined(HAVE_STRSEP)
char *strsep(char **, const char *);
#endif
#if !defined(HAVE_RECALLOCARRAY)
void *recallocarray(void *, size_t, size_t, size_t);
#endif
@ -80,13 +86,6 @@ int timingsafe_bcmp(const void *, const void *, size_t);
#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
#if !defined(HAVE_ERR_H)
#include "err.h"
#else

79
openbsd-compat/strsep.c Normal file
View File

@ -0,0 +1,79 @@
/* $OpenBSD: strsep.c,v 1.6 2005/08/08 08:05:37 espie Exp $ */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* OPENBSD ORIGINAL: lib/libc/string/strsep.c */
#include "openbsd-compat.h"
#if !defined(HAVE_STRSEP)
#include <string.h>
#include <stdio.h>
/*
* Get next token from string *stringp, where tokens are possibly-empty
* strings separated by characters from delim.
*
* Writes NULs into the string at *stringp to end tokens.
* delim need not remain constant from call to call.
* On return, *stringp points past the last NUL written (if there might
* be further tokens), or is NULL (if there are definitely no more tokens).
*
* If *stringp is NULL, strsep returns NULL.
*/
char *
strsep(char **stringp, const char *delim)
{
char *s;
const char *spanp;
int c, sc;
char *tok;
if ((s = *stringp) == NULL)
return (NULL);
for (tok = s;;) {
c = *s++;
spanp = delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
*stringp = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}
#endif /* !defined(HAVE_STRSEP) */

View File

@ -1,4 +1,4 @@
# 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.
@ -7,10 +7,14 @@ add_custom_target(regress ALL)
macro(add_regress_test NAME SOURCES)
add_executable(${NAME} ${SOURCES})
target_link_libraries(${NAME} fido2_shared)
add_custom_command(TARGET regress POST_BUILD COMMAND ${NAME}
DEPENDS ${NAME})
add_test(${NAME} ${NAME})
add_dependencies(regress ${NAME})
endmacro()
add_custom_command(TARGET regress POST_BUILD
COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
add_regress_test(regress_cred cred.c)
add_regress_test(regress_assert assert.c)
add_regress_test(regress_dev dev.c)

View File

@ -1,9 +1,11 @@
/*
* Copyright (c) 2018 Yubico AB. All rights reserved.
* Copyright (c) 2018-2021 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
#define _FIDO_INTERNAL
#include <assert.h>
#include <fido.h>
#include <fido/es256.h>
@ -24,6 +26,42 @@ static const unsigned char es256_pk[64] = {
0x64, 0x1a, 0x1d, 0xf8, 0xbe, 0x14, 0x90, 0x8a,
};
static const unsigned char rs256_pk[259] = {
0x9e, 0x54, 0x78, 0xb2, 0x51, 0xbe, 0x19, 0x7c,
0xcb, 0x1a, 0x9a, 0xc3, 0x49, 0x2a, 0x2f, 0xfd,
0x99, 0x64, 0x76, 0xc6, 0xdb, 0xca, 0x38, 0x3f,
0xb0, 0x6a, 0xc9, 0xc0, 0x07, 0x9f, 0x5c, 0x4d,
0xfc, 0xd1, 0x01, 0x7f, 0x69, 0x65, 0xab, 0x9c,
0x2a, 0xc2, 0x95, 0xd9, 0x44, 0xf3, 0xea, 0x94,
0x6b, 0x25, 0x66, 0x54, 0x81, 0xee, 0x24, 0x1d,
0xe1, 0x7d, 0x7f, 0xbe, 0xea, 0x76, 0x90, 0x5c,
0xbf, 0x59, 0x22, 0xd3, 0xa0, 0x68, 0x1a, 0x65,
0x8b, 0x2f, 0xb6, 0xa8, 0x30, 0x2d, 0x26, 0x81,
0xfa, 0x9e, 0x59, 0xec, 0x2f, 0xee, 0x59, 0x39,
0xe2, 0x79, 0x19, 0x54, 0x54, 0xdf, 0x24, 0x83,
0xee, 0x61, 0x5a, 0x66, 0x24, 0x2b, 0x7b, 0xfb,
0x82, 0x66, 0xe4, 0x85, 0x18, 0x20, 0x76, 0xe5,
0x4a, 0xb6, 0xcb, 0xec, 0x43, 0xbe, 0xfd, 0xb0,
0x8f, 0xfd, 0x2f, 0x69, 0xda, 0x06, 0x9c, 0x09,
0x68, 0x7a, 0x94, 0x6c, 0xb7, 0x51, 0x6d, 0x4c,
0xf7, 0x13, 0xe8, 0xd5, 0x22, 0x6b, 0x1e, 0xba,
0xb9, 0x85, 0xe8, 0x5f, 0xa1, 0x66, 0xe3, 0x20,
0x75, 0x30, 0x11, 0xb5, 0xa3, 0xc3, 0xb0, 0x72,
0x08, 0xff, 0xa3, 0xbb, 0xf1, 0x32, 0x0b, 0x06,
0xc4, 0x12, 0xa3, 0x49, 0x30, 0x19, 0xb9, 0xfe,
0x69, 0x0c, 0xd6, 0xe1, 0x58, 0x36, 0xe6, 0x41,
0x22, 0x41, 0xbf, 0x96, 0x50, 0x35, 0x56, 0x0d,
0x92, 0x8c, 0x34, 0xea, 0x28, 0x91, 0x88, 0x9e,
0x8a, 0xaa, 0x36, 0xd0, 0x0f, 0xbe, 0x16, 0xde,
0x9d, 0x5f, 0x7b, 0xda, 0x52, 0xf7, 0xf1, 0xb6,
0x28, 0x10, 0x05, 0x8f, 0xb9, 0x19, 0x7a, 0xcf,
0x18, 0x9b, 0x40, 0xcd, 0xff, 0x78, 0xea, 0x61,
0x24, 0x3b, 0x80, 0x68, 0x04, 0x9b, 0x40, 0x07,
0x98, 0xd4, 0x94, 0xd1, 0x18, 0x44, 0xa5, 0xed,
0xee, 0x18, 0xc2, 0x25, 0x52, 0x66, 0x42, 0xdf,
0x01, 0x00, 0x01,
};
static const unsigned char cdh[32] = {
0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7,
0x82, 0x34, 0xaa, 0xca, 0x07, 0xa1, 0xf6, 0x56,
@ -397,7 +435,7 @@ junk_cdh(void)
junk = malloc(sizeof(cdh));
assert(junk != NULL);
memcpy(junk, cdh, sizeof(cdh));
junk[0] = ~junk[0];
junk[0] = (unsigned char)~junk[0];
a = alloc_assert();
pk = alloc_es256_pk();
@ -448,7 +486,7 @@ junk_authdata(void)
junk = malloc(sizeof(authdata));
assert(junk != NULL);
memcpy(junk, authdata, sizeof(authdata));
junk[0] = ~junk[0];
junk[0] = (unsigned char)~junk[0];
a = alloc_assert();
assert(fido_assert_set_count(a, 1) == FIDO_OK);
@ -468,7 +506,7 @@ junk_sig(void)
junk = malloc(sizeof(sig));
assert(junk != NULL);
memcpy(junk, sig, sizeof(sig));
junk[0] = ~junk[0];
junk[0] = (unsigned char)~junk[0];
a = alloc_assert();
pk = alloc_es256_pk();
@ -531,6 +569,46 @@ bad_cbor_serialize(void)
free_assert(a);
}
/* rs256 <-> EVP_PKEY transformations */
static void
rs256_PKEY(void)
{
rs256_pk_t *pk1, *pk2;
EVP_PKEY *pkey;
pk1 = alloc_rs256_pk();
pk2 = alloc_rs256_pk();
assert(rs256_pk_from_ptr(pk1, rs256_pk, sizeof(rs256_pk)) == FIDO_OK);
assert((pkey = rs256_pk_to_EVP_PKEY(pk1)) != NULL);
assert(rs256_pk_from_EVP_PKEY(pk2, pkey) == FIDO_OK);
assert(memcmp(pk1, pk2, sizeof(*pk1)) == 0);
free_rs256_pk(pk1);
free_rs256_pk(pk2);
EVP_PKEY_free(pkey);
}
/* es256 <-> EVP_PKEY transformations */
static void
es256_PKEY(void)
{
es256_pk_t *pk1, *pk2;
EVP_PKEY *pkey;
pk1 = alloc_es256_pk();
pk2 = alloc_es256_pk();
assert(es256_pk_from_ptr(pk1, es256_pk, sizeof(es256_pk)) == FIDO_OK);
assert((pkey = es256_pk_to_EVP_PKEY(pk1)) != NULL);
assert(es256_pk_from_EVP_PKEY(pk2, pkey) == FIDO_OK);
assert(memcmp(pk1, pk2, sizeof(*pk1)) == 0);
free_es256_pk(pk1);
free_es256_pk(pk2);
EVP_PKEY_free(pkey);
}
int
main(void)
{
@ -548,6 +626,8 @@ main(void)
junk_sig();
wrong_options();
bad_cbor_serialize();
rs256_PKEY();
es256_PKEY();
exit(0);
}

View File

@ -1,5 +1,5 @@
/*
* 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.
*/
@ -102,6 +102,55 @@ static const unsigned char authdata_unsorted_keys[198] = {
0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2,
};
const unsigned char authdata_tpm[362] = {
0x59, 0x01, 0x67, 0x49, 0x96, 0x0d, 0xe5, 0x88,
0x0e, 0x8c, 0x68, 0x74, 0x34, 0x17, 0x0f, 0x64,
0x76, 0x60, 0x5b, 0x8f, 0xe4, 0xae, 0xb9, 0xa2,
0x86, 0x32, 0xc7, 0x99, 0x5c, 0xf3, 0xba, 0x83,
0x1d, 0x97, 0x63, 0x45, 0x00, 0x00, 0x00, 0x00,
0x08, 0x98, 0x70, 0x58, 0xca, 0xdc, 0x4b, 0x81,
0xb6, 0xe1, 0x30, 0xde, 0x50, 0xdc, 0xbe, 0x96,
0x00, 0x20, 0x89, 0x99, 0x6d, 0x5a, 0x00, 0x29,
0xe5, 0x3e, 0x6a, 0x1c, 0x72, 0x6d, 0x71, 0x4a,
0x4f, 0x03, 0x9b, 0x68, 0x17, 0xdb, 0x29, 0x1a,
0x6b, 0x02, 0x6c, 0x26, 0xf9, 0xbd, 0xc3, 0x0e,
0x38, 0x1a, 0xa4, 0x01, 0x03, 0x03, 0x39, 0x01,
0x00, 0x20, 0x59, 0x01, 0x00, 0xc5, 0xb6, 0x9c,
0x06, 0x1d, 0xcf, 0xb9, 0xf2, 0x5e, 0x99, 0x7d,
0x6d, 0x73, 0xd8, 0x36, 0xc1, 0x4a, 0x90, 0x05,
0x4d, 0x82, 0x57, 0xc1, 0xb6, 0x6a, 0xd1, 0x43,
0x03, 0x85, 0xf8, 0x52, 0x4f, 0xd2, 0x27, 0x91,
0x0b, 0xb5, 0x93, 0xa0, 0x68, 0xf8, 0x80, 0x1b,
0xaa, 0x65, 0x97, 0x45, 0x11, 0x86, 0x34, 0xd6,
0x67, 0xf8, 0xd5, 0x12, 0x79, 0x84, 0xee, 0x70,
0x99, 0x00, 0x63, 0xa8, 0xb4, 0x43, 0x0b, 0x4c,
0x57, 0x4a, 0xd6, 0x9b, 0x75, 0x63, 0x8a, 0x46,
0x57, 0xdb, 0x14, 0xc8, 0x71, 0xd1, 0xb3, 0x07,
0x68, 0x58, 0xbc, 0x55, 0x84, 0x80, 0x2a, 0xd2,
0x36, 0x9f, 0xc1, 0x64, 0xa0, 0x11, 0x4b, 0xc9,
0x32, 0x31, 0x3a, 0xd6, 0x87, 0x26, 0x1a, 0x3a,
0x78, 0x3d, 0x89, 0xdb, 0x00, 0x28, 0x3b, 0xae,
0x2b, 0x1b, 0x56, 0xe2, 0x8c, 0x4c, 0x63, 0xac,
0x6e, 0x6c, 0xf7, 0xb5, 0x7d, 0x4d, 0x0b, 0x9f,
0x06, 0xa0, 0x10, 0x35, 0x38, 0x20, 0x4d, 0xcc,
0x07, 0xd7, 0x00, 0x4e, 0x86, 0xba, 0xfe, 0x8b,
0xe4, 0x3f, 0x4a, 0xd6, 0xca, 0xbf, 0x67, 0x40,
0x1a, 0xa4, 0xda, 0x82, 0x52, 0x15, 0xb8, 0x14,
0x3a, 0x7c, 0xa9, 0x02, 0xc1, 0x01, 0x69, 0xc6,
0x51, 0xd4, 0xbc, 0x1f, 0x95, 0xb2, 0xee, 0x1f,
0xdd, 0xb5, 0x73, 0x16, 0x5e, 0x29, 0x3f, 0x47,
0xac, 0x65, 0xfb, 0x63, 0x5c, 0xb9, 0xc8, 0x13,
0x2d, 0xec, 0x85, 0xde, 0x71, 0x0d, 0x84, 0x93,
0x74, 0x76, 0x91, 0xdd, 0x1d, 0x6d, 0x3d, 0xc7,
0x36, 0x19, 0x19, 0x86, 0xde, 0x7c, 0xca, 0xd6,
0xc6, 0x65, 0x7e, 0x4b, 0x24, 0x9c, 0xce, 0x92,
0x6b, 0x1c, 0xe0, 0xa0, 0xa9, 0x6c, 0xc3, 0xed,
0x4f, 0x2a, 0x54, 0x07, 0x00, 0x32, 0x5e, 0x1b,
0x94, 0x37, 0xcd, 0xe2, 0x32, 0xa8, 0xd5, 0x2c,
0xfb, 0x03, 0x9d, 0x79, 0xdf, 0x21, 0x43, 0x01,
0x00, 0x01
};
static const unsigned char x509[742] = {
0x30, 0x82, 0x02, 0xe2, 0x30, 0x81, 0xcb, 0x02,
0x01, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
@ -221,6 +270,42 @@ const unsigned char pubkey[64] = {
0xfe, 0x5d, 0xe1, 0x30, 0xfc, 0x2b, 0x1e, 0xd2,
};
const unsigned char pubkey_tpm[259] = {
0xc5, 0xb6, 0x9c, 0x06, 0x1d, 0xcf, 0xb9, 0xf2,
0x5e, 0x99, 0x7d, 0x6d, 0x73, 0xd8, 0x36, 0xc1,
0x4a, 0x90, 0x05, 0x4d, 0x82, 0x57, 0xc1, 0xb6,
0x6a, 0xd1, 0x43, 0x03, 0x85, 0xf8, 0x52, 0x4f,
0xd2, 0x27, 0x91, 0x0b, 0xb5, 0x93, 0xa0, 0x68,
0xf8, 0x80, 0x1b, 0xaa, 0x65, 0x97, 0x45, 0x11,
0x86, 0x34, 0xd6, 0x67, 0xf8, 0xd5, 0x12, 0x79,
0x84, 0xee, 0x70, 0x99, 0x00, 0x63, 0xa8, 0xb4,
0x43, 0x0b, 0x4c, 0x57, 0x4a, 0xd6, 0x9b, 0x75,
0x63, 0x8a, 0x46, 0x57, 0xdb, 0x14, 0xc8, 0x71,
0xd1, 0xb3, 0x07, 0x68, 0x58, 0xbc, 0x55, 0x84,
0x80, 0x2a, 0xd2, 0x36, 0x9f, 0xc1, 0x64, 0xa0,
0x11, 0x4b, 0xc9, 0x32, 0x31, 0x3a, 0xd6, 0x87,
0x26, 0x1a, 0x3a, 0x78, 0x3d, 0x89, 0xdb, 0x00,
0x28, 0x3b, 0xae, 0x2b, 0x1b, 0x56, 0xe2, 0x8c,
0x4c, 0x63, 0xac, 0x6e, 0x6c, 0xf7, 0xb5, 0x7d,
0x4d, 0x0b, 0x9f, 0x06, 0xa0, 0x10, 0x35, 0x38,
0x20, 0x4d, 0xcc, 0x07, 0xd7, 0x00, 0x4e, 0x86,
0xba, 0xfe, 0x8b, 0xe4, 0x3f, 0x4a, 0xd6, 0xca,
0xbf, 0x67, 0x40, 0x1a, 0xa4, 0xda, 0x82, 0x52,
0x15, 0xb8, 0x14, 0x3a, 0x7c, 0xa9, 0x02, 0xc1,
0x01, 0x69, 0xc6, 0x51, 0xd4, 0xbc, 0x1f, 0x95,
0xb2, 0xee, 0x1f, 0xdd, 0xb5, 0x73, 0x16, 0x5e,
0x29, 0x3f, 0x47, 0xac, 0x65, 0xfb, 0x63, 0x5c,
0xb9, 0xc8, 0x13, 0x2d, 0xec, 0x85, 0xde, 0x71,
0x0d, 0x84, 0x93, 0x74, 0x76, 0x91, 0xdd, 0x1d,
0x6d, 0x3d, 0xc7, 0x36, 0x19, 0x19, 0x86, 0xde,
0x7c, 0xca, 0xd6, 0xc6, 0x65, 0x7e, 0x4b, 0x24,
0x9c, 0xce, 0x92, 0x6b, 0x1c, 0xe0, 0xa0, 0xa9,
0x6c, 0xc3, 0xed, 0x4f, 0x2a, 0x54, 0x07, 0x00,
0x32, 0x5e, 0x1b, 0x94, 0x37, 0xcd, 0xe2, 0x32,
0xa8, 0xd5, 0x2c, 0xfb, 0x03, 0x9d, 0x79, 0xdf,
0x01, 0x00, 0x01,
};
const unsigned char id[64] = {
0x53, 0xfb, 0xdf, 0xaa, 0xce, 0x63, 0xde, 0xc5,
0xfe, 0x47, 0xe6, 0x52, 0xeb, 0xf3, 0x5d, 0x53,
@ -232,16 +317,539 @@ const unsigned char id[64] = {
0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, 0x25,
};
const unsigned char id_tpm[32] = {
0x89, 0x99, 0x6d, 0x5a, 0x00, 0x29, 0xe5, 0x3e,
0x6a, 0x1c, 0x72, 0x6d, 0x71, 0x4a, 0x4f, 0x03,
0x9b, 0x68, 0x17, 0xdb, 0x29, 0x1a, 0x6b, 0x02,
0x6c, 0x26, 0xf9, 0xbd, 0xc3, 0x0e, 0x38, 0x1a
};
const unsigned char attstmt_tpm[4034] = {
0xa6, 0x63, 0x61, 0x6c, 0x67, 0x39, 0xff, 0xfe,
0x63, 0x73, 0x69, 0x67, 0x59, 0x01, 0x00, 0x1c,
0x09, 0x0d, 0x35, 0x97, 0x22, 0xfc, 0xfe, 0xc0,
0x58, 0x49, 0x9e, 0xd4, 0x7e, 0x6a, 0x7d, 0xdb,
0x6d, 0x20, 0x95, 0x5c, 0x0b, 0xd0, 0xd5, 0x72,
0x4f, 0x15, 0x22, 0x38, 0x97, 0xb2, 0x4b, 0xd0,
0xef, 0x31, 0x7c, 0xf2, 0x42, 0x19, 0x41, 0xa1,
0xe2, 0xc5, 0xca, 0xc6, 0x74, 0x95, 0xcf, 0xf9,
0x41, 0x75, 0x0b, 0x56, 0x39, 0x82, 0x78, 0xf6,
0x59, 0xf1, 0x09, 0x96, 0x9e, 0x38, 0x7f, 0x14,
0x9b, 0xf5, 0x36, 0xbb, 0x92, 0x32, 0xc4, 0x64,
0xe8, 0xff, 0xb4, 0xc7, 0xcf, 0xcd, 0x17, 0x48,
0x0f, 0x83, 0xd9, 0x44, 0x03, 0x35, 0x26, 0xad,
0x01, 0xb7, 0x57, 0x06, 0xb3, 0x9c, 0xa0, 0x6e,
0x2f, 0x58, 0xcb, 0x5c, 0xaa, 0x7c, 0xea, 0x7e,
0x3f, 0xbc, 0x76, 0xc9, 0x0e, 0x52, 0x39, 0x81,
0xa9, 0x9e, 0x37, 0x14, 0x1f, 0x50, 0x6a, 0x4f,
0xd7, 0xfc, 0xd4, 0xfa, 0xf2, 0x18, 0x60, 0xd5,
0xc3, 0x57, 0x7d, 0x6d, 0x05, 0x28, 0x25, 0xc3,
0xde, 0x86, 0x85, 0x06, 0x71, 0xfb, 0x84, 0xa2,
0x07, 0xb6, 0x77, 0xc9, 0x68, 0x41, 0x53, 0x32,
0x4c, 0xa8, 0x4b, 0xf7, 0x08, 0x84, 0x62, 0x6c,
0x8a, 0xb6, 0xcf, 0xc1, 0xde, 0x6b, 0x61, 0xc8,
0xdd, 0xc0, 0x13, 0x70, 0x22, 0x28, 0xe1, 0x0f,
0x46, 0x02, 0xc6, 0xb1, 0xfa, 0x30, 0xcb, 0xec,
0xd1, 0x82, 0xfa, 0x51, 0xcb, 0x71, 0x5e, 0x1f,
0x1b, 0x5f, 0xe0, 0xb0, 0x02, 0x8a, 0x7c, 0x78,
0xd1, 0xb7, 0x4d, 0x56, 0xb0, 0x92, 0x3e, 0xda,
0xc7, 0xb1, 0x74, 0xcf, 0x6a, 0x40, 0xeb, 0x98,
0x1c, 0x2e, 0xf2, 0x86, 0x76, 0xf8, 0x2e, 0x6a,
0x9f, 0x77, 0x51, 0x64, 0xce, 0xdc, 0x12, 0x85,
0x84, 0x6b, 0x01, 0xc8, 0xeb, 0xbc, 0x57, 0x6c,
0x32, 0x26, 0xcb, 0xb2, 0x84, 0x02, 0x2a, 0x33,
0x15, 0xd9, 0xe3, 0x15, 0xfc, 0x3a, 0x24, 0x63,
0x76, 0x65, 0x72, 0x63, 0x32, 0x2e, 0x30, 0x63,
0x78, 0x35, 0x63, 0x82, 0x59, 0x05, 0xc4, 0x30,
0x82, 0x05, 0xc0, 0x30, 0x82, 0x03, 0xa8, 0xa0,
0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x78, 0xd9,
0xa8, 0xb2, 0x64, 0xf9, 0x4d, 0x28, 0x82, 0xc0,
0xd3, 0x1b, 0x40, 0x3c, 0xc8, 0xd9, 0x30, 0x0d,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x41, 0x31,
0x3f, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x04, 0x03,
0x13, 0x36, 0x45, 0x55, 0x53, 0x2d, 0x53, 0x54,
0x4d, 0x2d, 0x4b, 0x45, 0x59, 0x49, 0x44, 0x2d,
0x31, 0x41, 0x44, 0x42, 0x39, 0x39, 0x34, 0x41,
0x42, 0x35, 0x38, 0x42, 0x45, 0x35, 0x37, 0x41,
0x30, 0x43, 0x43, 0x39, 0x42, 0x39, 0x30, 0x30,
0x45, 0x37, 0x38, 0x35, 0x31, 0x45, 0x31, 0x41,
0x34, 0x33, 0x43, 0x30, 0x38, 0x36, 0x36, 0x30,
0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x37,
0x31, 0x35, 0x31, 0x31, 0x31, 0x32, 0x31, 0x33,
0x5a, 0x17, 0x0d, 0x32, 0x35, 0x30, 0x33, 0x32,
0x31, 0x32, 0x30, 0x32, 0x39, 0x31, 0x35, 0x5a,
0x30, 0x00, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
0x01, 0x01, 0x00, 0xca, 0xbe, 0x77, 0x9f, 0x45,
0x97, 0x17, 0x8d, 0x01, 0xe1, 0x18, 0xcc, 0xf0,
0xb5, 0xed, 0x9a, 0xb7, 0x36, 0xac, 0x05, 0x26,
0xbe, 0x35, 0xd9, 0x5c, 0x00, 0x5c, 0x5d, 0x8b,
0x6f, 0x2a, 0xb8, 0xf6, 0x02, 0x4f, 0x33, 0xfe,
0x84, 0x45, 0x4c, 0x4f, 0x7a, 0xdb, 0xa9, 0x6a,
0x62, 0x0f, 0x19, 0x35, 0x5d, 0xd2, 0x34, 0x1a,
0x9d, 0x73, 0x55, 0xe5, 0x3e, 0x04, 0xa2, 0xd6,
0xbe, 0xe7, 0x5a, 0xb9, 0x16, 0x6c, 0x55, 0x18,
0xa8, 0x4b, 0xb2, 0x37, 0xb9, 0xa3, 0x87, 0xfc,
0x76, 0xa8, 0x55, 0xc9, 0xe7, 0x30, 0xe5, 0x0e,
0x3c, 0x7b, 0x74, 0xd2, 0x1e, 0xa8, 0x05, 0xd5,
0xe2, 0xe3, 0xcb, 0xaf, 0x63, 0x33, 0x12, 0xaa,
0xfd, 0x31, 0x32, 0x71, 0x4f, 0x41, 0x96, 0x05,
0xb5, 0x69, 0x73, 0x45, 0xbe, 0x6f, 0x90, 0xd9,
0x10, 0x36, 0xaf, 0x7a, 0x1c, 0xf1, 0x6d, 0x14,
0xb0, 0x1e, 0xbb, 0xae, 0x1c, 0x35, 0xec, 0x1c,
0xb5, 0x0e, 0xf6, 0x33, 0x98, 0x13, 0x4e, 0x44,
0x7b, 0x5c, 0x97, 0x47, 0xed, 0x4f, 0xfe, 0xbd,
0x08, 0xd2, 0xa9, 0xc6, 0xbe, 0x8c, 0x04, 0x9e,
0xdc, 0x3d, 0xbe, 0x98, 0xe9, 0x2a, 0xb1, 0xf4,
0xfa, 0x45, 0xf9, 0xc8, 0x9a, 0x55, 0x85, 0x26,
0xfc, 0x5f, 0xad, 0x00, 0x8b, 0xc8, 0x41, 0xf2,
0x86, 0x4e, 0xba, 0x55, 0x1c, 0xb2, 0x89, 0xe8,
0x85, 0x6e, 0x1e, 0x02, 0x9f, 0x55, 0x70, 0xbe,
0xfd, 0xe7, 0x9f, 0xba, 0x59, 0xa0, 0x2e, 0x9a,
0x74, 0x11, 0xe7, 0xad, 0xa9, 0xc7, 0x7b, 0x58,
0xc4, 0x16, 0xd3, 0x35, 0xcb, 0x61, 0x00, 0xec,
0x36, 0x4a, 0xa3, 0x51, 0xa3, 0xdd, 0x61, 0xb6,
0xd6, 0x29, 0xcb, 0x76, 0xe1, 0xab, 0x51, 0x3a,
0xe8, 0xbf, 0xdb, 0x09, 0x4a, 0x39, 0x96, 0xd9,
0xac, 0x8f, 0x6c, 0x62, 0xe0, 0x03, 0x23, 0x24,
0xbe, 0xd4, 0x83, 0x02, 0x03, 0x01, 0x00, 0x01,
0xa3, 0x82, 0x01, 0xf3, 0x30, 0x82, 0x01, 0xef,
0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80,
0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x6d,
0x06, 0x03, 0x55, 0x1d, 0x20, 0x01, 0x01, 0xff,
0x04, 0x63, 0x30, 0x61, 0x30, 0x5f, 0x06, 0x09,
0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15,
0x1f, 0x30, 0x52, 0x30, 0x50, 0x06, 0x08, 0x2b,
0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30,
0x44, 0x1e, 0x42, 0x00, 0x54, 0x00, 0x43, 0x00,
0x50, 0x00, 0x41, 0x00, 0x20, 0x00, 0x20, 0x00,
0x54, 0x00, 0x72, 0x00, 0x75, 0x00, 0x73, 0x00,
0x74, 0x00, 0x65, 0x00, 0x64, 0x00, 0x20, 0x00,
0x20, 0x00, 0x50, 0x00, 0x6c, 0x00, 0x61, 0x00,
0x74, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00,
0x6d, 0x00, 0x20, 0x00, 0x20, 0x00, 0x49, 0x00,
0x64, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00,
0x69, 0x00, 0x74, 0x00, 0x79, 0x30, 0x10, 0x06,
0x03, 0x55, 0x1d, 0x25, 0x04, 0x09, 0x30, 0x07,
0x06, 0x05, 0x67, 0x81, 0x05, 0x08, 0x03, 0x30,
0x59, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x01, 0x01,
0xff, 0x04, 0x4f, 0x30, 0x4d, 0xa4, 0x4b, 0x30,
0x49, 0x31, 0x16, 0x30, 0x14, 0x06, 0x05, 0x67,
0x81, 0x05, 0x02, 0x01, 0x0c, 0x0b, 0x69, 0x64,
0x3a, 0x35, 0x33, 0x35, 0x34, 0x34, 0x44, 0x32,
0x30, 0x31, 0x17, 0x30, 0x15, 0x06, 0x05, 0x67,
0x81, 0x05, 0x02, 0x02, 0x0c, 0x0c, 0x53, 0x54,
0x33, 0x33, 0x48, 0x54, 0x50, 0x48, 0x41, 0x48,
0x42, 0x34, 0x31, 0x16, 0x30, 0x14, 0x06, 0x05,
0x67, 0x81, 0x05, 0x02, 0x03, 0x0c, 0x0b, 0x69,
0x64, 0x3a, 0x30, 0x30, 0x34, 0x39, 0x30, 0x30,
0x30, 0x34, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xb8,
0x5f, 0xd5, 0x67, 0xca, 0x92, 0xc4, 0x0e, 0xcf,
0x0c, 0xd8, 0x1f, 0x6d, 0x3f, 0x03, 0x55, 0x6f,
0x38, 0xa6, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55,
0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xd4, 0x04,
0x64, 0xfc, 0x6e, 0x50, 0x0a, 0x56, 0x48, 0x0f,
0x05, 0xa9, 0x00, 0xb7, 0x1d, 0x5e, 0x57, 0x08,
0xd5, 0xdc, 0x30, 0x81, 0xb2, 0x06, 0x08, 0x2b,
0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04,
0x81, 0xa5, 0x30, 0x81, 0xa2, 0x30, 0x81, 0x9f,
0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
0x30, 0x02, 0x86, 0x81, 0x92, 0x68, 0x74, 0x74,
0x70, 0x3a, 0x2f, 0x2f, 0x61, 0x7a, 0x63, 0x73,
0x70, 0x72, 0x6f, 0x64, 0x65, 0x75, 0x73, 0x61,
0x69, 0x6b, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73,
0x68, 0x2e, 0x62, 0x6c, 0x6f, 0x62, 0x2e, 0x63,
0x6f, 0x72, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64,
0x6f, 0x77, 0x73, 0x2e, 0x6e, 0x65, 0x74, 0x2f,
0x65, 0x75, 0x73, 0x2d, 0x73, 0x74, 0x6d, 0x2d,
0x6b, 0x65, 0x79, 0x69, 0x64, 0x2d, 0x31, 0x61,
0x64, 0x62, 0x39, 0x39, 0x34, 0x61, 0x62, 0x35,
0x38, 0x62, 0x65, 0x35, 0x37, 0x61, 0x30, 0x63,
0x63, 0x39, 0x62, 0x39, 0x30, 0x30, 0x65, 0x37,
0x38, 0x35, 0x31, 0x65, 0x31, 0x61, 0x34, 0x33,
0x63, 0x30, 0x38, 0x36, 0x36, 0x30, 0x2f, 0x61,
0x62, 0x64, 0x36, 0x31, 0x35, 0x66, 0x32, 0x2d,
0x31, 0x35, 0x38, 0x61, 0x2d, 0x34, 0x35, 0x38,
0x65, 0x2d, 0x61, 0x31, 0x35, 0x35, 0x2d, 0x37,
0x63, 0x34, 0x63, 0x38, 0x63, 0x62, 0x31, 0x33,
0x63, 0x36, 0x35, 0x2e, 0x63, 0x65, 0x72, 0x30,
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82,
0x02, 0x01, 0x00, 0xa2, 0x10, 0xc5, 0xbf, 0x41,
0xa6, 0xba, 0x8c, 0x72, 0xca, 0x0f, 0x3e, 0x5e,
0x7f, 0xe2, 0xcb, 0x60, 0xb8, 0x3f, 0xfb, 0xde,
0x03, 0xe2, 0xfe, 0x20, 0x29, 0xdf, 0x11, 0xf5,
0xb0, 0x50, 0x6d, 0x32, 0xe8, 0x1b, 0x05, 0xad,
0x6b, 0x60, 0xb5, 0xed, 0xf3, 0xa4, 0x4a, 0xea,
0x09, 0xe5, 0x65, 0x7e, 0xe0, 0xd5, 0x3a, 0x6a,
0xdb, 0x64, 0xb7, 0x07, 0x8f, 0xa1, 0x63, 0xb3,
0x89, 0x8a, 0xac, 0x49, 0x97, 0xa0, 0x9a, 0xa3,
0xd3, 0x3a, 0xc2, 0x13, 0xb2, 0xbb, 0xab, 0x0d,
0xf2, 0x35, 0xc5, 0x03, 0xde, 0x1c, 0xad, 0x6a,
0x03, 0x0a, 0x4c, 0xe1, 0x37, 0x8f, 0xbc, 0x13,
0xc0, 0x9a, 0x17, 0xd4, 0x2e, 0x36, 0x17, 0x51,
0x12, 0xb0, 0x79, 0xbf, 0x9b, 0xb3, 0xb0, 0x74,
0x25, 0x81, 0x7e, 0x21, 0x31, 0xb7, 0xc2, 0x5e,
0xfb, 0x36, 0xab, 0xf3, 0x7a, 0x5f, 0xa4, 0x5e,
0x8f, 0x0c, 0xbd, 0xcf, 0xf5, 0x50, 0xe7, 0x0c,
0x51, 0x55, 0x48, 0xe6, 0x15, 0xb6, 0xd4, 0xaf,
0x95, 0x72, 0x56, 0x94, 0xf7, 0x0e, 0xd6, 0x90,
0xe3, 0xd3, 0x5d, 0xbd, 0x93, 0xa1, 0xbd, 0x6c,
0xe4, 0xf2, 0x39, 0x4d, 0x54, 0x74, 0xcf, 0xf5,
0xeb, 0x70, 0xdb, 0x4f, 0x52, 0xcd, 0x39, 0x8f,
0x11, 0x54, 0x28, 0x06, 0x29, 0x8f, 0x23, 0xde,
0x9e, 0x2f, 0x7b, 0xb6, 0x5f, 0xa3, 0x89, 0x04,
0x99, 0x0a, 0xf1, 0x2d, 0xf9, 0x66, 0xd3, 0x13,
0x45, 0xbd, 0x6c, 0x22, 0x57, 0xf5, 0xb1, 0xb9,
0xdf, 0x5b, 0x7b, 0x1a, 0x3a, 0xdd, 0x6b, 0xc7,
0x35, 0x88, 0xed, 0xc4, 0x09, 0x70, 0x4e, 0x5f,
0xb5, 0x3e, 0xd1, 0x0b, 0xd0, 0xca, 0xef, 0x0b,
0xe9, 0x8b, 0x6f, 0xc3, 0x16, 0xc3, 0x3d, 0x79,
0x06, 0xef, 0x81, 0xf0, 0x60, 0x0b, 0x32, 0xe3,
0x86, 0x6b, 0x92, 0x38, 0x90, 0x62, 0xed, 0x84,
0x3a, 0xb7, 0x45, 0x43, 0x2e, 0xd0, 0x3a, 0x71,
0x9e, 0x80, 0xcc, 0x9c, 0xac, 0x27, 0x10, 0x91,
0xb7, 0xb2, 0xbd, 0x41, 0x40, 0xa7, 0xb7, 0xcf,
0xe7, 0x38, 0xca, 0x68, 0xdd, 0x62, 0x09, 0xff,
0x68, 0xce, 0xba, 0xe2, 0x07, 0x49, 0x09, 0xe7,
0x1f, 0xdf, 0xe6, 0x26, 0xe5, 0x0f, 0xa9, 0xbf,
0x2a, 0x5b, 0x67, 0x92, 0xa1, 0x10, 0x53, 0xb2,
0x7a, 0x07, 0x29, 0x9d, 0xfd, 0x6d, 0xb6, 0x3b,
0x45, 0xc1, 0x94, 0xcb, 0x1c, 0xc3, 0xce, 0xf6,
0x8a, 0x1a, 0x81, 0x66, 0xb0, 0xa5, 0x14, 0xc7,
0x9e, 0x1f, 0x6e, 0xb6, 0xff, 0x8b, 0x90, 0x87,
0x3a, 0x3f, 0xa8, 0xc2, 0x2d, 0x8f, 0x6f, 0xdb,
0xb4, 0xc4, 0x14, 0x3c, 0x1d, 0x12, 0x1d, 0x6d,
0xcf, 0xa6, 0x04, 0x6a, 0xa8, 0x13, 0x5e, 0xf2,
0x5e, 0x77, 0x80, 0x6b, 0x85, 0x83, 0xfe, 0xbb,
0xeb, 0x70, 0xcb, 0x5f, 0xe4, 0x95, 0xaa, 0x0f,
0x61, 0x36, 0x7c, 0xbb, 0x22, 0x1e, 0xba, 0x98,
0x43, 0x52, 0x33, 0xae, 0xed, 0x5d, 0x10, 0x2c,
0xb3, 0xa9, 0x31, 0x8e, 0x60, 0x54, 0xaf, 0x40,
0x6d, 0x2e, 0x18, 0xc2, 0x6a, 0xf4, 0x7b, 0x9a,
0x73, 0x0f, 0x58, 0x69, 0x23, 0xbb, 0xc4, 0x84,
0x53, 0x30, 0xe2, 0xd6, 0x1e, 0x10, 0xc1, 0xec,
0x82, 0x13, 0xab, 0x53, 0x86, 0xa2, 0xb9, 0xda,
0xbb, 0x3a, 0xa2, 0xbe, 0xb0, 0x10, 0x99, 0x0e,
0xe5, 0x9c, 0xc9, 0xf1, 0xce, 0x76, 0x46, 0xea,
0x86, 0xaa, 0x36, 0x83, 0x99, 0x09, 0x9b, 0x30,
0xd3, 0x26, 0xc7, 0xdf, 0x66, 0xc7, 0xf0, 0xdd,
0x08, 0x09, 0x15, 0x15, 0x21, 0x49, 0x46, 0xd8,
0x8a, 0x66, 0xca, 0x62, 0x9c, 0x79, 0x1d, 0x81,
0xea, 0x5d, 0x82, 0xb0, 0xa6, 0x6b, 0x5c, 0xf5,
0xb8, 0x8c, 0xf6, 0x16, 0x01, 0x2c, 0xf8, 0x27,
0xf8, 0xcf, 0x88, 0xfe, 0xf3, 0xa4, 0xfc, 0x17,
0x97, 0xe7, 0x07, 0x59, 0x06, 0xef, 0x30, 0x82,
0x06, 0xeb, 0x30, 0x82, 0x04, 0xd3, 0xa0, 0x03,
0x02, 0x01, 0x02, 0x02, 0x13, 0x33, 0x00, 0x00,
0x02, 0x39, 0xf9, 0xbb, 0x6a, 0x1d, 0x49, 0x64,
0x47, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x02, 0x39,
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
0x81, 0x8c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
0x13, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e,
0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e,
0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x52,
0x65, 0x64, 0x6d, 0x6f, 0x6e, 0x64, 0x31, 0x1e,
0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
0x15, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f,
0x66, 0x74, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x36,
0x30, 0x34, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
0x2d, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f,
0x66, 0x74, 0x20, 0x54, 0x50, 0x4d, 0x20, 0x52,
0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20,
0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
0x79, 0x20, 0x32, 0x30, 0x31, 0x34, 0x30, 0x1e,
0x17, 0x0d, 0x31, 0x39, 0x30, 0x33, 0x32, 0x31,
0x32, 0x30, 0x32, 0x39, 0x31, 0x35, 0x5a, 0x17,
0x0d, 0x32, 0x35, 0x30, 0x33, 0x32, 0x31, 0x32,
0x30, 0x32, 0x39, 0x31, 0x35, 0x5a, 0x30, 0x41,
0x31, 0x3f, 0x30, 0x3d, 0x06, 0x03, 0x55, 0x04,
0x03, 0x13, 0x36, 0x45, 0x55, 0x53, 0x2d, 0x53,
0x54, 0x4d, 0x2d, 0x4b, 0x45, 0x59, 0x49, 0x44,
0x2d, 0x31, 0x41, 0x44, 0x42, 0x39, 0x39, 0x34,
0x41, 0x42, 0x35, 0x38, 0x42, 0x45, 0x35, 0x37,
0x41, 0x30, 0x43, 0x43, 0x39, 0x42, 0x39, 0x30,
0x30, 0x45, 0x37, 0x38, 0x35, 0x31, 0x45, 0x31,
0x41, 0x34, 0x33, 0x43, 0x30, 0x38, 0x36, 0x36,
0x30, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06,
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f,
0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02,
0x01, 0x00, 0xdb, 0xe2, 0x23, 0xf9, 0x86, 0x8f,
0xa9, 0x71, 0x9f, 0x8b, 0xf9, 0x7c, 0xe9, 0x45,
0x2d, 0x59, 0x56, 0x5e, 0x96, 0xf4, 0xdd, 0x9a,
0x12, 0xcd, 0x90, 0x1a, 0x0c, 0xb5, 0x03, 0xbf,
0x09, 0xbe, 0xbf, 0xf7, 0x55, 0x52, 0xe8, 0x39,
0x4c, 0xbe, 0x2a, 0x28, 0x88, 0x78, 0x39, 0xa7,
0xcb, 0xf9, 0x4c, 0x55, 0xd2, 0x31, 0x96, 0x3b,
0x48, 0xa2, 0xf3, 0xf6, 0xd3, 0x1a, 0x81, 0x7f,
0x90, 0x62, 0xab, 0xec, 0x5a, 0xc7, 0xa0, 0x7f,
0x81, 0x32, 0x27, 0x9b, 0x29, 0x75, 0x7d, 0x1e,
0x96, 0xc5, 0xfa, 0x0e, 0x7c, 0xe0, 0x60, 0x96,
0x7a, 0xca, 0x94, 0xba, 0xe6, 0xb2, 0x69, 0xdd,
0xc4, 0x7d, 0xbb, 0xd3, 0xc4, 0xb4, 0x6e, 0x00,
0x86, 0x1f, 0x9d, 0x25, 0xe8, 0xae, 0xc7, 0x10,
0x84, 0xdc, 0xc0, 0x34, 0x24, 0x6e, 0xf7, 0xfc,
0xdd, 0x3d, 0x32, 0x7a, 0x43, 0x96, 0xd6, 0xc8,
0x7b, 0xf4, 0x9b, 0x3d, 0xa7, 0x1e, 0xba, 0x4d,
0xd0, 0x3b, 0x3d, 0x84, 0x9a, 0xd1, 0x25, 0x22,
0x5d, 0x00, 0x44, 0xb0, 0x59, 0xb7, 0x40, 0xc5,
0xa3, 0x53, 0x53, 0xaf, 0x8f, 0x9e, 0xfd, 0x8f,
0x1e, 0x02, 0xd3, 0x4f, 0xf7, 0x09, 0xce, 0xc5,
0xc6, 0x71, 0x5c, 0xe9, 0xe8, 0x7a, 0xb5, 0x6b,
0xa4, 0xbf, 0x0b, 0xd9, 0xb6, 0xfa, 0x24, 0xb0,
0xcd, 0x52, 0x22, 0x1d, 0x7e, 0xe8, 0x15, 0x2f,
0x1e, 0x5e, 0xa2, 0xec, 0xd3, 0xa8, 0x02, 0x77,
0xb9, 0x55, 0x9a, 0xcf, 0xcc, 0xd7, 0x08, 0x20,
0xa5, 0xda, 0x39, 0x9a, 0x30, 0x76, 0x90, 0x37,
0xa7, 0x60, 0xdf, 0x18, 0x12, 0x65, 0x17, 0xaa,
0xdd, 0x48, 0xd5, 0x12, 0x1d, 0x4c, 0x83, 0x5d,
0x81, 0x07, 0x1d, 0x18, 0x81, 0x40, 0x55, 0x60,
0x8f, 0xa3, 0x6b, 0x34, 0x1e, 0xd5, 0xe6, 0xcf,
0x52, 0x73, 0x77, 0x4a, 0x50, 0x4f, 0x1b, 0x0f,
0x39, 0xc3, 0x0d, 0x16, 0xf9, 0xbb, 0x4c, 0x77,
0xf6, 0x4e, 0xac, 0x9c, 0xfe, 0xe8, 0xbb, 0x52,
0xa5, 0x0a, 0x0e, 0x9b, 0xf0, 0x0d, 0xef, 0xfb,
0x6f, 0x89, 0x34, 0x7d, 0x47, 0xec, 0x14, 0x6a,
0xf4, 0x0a, 0xe1, 0x60, 0x44, 0x73, 0x7b, 0xa0,
0xab, 0x5b, 0x8c, 0x43, 0xa6, 0x05, 0x42, 0x61,
0x46, 0xaa, 0x1c, 0xf5, 0xec, 0x2c, 0x86, 0x85,
0x21, 0x99, 0xdf, 0x45, 0x8e, 0xf4, 0xd1, 0x1e,
0xfb, 0xcd, 0x9b, 0x94, 0x32, 0xe0, 0xa0, 0xcc,
0x4f, 0xad, 0xae, 0x44, 0x8b, 0x86, 0x27, 0x91,
0xfe, 0x60, 0x9f, 0xf2, 0x63, 0x30, 0x6c, 0x5d,
0x8d, 0xbc, 0xab, 0xd4, 0xf5, 0xa2, 0xb2, 0x74,
0xe8, 0xd4, 0x95, 0xf2, 0xd6, 0x03, 0x8b, 0xc9,
0xa3, 0x52, 0xe7, 0x63, 0x05, 0x64, 0x50, 0xe5,
0x0a, 0x6a, 0xa0, 0x6c, 0x50, 0xcd, 0x37, 0x98,
0xa8, 0x87, 0x02, 0x38, 0x5b, 0x6c, 0x02, 0x69,
0x3d, 0x1f, 0x95, 0x74, 0x4d, 0x46, 0x76, 0x2a,
0x9d, 0x62, 0xd4, 0xc7, 0x1b, 0xf9, 0x31, 0xa6,
0x51, 0xee, 0x7b, 0xc8, 0xe4, 0x6e, 0x3a, 0xcf,
0x4f, 0x4f, 0x49, 0x8a, 0xf5, 0x4f, 0x25, 0x93,
0x23, 0x02, 0xef, 0x79, 0xa6, 0x27, 0xbe, 0x5a,
0xe7, 0x74, 0xb7, 0xd7, 0xa8, 0xc1, 0xae, 0x55,
0x88, 0xa4, 0xc7, 0x4d, 0xb7, 0x62, 0xf0, 0xf9,
0x5b, 0xbf, 0x47, 0x5b, 0xfe, 0xcc, 0x0b, 0x89,
0x19, 0x65, 0x4b, 0x6f, 0xdf, 0x4f, 0x7d, 0x4d,
0x96, 0x42, 0x0d, 0x2a, 0xa1, 0xbd, 0x3e, 0x70,
0x92, 0xba, 0xc8, 0x59, 0xd5, 0x1d, 0x3a, 0x98,
0x53, 0x75, 0xa6, 0x32, 0xc8, 0x72, 0x03, 0x46,
0x5f, 0x5c, 0x13, 0xa4, 0xdb, 0xc7, 0x55, 0x35,
0x22, 0x0d, 0xc6, 0x17, 0x85, 0xbd, 0x46, 0x4b,
0xfa, 0x1e, 0x49, 0xc2, 0xfe, 0x1e, 0xf9, 0x62,
0x89, 0x56, 0x84, 0xdf, 0xa0, 0xfb, 0xfd, 0x93,
0xa4, 0x25, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
0x82, 0x01, 0x8e, 0x30, 0x82, 0x01, 0x8a, 0x30,
0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x84, 0x30,
0x1b, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x14,
0x30, 0x12, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04,
0x01, 0x82, 0x37, 0x15, 0x24, 0x06, 0x05, 0x67,
0x81, 0x05, 0x08, 0x03, 0x30, 0x16, 0x06, 0x03,
0x55, 0x1d, 0x20, 0x04, 0x0f, 0x30, 0x0d, 0x30,
0x0b, 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01,
0x82, 0x37, 0x15, 0x1f, 0x30, 0x12, 0x06, 0x03,
0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08,
0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00,
0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
0x16, 0x04, 0x14, 0xb8, 0x5f, 0xd5, 0x67, 0xca,
0x92, 0xc4, 0x0e, 0xcf, 0x0c, 0xd8, 0x1f, 0x6d,
0x3f, 0x03, 0x55, 0x6f, 0x38, 0xa6, 0x51, 0x30,
0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
0x30, 0x16, 0x80, 0x14, 0x7a, 0x8c, 0x0a, 0xce,
0x2f, 0x48, 0x62, 0x17, 0xe2, 0x94, 0xd1, 0xae,
0x55, 0xc1, 0x52, 0xec, 0x71, 0x74, 0xa4, 0x56,
0x30, 0x70, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04,
0x69, 0x30, 0x67, 0x30, 0x65, 0xa0, 0x63, 0xa0,
0x61, 0x86, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x3a,
0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x6d, 0x69,
0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6b, 0x69, 0x6f,
0x70, 0x73, 0x2f, 0x63, 0x72, 0x6c, 0x2f, 0x4d,
0x69, 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74,
0x25, 0x32, 0x30, 0x54, 0x50, 0x4d, 0x25, 0x32,
0x30, 0x52, 0x6f, 0x6f, 0x74, 0x25, 0x32, 0x30,
0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x65, 0x25, 0x32, 0x30, 0x41, 0x75,
0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x25,
0x32, 0x30, 0x32, 0x30, 0x31, 0x34, 0x2e, 0x63,
0x72, 0x6c, 0x30, 0x7d, 0x06, 0x08, 0x2b, 0x06,
0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x71,
0x30, 0x6f, 0x30, 0x6d, 0x06, 0x08, 0x2b, 0x06,
0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x61,
0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
0x77, 0x77, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f,
0x73, 0x6f, 0x66, 0x74, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x70, 0x6b, 0x69, 0x6f, 0x70, 0x73, 0x2f,
0x63, 0x65, 0x72, 0x74, 0x73, 0x2f, 0x4d, 0x69,
0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x25,
0x32, 0x30, 0x54, 0x50, 0x4d, 0x25, 0x32, 0x30,
0x52, 0x6f, 0x6f, 0x74, 0x25, 0x32, 0x30, 0x43,
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
0x74, 0x65, 0x25, 0x32, 0x30, 0x41, 0x75, 0x74,
0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x25, 0x32,
0x30, 0x32, 0x30, 0x31, 0x34, 0x2e, 0x63, 0x72,
0x74, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
0x03, 0x82, 0x02, 0x01, 0x00, 0x41, 0xaa, 0xfe,
0x28, 0x6c, 0xf7, 0x6b, 0x53, 0xde, 0x77, 0xc0,
0x80, 0x50, 0x94, 0xd9, 0xdb, 0x46, 0x8e, 0x6a,
0x93, 0xa9, 0x10, 0x37, 0x27, 0x1f, 0xf5, 0x70,
0xf1, 0xa8, 0xcf, 0xa1, 0x45, 0x86, 0x2a, 0xdd,
0x8f, 0xb8, 0xb5, 0xc1, 0xe6, 0xcf, 0x8a, 0xfa,
0x32, 0xa1, 0x4b, 0xb7, 0xa4, 0xbf, 0x0a, 0x48,
0xcb, 0x42, 0x63, 0x71, 0xc1, 0x96, 0xb9, 0x3a,
0x37, 0x84, 0x0e, 0x24, 0x39, 0xeb, 0x58, 0xce,
0x3d, 0xb7, 0xa9, 0x44, 0x92, 0x59, 0xb9, 0xff,
0xdb, 0x18, 0xbe, 0x6a, 0x5e, 0xe7, 0xce, 0xef,
0xb8, 0x40, 0x53, 0xaf, 0xc1, 0x9b, 0xfb, 0x42,
0x99, 0x7e, 0x9d, 0x05, 0x2b, 0x71, 0x0a, 0x7a,
0x7a, 0x44, 0xd1, 0x31, 0xca, 0xf0, 0x5f, 0x74,
0x85, 0xa9, 0xe2, 0xbc, 0xc8, 0x0c, 0xad, 0x57,
0xd1, 0xe9, 0x48, 0x90, 0x88, 0x57, 0x86, 0xd7,
0xc5, 0xc9, 0xe6, 0xb2, 0x5e, 0x5f, 0x13, 0xdc,
0x10, 0x7f, 0xdf, 0x63, 0x8a, 0xd5, 0x9e, 0x90,
0xc2, 0x75, 0x53, 0x1e, 0x68, 0x17, 0x2b, 0x03,
0x29, 0x15, 0x03, 0xc5, 0x8c, 0x66, 0x3e, 0xae,
0xbd, 0x4a, 0x32, 0x7e, 0x59, 0x89, 0x0b, 0x84,
0xc2, 0xd9, 0x90, 0xfa, 0x02, 0x22, 0x90, 0x8d,
0x9c, 0xb6, 0x0c, 0x4d, 0xe1, 0x28, 0x76, 0xd7,
0x82, 0xc3, 0x36, 0xc2, 0xa3, 0x2a, 0x52, 0xe5,
0xfe, 0x3c, 0x8f, 0xe3, 0x4b, 0xda, 0x6a, 0xdb,
0xc0, 0x7a, 0x3c, 0x57, 0xfa, 0x85, 0x8f, 0xfb,
0x62, 0xc3, 0xa1, 0x38, 0xce, 0x84, 0xf2, 0xba,
0x12, 0xf4, 0x30, 0x2a, 0x4a, 0x94, 0xa9, 0x35,
0x2c, 0x7d, 0x11, 0xc7, 0x68, 0x1f, 0x47, 0xaa,
0x57, 0x43, 0x06, 0x70, 0x79, 0x8c, 0xb6, 0x3b,
0x5d, 0x57, 0xf3, 0xf3, 0xc0, 0x2c, 0xc5, 0xde,
0x41, 0x99, 0xf6, 0xdd, 0x55, 0x8a, 0xe4, 0x13,
0xca, 0xc9, 0xec, 0x69, 0x93, 0x13, 0x48, 0xf0,
0x5f, 0xda, 0x2e, 0xfd, 0xfb, 0xa9, 0x1b, 0x92,
0xde, 0x49, 0x71, 0x37, 0x8c, 0x3f, 0xc2, 0x08,
0x0a, 0x83, 0x25, 0xf1, 0x6e, 0x0a, 0xe3, 0x55,
0x85, 0x96, 0x9a, 0x2d, 0xa2, 0xc0, 0xa1, 0xee,
0xfe, 0x23, 0x3b, 0x69, 0x22, 0x03, 0xfd, 0xcc,
0x8a, 0xdd, 0xb4, 0x53, 0x8d, 0x84, 0xa6, 0xac,
0xe0, 0x1e, 0x07, 0xe5, 0xd7, 0xf9, 0xcb, 0xb9,
0xe3, 0x9a, 0xb7, 0x84, 0x70, 0xa1, 0x93, 0xd6,
0x02, 0x1e, 0xfe, 0xdb, 0x28, 0x7c, 0xf7, 0xd4,
0x62, 0x6f, 0x80, 0x75, 0xc8, 0xd8, 0x35, 0x26,
0x0c, 0xcb, 0x84, 0xed, 0xbb, 0x95, 0xdf, 0x7f,
0xd5, 0xbb, 0x00, 0x96, 0x97, 0x32, 0xe7, 0xba,
0xe8, 0x29, 0xb5, 0x1a, 0x51, 0x81, 0xbb, 0x04,
0xd1, 0x21, 0x76, 0x34, 0x6d, 0x1e, 0x93, 0x96,
0x1f, 0x96, 0x53, 0x5f, 0x5c, 0x9e, 0xf3, 0x9d,
0x82, 0x1c, 0x39, 0x36, 0x59, 0xae, 0xc9, 0x3c,
0x53, 0x4a, 0x67, 0x65, 0x6e, 0xbf, 0xa6, 0xac,
0x3e, 0xda, 0xb2, 0xa7, 0x63, 0x07, 0x17, 0xe1,
0x5b, 0xda, 0x6a, 0x31, 0x9f, 0xfb, 0xb4, 0xea,
0xa1, 0x97, 0x08, 0x6e, 0xb2, 0x68, 0xf3, 0x72,
0x76, 0x99, 0xe8, 0x00, 0x46, 0x88, 0x26, 0xe1,
0x3c, 0x07, 0x2b, 0x78, 0x49, 0xda, 0x79, 0x3a,
0xbd, 0x6f, 0xca, 0x5c, 0xa0, 0xa8, 0xed, 0x34,
0xcc, 0xdb, 0x13, 0xe2, 0x51, 0x9b, 0x3d, 0x03,
0xac, 0xc7, 0xf6, 0x32, 0xe1, 0x11, 0x5d, 0xe1,
0xc5, 0xfd, 0x9e, 0x7a, 0xcd, 0x06, 0xb9, 0xe6,
0xfc, 0xe0, 0x03, 0x31, 0xf4, 0x4a, 0xa9, 0x3b,
0x79, 0x01, 0xb0, 0x64, 0x68, 0x9f, 0x6e, 0x76,
0xa1, 0xcc, 0xec, 0x17, 0x41, 0x9d, 0xd4, 0x5b,
0x4e, 0x9d, 0xe5, 0x46, 0xd4, 0x6b, 0x60, 0x2a,
0x23, 0xb5, 0x7a, 0x89, 0x7c, 0x27, 0x96, 0x65,
0x97, 0x56, 0xec, 0x98, 0xe3, 0x67, 0x70, 0x75,
0x62, 0x41, 0x72, 0x65, 0x61, 0x59, 0x01, 0x36,
0x00, 0x01, 0x00, 0x0b, 0x00, 0x06, 0x04, 0x72,
0x00, 0x20, 0x9d, 0xff, 0xcb, 0xf3, 0x6c, 0x38,
0x3a, 0xe6, 0x99, 0xfb, 0x98, 0x68, 0xdc, 0x6d,
0xcb, 0x89, 0xd7, 0x15, 0x38, 0x84, 0xbe, 0x28,
0x03, 0x92, 0x2c, 0x12, 0x41, 0x58, 0xbf, 0xad,
0x22, 0xae, 0x00, 0x10, 0x00, 0x10, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xc5, 0xb6,
0x9c, 0x06, 0x1d, 0xcf, 0xb9, 0xf2, 0x5e, 0x99,
0x7d, 0x6d, 0x73, 0xd8, 0x36, 0xc1, 0x4a, 0x90,
0x05, 0x4d, 0x82, 0x57, 0xc1, 0xb6, 0x6a, 0xd1,
0x43, 0x03, 0x85, 0xf8, 0x52, 0x4f, 0xd2, 0x27,
0x91, 0x0b, 0xb5, 0x93, 0xa0, 0x68, 0xf8, 0x80,
0x1b, 0xaa, 0x65, 0x97, 0x45, 0x11, 0x86, 0x34,
0xd6, 0x67, 0xf8, 0xd5, 0x12, 0x79, 0x84, 0xee,
0x70, 0x99, 0x00, 0x63, 0xa8, 0xb4, 0x43, 0x0b,
0x4c, 0x57, 0x4a, 0xd6, 0x9b, 0x75, 0x63, 0x8a,
0x46, 0x57, 0xdb, 0x14, 0xc8, 0x71, 0xd1, 0xb3,
0x07, 0x68, 0x58, 0xbc, 0x55, 0x84, 0x80, 0x2a,
0xd2, 0x36, 0x9f, 0xc1, 0x64, 0xa0, 0x11, 0x4b,
0xc9, 0x32, 0x31, 0x3a, 0xd6, 0x87, 0x26, 0x1a,
0x3a, 0x78, 0x3d, 0x89, 0xdb, 0x00, 0x28, 0x3b,
0xae, 0x2b, 0x1b, 0x56, 0xe2, 0x8c, 0x4c, 0x63,
0xac, 0x6e, 0x6c, 0xf7, 0xb5, 0x7d, 0x4d, 0x0b,
0x9f, 0x06, 0xa0, 0x10, 0x35, 0x38, 0x20, 0x4d,
0xcc, 0x07, 0xd7, 0x00, 0x4e, 0x86, 0xba, 0xfe,
0x8b, 0xe4, 0x3f, 0x4a, 0xd6, 0xca, 0xbf, 0x67,
0x40, 0x1a, 0xa4, 0xda, 0x82, 0x52, 0x15, 0xb8,
0x14, 0x3a, 0x7c, 0xa9, 0x02, 0xc1, 0x01, 0x69,
0xc6, 0x51, 0xd4, 0xbc, 0x1f, 0x95, 0xb2, 0xee,
0x1f, 0xdd, 0xb5, 0x73, 0x16, 0x5e, 0x29, 0x3f,
0x47, 0xac, 0x65, 0xfb, 0x63, 0x5c, 0xb9, 0xc8,
0x13, 0x2d, 0xec, 0x85, 0xde, 0x71, 0x0d, 0x84,
0x93, 0x74, 0x76, 0x91, 0xdd, 0x1d, 0x6d, 0x3d,
0xc7, 0x36, 0x19, 0x19, 0x86, 0xde, 0x7c, 0xca,
0xd6, 0xc6, 0x65, 0x7e, 0x4b, 0x24, 0x9c, 0xce,
0x92, 0x6b, 0x1c, 0xe0, 0xa0, 0xa9, 0x6c, 0xc3,
0xed, 0x4f, 0x2a, 0x54, 0x07, 0x00, 0x32, 0x5e,
0x1b, 0x94, 0x37, 0xcd, 0xe2, 0x32, 0xa8, 0xd5,
0x2c, 0xfb, 0x03, 0x9d, 0x79, 0xdf, 0x68, 0x63,
0x65, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x58,
0xa1, 0xff, 0x54, 0x43, 0x47, 0x80, 0x17, 0x00,
0x22, 0x00, 0x0b, 0xdb, 0x1f, 0x74, 0x21, 0x4f,
0xa9, 0x0d, 0x90, 0x64, 0xa2, 0x33, 0xbe, 0x3f,
0xf1, 0x95, 0xb0, 0x4e, 0x3f, 0x02, 0xdc, 0xad,
0xb0, 0x05, 0x13, 0xe6, 0x32, 0x5f, 0xed, 0x90,
0x2c, 0xad, 0xc0, 0x00, 0x14, 0x58, 0x52, 0x07,
0x5d, 0x64, 0x6c, 0x1f, 0xd1, 0x13, 0x7f, 0xc3,
0x74, 0xf6, 0x4b, 0xe3, 0xa0, 0x2e, 0xb7, 0x71,
0xda, 0x00, 0x00, 0x00, 0x00, 0x29, 0x3c, 0x64,
0xdf, 0x95, 0x38, 0xba, 0x73, 0xe3, 0x57, 0x61,
0xa0, 0x01, 0x24, 0x01, 0x08, 0xc9, 0xd6, 0xea,
0x60, 0xe4, 0x00, 0x22, 0x00, 0x0b, 0xe1, 0x86,
0xbb, 0x79, 0x27, 0xe5, 0x01, 0x19, 0x90, 0xb3,
0xe9, 0x08, 0xb0, 0xee, 0xfa, 0x3a, 0x67, 0xa9,
0xf3, 0xc8, 0x9e, 0x03, 0x41, 0x07, 0x75, 0x60,
0xbc, 0x94, 0x0c, 0x2a, 0xb7, 0xad, 0x00, 0x22,
0x00, 0x0b, 0x35, 0xb1, 0x72, 0xd6, 0x3c, 0xe9,
0x85, 0xe8, 0x66, 0xed, 0x10, 0x7a, 0x5c, 0xa3,
0xe6, 0xd9, 0x4d, 0xf0, 0x52, 0x69, 0x26, 0x14,
0xb4, 0x36, 0x7e, 0xad, 0x76, 0x9e, 0x58, 0x68,
0x3e, 0x91
};
/*
* Security Key By Yubico
* 5.1.X
* f8a011f3-8c0a-4d15-8006-17111f9edc7d
*/
*/
const unsigned char aaguid[16] = {
0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15,
0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d,
};
/*
* Windows Hello by Microsoft
*/
const unsigned char aaguid_tpm[16] = {
0x08, 0x98, 0x70, 0x58, 0xca, 0xdc, 0x4b, 0x81,
0xb6, 0xe1, 0x30, 0xde, 0x50, 0xdc, 0xbe, 0x96,
};
const char rp_id[] = "localhost";
const char rp_name[] = "sweet home localhost";
@ -606,7 +1214,7 @@ junk_cdh(void)
junk = malloc(sizeof(cdh));
assert(junk != NULL);
memcpy(junk, cdh, sizeof(cdh));
junk[0] = ~junk[0];
junk[0] = (unsigned char)~junk[0];
c = alloc_cred();
assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
@ -708,7 +1316,7 @@ junk_authdata(void)
junk = malloc(sizeof(authdata));
assert(junk != NULL);
memcpy(junk, authdata, sizeof(authdata));
junk[0] = ~junk[0];
junk[0] = (unsigned char)~junk[0];
unset = calloc(1, sizeof(aaguid));
assert(unset != NULL);
@ -749,7 +1357,7 @@ junk_sig(void)
junk = malloc(sizeof(sig));
assert(junk != NULL);
memcpy(junk, sig, sizeof(sig));
junk[0] = ~junk[0];
junk[0] = (unsigned char)~junk[0];
c = alloc_cred();
assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
@ -781,7 +1389,7 @@ junk_x509(void)
junk = malloc(sizeof(x509));
assert(junk != NULL);
memcpy(junk, x509, sizeof(x509));
junk[0] = ~junk[0];
junk[0] = (unsigned char)~junk[0];
c = alloc_cred();
assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
@ -954,6 +1562,31 @@ fmt_none(void)
free_cred(c);
}
static void
valid_tpm_cred(void)
{
fido_cred_t *c;
c = alloc_cred();
assert(fido_cred_set_type(c, COSE_RS256) == FIDO_OK);
assert(fido_cred_set_clientdata(c, cdh, sizeof(cdh)) == FIDO_OK);
assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
assert(fido_cred_set_authdata(c, authdata_tpm, sizeof(authdata_tpm)) == FIDO_OK);
assert(fido_cred_set_rk(c, FIDO_OPT_FALSE) == FIDO_OK);
assert(fido_cred_set_uv(c, FIDO_OPT_TRUE) == FIDO_OK);
assert(fido_cred_set_fmt(c, "tpm") == FIDO_OK);
assert(fido_cred_set_attstmt(c, attstmt_tpm, sizeof(attstmt_tpm)) == FIDO_OK);
assert(fido_cred_verify(c) == FIDO_OK);
assert(fido_cred_prot(c) == 0);
assert(fido_cred_pubkey_len(c) == sizeof(pubkey_tpm));
assert(memcmp(fido_cred_pubkey_ptr(c), pubkey_tpm, sizeof(pubkey_tpm)) == 0);
assert(fido_cred_id_len(c) == sizeof(id_tpm));
assert(memcmp(fido_cred_id_ptr(c), id_tpm, sizeof(id_tpm)) == 0);
assert(fido_cred_aaguid_len(c) == sizeof(aaguid_tpm));
assert(memcmp(fido_cred_aaguid_ptr(c), aaguid_tpm, sizeof(aaguid_tpm)) == 0);
free_cred(c);
}
int
main(void)
{
@ -983,6 +1616,7 @@ main(void)
wrong_credprot();
raw_authdata();
fmt_none();
valid_tpm_cred();
exit(0);
}

View File

@ -1,12 +1,14 @@
/*
* Copyright (c) 2019 Yubico AB. All rights reserved.
* Copyright (c) 2019-2021 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
#include <assert.h>
#include <err.h>
#include <fido.h>
#include <string.h>
#include <time.h>
#include "../fuzz/wiredata_fido2.h"
@ -17,6 +19,7 @@ static uint8_t ctap_nonce[8];
static uint8_t *wiredata_ptr;
static size_t wiredata_len;
static int initialised;
static long interval_ms;
static void *
dummy_open(const char *path)
@ -35,9 +38,9 @@ dummy_close(void *handle)
static int
dummy_read(void *handle, unsigned char *ptr, size_t len, int ms)
{
size_t n;
(void)ms;
struct timespec tv;
size_t n;
long d;
assert(handle == FAKE_DEV_HANDLE);
assert(ptr != NULL);
@ -52,6 +55,21 @@ dummy_read(void *handle, unsigned char *ptr, size_t len, int ms)
initialised = 1;
}
if (ms >= 0 && ms < interval_ms)
d = ms;
else
d = interval_ms;
if (d) {
tv.tv_sec = d / 1000;
tv.tv_nsec = (d % 1000) * 1000000;
if (nanosleep(&tv, NULL) == -1)
err(1, "nanosleep");
}
if (d != interval_ms)
return (-1); /* timeout */
if (wiredata_len < len)
n = wiredata_len;
else
@ -67,6 +85,8 @@ dummy_read(void *handle, unsigned char *ptr, size_t len, int ms)
static int
dummy_write(void *handle, const unsigned char *ptr, size_t len)
{
struct timespec tv;
assert(handle == FAKE_DEV_HANDLE);
assert(ptr != NULL);
assert(len == REPORT_LEN);
@ -74,6 +94,13 @@ dummy_write(void *handle, const unsigned char *ptr, size_t len)
if (!initialised)
memcpy(&ctap_nonce, &ptr[8], sizeof(ctap_nonce));
if (interval_ms) {
tv.tv_sec = interval_ms / 1000;
tv.tv_nsec = (interval_ms % 1000) * 1000000;
if (nanosleep(&tv, NULL) == -1)
err(1, "nanosleep");
}
return ((int)len);
}
@ -153,6 +180,7 @@ reopen(void)
wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data));
assert(fido_dev_open(dev, "dummy") == FIDO_OK);
assert(fido_dev_close(dev) == FIDO_OK);
fido_dev_free(&dev);
wiredata_clear(&wiredata);
}
@ -177,6 +205,34 @@ double_open(void)
assert(fido_dev_open(dev, "dummy") == FIDO_OK);
assert(fido_dev_open(dev, "dummy") == FIDO_ERR_INVALID_ARGUMENT);
assert(fido_dev_close(dev) == FIDO_OK);
fido_dev_free(&dev);
wiredata_clear(&wiredata);
}
static void
double_close(void)
{
const uint8_t cbor_info_data[] = { WIREDATA_CTAP_CBOR_INFO };
uint8_t *wiredata;
fido_dev_t *dev = NULL;
fido_dev_io_t io;
memset(&io, 0, sizeof(io));
io.open = dummy_open;
io.close = dummy_close;
io.read = dummy_read;
io.write = dummy_write;
wiredata = wiredata_setup(cbor_info_data, sizeof(cbor_info_data));
assert((dev = fido_dev_new()) != NULL);
assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT);
assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT);
assert(fido_dev_open(dev, "dummy") == FIDO_OK);
assert(fido_dev_close(dev) == FIDO_OK);
assert(fido_dev_close(dev) == FIDO_ERR_INVALID_ARGUMENT);
fido_dev_free(&dev);
wiredata_clear(&wiredata);
}
@ -215,6 +271,7 @@ is_fido2(void)
assert(fido_dev_is_fido2(dev) == true);
assert(fido_dev_supports_pin(dev) == false);
assert(fido_dev_close(dev) == FIDO_OK);
fido_dev_free(&dev);
wiredata_clear(&wiredata);
}
@ -248,9 +305,94 @@ has_pin(void)
assert(fido_dev_reset(dev) == FIDO_OK);
assert(fido_dev_has_pin(dev) == false);
assert(fido_dev_close(dev) == FIDO_OK);
fido_dev_free(&dev);
wiredata_clear(&wiredata);
}
static void
timeout_rx(void)
{
const uint8_t timeout_rx_data[] = {
WIREDATA_CTAP_CBOR_INFO,
WIREDATA_CTAP_KEEPALIVE,
WIREDATA_CTAP_KEEPALIVE,
WIREDATA_CTAP_KEEPALIVE,
WIREDATA_CTAP_KEEPALIVE,
WIREDATA_CTAP_KEEPALIVE,
WIREDATA_CTAP_CBOR_STATUS
};
uint8_t *wiredata;
fido_dev_t *dev = NULL;
fido_dev_io_t io;
memset(&io, 0, sizeof(io));
io.open = dummy_open;
io.close = dummy_close;
io.read = dummy_read;
io.write = dummy_write;
wiredata = wiredata_setup(timeout_rx_data, sizeof(timeout_rx_data));
assert((dev = fido_dev_new()) != NULL);
assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
assert(fido_dev_open(dev, "dummy") == FIDO_OK);
assert(fido_dev_set_timeout(dev, 3 * 1000) == FIDO_OK);
interval_ms = 1000;
assert(fido_dev_reset(dev) == FIDO_ERR_RX);
assert(fido_dev_close(dev) == FIDO_OK);
fido_dev_free(&dev);
wiredata_clear(&wiredata);
interval_ms = 0;
}
static void
timeout_ok(void)
{
const uint8_t timeout_ok_data[] = {
WIREDATA_CTAP_CBOR_INFO,
WIREDATA_CTAP_KEEPALIVE,
WIREDATA_CTAP_KEEPALIVE,
WIREDATA_CTAP_KEEPALIVE,
WIREDATA_CTAP_KEEPALIVE,
WIREDATA_CTAP_KEEPALIVE,
WIREDATA_CTAP_CBOR_STATUS
};
uint8_t *wiredata;
fido_dev_t *dev = NULL;
fido_dev_io_t io;
memset(&io, 0, sizeof(io));
io.open = dummy_open;
io.close = dummy_close;
io.read = dummy_read;
io.write = dummy_write;
wiredata = wiredata_setup(timeout_ok_data, sizeof(timeout_ok_data));
assert((dev = fido_dev_new()) != NULL);
assert(fido_dev_set_io_functions(dev, &io) == FIDO_OK);
assert(fido_dev_open(dev, "dummy") == FIDO_OK);
assert(fido_dev_set_timeout(dev, 30 * 1000) == FIDO_OK);
interval_ms = 1000;
assert(fido_dev_reset(dev) == FIDO_OK);
assert(fido_dev_close(dev) == FIDO_OK);
fido_dev_free(&dev);
wiredata_clear(&wiredata);
interval_ms = 0;
}
static void
timeout_misc(void)
{
fido_dev_t *dev;
assert((dev = fido_dev_new()) != NULL);
assert(fido_dev_set_timeout(dev, -2) == FIDO_ERR_INVALID_ARGUMENT);
assert(fido_dev_set_timeout(dev, 3 * 1000) == FIDO_OK);
assert(fido_dev_set_timeout(dev, -1) == FIDO_OK);
fido_dev_free(&dev);
}
int
main(void)
{
@ -259,8 +401,12 @@ main(void)
open_iff_ok();
reopen();
double_open();
double_close();
is_fido2();
has_pin();
timeout_rx();
timeout_ok();
timeout_misc();
exit(0);
}

View File

@ -1,4 +1,4 @@
# 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.
@ -30,11 +30,16 @@ list(APPEND FIDO_SOURCES
pin.c
random.c
reset.c
rs1.c
rs256.c
time.c
tpm.c
types.c
u2f.c
)
if(FUZZ)
list(APPEND FIDO_SOURCES ../fuzz/clock.c)
list(APPEND FIDO_SOURCES ../fuzz/prng.c)
list(APPEND FIDO_SOURCES ../fuzz/uniform_random.c)
list(APPEND FIDO_SOURCES ../fuzz/udev.c)
@ -62,7 +67,8 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
list(APPEND FIDO_SOURCES hid_netbsd.c hid_unix.c)
elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
list(APPEND FIDO_SOURCES hid_openbsd.c hid_unix.c)
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
CMAKE_SYSTEM_NAME STREQUAL "MidnightBSD")
list(APPEND FIDO_SOURCES hid_freebsd.c hid_unix.c)
else()
message(FATAL_ERROR "please define a hid backend for your platform")
@ -75,11 +81,11 @@ endif()
list(APPEND COMPAT_SOURCES
../openbsd-compat/bsd-getpagesize.c
../openbsd-compat/clock_gettime.c
../openbsd-compat/endian_win32.c
../openbsd-compat/explicit_bzero.c
../openbsd-compat/explicit_bzero_win32.c
../openbsd-compat/freezero.c
../openbsd-compat/hkdf.c
../openbsd-compat/recallocarray.c
../openbsd-compat/strlcat.c
../openbsd-compat/timingsafe_bcmp.c
@ -87,9 +93,6 @@ list(APPEND COMPAT_SOURCES
if(WIN32)
list(APPEND BASE_LIBRARIES wsock32 ws2_32 bcrypt setupapi hid)
if(USE_WINHELLO)
list(APPEND BASE_LIBRARIES webauthn)
endif()
elseif(APPLE)
list(APPEND BASE_LIBRARIES "-framework CoreFoundation" "-framework IOKit")
endif()

View File

@ -4,7 +4,6 @@
* license that can be found in the LICENSE file.
*/
#include <openssl/ecdsa.h>
#include <openssl/sha.h>
#include "fido.h"
@ -79,7 +78,7 @@ parse_assert_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
static int
fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert,
const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin)
const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int *ms)
{
fido_blob_t f;
fido_opt_t uv = assert->uv;
@ -127,7 +126,7 @@ fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert,
if (pin != NULL || (uv == FIDO_OPT_TRUE &&
fido_dev_supports_permissions(dev))) {
if ((r = cbor_add_uv_params(dev, cmd, &assert->cdh, pk, ecdh,
pin, assert->rp_id, &argv[5], &argv[6])) != FIDO_OK) {
pin, assert->rp_id, &argv[5], &argv[6], ms)) != FIDO_OK) {
fido_log_debug("%s: cbor_add_uv_params", __func__);
goto fail;
}
@ -144,7 +143,7 @@ fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert,
/* frame and transmit */
if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -159,7 +158,7 @@ fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert,
}
static int
fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms)
fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
@ -200,11 +199,11 @@ fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms)
}
static int
fido_get_next_assert_tx(fido_dev_t *dev)
fido_get_next_assert_tx(fido_dev_t *dev, int *ms)
{
const unsigned char cbor[] = { CTAP_CBOR_NEXT_ASSERT };
if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor)) < 0) {
if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor), ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
return (FIDO_ERR_TX);
}
@ -213,7 +212,7 @@ fido_get_next_assert_tx(fido_dev_t *dev)
}
static int
fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms)
fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
@ -243,16 +242,17 @@ fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms)
static int
fido_dev_get_assert_wait(fido_dev_t *dev, fido_assert_t *assert,
const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int ms)
const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int *ms)
{
int r;
if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin)) != FIDO_OK ||
if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin,
ms)) != FIDO_OK ||
(r = fido_dev_get_assert_rx(dev, assert, ms)) != FIDO_OK)
return (r);
while (assert->stmt_len < assert->stmt_cnt) {
if ((r = fido_get_next_assert_tx(dev)) != FIDO_OK ||
if ((r = fido_get_next_assert_tx(dev, ms)) != FIDO_OK ||
(r = fido_get_next_assert_rx(dev, assert, ms)) != FIDO_OK)
return (r);
assert->stmt_len++;
@ -286,11 +286,12 @@ fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin)
{
fido_blob_t *ecdh = NULL;
es256_pk_t *pk = NULL;
int ms = dev->timeout_ms;
int r;
#ifdef USE_WINHELLO
if (dev->flags & FIDO_DEV_WINHELLO)
return (fido_winhello_get_assert(dev, assert, pin));
return (fido_winhello_get_assert(dev, assert, pin, ms));
#endif
if (assert->rp_id == NULL || assert->cdh.ptr == NULL) {
@ -302,19 +303,19 @@ 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.mask != 0)
return (FIDO_ERR_UNSUPPORTED_OPTION);
return (u2f_authenticate(dev, assert, -1));
return (u2f_authenticate(dev, assert, &ms));
}
if (pin != NULL || (assert->uv == FIDO_OPT_TRUE &&
fido_dev_supports_permissions(dev)) ||
(assert->ext.mask & FIDO_EXT_HMAC_SECRET)) {
if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
if ((r = fido_do_ecdh(dev, &pk, &ecdh, &ms)) != FIDO_OK) {
fido_log_debug("%s: fido_do_ecdh", __func__);
goto fail;
}
}
r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, -1);
r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, &ms);
if (r == FIDO_OK && (assert->ext.mask & FIDO_EXT_HMAC_SECRET))
if (decrypt_hmac_secrets(dev, assert, ecdh) < 0) {
fido_log_debug("%s: decrypt_hmac_secrets", __func__);
@ -372,7 +373,8 @@ fido_get_signed_hash(int cose_alg, fido_blob_t *dgst,
unsigned char *authdata_ptr = NULL;
size_t authdata_len;
struct cbor_load_result cbor;
SHA256_CTX ctx;
const EVP_MD *md = NULL;
EVP_MD_CTX *ctx = NULL;
int ok = -1;
if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len,
@ -386,10 +388,13 @@ fido_get_signed_hash(int cose_alg, fido_blob_t *dgst,
authdata_len = cbor_bytestring_length(item);
if (cose_alg != COSE_EDDSA) {
if (dgst->len < SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 ||
SHA256_Update(&ctx, authdata_ptr, authdata_len) == 0 ||
SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 ||
SHA256_Final(dgst->ptr, &ctx) == 0) {
if (dgst->len < SHA256_DIGEST_LENGTH ||
(md = EVP_sha256()) == NULL ||
(ctx = EVP_MD_CTX_new()) == NULL ||
EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
EVP_DigestUpdate(ctx, authdata_ptr, authdata_len) != 1 ||
EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 ||
EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) {
fido_log_debug("%s: sha256", __func__);
goto fail;
}
@ -411,122 +416,7 @@ fido_get_signed_hash(int cose_alg, fido_blob_t *dgst,
if (item != NULL)
cbor_decref(&item);
return (ok);
}
int
fido_verify_sig_es256(const fido_blob_t *dgst, const es256_pk_t *pk,
const fido_blob_t *sig)
{
EVP_PKEY *pkey = NULL;
EC_KEY *ec = NULL;
int ok = -1;
/* ECDSA_verify needs ints */
if (dgst->len > INT_MAX || sig->len > INT_MAX) {
fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
dgst->len, sig->len);
return (-1);
}
if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL ||
(ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) {
fido_log_debug("%s: pk -> ec", __func__);
goto fail;
}
if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr,
(int)sig->len, ec) != 1) {
fido_log_debug("%s: ECDSA_verify", __func__);
goto fail;
}
ok = 0;
fail:
if (pkey != NULL)
EVP_PKEY_free(pkey);
return (ok);
}
int
fido_verify_sig_rs256(const fido_blob_t *dgst, const rs256_pk_t *pk,
const fido_blob_t *sig)
{
EVP_PKEY *pkey = NULL;
RSA *rsa = NULL;
int ok = -1;
/* RSA_verify needs unsigned ints */
if (dgst->len > UINT_MAX || sig->len > UINT_MAX) {
fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
dgst->len, sig->len);
return (-1);
}
if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL ||
(rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) {
fido_log_debug("%s: pk -> ec", __func__);
goto fail;
}
if (RSA_verify(NID_sha256, dgst->ptr, (unsigned int)dgst->len, sig->ptr,
(unsigned int)sig->len, rsa) != 1) {
fido_log_debug("%s: RSA_verify", __func__);
goto fail;
}
ok = 0;
fail:
if (pkey != NULL)
EVP_PKEY_free(pkey);
return (ok);
}
int
fido_verify_sig_eddsa(const fido_blob_t *dgst, const eddsa_pk_t *pk,
const fido_blob_t *sig)
{
EVP_PKEY *pkey = NULL;
EVP_MD_CTX *mdctx = NULL;
int ok = -1;
/* EVP_DigestVerify needs ints */
if (dgst->len > INT_MAX || sig->len > INT_MAX) {
fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
dgst->len, sig->len);
return (-1);
}
if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
fido_log_debug("%s: pk -> pkey", __func__);
goto fail;
}
if ((mdctx = EVP_MD_CTX_new()) == NULL) {
fido_log_debug("%s: EVP_MD_CTX_new", __func__);
goto fail;
}
if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) {
fido_log_debug("%s: EVP_DigestVerifyInit", __func__);
goto fail;
}
if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr,
dgst->len) != 1) {
fido_log_debug("%s: EVP_DigestVerify", __func__);
goto fail;
}
ok = 0;
fail:
if (mdctx != NULL)
EVP_MD_CTX_free(mdctx);
if (pkey != NULL)
EVP_PKEY_free(pkey);
EVP_MD_CTX_free(ctx);
return (ok);
}
@ -589,13 +479,13 @@ fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg,
switch (cose_alg) {
case COSE_ES256:
ok = fido_verify_sig_es256(&dgst, pk, &stmt->sig);
ok = es256_pk_verify_sig(&dgst, pk, &stmt->sig);
break;
case COSE_RS256:
ok = fido_verify_sig_rs256(&dgst, pk, &stmt->sig);
ok = rs256_pk_verify_sig(&dgst, pk, &stmt->sig);
break;
case COSE_EDDSA:
ok = fido_verify_sig_eddsa(&dgst, pk, &stmt->sig);
ok = eddsa_pk_verify_sig(&dgst, pk, &stmt->sig);
break;
default:
fido_log_debug("%s: unsupported cose_alg %d", __func__,

View File

@ -22,7 +22,7 @@ parse_authkey(const cbor_item_t *key, const cbor_item_t *val, void *arg)
}
static int
fido_dev_authkey_tx(fido_dev_t *dev)
fido_dev_authkey_tx(fido_dev_t *dev, int *ms)
{
fido_blob_t f;
cbor_item_t *argv[2];
@ -43,7 +43,7 @@ fido_dev_authkey_tx(fido_dev_t *dev)
/* frame and transmit */
if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
&f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
&f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -58,13 +58,13 @@ fido_dev_authkey_tx(fido_dev_t *dev)
}
static int
fido_dev_authkey_rx(fido_dev_t *dev, es256_pk_t *authkey, int ms)
fido_dev_authkey_rx(fido_dev_t *dev, es256_pk_t *authkey, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
fido_log_debug("%s: dev=%p, authkey=%p, ms=%d", __func__, (void *)dev,
(void *)authkey, ms);
(void *)authkey, *ms);
memset(authkey, 0, sizeof(*authkey));
@ -79,11 +79,11 @@ fido_dev_authkey_rx(fido_dev_t *dev, es256_pk_t *authkey, int ms)
}
static int
fido_dev_authkey_wait(fido_dev_t *dev, es256_pk_t *authkey, int ms)
fido_dev_authkey_wait(fido_dev_t *dev, es256_pk_t *authkey, int *ms)
{
int r;
if ((r = fido_dev_authkey_tx(dev)) != FIDO_OK ||
if ((r = fido_dev_authkey_tx(dev, ms)) != FIDO_OK ||
(r = fido_dev_authkey_rx(dev, authkey, ms)) != FIDO_OK)
return (r);
@ -91,7 +91,7 @@ fido_dev_authkey_wait(fido_dev_t *dev, es256_pk_t *authkey, int ms)
}
int
fido_dev_authkey(fido_dev_t *dev, es256_pk_t *authkey)
fido_dev_authkey(fido_dev_t *dev, es256_pk_t *authkey, int *ms)
{
return (fido_dev_authkey_wait(dev, authkey, -1));
return (fido_dev_authkey_wait(dev, authkey, ms));
}

View File

@ -58,7 +58,7 @@ bio_prepare_hmac(uint8_t cmd, cbor_item_t **argv, size_t argc,
static int
bio_tx(fido_dev_t *dev, uint8_t subcmd, cbor_item_t **sub_argv, size_t sub_argc,
const char *pin, const fido_blob_t *token)
const char *pin, const fido_blob_t *token, int *ms)
{
cbor_item_t *argv[5];
es256_pk_t *pk = NULL;
@ -90,12 +90,12 @@ bio_tx(fido_dev_t *dev, uint8_t subcmd, cbor_item_t **sub_argv, size_t sub_argc,
/* pinProtocol, pinAuth */
if (pin) {
if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
fido_log_debug("%s: fido_do_ecdh", __func__);
goto fail;
}
if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin,
NULL, &argv[4], &argv[3])) != FIDO_OK) {
NULL, &argv[4], &argv[3], ms)) != FIDO_OK) {
fido_log_debug("%s: cbor_add_uv_params", __func__);
goto fail;
}
@ -109,7 +109,7 @@ bio_tx(fido_dev_t *dev, uint8_t subcmd, cbor_item_t **sub_argv, size_t sub_argc,
/* framing and transmission */
if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -231,7 +231,7 @@ bio_parse_template_array(const cbor_item_t *key, const cbor_item_t *val,
}
static int
bio_rx_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, int ms)
bio_rx_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
@ -256,11 +256,11 @@ bio_rx_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, int ms)
static int
bio_get_template_array_wait(fido_dev_t *dev, fido_bio_template_array_t *ta,
const char *pin, int ms)
const char *pin, int *ms)
{
int r;
if ((r = bio_tx(dev, CMD_ENUM, NULL, 0, pin, NULL)) != FIDO_OK ||
if ((r = bio_tx(dev, CMD_ENUM, NULL, 0, pin, NULL, ms)) != FIDO_OK ||
(r = bio_rx_template_array(dev, ta, ms)) != FIDO_OK)
return (r);
@ -271,15 +271,17 @@ int
fido_bio_dev_get_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta,
const char *pin)
{
int ms = dev->timeout_ms;
if (pin == NULL)
return (FIDO_ERR_INVALID_ARGUMENT);
return (bio_get_template_array_wait(dev, ta, pin, -1));
return (bio_get_template_array_wait(dev, ta, pin, &ms));
}
static int
bio_set_template_name_wait(fido_dev_t *dev, const fido_bio_template_t *t,
const char *pin, int ms)
const char *pin, int *ms)
{
cbor_item_t *argv[2];
int r = FIDO_ERR_INTERNAL;
@ -292,7 +294,8 @@ bio_set_template_name_wait(fido_dev_t *dev, const fido_bio_template_t *t,
goto fail;
}
if ((r = bio_tx(dev, CMD_SET_NAME, argv, 2, pin, NULL)) != FIDO_OK ||
if ((r = bio_tx(dev, CMD_SET_NAME, argv, 2, pin, NULL,
ms)) != FIDO_OK ||
(r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
fido_log_debug("%s: tx/rx", __func__);
goto fail;
@ -309,10 +312,12 @@ int
fido_bio_dev_set_template_name(fido_dev_t *dev, const fido_bio_template_t *t,
const char *pin)
{
int ms = dev->timeout_ms;
if (pin == NULL || t->name == NULL)
return (FIDO_ERR_INVALID_ARGUMENT);
return (bio_set_template_name_wait(dev, t, pin, -1));
return (bio_set_template_name_wait(dev, t, pin, &ms));
}
static void
@ -378,7 +383,7 @@ bio_parse_template_id(const cbor_item_t *key, const cbor_item_t *val,
static int
bio_rx_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t,
fido_bio_enroll_t *e, int ms)
fido_bio_enroll_t *e, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
@ -411,7 +416,7 @@ bio_rx_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t,
static int
bio_enroll_begin_wait(fido_dev_t *dev, fido_bio_template_t *t,
fido_bio_enroll_t *e, uint32_t timo_ms, int ms)
fido_bio_enroll_t *e, uint32_t timo_ms, int *ms)
{
cbor_item_t *argv[3];
const uint8_t cmd = CMD_ENROLL_BEGIN;
@ -424,7 +429,7 @@ bio_enroll_begin_wait(fido_dev_t *dev, fido_bio_template_t *t,
goto fail;
}
if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token)) != FIDO_OK ||
if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token, ms)) != FIDO_OK ||
(r = bio_rx_enroll_begin(dev, t, e, ms)) != FIDO_OK) {
fido_log_debug("%s: tx/rx", __func__);
goto fail;
@ -444,6 +449,7 @@ fido_bio_dev_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t,
es256_pk_t *pk = NULL;
fido_blob_t *ecdh = NULL;
fido_blob_t *token = NULL;
int ms = dev->timeout_ms;
int r;
if (pin == NULL || e->token != NULL)
@ -454,13 +460,13 @@ fido_bio_dev_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t,
goto fail;
}
if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
if ((r = fido_do_ecdh(dev, &pk, &ecdh, &ms)) != FIDO_OK) {
fido_log_debug("%s: fido_do_ecdh", __func__);
goto fail;
}
if ((r = fido_dev_get_uv_token(dev, CTAP_CBOR_BIO_ENROLL_PRE, pin, ecdh,
pk, NULL, token)) != FIDO_OK) {
pk, NULL, token, &ms)) != FIDO_OK) {
fido_log_debug("%s: fido_dev_get_uv_token", __func__);
goto fail;
}
@ -475,11 +481,11 @@ fido_bio_dev_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t,
if (r != FIDO_OK)
return (r);
return (bio_enroll_begin_wait(dev, t, e, timo_ms, -1));
return (bio_enroll_begin_wait(dev, t, e, timo_ms, &ms));
}
static int
bio_rx_enroll_continue(fido_dev_t *dev, fido_bio_enroll_t *e, int ms)
bio_rx_enroll_continue(fido_dev_t *dev, fido_bio_enroll_t *e, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
@ -505,7 +511,7 @@ bio_rx_enroll_continue(fido_dev_t *dev, fido_bio_enroll_t *e, int ms)
static int
bio_enroll_continue_wait(fido_dev_t *dev, const fido_bio_template_t *t,
fido_bio_enroll_t *e, uint32_t timo_ms, int ms)
fido_bio_enroll_t *e, uint32_t timo_ms, int *ms)
{
cbor_item_t *argv[3];
const uint8_t cmd = CMD_ENROLL_NEXT;
@ -519,7 +525,7 @@ bio_enroll_continue_wait(fido_dev_t *dev, const fido_bio_template_t *t,
goto fail;
}
if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token)) != FIDO_OK ||
if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token, ms)) != FIDO_OK ||
(r = bio_rx_enroll_continue(dev, e, ms)) != FIDO_OK) {
fido_log_debug("%s: tx/rx", __func__);
goto fail;
@ -536,19 +542,21 @@ int
fido_bio_dev_enroll_continue(fido_dev_t *dev, const fido_bio_template_t *t,
fido_bio_enroll_t *e, uint32_t timo_ms)
{
int ms = dev->timeout_ms;
if (e->token == NULL)
return (FIDO_ERR_INVALID_ARGUMENT);
return (bio_enroll_continue_wait(dev, t, e, timo_ms, -1));
return (bio_enroll_continue_wait(dev, t, e, timo_ms, &ms));
}
static int
bio_enroll_cancel_wait(fido_dev_t *dev, int ms)
bio_enroll_cancel_wait(fido_dev_t *dev, int *ms)
{
const uint8_t cmd = CMD_ENROLL_CANCEL;
int r;
if ((r = bio_tx(dev, cmd, NULL, 0, NULL, NULL)) != FIDO_OK ||
if ((r = bio_tx(dev, cmd, NULL, 0, NULL, NULL, ms)) != FIDO_OK ||
(r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
fido_log_debug("%s: tx/rx", __func__);
return (r);
@ -560,12 +568,14 @@ bio_enroll_cancel_wait(fido_dev_t *dev, int ms)
int
fido_bio_dev_enroll_cancel(fido_dev_t *dev)
{
return (bio_enroll_cancel_wait(dev, -1));
int ms = dev->timeout_ms;
return (bio_enroll_cancel_wait(dev, &ms));
}
static int
bio_enroll_remove_wait(fido_dev_t *dev, const fido_bio_template_t *t,
const char *pin, int ms)
const char *pin, int *ms)
{
cbor_item_t *argv[1];
const uint8_t cmd = CMD_ENROLL_REMOVE;
@ -578,7 +588,7 @@ bio_enroll_remove_wait(fido_dev_t *dev, const fido_bio_template_t *t,
goto fail;
}
if ((r = bio_tx(dev, cmd, argv, 1, pin, NULL)) != FIDO_OK ||
if ((r = bio_tx(dev, cmd, argv, 1, pin, NULL, ms)) != FIDO_OK ||
(r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
fido_log_debug("%s: tx/rx", __func__);
goto fail;
@ -595,7 +605,9 @@ int
fido_bio_dev_enroll_remove(fido_dev_t *dev, const fido_bio_template_t *t,
const char *pin)
{
return (bio_enroll_remove_wait(dev, t, pin, -1));
int ms = dev->timeout_ms;
return (bio_enroll_remove_wait(dev, t, pin, &ms));
}
static void
@ -640,7 +652,7 @@ bio_parse_info(const cbor_item_t *key, const cbor_item_t *val, void *arg)
}
static int
bio_rx_info(fido_dev_t *dev, fido_bio_info_t *i, int ms)
bio_rx_info(fido_dev_t *dev, fido_bio_info_t *i, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
@ -664,11 +676,12 @@ bio_rx_info(fido_dev_t *dev, fido_bio_info_t *i, int ms)
}
static int
bio_get_info_wait(fido_dev_t *dev, fido_bio_info_t *i, int ms)
bio_get_info_wait(fido_dev_t *dev, fido_bio_info_t *i, int *ms)
{
int r;
if ((r = bio_tx(dev, CMD_GET_INFO, NULL, 0, NULL, NULL)) != FIDO_OK ||
if ((r = bio_tx(dev, CMD_GET_INFO, NULL, 0, NULL, NULL,
ms)) != FIDO_OK ||
(r = bio_rx_info(dev, i, ms)) != FIDO_OK) {
fido_log_debug("%s: tx/rx", __func__);
return (r);
@ -680,7 +693,9 @@ bio_get_info_wait(fido_dev_t *dev, fido_bio_info_t *i, int ms)
int
fido_bio_dev_get_info(fido_dev_t *dev, fido_bio_info_t *i)
{
return (bio_get_info_wait(dev, i, -1));
int ms = dev->timeout_ms;
return (bio_get_info_wait(dev, i, &ms));
}
const char *

View File

@ -1,5 +1,5 @@
/*
* 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.
*/
@ -560,6 +560,32 @@ cbor_encode_pubkey_list(const fido_blob_array_t *list)
return (NULL);
}
cbor_item_t *
cbor_encode_str_array(const fido_str_array_t *a)
{
cbor_item_t *array = NULL;
cbor_item_t *entry = NULL;
if ((array = cbor_new_definite_array(a->len)) == NULL)
goto fail;
for (size_t i = 0; i < a->len; i++) {
if ((entry = cbor_build_string(a->ptr[i])) == NULL ||
cbor_array_push(array, entry) == false)
goto fail;
cbor_decref(&entry);
}
return (array);
fail:
if (entry != NULL)
cbor_decref(&entry);
if (array != NULL)
cbor_decref(&array);
return (NULL);
}
static int
cbor_encode_largeblob_key_ext(cbor_item_t *map)
{
@ -584,6 +610,8 @@ cbor_encode_cred_ext(const fido_cred_ext_t *ext, const fido_blob_t *blob)
size++;
if (ext->mask & FIDO_EXT_LARGEBLOB_KEY)
size++;
if (ext->mask & FIDO_EXT_MINPINLEN)
size++;
if (size == 0 || (item = cbor_new_definite_map(size)) == NULL)
return (NULL);
@ -615,6 +643,12 @@ cbor_encode_cred_ext(const fido_cred_ext_t *ext, const fido_blob_t *blob)
return (NULL);
}
}
if (ext->mask & FIDO_EXT_MINPINLEN) {
if (cbor_add_bool(item, "minPinLength", FIDO_OPT_TRUE) < 0) {
cbor_decref(&item);
return (NULL);
}
}
return (item);
}
@ -706,11 +740,7 @@ cbor_encode_change_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret,
unsigned int dgst_len;
cbor_item_t *item = NULL;
const EVP_MD *md = NULL;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
HMAC_CTX ctx;
#else
HMAC_CTX *ctx = NULL;
#endif
fido_blob_t key;
uint8_t prot;
size_t outlen;
@ -726,19 +756,6 @@ cbor_encode_change_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret,
if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32)
key.len = 32;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
HMAC_CTX_init(&ctx);
if ((md = EVP_sha256()) == NULL ||
HMAC_Init_ex(&ctx, key.ptr, (int)key.len, md, NULL) == 0 ||
HMAC_Update(&ctx, new_pin_enc->ptr, new_pin_enc->len) == 0 ||
HMAC_Update(&ctx, pin_hash_enc->ptr, pin_hash_enc->len) == 0 ||
HMAC_Final(&ctx, dgst, &dgst_len) == 0 ||
dgst_len != SHA256_DIGEST_LENGTH) {
fido_log_debug("%s: HMAC", __func__);
goto fail;
}
#else
if ((ctx = HMAC_CTX_new()) == NULL ||
(md = EVP_sha256()) == NULL ||
HMAC_Init_ex(ctx, key.ptr, (int)key.len, md, NULL) == 0 ||
@ -749,7 +766,6 @@ cbor_encode_change_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret,
fido_log_debug("%s: HMAC", __func__);
goto fail;
}
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len;
@ -759,10 +775,7 @@ cbor_encode_change_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret,
}
fail:
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
if (ctx != NULL)
HMAC_CTX_free(ctx);
#endif
HMAC_CTX_free(ctx);
return (item);
}
@ -775,6 +788,7 @@ cbor_encode_hmac_secret_param(const fido_dev_t *dev, cbor_item_t *item,
cbor_item_t *argv[4];
struct cbor_pair pair;
fido_blob_t *enc = NULL;
uint8_t prot;
int r;
memset(argv, 0, sizeof(argv));
@ -801,11 +815,17 @@ cbor_encode_hmac_secret_param(const fido_dev_t *dev, cbor_item_t *item,
goto fail;
}
if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
r = FIDO_ERR_INTERNAL;
goto fail;
}
/* XXX not pin, but salt */
if ((argv[0] = es256_pk_encode(pk, 1)) == NULL ||
(argv[1] = fido_blob_encode(enc)) == NULL ||
(argv[2] = cbor_encode_pin_auth(dev, ecdh, enc)) == NULL ||
(argv[3] = cbor_encode_pin_opt(dev)) == NULL) {
(prot != 1 && (argv[3] = cbor_build_uint8(prot)) == NULL)) {
fido_log_debug("%s: cbor encode", __func__);
r = FIDO_ERR_INTERNAL;
goto fail;
@ -896,7 +916,7 @@ cbor_decode_fmt(const cbor_item_t *item, char **fmt)
}
if (strcmp(type, "packed") && strcmp(type, "fido-u2f") &&
strcmp(type, "none")) {
strcmp(type, "none") && strcmp(type, "tpm")) {
fido_log_debug("%s: type=%s", __func__, type);
free(type);
return (-1);
@ -1141,6 +1161,14 @@ decode_cred_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg)
}
if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE)
authdata_ext->mask |= FIDO_EXT_CRED_BLOB;
} else if (strcmp(type, "minPinLength") == 0) {
if (cbor_isa_uint(val) == false ||
cbor_int_get_width(val) != CBOR_INT_8) {
fido_log_debug("%s: cbor type", __func__);
goto out;
}
authdata_ext->mask |= FIDO_EXT_MINPINLEN;
authdata_ext->minpinlen = cbor_get_uint8(val);
}
ok = 0;
@ -1365,7 +1393,6 @@ decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
{
fido_attstmt_t *attstmt = arg;
char *name = NULL;
int cose_alg = 0;
int ok = -1;
if (cbor_string_copy(key, &name) < 0) {
@ -1380,10 +1407,11 @@ decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
fido_log_debug("%s: alg", __func__);
goto out;
}
if ((cose_alg = -(int)cbor_get_int(val) - 1) != COSE_ES256 &&
cose_alg != COSE_RS256 && cose_alg != COSE_EDDSA) {
fido_log_debug("%s: unsupported cose_alg=%d", __func__,
cose_alg);
attstmt->alg = -(int)cbor_get_int(val) - 1;
if (attstmt->alg != COSE_ES256 && attstmt->alg != COSE_RS256 &&
attstmt->alg != COSE_EDDSA && attstmt->alg != COSE_RS1) {
fido_log_debug("%s: unsupported attstmt->alg=%d",
__func__, attstmt->alg);
goto out;
}
} else if (!strcmp(name, "sig")) {
@ -1398,6 +1426,16 @@ decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
fido_log_debug("%s: x5c", __func__);
goto out;
}
} else if (!strcmp(name, "certInfo")) {
if (fido_blob_decode(val, &attstmt->certinfo) < 0) {
fido_log_debug("%s: certinfo", __func__);
goto out;
}
} else if (!strcmp(name, "pubArea")) {
if (fido_blob_decode(val, &attstmt->pubarea) < 0) {
fido_log_debug("%s: pubarea", __func__);
goto out;
}
}
ok = 0;
@ -1410,6 +1448,8 @@ decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
int
cbor_decode_attstmt(const cbor_item_t *item, fido_attstmt_t *attstmt)
{
size_t alloc_len;
if (cbor_isa_map(item) == false ||
cbor_map_is_definite(item) == false ||
cbor_map_iter(item, attstmt, decode_attstmt_entry) < 0) {
@ -1417,6 +1457,13 @@ cbor_decode_attstmt(const cbor_item_t *item, fido_attstmt_t *attstmt)
return (-1);
}
if (attstmt->cbor.ptr != NULL ||
(attstmt->cbor.len = cbor_serialize_alloc(item,
&attstmt->cbor.ptr, &alloc_len)) == 0) {
fido_log_debug("%s: cbor_serialize_alloc", __func__);
return (-1);
}
return (0);
}

View File

@ -39,7 +39,7 @@ config_prepare_hmac(uint8_t subcmd, const cbor_item_t *item, fido_blob_t *hmac)
static int
config_tx(fido_dev_t *dev, uint8_t subcmd, cbor_item_t **paramv, size_t paramc,
const char *pin)
const char *pin, int *ms)
{
cbor_item_t *argv[4];
es256_pk_t *pk = NULL;
@ -68,12 +68,12 @@ config_tx(fido_dev_t *dev, uint8_t subcmd, cbor_item_t **paramv, size_t paramc,
fido_log_debug("%s: config_prepare_hmac", __func__);
goto fail;
}
if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
fido_log_debug("%s: fido_do_ecdh", __func__);
goto fail;
}
if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin,
NULL, &argv[3], &argv[2])) != FIDO_OK) {
NULL, &argv[3], &argv[2], ms)) != FIDO_OK) {
fido_log_debug("%s: cbor_add_uv_params", __func__);
goto fail;
}
@ -81,7 +81,7 @@ config_tx(fido_dev_t *dev, uint8_t subcmd, cbor_item_t **paramv, size_t paramc,
/* framing and transmission */
if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -99,11 +99,12 @@ config_tx(fido_dev_t *dev, uint8_t subcmd, cbor_item_t **paramv, size_t paramc,
}
static int
config_enable_entattest_wait(fido_dev_t *dev, const char *pin, int ms)
config_enable_entattest_wait(fido_dev_t *dev, const char *pin, int *ms)
{
int r;
if ((r = config_tx(dev, CMD_ENABLE_ENTATTEST, NULL, 0, pin)) != FIDO_OK)
if ((r = config_tx(dev, CMD_ENABLE_ENTATTEST, NULL, 0, pin,
ms)) != FIDO_OK)
return r;
return fido_rx_cbor_status(dev, ms);
@ -112,15 +113,18 @@ config_enable_entattest_wait(fido_dev_t *dev, const char *pin, int ms)
int
fido_dev_enable_entattest(fido_dev_t *dev, const char *pin)
{
return (config_enable_entattest_wait(dev, pin, -1));
int ms = dev->timeout_ms;
return (config_enable_entattest_wait(dev, pin, &ms));
}
static int
config_toggle_always_uv_wait(fido_dev_t *dev, const char *pin, int ms)
config_toggle_always_uv_wait(fido_dev_t *dev, const char *pin, int *ms)
{
int r;
if ((r = config_tx(dev, CMD_TOGGLE_ALWAYS_UV, NULL, 0, pin)) != FIDO_OK)
if ((r = config_tx(dev, CMD_TOGGLE_ALWAYS_UV, NULL, 0, pin,
ms)) != FIDO_OK)
return r;
return (fido_rx_cbor_status(dev, ms));
@ -129,18 +133,21 @@ config_toggle_always_uv_wait(fido_dev_t *dev, const char *pin, int ms)
int
fido_dev_toggle_always_uv(fido_dev_t *dev, const char *pin)
{
return config_toggle_always_uv_wait(dev, pin, -1);
int ms = dev->timeout_ms;
return config_toggle_always_uv_wait(dev, pin, &ms);
}
static int
config_pin_minlen_tx(fido_dev_t *dev, size_t len, bool force, const char *pin)
config_pin_minlen_tx(fido_dev_t *dev, size_t len, bool force,
const fido_str_array_t *rpid, const char *pin, int *ms)
{
cbor_item_t *argv[3];
int r;
memset(argv, 0, sizeof(argv));
if ((!len && !force) || len > UINT8_MAX) {
if ((rpid == NULL && len == 0 && !force) || len > UINT8_MAX) {
r = FIDO_ERR_INVALID_ARGUMENT;
goto fail;
}
@ -149,13 +156,18 @@ config_pin_minlen_tx(fido_dev_t *dev, size_t len, bool force, const char *pin)
r = FIDO_ERR_INTERNAL;
goto fail;
}
if (rpid != NULL && (argv[1] = cbor_encode_str_array(rpid)) == NULL) {
fido_log_debug("%s: cbor_encode_str_array", __func__);
r = FIDO_ERR_INTERNAL;
goto fail;
}
if (force && (argv[2] = cbor_build_bool(true)) == NULL) {
fido_log_debug("%s: cbor_build_bool", __func__);
r = FIDO_ERR_INTERNAL;
goto fail;
}
if ((r = config_tx(dev, CMD_SET_PIN_MINLEN, argv, nitems(argv),
pin)) != FIDO_OK) {
pin, ms)) != FIDO_OK) {
fido_log_debug("%s: config_tx", __func__);
goto fail;
}
@ -167,12 +179,13 @@ config_pin_minlen_tx(fido_dev_t *dev, size_t len, bool force, const char *pin)
}
static int
config_pin_minlen(fido_dev_t *dev, size_t len, bool force, const char *pin,
int ms)
config_pin_minlen(fido_dev_t *dev, size_t len, bool force,
const fido_str_array_t *rpid, const char *pin, int *ms)
{
int r;
if ((r = config_pin_minlen_tx(dev, len, force, pin)) != FIDO_OK)
if ((r = config_pin_minlen_tx(dev, len, force, rpid, pin,
ms)) != FIDO_OK)
return r;
return fido_rx_cbor_status(dev, ms);
@ -181,11 +194,36 @@ config_pin_minlen(fido_dev_t *dev, size_t len, bool force, const char *pin,
int
fido_dev_set_pin_minlen(fido_dev_t *dev, size_t len, const char *pin)
{
return config_pin_minlen(dev, len, false, pin, -1);
int ms = dev->timeout_ms;
return config_pin_minlen(dev, len, false, NULL, pin, &ms);
}
int
fido_dev_force_pin_change(fido_dev_t *dev, const char *pin)
{
return config_pin_minlen(dev, 0, true, pin, -1);
int ms = dev->timeout_ms;
return config_pin_minlen(dev, 0, true, NULL, pin, &ms);
}
int
fido_dev_set_pin_minlen_rpid(fido_dev_t *dev, const char * const *rpid,
size_t n, const char *pin)
{
fido_str_array_t sa;
int ms = dev->timeout_ms;
int r;
memset(&sa, 0, sizeof(sa));
if (fido_str_array_pack(&sa, rpid, n) < 0) {
fido_log_debug("%s: fido_str_array_pack", __func__);
r = FIDO_ERR_INTERNAL;
goto fail;
}
r = config_pin_minlen(dev, 0, false, &sa, pin, &ms);
fail:
fido_str_array_free(&sa);
return r;
}

View File

@ -1,5 +1,5 @@
/*
* 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.
*/
@ -10,6 +10,10 @@
#include "fido.h"
#include "fido/es256.h"
#ifndef FIDO_MAXMSG_CRED
#define FIDO_MAXMSG_CRED 4096
#endif
static int
parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
{
@ -43,7 +47,8 @@ parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
}
static int
fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
int *ms)
{
fido_blob_t f;
fido_blob_t *ecdh = NULL;
@ -92,12 +97,12 @@ fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
/* user verification */
if (pin != NULL || (uv == FIDO_OPT_TRUE &&
fido_dev_supports_permissions(dev))) {
if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
fido_log_debug("%s: fido_do_ecdh", __func__);
goto fail;
}
if ((r = cbor_add_uv_params(dev, cmd, &cred->cdh, pk, ecdh,
pin, cred->rp.id, &argv[7], &argv[8])) != FIDO_OK) {
pin, cred->rp.id, &argv[7], &argv[8], ms)) != FIDO_OK) {
fido_log_debug("%s: cbor_add_uv_params", __func__);
goto fail;
}
@ -114,7 +119,7 @@ fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
/* framing and transmission */
if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -131,42 +136,55 @@ fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
}
static int
fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int ms)
fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
int r;
unsigned char *reply;
int reply_len;
int r;
fido_cred_reset_rx(cred);
if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
if ((reply = malloc(FIDO_MAXMSG_CRED)) == NULL) {
r = FIDO_ERR_INTERNAL;
goto fail;
}
if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, reply, FIDO_MAXMSG_CRED,
ms)) < 0) {
fido_log_debug("%s: fido_rx", __func__);
return (FIDO_ERR_RX);
r = FIDO_ERR_RX;
goto fail;
}
if ((r = cbor_parse_reply(reply, (size_t)reply_len, cred,
parse_makecred_reply)) != FIDO_OK) {
fido_log_debug("%s: parse_makecred_reply", __func__);
return (r);
goto fail;
}
if (cred->fmt == NULL || fido_blob_is_empty(&cred->authdata_cbor) ||
fido_blob_is_empty(&cred->attcred.id)) {
fido_cred_reset_rx(cred);
return (FIDO_ERR_INVALID_CBOR);
r = FIDO_ERR_INVALID_CBOR;
goto fail;
}
return (FIDO_OK);
r = FIDO_OK;
fail:
free(reply);
if (r != FIDO_OK)
fido_cred_reset_rx(cred);
return (r);
}
static int
fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
int ms)
int *ms)
{
int r;
if ((r = fido_dev_make_cred_tx(dev, cred, pin)) != FIDO_OK ||
if ((r = fido_dev_make_cred_tx(dev, cred, pin, ms)) != FIDO_OK ||
(r = fido_dev_make_cred_rx(dev, cred, ms)) != FIDO_OK)
return (r);
@ -176,18 +194,20 @@ fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
int
fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
{
int ms = dev->timeout_ms;
#ifdef USE_WINHELLO
if (dev->flags & FIDO_DEV_WINHELLO)
return (fido_winhello_make_cred(dev, cred, pin));
return (fido_winhello_make_cred(dev, cred, pin, ms));
#endif
if (fido_dev_is_fido2(dev) == false) {
if (pin != NULL || cred->rk == FIDO_OPT_TRUE ||
cred->ext.mask != 0)
return (FIDO_ERR_UNSUPPORTED_OPTION);
return (u2f_register(dev, cred, -1));
return (u2f_register(dev, cred, &ms));
}
return (fido_dev_make_cred_wait(dev, cred, pin, -1));
return (fido_dev_make_cred_wait(dev, cred, pin, &ms));
}
static int
@ -225,66 +245,81 @@ get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id,
size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id,
const es256_pk_t *pk)
{
const uint8_t zero = 0;
const uint8_t four = 4; /* uncompressed point */
SHA256_CTX ctx;
if (dgst->len != SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 ||
SHA256_Update(&ctx, &zero, sizeof(zero)) == 0 ||
SHA256_Update(&ctx, rp_id, rp_id_len) == 0 ||
SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 ||
SHA256_Update(&ctx, id->ptr, id->len) == 0 ||
SHA256_Update(&ctx, &four, sizeof(four)) == 0 ||
SHA256_Update(&ctx, pk->x, sizeof(pk->x)) == 0 ||
SHA256_Update(&ctx, pk->y, sizeof(pk->y)) == 0 ||
SHA256_Final(dgst->ptr, &ctx) == 0) {
fido_log_debug("%s: sha256", __func__);
return (-1);
}
return (0);
}
static int
verify_sig(const fido_blob_t *dgst, const fido_blob_t *x5c,
const fido_blob_t *sig)
{
BIO *rawcert = NULL;
X509 *cert = NULL;
EVP_PKEY *pkey = NULL;
EC_KEY *ec;
const uint8_t zero = 0;
const uint8_t four = 4; /* uncompressed point */
const EVP_MD *md = NULL;
EVP_MD_CTX *ctx = NULL;
int ok = -1;
/* openssl needs ints */
if (dgst->len > INT_MAX || x5c->len > INT_MAX || sig->len > INT_MAX) {
fido_log_debug("%s: dgst->len=%zu, x5c->len=%zu, sig->len=%zu",
__func__, dgst->len, x5c->len, sig->len);
return (-1);
}
/* fetch key from x509 */
if ((rawcert = BIO_new_mem_buf(x5c->ptr, (int)x5c->len)) == NULL ||
(cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
(pkey = X509_get_pubkey(cert)) == NULL ||
(ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) {
fido_log_debug("%s: x509 key", __func__);
goto fail;
}
if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr,
(int)sig->len, ec) != 1) {
fido_log_debug("%s: ECDSA_verify", __func__);
if (dgst->len != SHA256_DIGEST_LENGTH ||
(md = EVP_sha256()) == NULL ||
(ctx = EVP_MD_CTX_new()) == NULL ||
EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
EVP_DigestUpdate(ctx, &zero, sizeof(zero)) != 1 ||
EVP_DigestUpdate(ctx, rp_id, rp_id_len) != 1 ||
EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 ||
EVP_DigestUpdate(ctx, id->ptr, id->len) != 1 ||
EVP_DigestUpdate(ctx, &four, sizeof(four)) != 1 ||
EVP_DigestUpdate(ctx, pk->x, sizeof(pk->x)) != 1 ||
EVP_DigestUpdate(ctx, pk->y, sizeof(pk->y)) != 1 ||
EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) {
fido_log_debug("%s: sha256", __func__);
goto fail;
}
ok = 0;
fail:
if (rawcert != NULL)
BIO_free(rawcert);
if (cert != NULL)
X509_free(cert);
if (pkey != NULL)
EVP_PKEY_free(pkey);
EVP_MD_CTX_free(ctx);
return (ok);
}
static int
verify_attstmt(const fido_blob_t *dgst, const fido_attstmt_t *attstmt)
{
BIO *rawcert = NULL;
X509 *cert = NULL;
EVP_PKEY *pkey = NULL;
int ok = -1;
/* openssl needs ints */
if (attstmt->x5c.len > INT_MAX) {
fido_log_debug("%s: x5c.len=%zu", __func__, attstmt->x5c.len);
return (-1);
}
/* fetch key from x509 */
if ((rawcert = BIO_new_mem_buf(attstmt->x5c.ptr,
(int)attstmt->x5c.len)) == NULL ||
(cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
(pkey = X509_get_pubkey(cert)) == NULL) {
fido_log_debug("%s: x509 key", __func__);
goto fail;
}
switch (attstmt->alg) {
case COSE_UNSPEC:
case COSE_ES256:
ok = es256_verify_sig(dgst, pkey, &attstmt->sig);
break;
case COSE_RS256:
ok = rs256_verify_sig(dgst, pkey, &attstmt->sig);
break;
case COSE_RS1:
ok = rs1_verify_sig(dgst, pkey, &attstmt->sig);
break;
case COSE_EDDSA:
ok = eddsa_verify_sig(dgst, pkey, &attstmt->sig);
break;
default:
fido_log_debug("%s: unknown alg %d", __func__, attstmt->alg);
break;
}
fail:
BIO_free(rawcert);
X509_free(cert);
EVP_PKEY_free(pkey);
return (ok);
}
@ -348,14 +383,21 @@ fido_cred_verify(const fido_cred_t *cred)
r = FIDO_ERR_INTERNAL;
goto out;
}
} else if (!strcmp(cred->fmt, "tpm")) {
if (fido_get_signed_hash_tpm(&dgst, &cred->cdh,
&cred->authdata_raw, &cred->attstmt, &cred->attcred) < 0) {
fido_log_debug("%s: fido_get_signed_hash_tpm", __func__);
r = FIDO_ERR_INTERNAL;
goto out;
}
} else {
fido_log_debug("%s: unknown fmt %s", __func__, cred->fmt);
r = FIDO_ERR_INVALID_ARGUMENT;
goto out;
}
if (verify_sig(&dgst, &cred->attstmt.x5c, &cred->attstmt.sig) < 0) {
fido_log_debug("%s: verify_sig", __func__);
if (verify_attstmt(&dgst, &cred->attstmt) < 0) {
fido_log_debug("%s: verify_attstmt", __func__);
r = FIDO_ERR_INVALID_SIG;
goto out;
}
@ -435,15 +477,15 @@ fido_cred_verify_self(const fido_cred_t *cred)
switch (cred->attcred.type) {
case COSE_ES256:
ok = fido_verify_sig_es256(&dgst, &cred->attcred.pubkey.es256,
ok = es256_pk_verify_sig(&dgst, &cred->attcred.pubkey.es256,
&cred->attstmt.sig);
break;
case COSE_RS256:
ok = fido_verify_sig_rs256(&dgst, &cred->attcred.pubkey.rs256,
ok = rs256_pk_verify_sig(&dgst, &cred->attcred.pubkey.rs256,
&cred->attstmt.sig);
break;
case COSE_EDDSA:
ok = fido_verify_sig_eddsa(&dgst, &cred->attcred.pubkey.eddsa,
ok = eddsa_pk_verify_sig(&dgst, &cred->attcred.pubkey.eddsa,
&cred->attstmt.sig);
break;
default:
@ -482,6 +524,18 @@ fido_cred_clean_authdata(fido_cred_t *cred)
memset(&cred->attcred, 0, sizeof(cred->attcred));
}
static void
fido_cred_clean_attstmt(fido_attstmt_t *attstmt)
{
fido_blob_reset(&attstmt->certinfo);
fido_blob_reset(&attstmt->pubarea);
fido_blob_reset(&attstmt->cbor);
fido_blob_reset(&attstmt->x5c);
fido_blob_reset(&attstmt->sig);
memset(attstmt, 0, sizeof(*attstmt));
}
void
fido_cred_reset_tx(fido_cred_t *cred)
{
@ -513,8 +567,7 @@ fido_cred_reset_rx(fido_cred_t *cred)
free(cred->fmt);
cred->fmt = NULL;
fido_cred_clean_authdata(cred);
fido_blob_reset(&cred->attstmt.x5c);
fido_blob_reset(&cred->attstmt.sig);
fido_cred_clean_attstmt(&cred->attstmt);
fido_blob_reset(&cred->largeblob_key);
}
@ -568,7 +621,6 @@ fido_cred_set_authdata(fido_cred_t *cred, const unsigned char *ptr, size_t len)
fido_cred_clean_authdata(cred);
return (r);
}
int
@ -610,7 +662,6 @@ fido_cred_set_authdata_raw(fido_cred_t *cred, const unsigned char *ptr,
fido_cred_clean_authdata(cred);
return (r);
}
int
@ -640,6 +691,39 @@ fido_cred_set_sig(fido_cred_t *cred, const unsigned char *ptr, size_t len)
return (FIDO_OK);
}
int
fido_cred_set_attstmt(fido_cred_t *cred, const unsigned char *ptr, size_t len)
{
cbor_item_t *item = NULL;
struct cbor_load_result cbor;
int r = FIDO_ERR_INVALID_ARGUMENT;
fido_cred_clean_attstmt(&cred->attstmt);
if (ptr == NULL || len == 0)
goto fail;
if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
fido_log_debug("%s: cbor_load", __func__);
goto fail;
}
if (cbor_decode_attstmt(item, &cred->attstmt) < 0) {
fido_log_debug("%s: cbor_decode_attstmt", __func__);
goto fail;
}
r = FIDO_OK;
fail:
if (item != NULL)
cbor_decref(&item);
if (r != FIDO_OK)
fido_cred_clean_attstmt(&cred->attstmt);
return (r);
}
int
fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len)
{
@ -833,6 +917,19 @@ fido_cred_set_prot(fido_cred_t *cred, int prot)
return (FIDO_OK);
}
int
fido_cred_set_pin_minlen(fido_cred_t *cred, size_t len)
{
if (len == 0)
cred->ext.mask &= ~FIDO_EXT_MINPINLEN;
else
cred->ext.mask |= FIDO_EXT_MINPINLEN;
cred->ext.minpinlen = len;
return (FIDO_OK);
}
int
fido_cred_set_blob(fido_cred_t *cred, const unsigned char *ptr, size_t len)
{
@ -856,7 +953,7 @@ fido_cred_set_fmt(fido_cred_t *cred, const char *fmt)
return (FIDO_ERR_INVALID_ARGUMENT);
if (strcmp(fmt, "packed") && strcmp(fmt, "fido-u2f") &&
strcmp(fmt, "none"))
strcmp(fmt, "none") && strcmp(fmt, "tpm"))
return (FIDO_ERR_INVALID_ARGUMENT);
if ((cred->fmt = strdup(fmt)) == NULL)
@ -955,6 +1052,18 @@ fido_cred_authdata_raw_len(const fido_cred_t *cred)
return (cred->authdata_raw.len);
}
const unsigned char *
fido_cred_attstmt_ptr(const fido_cred_t *cred)
{
return (cred->attstmt.cbor.ptr);
}
size_t
fido_cred_attstmt_len(const fido_cred_t *cred)
{
return (cred->attstmt.cbor.len);
}
const unsigned char *
fido_cred_pubkey_ptr(const fido_cred_t *cred)
{
@ -1031,6 +1140,12 @@ fido_cred_prot(const fido_cred_t *cred)
return (cred->ext.prot);
}
size_t
fido_cred_pin_minlen(const fido_cred_t *cred)
{
return (cred->ext.minpinlen);
}
const char *
fido_cred_fmt(const fido_cred_t *cred)
{

View File

@ -112,7 +112,7 @@ credman_prepare_hmac(uint8_t cmd, const void *body, cbor_item_t **param,
static int
credman_tx(fido_dev_t *dev, uint8_t subcmd, const void *param, const char *pin,
const char *rp_id, fido_opt_t uv)
const char *rp_id, fido_opt_t uv, int *ms)
{
fido_blob_t f;
fido_blob_t *ecdh = NULL;
@ -144,12 +144,12 @@ credman_tx(fido_dev_t *dev, uint8_t subcmd, const void *param, const char *pin,
fido_log_debug("%s: credman_prepare_hmac", __func__);
goto fail;
}
if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
fido_log_debug("%s: fido_do_ecdh", __func__);
goto fail;
}
if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin,
rp_id, &argv[3], &argv[2])) != FIDO_OK) {
rp_id, &argv[3], &argv[2], ms)) != FIDO_OK) {
fido_log_debug("%s: cbor_add_uv_params", __func__);
goto fail;
}
@ -157,7 +157,7 @@ credman_tx(fido_dev_t *dev, uint8_t subcmd, const void *param, const char *pin,
/* framing and transmission */
if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -198,7 +198,7 @@ credman_parse_metadata(const cbor_item_t *key, const cbor_item_t *val,
}
static int
credman_rx_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, int ms)
credman_rx_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
@ -223,12 +223,12 @@ credman_rx_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, int ms)
static int
credman_get_metadata_wait(fido_dev_t *dev, fido_credman_metadata_t *metadata,
const char *pin, int ms)
const char *pin, int *ms)
{
int r;
if ((r = credman_tx(dev, CMD_CRED_METADATA, NULL, pin, NULL,
FIDO_OPT_TRUE)) != FIDO_OK ||
FIDO_OPT_TRUE, ms)) != FIDO_OK ||
(r = credman_rx_metadata(dev, metadata, ms)) != FIDO_OK)
return (r);
@ -239,7 +239,9 @@ int
fido_credman_get_dev_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata,
const char *pin)
{
return (credman_get_metadata_wait(dev, metadata, pin, -1));
int ms = dev->timeout_ms;
return (credman_get_metadata_wait(dev, metadata, pin, &ms));
}
static int
@ -321,7 +323,7 @@ credman_parse_rk_count(const cbor_item_t *key, const cbor_item_t *val,
}
static int
credman_rx_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms)
credman_rx_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
@ -360,7 +362,7 @@ credman_rx_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms)
}
static int
credman_rx_next_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms)
credman_rx_next_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
@ -390,7 +392,7 @@ credman_rx_next_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms)
static int
credman_get_rk_wait(fido_dev_t *dev, const char *rp_id, fido_credman_rk_t *rk,
const char *pin, int ms)
const char *pin, int *ms)
{
fido_blob_t rp_dgst;
uint8_t dgst[SHA256_DIGEST_LENGTH];
@ -405,13 +407,13 @@ credman_get_rk_wait(fido_dev_t *dev, const char *rp_id, fido_credman_rk_t *rk,
rp_dgst.len = sizeof(dgst);
if ((r = credman_tx(dev, CMD_RK_BEGIN, &rp_dgst, pin, rp_id,
FIDO_OPT_TRUE)) != FIDO_OK ||
FIDO_OPT_TRUE, ms)) != FIDO_OK ||
(r = credman_rx_rk(dev, rk, ms)) != FIDO_OK)
return (r);
while (rk->n_rx < rk->n_alloc) {
if ((r = credman_tx(dev, CMD_RK_NEXT, NULL, NULL, NULL,
FIDO_OPT_FALSE)) != FIDO_OK ||
FIDO_OPT_FALSE, ms)) != FIDO_OK ||
(r = credman_rx_next_rk(dev, rk, ms)) != FIDO_OK)
return (r);
rk->n_rx++;
@ -424,12 +426,14 @@ int
fido_credman_get_dev_rk(fido_dev_t *dev, const char *rp_id,
fido_credman_rk_t *rk, const char *pin)
{
return (credman_get_rk_wait(dev, rp_id, rk, pin, -1));
int ms = dev->timeout_ms;
return (credman_get_rk_wait(dev, rp_id, rk, pin, &ms));
}
static int
credman_del_rk_wait(fido_dev_t *dev, const unsigned char *cred_id,
size_t cred_id_len, const char *pin, int ms)
size_t cred_id_len, const char *pin, int *ms)
{
fido_blob_t cred;
int r;
@ -440,7 +444,7 @@ credman_del_rk_wait(fido_dev_t *dev, const unsigned char *cred_id,
return (FIDO_ERR_INVALID_ARGUMENT);
if ((r = credman_tx(dev, CMD_DELETE_CRED, &cred, pin, NULL,
FIDO_OPT_TRUE)) != FIDO_OK ||
FIDO_OPT_TRUE, ms)) != FIDO_OK ||
(r = fido_rx_cbor_status(dev, ms)) != FIDO_OK)
goto fail;
@ -455,7 +459,9 @@ int
fido_credman_del_dev_rk(fido_dev_t *dev, const unsigned char *cred_id,
size_t cred_id_len, const char *pin)
{
return (credman_del_rk_wait(dev, cred_id, cred_id_len, pin, -1));
int ms = dev->timeout_ms;
return (credman_del_rk_wait(dev, cred_id, cred_id_len, pin, &ms));
}
static int
@ -526,7 +532,7 @@ credman_parse_rp_count(const cbor_item_t *key, const cbor_item_t *val,
}
static int
credman_rx_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms)
credman_rx_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
@ -565,7 +571,7 @@ credman_rx_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms)
}
static int
credman_rx_next_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms)
credman_rx_next_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
@ -595,18 +601,18 @@ credman_rx_next_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms)
static int
credman_get_rp_wait(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin,
int ms)
int *ms)
{
int r;
if ((r = credman_tx(dev, CMD_RP_BEGIN, NULL, pin, NULL,
FIDO_OPT_TRUE)) != FIDO_OK ||
FIDO_OPT_TRUE, ms)) != FIDO_OK ||
(r = credman_rx_rp(dev, rp, ms)) != FIDO_OK)
return (r);
while (rp->n_rx < rp->n_alloc) {
if ((r = credman_tx(dev, CMD_RP_NEXT, NULL, NULL, NULL,
FIDO_OPT_FALSE)) != FIDO_OK ||
FIDO_OPT_FALSE, ms)) != FIDO_OK ||
(r = credman_rx_next_rp(dev, rp, ms)) != FIDO_OK)
return (r);
rp->n_rx++;
@ -618,17 +624,19 @@ credman_get_rp_wait(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin,
int
fido_credman_get_dev_rp(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin)
{
return (credman_get_rp_wait(dev, rp, pin, -1));
int ms = dev->timeout_ms;
return (credman_get_rp_wait(dev, rp, pin, &ms));
}
static int
credman_set_dev_rk_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
int ms)
int *ms)
{
int r;
if ((r = credman_tx(dev, CMD_UPDATE_CRED, cred, pin, NULL,
FIDO_OPT_TRUE)) != FIDO_OK ||
FIDO_OPT_TRUE, ms)) != FIDO_OK ||
(r = fido_rx_cbor_status(dev, ms)) != FIDO_OK)
return (r);
@ -638,7 +646,9 @@ credman_set_dev_rk_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
int
fido_credman_set_dev_rk(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
{
return (credman_set_dev_rk_wait(dev, cred, pin, -1));
int ms = dev->timeout_ms;
return (credman_set_dev_rk_wait(dev, cred, pin, &ms));
}
fido_credman_rk_t *

View File

@ -106,7 +106,7 @@ fido_dev_set_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
}
static int
fido_dev_open_tx(fido_dev_t *dev, const char *path)
fido_dev_open_tx(fido_dev_t *dev, const char *path, int *ms)
{
int r;
@ -161,7 +161,8 @@ fido_dev_open_tx(fido_dev_t *dev, const char *path)
goto fail;
}
if (fido_tx(dev, CTAP_CMD_INIT, &dev->nonce, sizeof(dev->nonce)) < 0) {
if (fido_tx(dev, CTAP_CMD_INIT, &dev->nonce, sizeof(dev->nonce),
ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -176,7 +177,7 @@ fido_dev_open_tx(fido_dev_t *dev, const char *path)
}
static int
fido_dev_open_rx(fido_dev_t *dev, int ms)
fido_dev_open_rx(fido_dev_t *dev, int *ms)
{
fido_cbor_info_t *info = NULL;
int reply_len;
@ -241,7 +242,7 @@ fido_dev_open_rx(fido_dev_t *dev, int ms)
}
static int
fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms)
fido_dev_open_wait(fido_dev_t *dev, const char *path, int *ms)
{
int r;
@ -249,7 +250,7 @@ fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms)
if (strcmp(path, FIDO_WINHELLO_PATH) == 0)
return (fido_winhello_open(dev));
#endif
if ((r = fido_dev_open_tx(dev, path)) != FIDO_OK ||
if ((r = fido_dev_open_tx(dev, path, ms)) != FIDO_OK ||
(r = fido_dev_open_rx(dev, ms)) != FIDO_OK)
return (r);
@ -331,24 +332,21 @@ fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
int
fido_dev_open_with_info(fido_dev_t *dev)
{
int ms = dev->timeout_ms;
if (dev->path == NULL)
return (FIDO_ERR_INVALID_ARGUMENT);
return (fido_dev_open_wait(dev, dev->path, -1));
return (fido_dev_open_wait(dev, dev->path, &ms));
}
int
fido_dev_open(fido_dev_t *dev, const char *path)
{
int ms = dev->timeout_ms;
#ifdef NFC_LINUX
/*
* this is a hack to get existing applications up and running with nfc;
* it will *NOT* be part of a libfido2 release. to support nfc in your
* application, please change it to use fido_dev_open_with_info().
*/
if (strncmp(path, "/sys", strlen("/sys")) == 0 && strlen(path) > 4 &&
path[strlen(path) - 4] == 'n' && path[strlen(path) - 3] == 'f' &&
path[strlen(path) - 2] == 'c') {
if (strncmp(path, FIDO_NFC_PREFIX, strlen(FIDO_NFC_PREFIX)) == 0) {
dev->io_own = true;
dev->io = (fido_dev_io_t) {
fido_nfc_open,
@ -363,7 +361,7 @@ fido_dev_open(fido_dev_t *dev, const char *path)
}
#endif
return (fido_dev_open_wait(dev, path, -1));
return (fido_dev_open_wait(dev, path, &ms));
}
int
@ -386,26 +384,31 @@ fido_dev_close(fido_dev_t *dev)
int
fido_dev_set_sigmask(fido_dev_t *dev, const fido_sigset_t *sigmask)
{
if (dev->io_own || dev->io_handle == NULL || sigmask == NULL)
if (dev->io_handle == NULL || sigmask == NULL)
return (FIDO_ERR_INVALID_ARGUMENT);
#ifdef NFC_LINUX
if (dev->transport.rx == fido_nfc_rx)
if (dev->transport.rx == fido_nfc_rx && dev->io.read == fido_nfc_read)
return (fido_nfc_set_sigmask(dev->io_handle, sigmask));
#endif
return (fido_hid_set_sigmask(dev->io_handle, sigmask));
if (dev->transport.rx == NULL && dev->io.read == fido_hid_read)
return (fido_hid_set_sigmask(dev->io_handle, sigmask));
return (FIDO_ERR_INVALID_ARGUMENT);
}
int
fido_dev_cancel(fido_dev_t *dev)
{
int ms = dev->timeout_ms;
#ifdef USE_WINHELLO
if (dev->flags & FIDO_DEV_WINHELLO)
return (fido_winhello_cancel(dev));
#endif
if (fido_dev_is_fido2(dev) == false)
return (FIDO_ERR_INVALID_ARGUMENT);
if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0) < 0)
if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0, &ms) < 0)
return (FIDO_ERR_TX);
return (FIDO_OK);
@ -421,6 +424,7 @@ fido_dev_get_touch_begin(fido_dev_t *dev)
unsigned char cdh[SHA256_DIGEST_LENGTH];
fido_rp_t rp;
fido_user_t user;
int ms = dev->timeout_ms;
int r = FIDO_ERR_INTERNAL;
memset(&f, 0, sizeof(f));
@ -430,7 +434,7 @@ fido_dev_get_touch_begin(fido_dev_t *dev)
memset(&user, 0, sizeof(user));
if (fido_dev_is_fido2(dev) == false)
return (u2f_get_touch_begin(dev));
return (u2f_get_touch_begin(dev, &ms));
if (SHA256((const void *)clientdata, strlen(clientdata), cdh) != cdh) {
fido_log_debug("%s: sha256", __func__);
@ -465,7 +469,7 @@ fido_dev_get_touch_begin(fido_dev_t *dev)
}
if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, nitems(argv), &f) < 0 ||
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, &ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -490,9 +494,9 @@ fido_dev_get_touch_status(fido_dev_t *dev, int *touched, int ms)
*touched = 0;
if (fido_dev_is_fido2(dev) == false)
return (u2f_get_touch_status(dev, touched, ms));
return (u2f_get_touch_status(dev, touched, &ms));
switch ((r = fido_rx_cbor_status(dev, ms))) {
switch ((r = fido_rx_cbor_status(dev, &ms))) {
case FIDO_ERR_PIN_AUTH_INVALID:
case FIDO_ERR_PIN_INVALID:
case FIDO_ERR_PIN_NOT_SET:
@ -562,6 +566,7 @@ fido_dev_new(void)
return (NULL);
dev->cid = CTAP_CID_BROADCAST;
dev->timeout_ms = -1;
dev->io = (fido_dev_io_t) {
&fido_hid_open,
&fido_hid_close,
@ -593,6 +598,7 @@ fido_dev_new_with_info(const fido_dev_info_t *di)
dev->io_own = di->transport.tx != NULL || di->transport.rx != NULL;
dev->transport = di->transport;
dev->cid = CTAP_CID_BROADCAST;
dev->timeout_ms = -1;
if ((dev->path = strdup(di->path)) == NULL) {
fido_log_debug("%s: strdup", __func__);
@ -730,3 +736,14 @@ fido_dev_maxmsgsize(const fido_dev_t *dev)
{
return (dev->maxmsgsize);
}
int
fido_dev_set_timeout(fido_dev_t *dev, int ms)
{
if (ms < -1)
return (FIDO_ERR_INVALID_ARGUMENT);
dev->timeout_ms = ms;
return (FIDO_OK);
}

View File

@ -8,14 +8,14 @@
#include <openssl/sha.h>
#if defined(LIBRESSL_VERSION_NUMBER)
#include <openssl/hkdf.h>
#elif OPENSSL_VERSION_NUMBER >= 0x10100000L
#else
#include <openssl/kdf.h>
#endif
#include "fido.h"
#include "fido/es256.h"
#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L
#if defined(LIBRESSL_VERSION_NUMBER)
static int
hkdf_sha256(uint8_t *key, const char *info, const fido_blob_t *secret)
{
@ -56,7 +56,7 @@ hkdf_sha256(uint8_t *key, char *info, fido_blob_t *secret)
EVP_PKEY_CTX_set_hkdf_md(ctx, md) < 1 ||
EVP_PKEY_CTX_set1_hkdf_salt(ctx, salt, sizeof(salt)) < 1 ||
EVP_PKEY_CTX_set1_hkdf_key(ctx, secret->ptr, (int)secret->len) < 1 ||
EVP_PKEY_CTX_add1_hkdf_info(ctx, info, (int)strlen(info)) < 1) {
EVP_PKEY_CTX_add1_hkdf_info(ctx, (void *)info, (int)strlen(info)) < 1) {
fido_log_debug("%s: EVP_PKEY_CTX", __func__);
goto fail;
}
@ -74,7 +74,7 @@ hkdf_sha256(uint8_t *key, char *info, fido_blob_t *secret)
return ok;
}
#endif /* defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10100000L */
#endif /* defined(LIBRESSL_VERSION_NUMBER) */
static int
kdf(uint8_t prot, fido_blob_t *key, /* const */ fido_blob_t *secret)
@ -164,7 +164,7 @@ do_ecdh(const fido_dev_t *dev, const es256_sk_t *sk, const es256_pk_t *pk,
}
int
fido_do_ecdh(fido_dev_t *dev, es256_pk_t **pk, fido_blob_t **ecdh)
fido_do_ecdh(fido_dev_t *dev, es256_pk_t **pk, fido_blob_t **ecdh, int *ms)
{
es256_sk_t *sk = NULL; /* our private key */
es256_pk_t *ak = NULL; /* authenticator's public key */
@ -182,7 +182,7 @@ fido_do_ecdh(fido_dev_t *dev, es256_pk_t **pk, fido_blob_t **ecdh)
goto fail;
}
if ((ak = es256_pk_new()) == NULL ||
fido_dev_authkey(dev, ak) != FIDO_OK) {
fido_dev_authkey(dev, ak, ms) != FIDO_OK) {
fido_log_debug("%s: fido_dev_authkey", __func__);
r = FIDO_ERR_INTERNAL;
goto fail;

View File

@ -10,7 +10,7 @@
#include "fido.h"
#include "fido/eddsa.h"
#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10101000L
#if defined(LIBRESSL_VERSION_NUMBER)
EVP_PKEY *
EVP_PKEY_new_raw_public_key(int type, ENGINE *e, const unsigned char *key,
size_t keylen)
@ -52,23 +52,7 @@ EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen,
return (0);
}
#endif /* LIBRESSL_VERSION_NUMBER || OPENSSL_VERSION_NUMBER < 0x10101000L */
#if OPENSSL_VERSION_NUMBER < 0x10100000L
EVP_MD_CTX *
EVP_MD_CTX_new(void)
{
fido_log_debug("%s: unimplemented", __func__);
return (NULL);
}
void
EVP_MD_CTX_free(EVP_MD_CTX *ctx)
{
(void)ctx;
}
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
#endif /* LIBRESSL_VERSION_NUMBER */
static int
decode_coord(const cbor_item_t *item, void *xy, size_t xy_len)
@ -170,3 +154,65 @@ eddsa_pk_from_EVP_PKEY(eddsa_pk_t *pk, const EVP_PKEY *pkey)
return (FIDO_OK);
}
int
eddsa_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
const fido_blob_t *sig)
{
EVP_MD_CTX *mdctx = NULL;
int ok = -1;
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_ED25519) {
fido_log_debug("%s: EVP_PKEY_base_id", __func__);
goto fail;
}
/* EVP_DigestVerify needs ints */
if (dgst->len > INT_MAX || sig->len > INT_MAX) {
fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
dgst->len, sig->len);
return (-1);
}
if ((mdctx = EVP_MD_CTX_new()) == NULL) {
fido_log_debug("%s: EVP_MD_CTX_new", __func__);
goto fail;
}
if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) {
fido_log_debug("%s: EVP_DigestVerifyInit", __func__);
goto fail;
}
if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr,
dgst->len) != 1) {
fido_log_debug("%s: EVP_DigestVerify", __func__);
goto fail;
}
ok = 0;
fail:
EVP_MD_CTX_free(mdctx);
return (ok);
}
int
eddsa_pk_verify_sig(const fido_blob_t *dgst, const eddsa_pk_t *pk,
const fido_blob_t *sig)
{
EVP_PKEY *pkey;
int ok = -1;
if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL ||
eddsa_verify_sig(dgst, pkey, sig) < 0) {
fido_log_debug("%s: eddsa_verify_sig", __func__);
goto fail;
}
ok = 0;
fail:
EVP_PKEY_free(pkey);
return (ok);
}

View File

@ -1,10 +1,11 @@
/*
* 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/bn.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
#include "fido.h"
@ -362,6 +363,18 @@ es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec)
return (ok);
}
int
es256_pk_from_EVP_PKEY(es256_pk_t *pk, const EVP_PKEY *pkey)
{
EC_KEY *ec;
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC ||
(ec = EVP_PKEY_get0(pkey)) == NULL)
return (FIDO_ERR_INVALID_ARGUMENT);
return (es256_pk_from_EC_KEY(pk, ec));
}
EVP_PKEY *
es256_sk_to_EVP_PKEY(const es256_sk_t *k)
{
@ -451,3 +464,50 @@ es256_derive_pk(const es256_sk_t *sk, es256_pk_t *pk)
return (ok);
}
int
es256_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
const fido_blob_t *sig)
{
EVP_PKEY_CTX *pctx = NULL;
int ok = -1;
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) {
fido_log_debug("%s: EVP_PKEY_base_id", __func__);
goto fail;
}
if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL ||
EVP_PKEY_verify_init(pctx) != 1 ||
EVP_PKEY_verify(pctx, sig->ptr, sig->len, dgst->ptr,
dgst->len) != 1) {
fido_log_debug("%s: EVP_PKEY_verify", __func__);
goto fail;
}
ok = 0;
fail:
EVP_PKEY_CTX_free(pctx);
return (ok);
}
int
es256_pk_verify_sig(const fido_blob_t *dgst, const es256_pk_t *pk,
const fido_blob_t *sig)
{
EVP_PKEY *pkey;
int ok = -1;
if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL ||
es256_verify_sig(dgst, pkey, sig) < 0) {
fido_log_debug("%s: es256_verify_sig", __func__);
goto fail;
}
ok = 0;
fail:
EVP_PKEY_free(pkey);
return (ok);
}

View File

@ -7,6 +7,7 @@
eddsa_pk_to_EVP_PKEY;
es256_pk_free;
es256_pk_from_EC_KEY;
es256_pk_from_EVP_PKEY;
es256_pk_from_ptr;
es256_pk_new;
es256_pk_to_EVP_PKEY;
@ -99,6 +100,8 @@
fido_cbor_info_transports_ptr;
fido_cbor_info_versions_len;
fido_cbor_info_versions_ptr;
fido_cred_attstmt_len;
fido_cred_attstmt_ptr;
fido_cred_authdata_len;
fido_cred_authdata_ptr;
fido_cred_authdata_raw_len;
@ -138,11 +141,13 @@
fido_credman_rp_new;
fido_credman_set_dev_rk;
fido_cred_new;
fido_cred_pin_minlen;
fido_cred_prot;
fido_cred_pubkey_len;
fido_cred_pubkey_ptr;
fido_cred_rp_id;
fido_cred_rp_name;
fido_cred_set_attstmt;
fido_cred_set_authdata;
fido_cred_set_authdata_raw;
fido_cred_set_blob;
@ -152,6 +157,7 @@
fido_cred_set_fmt;
fido_cred_set_id;
fido_cred_set_options;
fido_cred_set_pin_minlen;
fido_cred_set_prot;
fido_cred_set_rk;
fido_cred_set_rp;
@ -208,7 +214,9 @@
fido_dev_set_io_functions;
fido_dev_set_pin;
fido_dev_set_pin_minlen;
fido_dev_set_pin_minlen_rpid;
fido_dev_set_sigmask;
fido_dev_set_timeout;
fido_dev_set_transport_functions;
fido_dev_supports_cred_prot;
fido_dev_supports_credman;
@ -226,6 +234,7 @@
fido_strerr;
rs256_pk_free;
rs256_pk_from_ptr;
rs256_pk_from_EVP_PKEY;
rs256_pk_from_RSA;
rs256_pk_new;
rs256_pk_to_EVP_PKEY;

View File

@ -5,6 +5,7 @@ _eddsa_pk_new
_eddsa_pk_to_EVP_PKEY
_es256_pk_free
_es256_pk_from_EC_KEY
_es256_pk_from_EVP_PKEY
_es256_pk_from_ptr
_es256_pk_new
_es256_pk_to_EVP_PKEY
@ -97,6 +98,8 @@ _fido_cbor_info_transports_len
_fido_cbor_info_transports_ptr
_fido_cbor_info_versions_len
_fido_cbor_info_versions_ptr
_fido_cred_attstmt_len
_fido_cred_attstmt_ptr
_fido_cred_authdata_len
_fido_cred_authdata_ptr
_fido_cred_authdata_raw_len
@ -136,11 +139,13 @@ _fido_credman_rp_name
_fido_credman_rp_new
_fido_credman_set_dev_rk
_fido_cred_new
_fido_cred_pin_minlen
_fido_cred_prot
_fido_cred_pubkey_len
_fido_cred_pubkey_ptr
_fido_cred_rp_id
_fido_cred_rp_name
_fido_cred_set_attstmt
_fido_cred_set_authdata
_fido_cred_set_authdata_raw
_fido_cred_set_blob
@ -150,6 +155,7 @@ _fido_cred_set_extensions
_fido_cred_set_fmt
_fido_cred_set_id
_fido_cred_set_options
_fido_cred_set_pin_minlen
_fido_cred_set_prot
_fido_cred_set_rk
_fido_cred_set_rp
@ -206,7 +212,9 @@ _fido_dev_reset
_fido_dev_set_io_functions
_fido_dev_set_pin
_fido_dev_set_pin_minlen
_fido_dev_set_pin_minlen_rpid
_fido_dev_set_sigmask
_fido_dev_set_timeout
_fido_dev_set_transport_functions
_fido_dev_supports_cred_prot
_fido_dev_supports_credman
@ -224,6 +232,7 @@ _fido_set_log_handler
_fido_strerr
_rs256_pk_free
_rs256_pk_from_ptr
_rs256_pk_from_EVP_PKEY
_rs256_pk_from_RSA
_rs256_pk_new
_rs256_pk_to_EVP_PKEY

View File

@ -6,6 +6,7 @@ eddsa_pk_new
eddsa_pk_to_EVP_PKEY
es256_pk_free
es256_pk_from_EC_KEY
es256_pk_from_EVP_PKEY
es256_pk_from_ptr
es256_pk_new
es256_pk_to_EVP_PKEY
@ -98,6 +99,8 @@ fido_cbor_info_transports_len
fido_cbor_info_transports_ptr
fido_cbor_info_versions_len
fido_cbor_info_versions_ptr
fido_cred_attstmt_len
fido_cred_attstmt_ptr
fido_cred_authdata_len
fido_cred_authdata_ptr
fido_cred_authdata_raw_len
@ -137,11 +140,13 @@ fido_credman_rp_name
fido_credman_rp_new
fido_credman_set_dev_rk
fido_cred_new
fido_cred_pin_minlen
fido_cred_prot
fido_cred_pubkey_len
fido_cred_pubkey_ptr
fido_cred_rp_id
fido_cred_rp_name
fido_cred_set_attstmt
fido_cred_set_authdata
fido_cred_set_authdata_raw
fido_cred_set_blob
@ -151,6 +156,7 @@ fido_cred_set_extensions
fido_cred_set_fmt
fido_cred_set_id
fido_cred_set_options
fido_cred_set_pin_minlen
fido_cred_set_prot
fido_cred_set_rk
fido_cred_set_rp
@ -207,7 +213,9 @@ fido_dev_reset
fido_dev_set_io_functions
fido_dev_set_pin
fido_dev_set_pin_minlen
fido_dev_set_pin_minlen_rpid
fido_dev_set_sigmask
fido_dev_set_timeout
fido_dev_set_transport_functions
fido_dev_supports_cred_prot
fido_dev_supports_credman
@ -225,6 +233,7 @@ fido_set_log_handler
fido_strerr
rs256_pk_free
rs256_pk_from_ptr
rs256_pk_from_EVP_PKEY
rs256_pk_from_RSA
rs256_pk_new
rs256_pk_to_EVP_PKEY

View File

@ -1,5 +1,5 @@
/*
* 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.
*/
@ -51,6 +51,7 @@ cbor_item_t *cbor_encode_pubkey(const fido_blob_t *);
cbor_item_t *cbor_encode_pubkey_list(const fido_blob_array_t *);
cbor_item_t *cbor_encode_pubkey_param(int);
cbor_item_t *cbor_encode_rp_entity(const fido_rp_t *);
cbor_item_t *cbor_encode_str_array(const fido_str_array_t *);
cbor_item_t *cbor_encode_user_entity(const fido_user_t *);
cbor_item_t *es256_pk_encode(const es256_pk_t *, int);
@ -86,7 +87,7 @@ int cbor_parse_reply(const unsigned char *, size_t, void *,
int(*)(const cbor_item_t *, const cbor_item_t *, void *));
int cbor_add_uv_params(fido_dev_t *, uint8_t, const fido_blob_t *,
const es256_pk_t *, const fido_blob_t *, const char *, const char *,
cbor_item_t **, cbor_item_t **);
cbor_item_t **, cbor_item_t **, int *);
void cbor_vector_free(cbor_item_t **, size_t);
int cbor_array_append(cbor_item_t **, cbor_item_t *);
int cbor_array_drop(cbor_item_t **, size_t);
@ -130,14 +131,14 @@ int fido_winhello_manifest(fido_dev_info_t *, size_t, size_t *);
int fido_winhello_open(fido_dev_t *);
int fido_winhello_close(fido_dev_t *);
int fido_winhello_cancel(fido_dev_t *);
int fido_winhello_get_assert(fido_dev_t *, fido_assert_t *, const char *);
int fido_winhello_get_assert(fido_dev_t *, fido_assert_t *, const char *, int);
int fido_winhello_get_cbor_info(fido_dev_t *, fido_cbor_info_t *);
int fido_winhello_make_cred(fido_dev_t *, fido_cred_t *, const char *);
int fido_winhello_make_cred(fido_dev_t *, fido_cred_t *, const char *, int);
/* generic i/o */
int fido_rx_cbor_status(fido_dev_t *, int);
int fido_rx(fido_dev_t *, uint8_t, void *, size_t, int);
int fido_tx(fido_dev_t *, uint8_t, const void *, size_t);
int fido_rx_cbor_status(fido_dev_t *, int *);
int fido_rx(fido_dev_t *, uint8_t, void *, size_t, int *);
int fido_tx(fido_dev_t *, uint8_t, const void *, size_t, int *);
/* log */
#ifdef FIDO_NO_DIAGNOSTIC
@ -163,21 +164,30 @@ void fido_log_error(int, const char *, ...);
#endif /* FIDO_NO_DIAGNOSTIC */
/* u2f */
int u2f_register(fido_dev_t *, fido_cred_t *, int);
int u2f_authenticate(fido_dev_t *, fido_assert_t *, int);
int u2f_get_touch_begin(fido_dev_t *);
int u2f_get_touch_status(fido_dev_t *, int *, int);
int u2f_register(fido_dev_t *, fido_cred_t *, int *);
int u2f_authenticate(fido_dev_t *, fido_assert_t *, int *);
int u2f_get_touch_begin(fido_dev_t *, int *);
int u2f_get_touch_status(fido_dev_t *, int *, int *);
/* unexposed fido ops */
uint8_t fido_dev_get_pin_protocol(const fido_dev_t *);
int fido_dev_authkey(fido_dev_t *, es256_pk_t *);
int fido_dev_get_cbor_info_wait(fido_dev_t *, fido_cbor_info_t *, int);
int fido_dev_authkey(fido_dev_t *, es256_pk_t *, int *);
int fido_dev_get_cbor_info_wait(fido_dev_t *, fido_cbor_info_t *, int *);
int fido_dev_get_uv_token(fido_dev_t *, uint8_t, const char *,
const fido_blob_t *, const es256_pk_t *, const char *, fido_blob_t *);
const fido_blob_t *, const es256_pk_t *, const char *, fido_blob_t *,
int *);
uint64_t fido_dev_maxmsgsize(const fido_dev_t *);
int fido_do_ecdh(fido_dev_t *, es256_pk_t **, fido_blob_t **);
int fido_do_ecdh(fido_dev_t *, es256_pk_t **, fido_blob_t **, int *);
bool fido_dev_supports_permissions(const fido_dev_t *);
/* types */
void fido_algo_array_free(fido_algo_array_t *);
void fido_byte_array_free(fido_byte_array_t *);
void fido_opt_array_free(fido_opt_array_t *);
void fido_str_array_free(fido_str_array_t *);
void fido_algo_free(fido_algo_t *);
int fido_str_array_pack(fido_str_array_t *, const char * const *, size_t);
/* misc */
void fido_assert_reset_rx(fido_assert_t *);
void fido_assert_reset_tx(fido_assert_t *);
@ -189,16 +199,24 @@ int fido_check_flags(uint8_t, fido_opt_t, fido_opt_t);
int fido_check_rp_id(const char *, const unsigned char *);
int fido_get_random(void *, size_t);
int fido_sha256(fido_blob_t *, const u_char *, size_t);
int fido_time_now(struct timespec *);
int fido_time_delta(const struct timespec *, int *);
/* crypto */
int fido_verify_sig_es256(const fido_blob_t *, const es256_pk_t *,
int es256_verify_sig(const fido_blob_t *, EVP_PKEY *, const fido_blob_t *);
int rs256_verify_sig(const fido_blob_t *, EVP_PKEY *, const fido_blob_t *);
int eddsa_verify_sig(const fido_blob_t *, EVP_PKEY *, const fido_blob_t *);
int rs1_verify_sig(const fido_blob_t *, EVP_PKEY *, const fido_blob_t *);
int es256_pk_verify_sig(const fido_blob_t *, const es256_pk_t *,
const fido_blob_t *);
int fido_verify_sig_rs256(const fido_blob_t *, const rs256_pk_t *,
int rs256_pk_verify_sig(const fido_blob_t *, const rs256_pk_t *,
const fido_blob_t *);
int fido_verify_sig_eddsa(const fido_blob_t *, const eddsa_pk_t *,
int eddsa_pk_verify_sig(const fido_blob_t *, const eddsa_pk_t *,
const fido_blob_t *);
int fido_get_signed_hash(int, fido_blob_t *, const fido_blob_t *,
const fido_blob_t *);
int fido_get_signed_hash_tpm(fido_blob_t *, const fido_blob_t *,
const fido_blob_t *, const fido_attstmt_t *, const fido_attcred_t *);
/* device manifest functions */
int fido_hid_manifest(fido_dev_info_t *, size_t, size_t *);
@ -232,6 +250,7 @@ uint32_t uniform_random(uint32_t);
#define FIDO_DUMMY_USER_NAME "dummy"
#define FIDO_DUMMY_USER_ID 1
#define FIDO_WINHELLO_PATH "windows://hello"
#define FIDO_NFC_PREFIX "nfc:"
#ifdef __cplusplus
} /* extern "C" */

View File

@ -86,16 +86,17 @@ const char *fido_dev_info_product_string(const fido_dev_info_t *);
const fido_dev_info_t *fido_dev_info_ptr(const fido_dev_info_t *, size_t);
const uint8_t *fido_cbor_info_protocols_ptr(const fido_cbor_info_t *);
const unsigned char *fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *);
const unsigned char *fido_cred_aaguid_ptr(const fido_cred_t *);
const unsigned char *fido_cred_attstmt_ptr(const fido_cred_t *);
const unsigned char *fido_cred_authdata_ptr(const fido_cred_t *);
const unsigned char *fido_cred_authdata_raw_ptr(const fido_cred_t *);
const unsigned char *fido_cred_clientdata_hash_ptr(const fido_cred_t *);
const unsigned char *fido_cred_id_ptr(const fido_cred_t *);
const unsigned char *fido_cred_aaguid_ptr(const fido_cred_t *);
const unsigned char *fido_cred_user_id_ptr(const fido_cred_t *);
const unsigned char *fido_cred_largeblob_key_ptr(const fido_cred_t *);
const unsigned char *fido_cred_pubkey_ptr(const fido_cred_t *);
const unsigned char *fido_cred_sig_ptr(const fido_cred_t *);
const unsigned char *fido_cred_user_id_ptr(const fido_cred_t *);
const unsigned char *fido_cred_x5c_ptr(const fido_cred_t *);
const unsigned char *fido_cred_largeblob_key_ptr(const fido_cred_t *);
int fido_assert_allow_cred(fido_assert_t *, const unsigned char *, size_t);
int fido_assert_set_authdata(fido_assert_t *, size_t, const unsigned char *,
@ -119,6 +120,7 @@ int fido_assert_verify(const fido_assert_t *, size_t, int, const void *);
int fido_cbor_info_algorithm_cose(const fido_cbor_info_t *, size_t);
int fido_cred_exclude(fido_cred_t *, const unsigned char *, size_t);
int fido_cred_prot(const fido_cred_t *);
int fido_cred_set_attstmt(fido_cred_t *, const unsigned char *, size_t);
int fido_cred_set_authdata(fido_cred_t *, const unsigned char *, size_t);
int fido_cred_set_authdata_raw(fido_cred_t *, const unsigned char *, size_t);
int fido_cred_set_blob(fido_cred_t *, const unsigned char *, size_t);
@ -128,6 +130,7 @@ int fido_cred_set_extensions(fido_cred_t *, int);
int fido_cred_set_fmt(fido_cred_t *, const char *);
int fido_cred_set_id(fido_cred_t *, const unsigned char *, size_t);
int fido_cred_set_options(fido_cred_t *, bool, bool);
int fido_cred_set_pin_minlen(fido_cred_t *, size_t);
int fido_cred_set_prot(fido_cred_t *, int);
int fido_cred_set_rk(fido_cred_t *, fido_opt_t);
int fido_cred_set_rp(fido_cred_t *, const char *, const char *);
@ -157,6 +160,7 @@ int fido_dev_reset(fido_dev_t *);
int fido_dev_set_io_functions(fido_dev_t *, const fido_dev_io_t *);
int fido_dev_set_pin(fido_dev_t *, const char *, const char *);
int fido_dev_set_transport_functions(fido_dev_t *, const fido_dev_transport_t *);
int fido_dev_set_timeout(fido_dev_t *, int);
size_t fido_assert_authdata_len(const fido_assert_t *, size_t);
size_t fido_assert_clientdata_hash_len(const fido_assert_t *);
@ -174,16 +178,18 @@ size_t fido_cbor_info_options_len(const fido_cbor_info_t *);
size_t fido_cbor_info_protocols_len(const fido_cbor_info_t *);
size_t fido_cbor_info_transports_len(const fido_cbor_info_t *);
size_t fido_cbor_info_versions_len(const fido_cbor_info_t *);
size_t fido_cred_aaguid_len(const fido_cred_t *);
size_t fido_cred_attstmt_len(const fido_cred_t *);
size_t fido_cred_authdata_len(const fido_cred_t *);
size_t fido_cred_authdata_raw_len(const fido_cred_t *);
size_t fido_cred_clientdata_hash_len(const fido_cred_t *);
size_t fido_cred_id_len(const fido_cred_t *);
size_t fido_cred_aaguid_len(const fido_cred_t *);
size_t fido_cred_user_id_len(const fido_cred_t *);
size_t fido_cred_largeblob_key_len(const fido_cred_t *);
size_t fido_cred_pin_minlen(const fido_cred_t *);
size_t fido_cred_pubkey_len(const fido_cred_t *);
size_t fido_cred_sig_len(const fido_cred_t *);
size_t fido_cred_user_id_len(const fido_cred_t *);
size_t fido_cred_x5c_len(const fido_cred_t *);
size_t fido_cred_largeblob_key_len(const fido_cred_t *);
uint8_t fido_assert_flags(const fido_assert_t *, size_t);
uint32_t fido_assert_sigcount(const fido_assert_t *, size_t);

View File

@ -26,6 +26,8 @@ int fido_dev_enable_entattest(fido_dev_t *, const char *);
int fido_dev_force_pin_change(fido_dev_t *, const char *);
int fido_dev_toggle_always_uv(fido_dev_t *, const char *);
int fido_dev_set_pin_minlen(fido_dev_t *, size_t, const char *);
int fido_dev_set_pin_minlen_rpid(fido_dev_t *, const char * const *, size_t,
const char *);
#ifdef __cplusplus
} /* extern "C" */

View File

@ -31,19 +31,14 @@ int eddsa_pk_from_ptr(eddsa_pk_t *, const void *, size_t);
#ifdef _FIDO_INTERNAL
#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10101000L
#if defined(LIBRESSL_VERSION_NUMBER)
#define EVP_PKEY_ED25519 EVP_PKEY_NONE
int EVP_PKEY_get_raw_public_key(const EVP_PKEY *, unsigned char *, size_t *);
EVP_PKEY *EVP_PKEY_new_raw_public_key(int, ENGINE *, const unsigned char *,
size_t);
int EVP_DigestVerify(EVP_MD_CTX *, const unsigned char *, size_t,
const unsigned char *, size_t);
#endif /* LIBRESSL_VERSION_NUMBER || OPENSSL_VERSION_NUMBER < 0x10101000L */
#if OPENSSL_VERSION_NUMBER < 0x10100000L
EVP_MD_CTX *EVP_MD_CTX_new(void);
void EVP_MD_CTX_free(EVP_MD_CTX *);
#endif
#endif /* LIBRESSL_VERSION_NUMBER */
#endif /* _FIDO_INTERNAL */

View File

@ -1,5 +1,5 @@
/*
* 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.
*/
@ -27,6 +27,7 @@ void es256_pk_free(es256_pk_t **);
EVP_PKEY *es256_pk_to_EVP_PKEY(const es256_pk_t *);
int es256_pk_from_EC_KEY(es256_pk_t *, const EC_KEY *);
int es256_pk_from_EVP_PKEY(es256_pk_t *, const EVP_PKEY *);
int es256_pk_from_ptr(es256_pk_t *, const void *, size_t);
#ifdef _FIDO_INTERNAL

View File

@ -1,5 +1,5 @@
/*
* 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.
*/
@ -82,10 +82,12 @@
#define FIDO_CAP_NMSG 0x08 /* if set, device doesn't support CTAP_CMD_MSG */
/* Supported COSE algorithms. */
#define COSE_UNSPEC 0
#define COSE_ES256 -7
#define COSE_EDDSA -8
#define COSE_ECDH_ES256 -25
#define COSE_RS256 -257
#define COSE_RS1 -65535
/* Supported COSE types. */
#define COSE_KTY_OKP 1
@ -101,6 +103,7 @@
#define FIDO_EXT_CRED_PROTECT 0x02
#define FIDO_EXT_LARGEBLOB_KEY 0x04
#define FIDO_EXT_CRED_BLOB 0x08
#define FIDO_EXT_MINPINLEN 0x10
/* Supported credential protection policies. */
#define FIDO_CRED_PROT_UV_OPTIONAL 0x01
@ -111,7 +114,8 @@
#define FIDO_EXT_ASSERT_MASK (FIDO_EXT_HMAC_SECRET|FIDO_EXT_LARGEBLOB_KEY| \
FIDO_EXT_CRED_BLOB)
#define FIDO_EXT_CRED_MASK (FIDO_EXT_HMAC_SECRET|FIDO_EXT_CRED_PROTECT| \
FIDO_EXT_LARGEBLOB_KEY|FIDO_EXT_CRED_BLOB)
FIDO_EXT_LARGEBLOB_KEY|FIDO_EXT_CRED_BLOB| \
FIDO_EXT_MINPINLEN)
#endif /* _FIDO_INTERNAL */
#endif /* !_FIDO_PARAM_H */

View File

@ -1,5 +1,5 @@
/*
* 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.
*/
@ -26,6 +26,7 @@ rs256_pk_t *rs256_pk_new(void);
void rs256_pk_free(rs256_pk_t **);
EVP_PKEY *rs256_pk_to_EVP_PKEY(const rs256_pk_t *);
int rs256_pk_from_EVP_PKEY(rs256_pk_t *, const EVP_PKEY *);
int rs256_pk_from_RSA(rs256_pk_t *, const RSA *);
int rs256_pk_from_ptr(rs256_pk_t *, const void *, size_t);

View File

@ -107,8 +107,12 @@ typedef struct fido_attcred {
} fido_attcred_t;
typedef struct fido_attstmt {
fido_blob_t x5c; /* attestation certificate */
fido_blob_t sig; /* attestation signature */
fido_blob_t certinfo; /* tpm attestation TPMS_ATTEST structure */
fido_blob_t pubarea; /* tpm attestation TPMT_PUBLIC structure */
fido_blob_t cbor; /* cbor-encoded attestation statement */
fido_blob_t x5c; /* attestation certificate */
fido_blob_t sig; /* attestation signature */
int alg; /* attestation algorithm (cose) */
} fido_attstmt_t;
typedef struct fido_rp {
@ -124,8 +128,9 @@ typedef struct fido_user {
} fido_user_t;
typedef struct fido_cred_ext {
int mask; /* enabled extensions */
int prot; /* protection policy */
int mask; /* enabled extensions */
int prot; /* protection policy */
size_t minpinlen; /* minimum pin length */
} fido_cred_ext_t;
typedef struct fido_cred {
@ -260,6 +265,7 @@ typedef struct fido_dev {
int flags; /* internal flags; see FIDO_DEV_* */
fido_dev_transport_t transport; /* transport functions */
uint64_t maxmsgsize; /* max message size */
int timeout_ms; /* read timeout in ms */
} fido_dev_t;
#else

View File

@ -14,6 +14,12 @@
#include "fido.h"
#if defined(__MidnightBSD__)
#define UHID_VENDOR "MidnightBSD"
#else
#define UHID_VENDOR "FreeBSD"
#endif
#define MAX_UHID 64
struct hid_freebsd {
@ -66,7 +72,7 @@ copy_info(fido_dev_info_t *di, const char *path)
if (ioctl(fd, IOCTL_REQ(USB_GET_DEVICEINFO), &udi) == -1) {
fido_log_error(errno, "%s: ioctl", __func__);
strlcpy(udi.udi_vendor, "FreeBSD", sizeof(udi.udi_vendor));
strlcpy(udi.udi_vendor, UHID_VENDOR, sizeof(udi.udi_vendor));
strlcpy(udi.udi_product, "uhid(4)", sizeof(udi.udi_product));
udi.udi_vendorNo = 0x0b5d; /* stolen from PCI_VENDOR_OPENBSD */
}

View File

@ -160,9 +160,9 @@ copy_info(fido_dev_info_t *di, struct udev *udev,
di->path = strdup(path);
if ((di->manufacturer = get_usb_attr(dev, "manufacturer")) == NULL)
di->manufacturer = strdup("unknown");
di->manufacturer = strdup("");
if ((di->product = get_usb_attr(dev, "product")) == NULL)
di->product = strdup("unknown");
di->product = strdup("");
if (di->path == NULL || di->manufacturer == NULL || di->product == NULL)
goto fail;

View File

@ -23,6 +23,8 @@ struct hid_openbsd {
int fd;
size_t report_in_len;
size_t report_out_len;
sigset_t sigmask;
const sigset_t *sigmaskp;
};
int
@ -185,10 +187,12 @@ fido_hid_close(void *handle)
int
fido_hid_set_sigmask(void *handle, const fido_sigset_t *sigmask)
{
(void)handle;
(void)sigmask;
struct hid_openbsd *ctx = handle;
return (FIDO_ERR_INTERNAL);
ctx->sigmask = *sigmask;
ctx->sigmaskp = &ctx->sigmask;
return (FIDO_OK);
}
int
@ -197,14 +201,17 @@ fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
struct hid_openbsd *ctx = (struct hid_openbsd *)handle;
ssize_t r;
(void)ms; /* XXX */
if (len != ctx->report_in_len) {
fido_log_debug("%s: invalid len: got %zu, want %zu", __func__,
len, ctx->report_in_len);
return (-1);
}
if (fido_hid_unix_wait(ctx->fd, ms, ctx->sigmaskp) < 0) {
fido_log_debug("%s: fd not ready", __func__);
return (-1);
}
if ((r = read(ctx->fd, buf, len)) == -1) {
fido_log_error(errno, "%s: read", __func__);
return (-1);

View File

@ -11,6 +11,7 @@
#include <signal.h>
#include <unistd.h>
#include <Availability.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/hid/IOHIDKeys.h>
@ -18,6 +19,10 @@
#include "fido.h"
#if __MAC_OS_X_VERSION_MIN_REQUIRED < 120000
#define kIOMainPortDefault kIOMasterPortDefault
#endif
struct hid_osx {
IOHIDDeviceRef ref;
CFStringRef loop_id;
@ -131,23 +136,18 @@ get_str(IOHIDDeviceRef dev, char **manufacturer, char **product)
*manufacturer = NULL;
*product = NULL;
if (get_utf8(dev, CFSTR(kIOHIDManufacturerKey), buf, sizeof(buf)) < 0) {
fido_log_debug("%s: get_utf8 manufacturer", __func__);
goto fail;
}
if (get_utf8(dev, CFSTR(kIOHIDManufacturerKey), buf, sizeof(buf)) < 0)
*manufacturer = strdup("");
else
*manufacturer = strdup(buf);
if ((*manufacturer = strdup(buf)) == NULL) {
fido_log_debug("%s: strdup manufacturer", __func__);
goto fail;
}
if (get_utf8(dev, CFSTR(kIOHIDProductKey), buf, sizeof(buf)) < 0)
*product = strdup("");
else
*product = strdup(buf);
if (get_utf8(dev, CFSTR(kIOHIDProductKey), buf, sizeof(buf)) < 0) {
fido_log_debug("%s: get_utf8 product", __func__);
goto fail;
}
if ((*product = strdup(buf)) == NULL) {
fido_log_debug("%s: strdup product", __func__);
if (*manufacturer == NULL || *product == NULL) {
fido_log_debug("%s: strdup", __func__);
goto fail;
}
@ -398,7 +398,7 @@ fido_hid_open(const char *path)
goto fail;
}
if ((entry = IORegistryEntryFromPath(kIOMasterPortDefault,
if ((entry = IORegistryEntryFromPath(kIOMainPortDefault,
path)) == MACH_PORT_NULL) {
fido_log_debug("%s: IORegistryEntryFromPath", __func__);
goto fail;

View File

@ -58,8 +58,7 @@ fido_hid_unix_wait(int fd, int ms, const fido_sigset_t *sigmask)
pfd.fd = fd;
#ifdef FIDO_FUZZ
if (ms < 0)
return (0);
return (0);
#endif
if (ms > -1) {
ts.tv_sec = ms / 1000;

View File

@ -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.
*/
@ -103,7 +103,7 @@ get_report_len(HANDLE dev, int dir, size_t *report_len)
}
static int
get_int(HANDLE dev, int16_t *vendor_id, int16_t *product_id)
get_id(HANDLE dev, int16_t *vendor_id, int16_t *product_id)
{
HIDD_ATTRIBUTES attr;
@ -121,14 +121,13 @@ get_int(HANDLE dev, int16_t *vendor_id, int16_t *product_id)
}
static int
get_str(HANDLE dev, char **manufacturer, char **product)
get_manufacturer(HANDLE dev, char **manufacturer)
{
wchar_t buf[512];
int utf8_len;
int ok = -1;
*manufacturer = NULL;
*product = NULL;
if (HidD_GetManufacturerString(dev, &buf, sizeof(buf)) == false) {
fido_log_debug("%s: HidD_GetManufacturerString", __func__);
@ -152,6 +151,25 @@ get_str(HANDLE dev, char **manufacturer, char **product)
goto fail;
}
ok = 0;
fail:
if (ok < 0) {
free(*manufacturer);
*manufacturer = NULL;
}
return (ok);
}
static int
get_product(HANDLE dev, char **product)
{
wchar_t buf[512];
int utf8_len;
int ok = -1;
*product = NULL;
if (HidD_GetProductString(dev, &buf, sizeof(buf)) == false) {
fido_log_debug("%s: HidD_GetProductString", __func__);
goto fail;
@ -177,9 +195,7 @@ get_str(HANDLE dev, char **manufacturer, char **product)
ok = 0;
fail:
if (ok < 0) {
free(*manufacturer);
free(*product);
*manufacturer = NULL;
*product = NULL;
}
@ -313,9 +329,23 @@ copy_info(fido_dev_info_t *di, HDEVINFO devinfo, DWORD idx,
goto fail;
}
if (get_int(dev, &di->vendor_id, &di->product_id) < 0 ||
get_str(dev, &di->manufacturer, &di->product) < 0) {
fido_log_debug("%s: get_int/get_str", __func__);
if (get_id(dev, &di->vendor_id, &di->product_id) < 0) {
fido_log_debug("%s: get_id", __func__);
goto fail;
}
if (get_manufacturer(dev, &di->manufacturer) < 0) {
fido_log_debug("%s: get_manufacturer", __func__);
di->manufacturer = strdup("");
}
if (get_product(dev, &di->product) < 0) {
fido_log_debug("%s: get_product", __func__);
di->product = strdup("");
}
if (di->manufacturer == NULL || di->product == NULL) {
fido_log_debug("%s: manufacturer/product", __func__);
goto fail;
}

View File

@ -186,14 +186,6 @@ decode_algorithm_entry(const cbor_item_t *key, const cbor_item_t *val,
return (ok);
}
static void
free_algo(fido_algo_t *a)
{
free(a->type);
a->type = NULL;
a->cose = 0;
}
static int
decode_algorithm(const cbor_item_t *item, void *arg)
{
@ -210,7 +202,7 @@ decode_algorithm(const cbor_item_t *item, void *arg)
if (cbor_map_iter(item, &aa->ptr[i], decode_algorithm_entry) < 0) {
fido_log_debug("%s: decode_algorithm_entry", __func__);
free_algo(&aa->ptr[i]);
fido_algo_free(&aa->ptr[i]);
return (-1);
}
@ -287,13 +279,13 @@ parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg)
}
static int
fido_dev_get_cbor_info_tx(fido_dev_t *dev)
fido_dev_get_cbor_info_tx(fido_dev_t *dev, int *ms)
{
const unsigned char cbor[] = { CTAP_CBOR_GETINFO };
fido_log_debug("%s: dev=%p", __func__, (void *)dev);
if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor)) < 0) {
if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor), ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
return (FIDO_ERR_TX);
}
@ -302,13 +294,13 @@ fido_dev_get_cbor_info_tx(fido_dev_t *dev)
}
static int
fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int ms)
fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
fido_log_debug("%s: dev=%p, ci=%p, ms=%d", __func__, (void *)dev,
(void *)ci, ms);
(void *)ci, *ms);
fido_cbor_info_reset(ci);
@ -323,7 +315,7 @@ fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int ms)
}
int
fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int ms)
fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int *ms)
{
int r;
@ -331,7 +323,7 @@ fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int ms)
if (dev->flags & FIDO_DEV_WINHELLO)
return (fido_winhello_get_cbor_info(dev, ci));
#endif
if ((r = fido_dev_get_cbor_info_tx(dev)) != FIDO_OK ||
if ((r = fido_dev_get_cbor_info_tx(dev, ms)) != FIDO_OK ||
(r = fido_dev_get_cbor_info_rx(dev, ci, ms)) != FIDO_OK)
return (r);
@ -341,7 +333,9 @@ fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int ms)
int
fido_dev_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci)
{
return (fido_dev_get_cbor_info_wait(dev, ci, -1));
int ms = dev->timeout_ms;
return (fido_dev_get_cbor_info_wait(dev, ci, &ms));
}
/*
@ -354,58 +348,15 @@ fido_cbor_info_new(void)
return (calloc(1, sizeof(fido_cbor_info_t)));
}
static void
free_str_array(fido_str_array_t *sa)
{
for (size_t i = 0; i < sa->len; i++)
free(sa->ptr[i]);
free(sa->ptr);
sa->ptr = NULL;
sa->len = 0;
}
static void
free_opt_array(fido_opt_array_t *oa)
{
for (size_t i = 0; i < oa->len; i++)
free(oa->name[i]);
free(oa->name);
free(oa->value);
oa->name = NULL;
oa->value = NULL;
}
static void
free_byte_array(fido_byte_array_t *ba)
{
free(ba->ptr);
ba->ptr = NULL;
ba->len = 0;
}
static void
free_algo_array(fido_algo_array_t *aa)
{
for (size_t i = 0; i < aa->len; i++)
free_algo(&aa->ptr[i]);
free(aa->ptr);
aa->ptr = NULL;
aa->len = 0;
}
void
fido_cbor_info_reset(fido_cbor_info_t *ci)
{
free_str_array(&ci->versions);
free_str_array(&ci->extensions);
free_str_array(&ci->transports);
free_opt_array(&ci->options);
free_byte_array(&ci->protocols);
free_algo_array(&ci->algorithms);
fido_str_array_free(&ci->versions);
fido_str_array_free(&ci->extensions);
fido_str_array_free(&ci->transports);
fido_opt_array_free(&ci->options);
fido_byte_array_free(&ci->protocols);
fido_algo_array_free(&ci->algorithms);
}
void

106
src/io.c
View File

@ -30,7 +30,24 @@ struct frame {
#endif
static int
tx_empty(fido_dev_t *d, uint8_t cmd)
tx_pkt(fido_dev_t *d, const void *pkt, size_t len, int *ms)
{
struct timespec ts;
int n;
if (fido_time_now(&ts) != 0)
return (-1);
n = d->io.write(d->io_handle, pkt, len);
if (fido_time_delta(&ts, ms) != 0)
return (-1);
return (n);
}
static int
tx_empty(fido_dev_t *d, uint8_t cmd, int *ms)
{
struct frame *fp;
unsigned char pkt[sizeof(*fp) + 1];
@ -42,15 +59,15 @@ tx_empty(fido_dev_t *d, uint8_t cmd)
fp->cid = d->cid;
fp->body.init.cmd = CTAP_FRAME_INIT | cmd;
if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt,
len)) < 0 || (size_t)n != len)
if (len > sizeof(pkt) || (n = tx_pkt(d, pkt, len, ms)) < 0 ||
(size_t)n != len)
return (-1);
return (0);
}
static size_t
tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count, int *ms)
{
struct frame *fp;
unsigned char pkt[sizeof(*fp) + 1];
@ -69,15 +86,15 @@ tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
count = MIN(count, d->tx_len - CTAP_INIT_HEADER_LEN);
memcpy(&fp->body.init.data, buf, count);
if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt,
len)) < 0 || (size_t)n != len)
if (len > sizeof(pkt) || (n = tx_pkt(d, pkt, len, ms)) < 0 ||
(size_t)n != len)
return (0);
return (count);
}
static size_t
tx_frame(fido_dev_t *d, uint8_t seq, const void *buf, size_t count)
tx_frame(fido_dev_t *d, uint8_t seq, const void *buf, size_t count, int *ms)
{
struct frame *fp;
unsigned char pkt[sizeof(*fp) + 1];
@ -94,19 +111,19 @@ tx_frame(fido_dev_t *d, uint8_t seq, const void *buf, size_t count)
count = MIN(count, d->tx_len - CTAP_CONT_HEADER_LEN);
memcpy(&fp->body.cont.data, buf, count);
if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt,
len)) < 0 || (size_t)n != len)
if (len > sizeof(pkt) || (n = tx_pkt(d, pkt, len, ms)) < 0 ||
(size_t)n != len)
return (0);
return (count);
}
static int
tx(fido_dev_t *d, uint8_t cmd, const unsigned char *buf, size_t count)
tx(fido_dev_t *d, uint8_t cmd, const unsigned char *buf, size_t count, int *ms)
{
size_t n, sent;
if ((sent = tx_preamble(d, cmd, buf, count)) == 0) {
if ((sent = tx_preamble(d, cmd, buf, count, ms)) == 0) {
fido_log_debug("%s: tx_preamble", __func__);
return (-1);
}
@ -116,7 +133,8 @@ tx(fido_dev_t *d, uint8_t cmd, const unsigned char *buf, size_t count)
fido_log_debug("%s: seq & 0x80", __func__);
return (-1);
}
if ((n = tx_frame(d, seq++, buf + sent, count - sent)) == 0) {
if ((n = tx_frame(d, seq++, buf + sent, count - sent,
ms)) == 0) {
fido_log_debug("%s: tx_frame", __func__);
return (-1);
}
@ -125,38 +143,59 @@ tx(fido_dev_t *d, uint8_t cmd, const unsigned char *buf, size_t count)
return (0);
}
static int
transport_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count, int *ms)
{
struct timespec ts;
int n;
if (fido_time_now(&ts) != 0)
return (-1);
n = d->transport.tx(d, cmd, buf, count);
if (fido_time_delta(&ts, ms) != 0)
return (-1);
return (n);
}
int
fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count, int *ms)
{
fido_log_debug("%s: dev=%p, cmd=0x%02x", __func__, (void *)d, cmd);
fido_log_xxd(buf, count, "%s", __func__);
if (d->transport.tx != NULL)
return (d->transport.tx(d, cmd, buf, count));
return (transport_tx(d, cmd, buf, count, ms));
if (d->io_handle == NULL || d->io.write == NULL || count > UINT16_MAX) {
fido_log_debug("%s: invalid argument", __func__);
return (-1);
}
return (count == 0 ? tx_empty(d, cmd) : tx(d, cmd, buf, count));
return (count == 0 ? tx_empty(d, cmd, ms) : tx(d, cmd, buf, count, ms));
}
static int
rx_frame(fido_dev_t *d, struct frame *fp, int ms)
rx_frame(fido_dev_t *d, struct frame *fp, int *ms)
{
struct timespec ts;
int n;
memset(fp, 0, sizeof(*fp));
if (d->rx_len > sizeof(*fp) || (n = d->io.read(d->io_handle,
(unsigned char *)fp, d->rx_len, ms)) < 0 || (size_t)n != d->rx_len)
if (fido_time_now(&ts) != 0)
return (-1);
return (0);
if (d->rx_len > sizeof(*fp) || (n = d->io.read(d->io_handle,
(unsigned char *)fp, d->rx_len, *ms)) < 0 || (size_t)n != d->rx_len)
return (-1);
return (fido_time_delta(&ts, ms));
}
static int
rx_preamble(fido_dev_t *d, uint8_t cmd, struct frame *fp, int ms)
rx_preamble(fido_dev_t *d, uint8_t cmd, struct frame *fp, int *ms)
{
do {
if (rx_frame(d, fp, ms) < 0)
@ -185,7 +224,7 @@ rx_preamble(fido_dev_t *d, uint8_t cmd, struct frame *fp, int ms)
}
static int
rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms)
rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int *ms)
{
struct frame f;
size_t r, payload_len, init_data_len, cont_data_len;
@ -252,16 +291,33 @@ rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms)
return ((int)r);
}
static int
transport_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int *ms)
{
struct timespec ts;
int n;
if (fido_time_now(&ts) != 0)
return (-1);
n = d->transport.rx(d, cmd, buf, count, *ms);
if (fido_time_delta(&ts, ms) != 0)
return (-1);
return (n);
}
int
fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms)
fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int *ms)
{
int n;
fido_log_debug("%s: dev=%p, cmd=0x%02x, ms=%d", __func__, (void *)d,
cmd, ms);
cmd, *ms);
if (d->transport.rx != NULL)
return (d->transport.rx(d, cmd, buf, count, ms));
return (transport_rx(d, cmd, buf, count, ms));
if (d->io_handle == NULL || d->io.read == NULL || count > UINT16_MAX) {
fido_log_debug("%s: invalid argument", __func__);
return (-1);
@ -273,7 +329,7 @@ fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms)
}
int
fido_rx_cbor_status(fido_dev_t *d, int ms)
fido_rx_cbor_status(fido_dev_t *d, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;

View File

@ -59,6 +59,6 @@ iso7816_ptr(const iso7816_apdu_t *apdu)
size_t
iso7816_len(const iso7816_apdu_t *apdu)
{
return apdu->alloc_len - sizeof(apdu->alloc_len) -
sizeof(apdu->payload_len) - sizeof(apdu->payload_ptr);
return apdu->alloc_len - offsetof(iso7816_apdu_t, header) -
(sizeof(iso7816_apdu_t) - offsetof(iso7816_apdu_t, payload));
}

View File

@ -27,14 +27,13 @@ struct iso7816_header {
uint8_t lc3;
})
PACKED_TYPE(iso7816_apdu_t,
struct iso7816_apdu {
typedef struct iso7816_apdu {
size_t alloc_len;
uint16_t payload_len;
uint8_t *payload_ptr;
iso7816_header_t header;
uint8_t payload[];
})
} iso7816_apdu_t;
const unsigned char *iso7816_ptr(const iso7816_apdu_t *);
int iso7816_add(iso7816_apdu_t *, const void *, size_t);

View File

@ -153,7 +153,7 @@ largeblob_seal(largeblob_t *blob, const fido_blob_t *body,
}
static int
largeblob_get_tx(fido_dev_t *dev, size_t offset, size_t count)
largeblob_get_tx(fido_dev_t *dev, size_t offset, size_t count, int *ms)
{
fido_blob_t f;
cbor_item_t *argv[3];
@ -169,7 +169,7 @@ largeblob_get_tx(fido_dev_t *dev, size_t offset, size_t count)
goto fail;
}
if (cbor_build_frame(CTAP_CBOR_LARGEBLOB, argv, nitems(argv), &f) < 0 ||
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -198,7 +198,7 @@ parse_largeblob_reply(const cbor_item_t *key, const cbor_item_t *val,
}
static int
largeblob_get_rx(fido_dev_t *dev, fido_blob_t **chunk, int ms)
largeblob_get_rx(fido_dev_t *dev, fido_blob_t **chunk, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len, r;
@ -419,7 +419,7 @@ largeblob_array_check(const fido_blob_t *array)
}
static int
largeblob_get_array(fido_dev_t *dev, cbor_item_t **item)
largeblob_get_array(fido_dev_t *dev, cbor_item_t **item, int *ms)
{
fido_blob_t *array, *chunk = NULL;
size_t n;
@ -432,8 +432,8 @@ largeblob_get_array(fido_dev_t *dev, cbor_item_t **item)
return FIDO_ERR_INTERNAL;
do {
fido_blob_free(&chunk);
if ((r = largeblob_get_tx(dev, array->len, n)) != FIDO_OK ||
(r = largeblob_get_rx(dev, &chunk, -1)) != FIDO_OK) {
if ((r = largeblob_get_tx(dev, array->len, n, ms)) != FIDO_OK ||
(r = largeblob_get_rx(dev, &chunk, ms)) != FIDO_OK) {
fido_log_debug("%s: largeblob_get_wait %zu/%zu",
__func__, array->len, n);
goto fail;
@ -491,7 +491,7 @@ prepare_hmac(size_t offset, const u_char *data, size_t len, fido_blob_t *hmac)
static int
largeblob_set_tx(fido_dev_t *dev, const fido_blob_t *token, const u_char *chunk,
size_t chunk_len, size_t offset, size_t totalsiz)
size_t chunk_len, size_t offset, size_t totalsiz, int *ms)
{
fido_blob_t *hmac = NULL, f;
cbor_item_t *argv[6];
@ -518,7 +518,7 @@ largeblob_set_tx(fido_dev_t *dev, const fido_blob_t *token, const u_char *chunk,
}
}
if (cbor_build_frame(CTAP_CBOR_LARGEBLOB, argv, nitems(argv), &f) < 0 ||
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -534,7 +534,8 @@ largeblob_set_tx(fido_dev_t *dev, const fido_blob_t *token, const u_char *chunk,
}
static int
largeblob_get_uv_token(fido_dev_t *dev, const char *pin, fido_blob_t **token)
largeblob_get_uv_token(fido_dev_t *dev, const char *pin, fido_blob_t **token,
int *ms)
{
es256_pk_t *pk = NULL;
fido_blob_t *ecdh = NULL;
@ -542,12 +543,12 @@ largeblob_get_uv_token(fido_dev_t *dev, const char *pin, fido_blob_t **token)
if ((*token = fido_blob_new()) == NULL)
return FIDO_ERR_INTERNAL;
if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
fido_log_debug("%s: fido_do_ecdh", __func__);
goto fail;
}
if ((r = fido_dev_get_uv_token(dev, CTAP_CBOR_LARGEBLOB, pin, ecdh, pk,
NULL, *token)) != FIDO_OK) {
NULL, *token, ms)) != FIDO_OK) {
fido_log_debug("%s: fido_dev_get_uv_token", __func__);
goto fail;
}
@ -564,7 +565,8 @@ largeblob_get_uv_token(fido_dev_t *dev, const char *pin, fido_blob_t **token)
}
static int
largeblob_set_array(fido_dev_t *dev, const cbor_item_t *item, const char *pin)
largeblob_set_array(fido_dev_t *dev, const cbor_item_t *item, const char *pin,
int *ms)
{
unsigned char dgst[SHA256_DIGEST_LENGTH];
fido_blob_t cbor, *token = NULL;
@ -600,7 +602,8 @@ largeblob_set_array(fido_dev_t *dev, const cbor_item_t *item, const char *pin)
}
totalsize = cbor.len + sizeof(dgst) - 16; /* the first 16 bytes only */
if (pin != NULL || fido_dev_supports_permissions(dev)) {
if ((r = largeblob_get_uv_token(dev, pin, &token)) != FIDO_OK) {
if ((r = largeblob_get_uv_token(dev, pin, &token,
ms)) != FIDO_OK) {
fido_log_debug("%s: largeblob_get_uv_token", __func__);
goto fail;
}
@ -609,15 +612,15 @@ largeblob_set_array(fido_dev_t *dev, const cbor_item_t *item, const char *pin)
if ((chunklen = cbor.len - offset) > maxchunklen)
chunklen = maxchunklen;
if ((r = largeblob_set_tx(dev, token, cbor.ptr + offset,
chunklen, offset, totalsize)) != FIDO_OK ||
(r = fido_rx_cbor_status(dev, -1)) != FIDO_OK) {
chunklen, offset, totalsize, ms)) != FIDO_OK ||
(r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
fido_log_debug("%s: body", __func__);
goto fail;
}
}
if ((r = largeblob_set_tx(dev, token, dgst, sizeof(dgst) - 16, cbor.len,
totalsize)) != FIDO_OK ||
(r = fido_rx_cbor_status(dev, -1)) != FIDO_OK) {
totalsize, ms)) != FIDO_OK ||
(r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
fido_log_debug("%s: dgst", __func__);
goto fail;
}
@ -632,13 +635,13 @@ largeblob_set_array(fido_dev_t *dev, const cbor_item_t *item, const char *pin)
static int
largeblob_add(fido_dev_t *dev, const fido_blob_t *key, cbor_item_t *item,
const char *pin)
const char *pin, int *ms)
{
cbor_item_t *array = NULL;
size_t idx;
int r;
if ((r = largeblob_get_array(dev, &array)) != FIDO_OK) {
if ((r = largeblob_get_array(dev, &array, ms)) != FIDO_OK) {
fido_log_debug("%s: largeblob_get_array", __func__);
goto fail;
}
@ -661,7 +664,7 @@ largeblob_add(fido_dev_t *dev, const fido_blob_t *key, cbor_item_t *item,
goto fail;
}
if ((r = largeblob_set_array(dev, array, pin)) != FIDO_OK) {
if ((r = largeblob_set_array(dev, array, pin, ms)) != FIDO_OK) {
fido_log_debug("%s: largeblob_set_array", __func__);
goto fail;
}
@ -675,13 +678,14 @@ largeblob_add(fido_dev_t *dev, const fido_blob_t *key, cbor_item_t *item,
}
static int
largeblob_drop(fido_dev_t *dev, const fido_blob_t *key, const char *pin)
largeblob_drop(fido_dev_t *dev, const fido_blob_t *key, const char *pin,
int *ms)
{
cbor_item_t *array = NULL;
size_t idx;
int r;
if ((r = largeblob_get_array(dev, &array)) != FIDO_OK) {
if ((r = largeblob_get_array(dev, &array, ms)) != FIDO_OK) {
fido_log_debug("%s: largeblob_get_array", __func__);
goto fail;
}
@ -694,7 +698,7 @@ largeblob_drop(fido_dev_t *dev, const fido_blob_t *key, const char *pin)
r = FIDO_ERR_INTERNAL;
goto fail;
}
if ((r = largeblob_set_array(dev, array, pin)) != FIDO_OK) {
if ((r = largeblob_set_array(dev, array, pin, ms)) != FIDO_OK) {
fido_log_debug("%s: largeblob_set_array", __func__);
goto fail;
}
@ -713,6 +717,7 @@ fido_dev_largeblob_get(fido_dev_t *dev, const unsigned char *key_ptr,
{
cbor_item_t *item = NULL;
fido_blob_t key, body;
int ms = dev->timeout_ms;
int r;
memset(&key, 0, sizeof(key));
@ -733,7 +738,7 @@ fido_dev_largeblob_get(fido_dev_t *dev, const unsigned char *key_ptr,
fido_log_debug("%s: fido_blob_set", __func__);
return FIDO_ERR_INTERNAL;
}
if ((r = largeblob_get_array(dev, &item)) != FIDO_OK) {
if ((r = largeblob_get_array(dev, &item, &ms)) != FIDO_OK) {
fido_log_debug("%s: largeblob_get_array", __func__);
goto fail;
}
@ -759,6 +764,7 @@ fido_dev_largeblob_set(fido_dev_t *dev, const unsigned char *key_ptr,
{
cbor_item_t *item = NULL;
fido_blob_t key, body;
int ms = dev->timeout_ms;
int r;
memset(&key, 0, sizeof(key));
@ -784,7 +790,7 @@ fido_dev_largeblob_set(fido_dev_t *dev, const unsigned char *key_ptr,
r = FIDO_ERR_INTERNAL;
goto fail;
}
if ((r = largeblob_add(dev, &key, item, pin)) != FIDO_OK)
if ((r = largeblob_add(dev, &key, item, pin, &ms)) != FIDO_OK)
fido_log_debug("%s: largeblob_add", __func__);
fail:
if (item != NULL)
@ -801,6 +807,7 @@ fido_dev_largeblob_remove(fido_dev_t *dev, const unsigned char *key_ptr,
size_t key_len, const char *pin)
{
fido_blob_t key;
int ms = dev->timeout_ms;
int r;
memset(&key, 0, sizeof(key));
@ -813,7 +820,7 @@ fido_dev_largeblob_remove(fido_dev_t *dev, const unsigned char *key_ptr,
fido_log_debug("%s: fido_blob_set", __func__);
return FIDO_ERR_INTERNAL;
}
if ((r = largeblob_drop(dev, &key, pin)) != FIDO_OK)
if ((r = largeblob_drop(dev, &key, pin, &ms)) != FIDO_OK)
fido_log_debug("%s: largeblob_drop", __func__);
fido_blob_reset(&key);
@ -827,6 +834,7 @@ fido_dev_largeblob_get_array(fido_dev_t *dev, unsigned char **cbor_ptr,
{
cbor_item_t *item = NULL;
fido_blob_t cbor;
int ms = dev->timeout_ms;
int r;
memset(&cbor, 0, sizeof(cbor));
@ -838,7 +846,7 @@ fido_dev_largeblob_get_array(fido_dev_t *dev, unsigned char **cbor_ptr,
}
*cbor_ptr = NULL;
*cbor_len = 0;
if ((r = largeblob_get_array(dev, &item)) != FIDO_OK) {
if ((r = largeblob_get_array(dev, &item, &ms)) != FIDO_OK) {
fido_log_debug("%s: largeblob_get_array", __func__);
return r;
}
@ -861,6 +869,7 @@ fido_dev_largeblob_set_array(fido_dev_t *dev, const unsigned char *cbor_ptr,
{
cbor_item_t *item = NULL;
struct cbor_load_result cbor_result;
int ms = dev->timeout_ms;
int r;
if (cbor_ptr == NULL || cbor_len == 0) {
@ -872,7 +881,7 @@ fido_dev_largeblob_set_array(fido_dev_t *dev, const unsigned char *cbor_ptr,
fido_log_debug("%s: cbor_load", __func__);
return FIDO_ERR_INVALID_ARGUMENT;
}
if ((r = largeblob_set_array(dev, item, pin)) != FIDO_OK)
if ((r = largeblob_set_array(dev, item, pin, &ms)) != FIDO_OK)
fido_log_debug("%s: largeblob_set_array", __func__);
cbor_decref(&item);

View File

@ -30,6 +30,8 @@ static ssize_t (*fuzz_write)(int, const void *, size_t);
#define SOL_NETLINK 270
#endif
#define NETLINK_POLL_MS 100
/* XXX avoid signed NLA_ALIGNTO */
#undef NLA_HDRLEN
#define NLA_HDRLEN NLMSG_ALIGN(sizeof(struct nlattr))
@ -694,7 +696,7 @@ fido_nl_get_nfc_target(fido_nl_t *nl, uint32_t dev, uint32_t *target)
return (-1);
}
#endif
r = nlmsg_rx(nl->fd, reply, sizeof(reply), -1);
r = nlmsg_rx(nl->fd, reply, sizeof(reply), NETLINK_POLL_MS);
#ifndef FIDO_FUZZ
if (setsockopt(nl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
&nl->nfc_mcastgrp, sizeof(nl->nfc_mcastgrp)) == -1) {

View File

@ -13,6 +13,8 @@
#include <errno.h>
#include <libudev.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "fido.h"
@ -218,16 +220,23 @@ tx_get_response(fido_dev_t *d, uint8_t count)
}
static int
rx_apdu(fido_dev_t *d, uint8_t sw[2], unsigned char **buf, size_t *count, int ms)
rx_apdu(fido_dev_t *d, uint8_t sw[2], unsigned char **buf, size_t *count, int *ms)
{
uint8_t f[256 + 2];
struct timespec ts;
int n, ok = -1;
if ((n = d->io.read(d->io_handle, f, sizeof(f), ms)) < 2) {
if (fido_time_now(&ts) != 0)
goto fail;
if ((n = d->io.read(d->io_handle, f, sizeof(f), *ms)) < 2) {
fido_log_debug("%s: read", __func__);
goto fail;
}
if (fido_time_delta(&ts, ms) != 0)
goto fail;
if (fido_buf_write(buf, count, f, (size_t)(n - 2)) < 0) {
fido_log_debug("%s: fido_buf_write", __func__);
goto fail;
@ -248,14 +257,14 @@ rx_msg(fido_dev_t *d, unsigned char *buf, size_t count, int ms)
uint8_t sw[2];
const size_t bufsiz = count;
if (rx_apdu(d, sw, &buf, &count, ms) < 0) {
if (rx_apdu(d, sw, &buf, &count, &ms) < 0) {
fido_log_debug("%s: preamble", __func__);
return (-1);
}
while (sw[0] == SW1_MORE_DATA)
if (tx_get_response(d, sw[1]) < 0 ||
rx_apdu(d, sw, &buf, &count, ms) < 0) {
rx_apdu(d, sw, &buf, &count, &ms) < 0) {
fido_log_debug("%s: chain", __func__);
return (-1);
}
@ -347,6 +356,7 @@ copy_info(fido_dev_info_t *di, struct udev *udev,
const char *name;
char *str;
struct udev_device *dev = NULL;
void *ctx = NULL;
int id, ok = -1;
memset(di, 0, sizeof(*di));
@ -354,27 +364,35 @@ copy_info(fido_dev_info_t *di, struct udev *udev,
if ((name = udev_list_entry_get_name(udev_entry)) == NULL ||
(dev = udev_device_new_from_syspath(udev, name)) == NULL)
goto fail;
if ((di->path = strdup(name)) == NULL ||
(di->manufacturer = get_usb_attr(dev, "manufacturer")) == NULL ||
(di->product = get_usb_attr(dev, "product")) == NULL)
if (asprintf(&di->path, "%s/%s", FIDO_NFC_PREFIX, name) == -1)
goto fail;
if ((di->manufacturer = get_usb_attr(dev, "manufacturer")) == NULL)
di->manufacturer = strdup("");
if ((di->product = get_usb_attr(dev, "product")) == NULL)
di->product = strdup("");
if (di->manufacturer == NULL || di->product == NULL)
goto fail;
/* XXX assumes USB for vendor/product info */
if ((str = get_usb_attr(dev, "idVendor")) != NULL &&
(id = to_int(str, 16)) > 0 && id <= UINT16_MAX)
di->vendor_id = (int16_t)id;
free(str);
if ((str = get_usb_attr(dev, "idProduct")) != NULL &&
(id = to_int(str, 16)) > 0 && id <= UINT16_MAX)
di->product_id = (int16_t)id;
free(str);
if ((ctx = fido_nfc_open(di->path)) == NULL) {
fido_log_debug("%s: fido_nfc_open", __func__);
goto fail;
}
ok = 0;
fail:
if (dev != NULL)
udev_device_unref(dev);
if (ctx != NULL)
fido_nfc_close(ctx);
if (ok < 0) {
free(di->path);
@ -532,7 +550,11 @@ fido_nfc_open(const char *path)
struct nfc_linux *ctx = NULL;
int idx;
if ((idx = sysnum_from_syspath(path)) < 0 ||
if (strncmp(path, FIDO_NFC_PREFIX, strlen(FIDO_NFC_PREFIX)) != 0) {
fido_log_debug("%s: bad prefix", __func__);
goto fail;
}
if ((idx = sysnum_from_syspath(path + strlen(FIDO_NFC_PREFIX))) < 0 ||
(ctx = nfc_new((uint32_t)idx)) == NULL) {
fido_log_debug("%s: nfc_new", __func__);
goto fail;

View File

@ -146,7 +146,7 @@ encode_uv_permission(uint8_t cmd)
static int
ctap20_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh,
const es256_pk_t *pk)
const es256_pk_t *pk, int *ms)
{
fido_blob_t f;
fido_blob_t *p = NULL;
@ -185,7 +185,7 @@ ctap20_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh,
}
if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
&f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
&f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -203,7 +203,7 @@ ctap20_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh,
static int
ctap21_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh,
const es256_pk_t *pk, uint8_t cmd, const char *rpid)
const es256_pk_t *pk, uint8_t cmd, const char *rpid, int *ms)
{
fido_blob_t f;
fido_blob_t *p = NULL;
@ -248,7 +248,7 @@ ctap21_uv_token_tx(fido_dev_t *dev, const char *pin, const fido_blob_t *ecdh,
}
if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
&f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
&f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -281,7 +281,7 @@ parse_uv_token(const cbor_item_t *key, const cbor_item_t *val, void *arg)
static int
uv_token_rx(fido_dev_t *dev, const fido_blob_t *ecdh, fido_blob_t *token,
int ms)
int *ms)
{
fido_blob_t *aes_token = NULL;
unsigned char reply[FIDO_MAXMSG];
@ -322,16 +322,16 @@ uv_token_rx(fido_dev_t *dev, const fido_blob_t *ecdh, fido_blob_t *token,
static int
uv_token_wait(fido_dev_t *dev, uint8_t cmd, const char *pin,
const fido_blob_t *ecdh, const es256_pk_t *pk, const char *rpid,
fido_blob_t *token, int ms)
fido_blob_t *token, int *ms)
{
int r;
if (ecdh == NULL || pk == NULL)
return (FIDO_ERR_INVALID_ARGUMENT);
if (fido_dev_supports_permissions(dev))
r = ctap21_uv_token_tx(dev, pin, ecdh, pk, cmd, rpid);
r = ctap21_uv_token_tx(dev, pin, ecdh, pk, cmd, rpid, ms);
else
r = ctap20_uv_token_tx(dev, pin, ecdh, pk);
r = ctap20_uv_token_tx(dev, pin, ecdh, pk, ms);
if (r != FIDO_OK)
return (r);
@ -341,13 +341,14 @@ uv_token_wait(fido_dev_t *dev, uint8_t cmd, const char *pin,
int
fido_dev_get_uv_token(fido_dev_t *dev, uint8_t cmd, const char *pin,
const fido_blob_t *ecdh, const es256_pk_t *pk, const char *rpid,
fido_blob_t *token)
fido_blob_t *token, int *ms)
{
return (uv_token_wait(dev, cmd, pin, ecdh, pk, rpid, token, -1));
return (uv_token_wait(dev, cmd, pin, ecdh, pk, rpid, token, ms));
}
static int
fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin)
fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin,
int *ms)
{
fido_blob_t f;
fido_blob_t *ppine = NULL;
@ -368,7 +369,7 @@ fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin)
goto fail;
}
if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
fido_log_debug("%s: fido_do_ecdh", __func__);
goto fail;
}
@ -397,7 +398,7 @@ fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin)
}
if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
&f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
&f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -418,7 +419,7 @@ fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin)
}
static int
fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin)
fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin, int *ms)
{
fido_blob_t f;
fido_blob_t *ppine = NULL;
@ -430,7 +431,7 @@ fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin)
memset(&f, 0, sizeof(f));
memset(argv, 0, sizeof(argv));
if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
fido_log_debug("%s: fido_do_ecdh", __func__);
goto fail;
}
@ -451,7 +452,7 @@ fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin)
}
if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
&f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
&f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -470,17 +471,18 @@ fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin)
static int
fido_dev_set_pin_wait(fido_dev_t *dev, const char *pin, const char *oldpin,
int ms)
int *ms)
{
int r;
if (oldpin != NULL) {
if ((r = fido_dev_change_pin_tx(dev, pin, oldpin)) != FIDO_OK) {
if ((r = fido_dev_change_pin_tx(dev, pin, oldpin,
ms)) != FIDO_OK) {
fido_log_debug("%s: fido_dev_change_pin_tx", __func__);
return (r);
}
} else {
if ((r = fido_dev_set_pin_tx(dev, pin)) != FIDO_OK) {
if ((r = fido_dev_set_pin_tx(dev, pin, ms)) != FIDO_OK) {
fido_log_debug("%s: fido_dev_set_pin_tx", __func__);
return (r);
}
@ -502,7 +504,9 @@ fido_dev_set_pin_wait(fido_dev_t *dev, const char *pin, const char *oldpin,
int
fido_dev_set_pin(fido_dev_t *dev, const char *pin, const char *oldpin)
{
return (fido_dev_set_pin_wait(dev, pin, oldpin, -1));
int ms = dev->timeout_ms;
return (fido_dev_set_pin_wait(dev, pin, oldpin, &ms));
}
static int
@ -542,7 +546,7 @@ parse_uv_retry_count(const cbor_item_t *key, const cbor_item_t *val, void *arg)
}
static int
fido_dev_get_retry_count_tx(fido_dev_t *dev, uint8_t subcmd)
fido_dev_get_retry_count_tx(fido_dev_t *dev, uint8_t subcmd, int *ms)
{
fido_blob_t f;
cbor_item_t *argv[2];
@ -558,7 +562,7 @@ fido_dev_get_retry_count_tx(fido_dev_t *dev, uint8_t subcmd)
}
if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, nitems(argv),
&f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
&f) < 0 || fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -573,7 +577,7 @@ fido_dev_get_retry_count_tx(fido_dev_t *dev, uint8_t subcmd)
}
static int
fido_dev_get_pin_retry_count_rx(fido_dev_t *dev, int *retries, int ms)
fido_dev_get_pin_retry_count_rx(fido_dev_t *dev, int *retries, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
@ -597,11 +601,11 @@ fido_dev_get_pin_retry_count_rx(fido_dev_t *dev, int *retries, int ms)
}
static int
fido_dev_get_pin_retry_count_wait(fido_dev_t *dev, int *retries, int ms)
fido_dev_get_pin_retry_count_wait(fido_dev_t *dev, int *retries, int *ms)
{
int r;
if ((r = fido_dev_get_retry_count_tx(dev, 1)) != FIDO_OK ||
if ((r = fido_dev_get_retry_count_tx(dev, 1, ms)) != FIDO_OK ||
(r = fido_dev_get_pin_retry_count_rx(dev, retries, ms)) != FIDO_OK)
return (r);
@ -611,11 +615,13 @@ fido_dev_get_pin_retry_count_wait(fido_dev_t *dev, int *retries, int ms)
int
fido_dev_get_retry_count(fido_dev_t *dev, int *retries)
{
return (fido_dev_get_pin_retry_count_wait(dev, retries, -1));
int ms = dev->timeout_ms;
return (fido_dev_get_pin_retry_count_wait(dev, retries, &ms));
}
static int
fido_dev_get_uv_retry_count_rx(fido_dev_t *dev, int *retries, int ms)
fido_dev_get_uv_retry_count_rx(fido_dev_t *dev, int *retries, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
@ -639,11 +645,11 @@ fido_dev_get_uv_retry_count_rx(fido_dev_t *dev, int *retries, int ms)
}
static int
fido_dev_get_uv_retry_count_wait(fido_dev_t *dev, int *retries, int ms)
fido_dev_get_uv_retry_count_wait(fido_dev_t *dev, int *retries, int *ms)
{
int r;
if ((r = fido_dev_get_retry_count_tx(dev, 7)) != FIDO_OK ||
if ((r = fido_dev_get_retry_count_tx(dev, 7, ms)) != FIDO_OK ||
(r = fido_dev_get_uv_retry_count_rx(dev, retries, ms)) != FIDO_OK)
return (r);
@ -653,13 +659,15 @@ fido_dev_get_uv_retry_count_wait(fido_dev_t *dev, int *retries, int ms)
int
fido_dev_get_uv_retry_count(fido_dev_t *dev, int *retries)
{
return (fido_dev_get_uv_retry_count_wait(dev, retries, -1));
int ms = dev->timeout_ms;
return (fido_dev_get_uv_retry_count_wait(dev, retries, &ms));
}
int
cbor_add_uv_params(fido_dev_t *dev, uint8_t cmd, const fido_blob_t *hmac_data,
const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin,
const char *rpid, cbor_item_t **auth, cbor_item_t **opt)
const char *rpid, cbor_item_t **auth, cbor_item_t **opt, int *ms)
{
fido_blob_t *token = NULL;
int r;
@ -670,7 +678,7 @@ cbor_add_uv_params(fido_dev_t *dev, uint8_t cmd, const fido_blob_t *hmac_data,
}
if ((r = fido_dev_get_uv_token(dev, cmd, pin, ecdh, pk, rpid,
token)) != FIDO_OK) {
token, ms)) != FIDO_OK) {
fido_log_debug("%s: fido_dev_get_uv_token", __func__);
goto fail;
}

View File

@ -7,11 +7,11 @@
#include "fido.h"
static int
fido_dev_reset_tx(fido_dev_t *dev)
fido_dev_reset_tx(fido_dev_t *dev, int *ms)
{
const unsigned char cbor[] = { CTAP_CBOR_RESET };
if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor)) < 0) {
if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor), ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
return (FIDO_ERR_TX);
}
@ -20,11 +20,11 @@ fido_dev_reset_tx(fido_dev_t *dev)
}
static int
fido_dev_reset_wait(fido_dev_t *dev, int ms)
fido_dev_reset_wait(fido_dev_t *dev, int *ms)
{
int r;
if ((r = fido_dev_reset_tx(dev)) != FIDO_OK ||
if ((r = fido_dev_reset_tx(dev, ms)) != FIDO_OK ||
(r = fido_rx_cbor_status(dev, ms)) != FIDO_OK)
return (r);
@ -39,5 +39,7 @@ fido_dev_reset_wait(fido_dev_t *dev, int ms)
int
fido_dev_reset(fido_dev_t *dev)
{
return (fido_dev_reset_wait(dev, -1));
int ms = dev->timeout_ms;
return (fido_dev_reset_wait(dev, &ms));
}

99
src/rs1.c Normal file
View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2021 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
#include <openssl/rsa.h>
#include <openssl/obj_mac.h>
#include "fido.h"
#if defined(LIBRESSL_VERSION_NUMBER)
static EVP_MD *
rs1_get_EVP_MD(void)
{
const EVP_MD *from;
EVP_MD *to = NULL;
if ((from = EVP_sha1()) != NULL && (to = malloc(sizeof(*to))) != NULL)
memcpy(to, from, sizeof(*to));
return (to);
}
static void
rs1_free_EVP_MD(EVP_MD *md)
{
freezero(md, sizeof(*md));
}
#elif OPENSSL_VERSION_NUMBER >= 0x30000000
static EVP_MD *
rs1_get_EVP_MD(void)
{
return (EVP_MD_fetch(NULL, "SHA-1", NULL));
}
static void
rs1_free_EVP_MD(EVP_MD *md)
{
EVP_MD_free(md);
}
#else
static EVP_MD *
rs1_get_EVP_MD(void)
{
const EVP_MD *md;
if ((md = EVP_sha1()) == NULL)
return (NULL);
return (EVP_MD_meth_dup(md));
}
static void
rs1_free_EVP_MD(EVP_MD *md)
{
EVP_MD_meth_free(md);
}
#endif /* LIBRESSL_VERSION_NUMBER */
int
rs1_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
const fido_blob_t *sig)
{
EVP_PKEY_CTX *pctx = NULL;
EVP_MD *md = NULL;
int ok = -1;
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
fido_log_debug("%s: EVP_PKEY_base_id", __func__);
goto fail;
}
if ((md = rs1_get_EVP_MD()) == NULL) {
fido_log_debug("%s: rs1_get_EVP_MD", __func__);
goto fail;
}
if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL ||
EVP_PKEY_verify_init(pctx) != 1 ||
EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) != 1 ||
EVP_PKEY_CTX_set_signature_md(pctx, md) != 1) {
fido_log_debug("%s: EVP_PKEY_CTX", __func__);
goto fail;
}
if (EVP_PKEY_verify(pctx, sig->ptr, sig->len, dgst->ptr,
dgst->len) != 1) {
fido_log_debug("%s: EVP_PKEY_verify", __func__);
goto fail;
}
ok = 0;
fail:
EVP_PKEY_CTX_free(pctx);
rs1_free_EVP_MD(md);
return (ok);
}

View File

@ -1,5 +1,5 @@
/*
* 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.
*/
@ -11,31 +11,54 @@
#include "fido.h"
#include "fido/rs256.h"
#if OPENSSL_VERSION_NUMBER < 0x10100000L
static int
RSA_bits(const RSA *r)
#if defined(LIBRESSL_VERSION_NUMBER)
static EVP_MD *
rs256_get_EVP_MD(void)
{
return (BN_num_bits(r->n));
}
const EVP_MD *from;
EVP_MD *to = NULL;
static int
RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
{
r->n = n;
r->e = e;
r->d = d;
if ((from = EVP_sha256()) != NULL && (to = malloc(sizeof(*to))) != NULL)
memcpy(to, from, sizeof(*to));
return (1);
return (to);
}
static void
RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
rs256_free_EVP_MD(EVP_MD *md)
{
*n = r->n;
*e = r->e;
*d = r->d;
freezero(md, sizeof(*md));
}
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
#elif OPENSSL_VERSION_NUMBER >= 0x30000000
static EVP_MD *
rs256_get_EVP_MD(void)
{
return (EVP_MD_fetch(NULL, "SHA2-256", NULL));
}
static void
rs256_free_EVP_MD(EVP_MD *md)
{
EVP_MD_free(md);
}
#else
static EVP_MD *
rs256_get_EVP_MD(void)
{
const EVP_MD *md;
if ((md = EVP_sha256()) == NULL)
return (NULL);
return (EVP_MD_meth_dup(md));
}
static void
rs256_free_EVP_MD(EVP_MD *md)
{
EVP_MD_meth_free(md);
}
#endif /* LIBRESSL_VERSION_NUMBER */
static int
decode_bignum(const cbor_item_t *item, void *ptr, size_t len)
@ -198,3 +221,75 @@ rs256_pk_from_RSA(rs256_pk_t *pk, const RSA *rsa)
return (FIDO_OK);
}
int
rs256_pk_from_EVP_PKEY(rs256_pk_t *pk, const EVP_PKEY *pkey)
{
RSA *rsa;
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA ||
(rsa = EVP_PKEY_get0(pkey)) == NULL)
return (FIDO_ERR_INVALID_ARGUMENT);
return (rs256_pk_from_RSA(pk, rsa));
}
int
rs256_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
const fido_blob_t *sig)
{
EVP_PKEY_CTX *pctx = NULL;
EVP_MD *md = NULL;
int ok = -1;
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
fido_log_debug("%s: EVP_PKEY_base_id", __func__);
goto fail;
}
if ((md = rs256_get_EVP_MD()) == NULL) {
fido_log_debug("%s: rs256_get_EVP_MD", __func__);
goto fail;
}
if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL ||
EVP_PKEY_verify_init(pctx) != 1 ||
EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) != 1 ||
EVP_PKEY_CTX_set_signature_md(pctx, md) != 1) {
fido_log_debug("%s: EVP_PKEY_CTX", __func__);
goto fail;
}
if (EVP_PKEY_verify(pctx, sig->ptr, sig->len, dgst->ptr,
dgst->len) != 1) {
fido_log_debug("%s: EVP_PKEY_verify", __func__);
goto fail;
}
ok = 0;
fail:
EVP_PKEY_CTX_free(pctx);
rs256_free_EVP_MD(md);
return (ok);
}
int
rs256_pk_verify_sig(const fido_blob_t *dgst, const rs256_pk_t *pk,
const fido_blob_t *sig)
{
EVP_PKEY *pkey;
int ok = -1;
if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL ||
rs256_verify_sig(dgst, pkey, sig) < 0) {
fido_log_debug("%s: rs256_verify_sig", __func__);
goto fail;
}
ok = 0;
fail:
EVP_PKEY_free(pkey);
return (ok);
}

74
src/time.c Normal file
View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2021 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
#include <errno.h>
#include "fido.h"
static int
timespec_to_ms(const struct timespec *ts)
{
int64_t x, y;
if (ts->tv_sec < 0 || ts->tv_nsec < 0 ||
ts->tv_nsec >= 1000000000LL)
return -1;
if ((uint64_t)ts->tv_sec >= INT64_MAX / 1000LL)
return -1;
x = ts->tv_sec * 1000LL;
y = ts->tv_nsec / 1000000LL;
if (INT64_MAX - x < y || x + y > INT_MAX)
return -1;
return (int)(x + y);
}
int
fido_time_now(struct timespec *ts_now)
{
if (clock_gettime(CLOCK_MONOTONIC, ts_now) != 0) {
fido_log_error(errno, "%s: clock_gettime", __func__);
return -1;
}
return 0;
}
int
fido_time_delta(const struct timespec *ts_start, int *ms_remain)
{
struct timespec ts_end, ts_delta;
int ms;
if (*ms_remain < 0)
return 0;
if (clock_gettime(CLOCK_MONOTONIC, &ts_end) != 0) {
fido_log_error(errno, "%s: clock_gettime", __func__);
return -1;
}
if (timespeccmp(&ts_end, ts_start, <)) {
fido_log_debug("%s: timespeccmp", __func__);
return -1;
}
timespecsub(&ts_end, ts_start, &ts_delta);
if ((ms = timespec_to_ms(&ts_delta)) < 0) {
fido_log_debug("%s: timespec_to_ms", __func__);
return -1;
}
if (ms > *ms_remain)
ms = *ms_remain;
*ms_remain -= ms;
return 0;
}

286
src/tpm.c Normal file
View File

@ -0,0 +1,286 @@
/*
* Copyright (c) 2021 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
/*
* Trusted Platform Module (TPM) 2.0 attestation support. Documentation
* references are relative to revision 01.38 of the TPM 2.0 specification.
*/
#include <openssl/sha.h>
#include "packed.h"
#include "fido.h"
/* Part 1, 4.89: TPM_GENERATED_VALUE */
#define TPM_MAGIC 0xff544347
/* Part 2, 6.3: TPM_ALG_ID */
#define TPM_ALG_RSA 0x0001
#define TPM_ALG_SHA256 0x000b
#define TPM_ALG_NULL 0x0010
/* Part 2, 6.9: TPM_ST_ATTEST_CERTIFY */
#define TPM_ST_CERTIFY 0x8017
/* Part 2, 8.3: TPMA_OBJECT */
#define TPMA_RESERVED 0xfff8f309 /* reserved bits; must be zero */
#define TPMA_FIXED 0x00000002 /* object has fixed hierarchy */
#define TPMA_CLEAR 0x00000004 /* object persists */
#define TPMA_FIXED_P 0x00000010 /* object has fixed parent */
#define TPMA_SENSITIVE 0x00000020 /* data originates within tpm */
#define TPMA_SIGN 0x00020000 /* object may sign */
/* Part 2, 10.4.2: TPM2B_DIGEST */
PACKED_TYPE(tpm_sha256_digest_t,
struct tpm_sha256_digest {
uint16_t size; /* sizeof(body) */
uint8_t body[32];
})
/* Part 2, 10.4.3: TPM2B_DATA */
PACKED_TYPE(tpm_sha1_data_t,
struct tpm_sha1_data {
uint16_t size; /* sizeof(body */
uint8_t body[20];
})
/* Part 2, 10.5.3: TPM2B_NAME */
PACKED_TYPE(tpm_sha256_name_t,
struct tpm_sha256_name {
uint16_t size; /* sizeof(alg) + sizeof(body) */
uint16_t alg; /* TPM_ALG_SHA256 */
uint8_t body[32];
})
/* Part 2, 10.11.1: TPMS_CLOCK_INFO */
PACKED_TYPE(tpm_clock_info_t,
struct tpm_clock_info {
uint64_t timestamp_ms;
uint32_t reset_count; /* obfuscated by tpm */
uint32_t restart_count; /* obfuscated by tpm */
uint8_t safe; /* 1 if timestamp_ms is current */
})
/* Part 2, 10.12.8 TPMS_ATTEST */
PACKED_TYPE(tpm_sha1_attest_t,
struct tpm_sha1_attest {
uint32_t magic; /* TPM_MAGIC */
uint16_t type; /* TPM_ST_ATTEST_CERTIFY */
tpm_sha256_name_t signer; /* full tpm path of signing key */
tpm_sha1_data_t data; /* signed sha1 */
tpm_clock_info_t clock;
uint64_t fwversion; /* obfuscated by tpm */
tpm_sha256_name_t name; /* sha256 of tpm_rsa2048_pubarea_t */
tpm_sha256_name_t qual_name; /* full tpm path of attested key */
})
/* Part 2, 11.2.4.5: TPM2B_PUBLIC_KEY_RSA */
PACKED_TYPE(tpm_rsa2048_key_t,
struct tpm_rsa2048_key {
uint16_t size; /* sizeof(body) */
uint8_t body[256];
})
/* Part 2, 12.2.3.5: TPMS_RSA_PARMS */
PACKED_TYPE(tpm_rsa2048_param_t,
struct tpm_rsa2048_param {
uint16_t symmetric; /* TPM_ALG_NULL */
uint16_t scheme; /* TPM_ALG_NULL */
uint16_t keybits; /* 2048 */
uint32_t exponent; /* zero (meaning 2^16 + 1) */
})
/* Part 2, 12.2.4: TPMT_PUBLIC */
PACKED_TYPE(tpm_rsa2048_pubarea_t,
struct tpm_rsa2048_pubarea {
uint16_t alg; /* TPM_ALG_RSA */
uint16_t hash; /* TPM_ALG_SHA256 */
uint32_t attr;
tpm_sha256_digest_t policy; /* must be present? */
tpm_rsa2048_param_t param;
tpm_rsa2048_key_t key;
})
static int
get_signed_sha1(tpm_sha1_data_t *dgst, const fido_blob_t *authdata,
const fido_blob_t *clientdata)
{
const EVP_MD *md = NULL;
EVP_MD_CTX *ctx = NULL;
int ok = -1;
if ((dgst->size = sizeof(dgst->body)) != SHA_DIGEST_LENGTH ||
(md = EVP_sha1()) == NULL ||
(ctx = EVP_MD_CTX_new()) == NULL ||
EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
EVP_DigestUpdate(ctx, authdata->ptr, authdata->len) != 1 ||
EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 ||
EVP_DigestFinal_ex(ctx, dgst->body, NULL) != 1) {
fido_log_debug("%s: sha1", __func__);
goto fail;
}
ok = 0;
fail:
EVP_MD_CTX_free(ctx);
return (ok);
}
static int
get_signed_name(tpm_sha256_name_t *name, const fido_blob_t *pubarea)
{
name->alg = TPM_ALG_SHA256;
name->size = sizeof(name->alg) + sizeof(name->body);
if (sizeof(name->body) != SHA256_DIGEST_LENGTH ||
SHA256(pubarea->ptr, pubarea->len, name->body) != name->body) {
fido_log_debug("%s: sha256", __func__);
return -1;
}
return 0;
}
static void
bswap_rsa2048_pubarea(tpm_rsa2048_pubarea_t *x)
{
x->alg = htobe16(x->alg);
x->hash = htobe16(x->hash);
x->attr = htobe32(x->attr);
x->policy.size = htobe16(x->policy.size);
x->param.symmetric = htobe16(x->param.symmetric);
x->param.scheme = htobe16(x->param.scheme);
x->param.keybits = htobe16(x->param.keybits);
x->key.size = htobe16(x->key.size);
}
static void
bswap_sha1_certinfo(tpm_sha1_attest_t *x)
{
x->magic = htobe32(x->magic);
x->type = htobe16(x->type);
x->signer.size = htobe16(x->signer.size);
x->data.size = htobe16(x->data.size);
x->name.alg = htobe16(x->name.alg);
x->name.size = htobe16(x->name.size);
}
static int
check_rsa2048_pubarea(const fido_blob_t *buf, const rs256_pk_t *pk)
{
const tpm_rsa2048_pubarea_t *actual;
tpm_rsa2048_pubarea_t expected;
int ok;
if (buf->len != sizeof(*actual)) {
fido_log_debug("%s: buf->len=%zu", __func__, buf->len);
return -1;
}
actual = (const void *)buf->ptr;
memset(&expected, 0, sizeof(expected));
expected.alg = TPM_ALG_RSA;
expected.hash = TPM_ALG_SHA256;
expected.attr = be32toh(actual->attr);
expected.attr &= ~(TPMA_RESERVED|TPMA_CLEAR);
expected.attr |= (TPMA_FIXED|TPMA_FIXED_P|TPMA_SENSITIVE|TPMA_SIGN);
expected.policy = actual->policy;
expected.policy.size = sizeof(expected.policy.body);
expected.param.symmetric = TPM_ALG_NULL;
expected.param.scheme = TPM_ALG_NULL;
expected.param.keybits = 2048;
expected.param.exponent = 0; /* meaning 2^16+1 */
expected.key.size = sizeof(expected.key.body);
memcpy(&expected.key.body, &pk->n, sizeof(expected.key.body));
bswap_rsa2048_pubarea(&expected);
ok = timingsafe_bcmp(&expected, actual, sizeof(expected));
explicit_bzero(&expected, sizeof(expected));
return ok != 0 ? -1 : 0;
}
static int
check_sha1_certinfo(const fido_blob_t *buf, const fido_blob_t *clientdata_hash,
const fido_blob_t *authdata_raw, const fido_blob_t *pubarea)
{
const tpm_sha1_attest_t *actual;
tpm_sha1_attest_t expected;
tpm_sha1_data_t signed_data;
tpm_sha256_name_t signed_name;
int ok = -1;
memset(&signed_data, 0, sizeof(signed_data));
memset(&signed_name, 0, sizeof(signed_name));
if (get_signed_sha1(&signed_data, authdata_raw, clientdata_hash) < 0 ||
get_signed_name(&signed_name, pubarea) < 0) {
fido_log_debug("%s: get_signed_sha1/name", __func__);
goto fail;
}
if (buf->len != sizeof(*actual)) {
fido_log_debug("%s: buf->len=%zu", __func__, buf->len);
goto fail;
}
actual = (const void *)buf->ptr;
memset(&expected, 0, sizeof(expected));
expected.magic = TPM_MAGIC;
expected.type = TPM_ST_CERTIFY;
expected.signer = actual->signer;
expected.signer.size = sizeof(expected.signer.alg) +
sizeof(expected.signer.body);
expected.data = signed_data;
expected.clock = actual->clock;
expected.clock.safe = 1;
expected.fwversion = actual->fwversion;
expected.name = signed_name;
expected.qual_name = actual->qual_name;
bswap_sha1_certinfo(&expected);
ok = timingsafe_bcmp(&expected, actual, sizeof(expected));
fail:
explicit_bzero(&expected, sizeof(expected));
explicit_bzero(&signed_data, sizeof(signed_data));
explicit_bzero(&signed_name, sizeof(signed_name));
return ok != 0 ? -1 : 0;
}
int
fido_get_signed_hash_tpm(fido_blob_t *dgst, const fido_blob_t *clientdata_hash,
const fido_blob_t *authdata_raw, const fido_attstmt_t *attstmt,
const fido_attcred_t *attcred)
{
const fido_blob_t *pubarea = &attstmt->pubarea;
const fido_blob_t *certinfo = &attstmt->certinfo;
if (attstmt->alg != COSE_RS1 || attcred->type != COSE_RS256) {
fido_log_debug("%s: unsupported alg %d, type %d", __func__,
attstmt->alg, attcred->type);
return -1;
}
if (check_rsa2048_pubarea(pubarea, &attcred->pubkey.rs256) < 0) {
fido_log_debug("%s: check_rsa2048_pubarea", __func__);
return -1;
}
if (check_sha1_certinfo(certinfo, clientdata_hash, authdata_raw,
pubarea) < 0) {
fido_log_debug("%s: check_sha1_certinfo", __func__);
return -1;
}
if (dgst->len < SHA_DIGEST_LENGTH ||
SHA1(certinfo->ptr, certinfo->len, dgst->ptr) != dgst->ptr) {
fido_log_debug("%s: sha1", __func__);
return -1;
}
dgst->len = SHA_DIGEST_LENGTH;
return 0;
}

76
src/types.c Normal file
View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2018-2021 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
#include "fido.h"
void
fido_str_array_free(fido_str_array_t *sa)
{
for (size_t i = 0; i < sa->len; i++)
free(sa->ptr[i]);
free(sa->ptr);
sa->ptr = NULL;
sa->len = 0;
}
void
fido_opt_array_free(fido_opt_array_t *oa)
{
for (size_t i = 0; i < oa->len; i++)
free(oa->name[i]);
free(oa->name);
free(oa->value);
oa->name = NULL;
oa->value = NULL;
}
void
fido_byte_array_free(fido_byte_array_t *ba)
{
free(ba->ptr);
ba->ptr = NULL;
ba->len = 0;
}
void
fido_algo_free(fido_algo_t *a)
{
free(a->type);
a->type = NULL;
a->cose = 0;
}
void
fido_algo_array_free(fido_algo_array_t *aa)
{
for (size_t i = 0; i < aa->len; i++)
fido_algo_free(&aa->ptr[i]);
free(aa->ptr);
aa->ptr = NULL;
aa->len = 0;
}
int
fido_str_array_pack(fido_str_array_t *sa, const char * const *v, size_t n)
{
if ((sa->ptr = calloc(n, sizeof(char *))) == NULL) {
fido_log_debug("%s: calloc", __func__);
return -1;
}
for (size_t i = 0; i < n; i++) {
if ((sa->ptr[i] = strdup(v[i])) == NULL) {
fido_log_debug("%s: strdup", __func__);
return -1;
}
sa->len++;
}
return 0;
}

158
src/u2f.c
View File

@ -1,5 +1,5 @@
/*
* 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.
*/
@ -10,10 +10,13 @@
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <errno.h>
#include "fido.h"
#include "fido/es256.h"
#define U2F_PACE_MS (100)
#if defined(_MSC_VER)
static int
usleep(unsigned int usec)
@ -24,6 +27,28 @@ usleep(unsigned int usec)
}
#endif
static int
delay_ms(unsigned int ms, int *ms_remain)
{
if (*ms_remain > -1 && (unsigned int)*ms_remain < ms)
ms = (unsigned int)*ms_remain;
if (ms > UINT_MAX / 1000) {
fido_log_debug("%s: ms=%u", __func__, ms);
return (-1);
}
if (usleep(ms * 1000) < 0) {
fido_log_error(errno, "%s: usleep", __func__);
return (-1);
}
if (*ms_remain > -1)
*ms_remain -= (int)ms;
return (0);
}
static int
sig_get(fido_blob_t *sig, const unsigned char **buf, size_t *len)
{
@ -115,7 +140,7 @@ authdata_fake(const char *rp_id, uint8_t flags, uint32_t sigcount,
/* TODO: use u2f_get_touch_begin & u2f_get_touch_status instead */
static int
send_dummy_register(fido_dev_t *dev, int ms)
send_dummy_register(fido_dev_t *dev, int *ms)
{
iso7816_apdu_t *apdu = NULL;
unsigned char challenge[SHA256_DIGEST_LENGTH];
@ -123,10 +148,6 @@ send_dummy_register(fido_dev_t *dev, int ms)
unsigned char reply[FIDO_MAXMSG];
int r;
#ifdef FIDO_FUZZ
ms = 0; /* XXX */
#endif
/* dummy challenge & application */
memset(&challenge, 0xff, sizeof(challenge));
memset(&application, 0xff, sizeof(application));
@ -142,7 +163,7 @@ send_dummy_register(fido_dev_t *dev, int ms)
do {
if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
iso7816_len(apdu)) < 0) {
iso7816_len(apdu), ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -152,8 +173,8 @@ send_dummy_register(fido_dev_t *dev, int ms)
r = FIDO_ERR_RX;
goto fail;
}
if (usleep((unsigned)(ms == -1 ? 100 : ms) * 1000) < 0) {
fido_log_debug("%s: usleep", __func__);
if (delay_ms(U2F_PACE_MS, ms) != 0) {
fido_log_debug("%s: delay_ms", __func__);
r = FIDO_ERR_RX;
goto fail;
}
@ -168,7 +189,7 @@ send_dummy_register(fido_dev_t *dev, int ms)
static int
key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id,
int *found, int ms)
int *found, int *ms)
{
iso7816_apdu_t *apdu = NULL;
unsigned char challenge[SHA256_DIGEST_LENGTH];
@ -208,7 +229,7 @@ key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id,
}
if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
iso7816_len(apdu)) < 0) {
iso7816_len(apdu), ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -274,7 +295,7 @@ parse_auth_reply(fido_blob_t *sig, fido_blob_t *ad, const char *rp_id,
static int
do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id,
const fido_blob_t *key_id, fido_blob_t *sig, fido_blob_t *ad, int ms)
const fido_blob_t *key_id, fido_blob_t *sig, fido_blob_t *ad, int *ms)
{
iso7816_apdu_t *apdu = NULL;
unsigned char rp_id_hash[SHA256_DIGEST_LENGTH];
@ -284,7 +305,7 @@ do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id,
int r;
#ifdef FIDO_FUZZ
ms = 0; /* XXX */
*ms = 0; /* XXX */
#endif
if (cdh->len != SHA256_DIGEST_LENGTH || key_id->len > UINT8_MAX ||
@ -317,7 +338,7 @@ do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id,
do {
if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
iso7816_len(apdu)) < 0) {
iso7816_len(apdu), ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -328,8 +349,8 @@ do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id,
r = FIDO_ERR_RX;
goto fail;
}
if (usleep((unsigned)(ms == -1 ? 100 : ms) * 1000) < 0) {
fido_log_debug("%s: usleep", __func__);
if (delay_ms(U2F_PACE_MS, ms) != 0) {
fido_log_debug("%s: delay_ms", __func__);
r = FIDO_ERR_RX;
goto fail;
}
@ -390,6 +411,71 @@ cbor_blob_from_ec_point(const uint8_t *ec_point, size_t ec_point_len,
return (ok);
}
static int
encode_cred_attstmt(int cose_alg, const fido_blob_t *x5c,
const fido_blob_t *sig, fido_blob_t *out)
{
cbor_item_t *item = NULL;
cbor_item_t *x5c_cbor = NULL;
const uint8_t alg_cbor = (uint8_t)(-cose_alg - 1);
struct cbor_pair kv[3];
size_t alloc_len;
int ok = -1;
memset(&kv, 0, sizeof(kv));
memset(out, 0, sizeof(*out));
if ((item = cbor_new_definite_map(3)) == NULL) {
fido_log_debug("%s: cbor_new_definite_map", __func__);
goto fail;
}
if ((kv[0].key = cbor_build_string("alg")) == NULL ||
(kv[0].value = cbor_build_negint8(alg_cbor)) == NULL ||
!cbor_map_add(item, kv[0])) {
fido_log_debug("%s: alg", __func__);
goto fail;
}
if ((kv[1].key = cbor_build_string("sig")) == NULL ||
(kv[1].value = fido_blob_encode(sig)) == NULL ||
!cbor_map_add(item, kv[1])) {
fido_log_debug("%s: sig", __func__);
goto fail;
}
if ((kv[2].key = cbor_build_string("x5c")) == NULL ||
(kv[2].value = cbor_new_definite_array(1)) == NULL ||
(x5c_cbor = fido_blob_encode(x5c)) == NULL ||
!cbor_array_push(kv[2].value, x5c_cbor) ||
!cbor_map_add(item, kv[2])) {
fido_log_debug("%s: x5c", __func__);
goto fail;
}
if ((out->len = cbor_serialize_alloc(item, &out->ptr,
&alloc_len)) == 0) {
fido_log_debug("%s: cbor_serialize_alloc", __func__);
goto fail;
}
ok = 0;
fail:
if (item != NULL)
cbor_decref(&item);
if (x5c_cbor != NULL)
cbor_decref(&x5c_cbor);
for (size_t i = 0; i < nitems(kv); i++) {
if (kv[i].key)
cbor_decref(&kv[i].key);
if (kv[i].value)
cbor_decref(&kv[i].value);
}
return (ok);
}
static int
encode_cred_authdata(const char *rp_id, const uint8_t *kh, uint8_t kh_len,
const uint8_t *pubkey, size_t pubkey_len, fido_blob_t *out)
@ -476,6 +562,7 @@ parse_register_reply(fido_cred_t *cred, const unsigned char *reply, size_t len)
fido_blob_t x5c;
fido_blob_t sig;
fido_blob_t ad;
fido_blob_t stmt;
uint8_t dummy;
uint8_t pubkey[65];
uint8_t kh_len = 0;
@ -485,6 +572,7 @@ parse_register_reply(fido_cred_t *cred, const unsigned char *reply, size_t len)
memset(&x5c, 0, sizeof(x5c));
memset(&sig, 0, sizeof(sig));
memset(&ad, 0, sizeof(ad));
memset(&stmt, 0, sizeof(stmt));
r = FIDO_ERR_RX;
/* status word */
@ -518,6 +606,12 @@ parse_register_reply(fido_cred_t *cred, const unsigned char *reply, size_t len)
goto fail;
}
/* attstmt */
if (encode_cred_attstmt(COSE_ES256, &x5c, &sig, &stmt) < 0) {
fido_log_debug("%s: encode_cred_attstmt", __func__);
goto fail;
}
/* authdata */
if (encode_cred_authdata(cred->rp.id, kh, kh_len, pubkey,
sizeof(pubkey), &ad) < 0) {
@ -527,8 +621,7 @@ parse_register_reply(fido_cred_t *cred, const unsigned char *reply, size_t len)
if (fido_cred_set_fmt(cred, "fido-u2f") != FIDO_OK ||
fido_cred_set_authdata(cred, ad.ptr, ad.len) != FIDO_OK ||
fido_cred_set_x509(cred, x5c.ptr, x5c.len) != FIDO_OK ||
fido_cred_set_sig(cred, sig.ptr, sig.len) != FIDO_OK) {
fido_cred_set_attstmt(cred, stmt.ptr, stmt.len) != FIDO_OK) {
fido_log_debug("%s: fido_cred_set", __func__);
r = FIDO_ERR_INTERNAL;
goto fail;
@ -540,12 +633,13 @@ parse_register_reply(fido_cred_t *cred, const unsigned char *reply, size_t len)
fido_blob_reset(&x5c);
fido_blob_reset(&sig);
fido_blob_reset(&ad);
fido_blob_reset(&stmt);
return (r);
}
int
u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms)
u2f_register(fido_dev_t *dev, fido_cred_t *cred, int *ms)
{
iso7816_apdu_t *apdu = NULL;
unsigned char rp_id_hash[SHA256_DIGEST_LENGTH];
@ -554,10 +648,6 @@ u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms)
int found;
int r;
#ifdef FIDO_FUZZ
ms = 0; /* XXX */
#endif
if (cred->rk == FIDO_OPT_TRUE || cred->uv == FIDO_OPT_TRUE) {
fido_log_debug("%s: rk=%d, uv=%d", __func__, cred->rk,
cred->uv);
@ -606,7 +696,7 @@ u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms)
do {
if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
iso7816_len(apdu)) < 0) {
iso7816_len(apdu), ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -617,8 +707,8 @@ u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms)
r = FIDO_ERR_RX;
goto fail;
}
if (usleep((unsigned)(ms == -1 ? 100 : ms) * 1000) < 0) {
fido_log_debug("%s: usleep", __func__);
if (delay_ms(U2F_PACE_MS, ms) != 0) {
fido_log_debug("%s: delay_ms", __func__);
r = FIDO_ERR_RX;
goto fail;
}
@ -637,7 +727,7 @@ u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms)
static int
u2f_authenticate_single(fido_dev_t *dev, const fido_blob_t *key_id,
fido_assert_t *fa, size_t idx, int ms)
fido_assert_t *fa, size_t idx, int *ms)
{
fido_blob_t sig;
fido_blob_t ad;
@ -692,7 +782,7 @@ u2f_authenticate_single(fido_dev_t *dev, const fido_blob_t *key_id,
}
int
u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms)
u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int *ms)
{
size_t nfound = 0;
size_t nauth_ok = 0;
@ -739,7 +829,7 @@ u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms)
}
int
u2f_get_touch_begin(fido_dev_t *dev)
u2f_get_touch_begin(fido_dev_t *dev, int *ms)
{
iso7816_apdu_t *apdu = NULL;
const char *clientdata = FIDO_DUMMY_CLIENTDATA;
@ -769,12 +859,12 @@ u2f_get_touch_begin(fido_dev_t *dev)
}
if (dev->attr.flags & FIDO_CAP_WINK) {
fido_tx(dev, CTAP_CMD_WINK, NULL, 0);
fido_rx(dev, CTAP_CMD_WINK, &reply, sizeof(reply), 200);
fido_tx(dev, CTAP_CMD_WINK, NULL, 0, ms);
fido_rx(dev, CTAP_CMD_WINK, &reply, sizeof(reply), ms);
}
if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
iso7816_len(apdu)) < 0) {
iso7816_len(apdu), ms) < 0) {
fido_log_debug("%s: fido_tx", __func__);
r = FIDO_ERR_TX;
goto fail;
@ -788,7 +878,7 @@ u2f_get_touch_begin(fido_dev_t *dev)
}
int
u2f_get_touch_status(fido_dev_t *dev, int *touched, int ms)
u2f_get_touch_status(fido_dev_t *dev, int *touched, int *ms)
{
unsigned char reply[FIDO_MAXMSG];
int reply_len;
@ -802,7 +892,7 @@ u2f_get_touch_status(fido_dev_t *dev, int *touched, int ms)
switch ((reply[reply_len - 2] << 8) | reply[reply_len - 1]) {
case SW_CONDITIONS_NOT_SATISFIED:
if ((r = u2f_get_touch_begin(dev)) != FIDO_OK) {
if ((r = u2f_get_touch_begin(dev, ms)) != FIDO_OK) {
fido_log_debug("%s: u2f_get_touch_begin", __func__);
return (r);
}

839
src/webauthn.h Normal file
View File

@ -0,0 +1,839 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#ifndef __WEBAUTHN_H_
#define __WEBAUTHN_H_
#pragma once
#include <winapifamily.h>
#pragma region Desktop Family or OneCore Family
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
#ifdef __cplusplus
extern "C" {
#endif
#ifndef WINAPI
#define WINAPI __stdcall
#endif
#ifndef INITGUID
#define INITGUID
#include <guiddef.h>
#undef INITGUID
#else
#include <guiddef.h>
#endif
//+------------------------------------------------------------------------------------------
// API Version Information.
// Caller should check for WebAuthNGetApiVersionNumber to check the presence of relevant APIs
// and features for their usage.
//-------------------------------------------------------------------------------------------
#define WEBAUTHN_API_VERSION_1 1
// WEBAUTHN_API_VERSION_1 : Baseline Version
// Data Structures and their sub versions:
// - WEBAUTHN_RP_ENTITY_INFORMATION : 1
// - WEBAUTHN_USER_ENTITY_INFORMATION : 1
// - WEBAUTHN_CLIENT_DATA : 1
// - WEBAUTHN_COSE_CREDENTIAL_PARAMETER : 1
// - WEBAUTHN_COSE_CREDENTIAL_PARAMETERS : Not Applicable
// - WEBAUTHN_CREDENTIAL : 1
// - WEBAUTHN_CREDENTIALS : Not Applicable
// - WEBAUTHN_CREDENTIAL_EX : 1
// - WEBAUTHN_CREDENTIAL_LIST : Not Applicable
// - WEBAUTHN_EXTENSION : Not Applicable
// - WEBAUTHN_EXTENSIONS : Not Applicable
// - WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS : 3
// - WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS : 4
// - WEBAUTHN_COMMON_ATTESTATION : 1
// - WEBAUTHN_CREDENTIAL_ATTESTATION : 3
// - WEBAUTHN_ASSERTION : 1
// Extensions:
// - WEBAUTHN_EXTENSIONS_IDENTIFIER_HMAC_SECRET
// APIs:
// - WebAuthNGetApiVersionNumber
// - WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable
// - WebAuthNAuthenticatorMakeCredential
// - WebAuthNAuthenticatorGetAssertion
// - WebAuthNFreeCredentialAttestation
// - WebAuthNFreeAssertion
// - WebAuthNGetCancellationId
// - WebAuthNCancelCurrentOperation
// - WebAuthNGetErrorName
// - WebAuthNGetW3CExceptionDOMError
#define WEBAUTHN_API_VERSION_2 2
// WEBAUTHN_API_VERSION_2 : Delta From WEBAUTHN_API_VERSION_1
// Added Extensions:
// - WEBAUTHN_EXTENSIONS_IDENTIFIER_CRED_PROTECT
//
#define WEBAUTHN_API_VERSION_3 3
// WEBAUTHN_API_VERSION_3 : Delta From WEBAUTHN_API_VERSION_2
// Data Structures and their sub versions:
// - WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS : 4
// - WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS : 5
// - WEBAUTHN_CREDENTIAL_ATTESTATION : 4
// - WEBAUTHN_ASSERTION : 2
// Added Extensions:
// - WEBAUTHN_EXTENSIONS_IDENTIFIER_CRED_BLOB
// - WEBAUTHN_EXTENSIONS_IDENTIFIER_MIN_PIN_LENGTH
//
#define WEBAUTHN_API_CURRENT_VERSION WEBAUTHN_API_VERSION_3
//+------------------------------------------------------------------------------------------
// Information about an RP Entity
//-------------------------------------------------------------------------------------------
#define WEBAUTHN_RP_ENTITY_INFORMATION_CURRENT_VERSION 1
typedef struct _WEBAUTHN_RP_ENTITY_INFORMATION {
// Version of this structure, to allow for modifications in the future.
// This field is required and should be set to CURRENT_VERSION above.
DWORD dwVersion;
// Identifier for the RP. This field is required.
PCWSTR pwszId;
// Contains the friendly name of the Relying Party, such as "Acme Corporation", "Widgets Inc" or "Awesome Site".
// This field is required.
PCWSTR pwszName;
// Optional URL pointing to RP's logo.
PCWSTR pwszIcon;
} WEBAUTHN_RP_ENTITY_INFORMATION, *PWEBAUTHN_RP_ENTITY_INFORMATION;
typedef const WEBAUTHN_RP_ENTITY_INFORMATION *PCWEBAUTHN_RP_ENTITY_INFORMATION;
//+------------------------------------------------------------------------------------------
// Information about an User Entity
//-------------------------------------------------------------------------------------------
#define WEBAUTHN_MAX_USER_ID_LENGTH 64
#define WEBAUTHN_USER_ENTITY_INFORMATION_CURRENT_VERSION 1
typedef struct _WEBAUTHN_USER_ENTITY_INFORMATION {
// Version of this structure, to allow for modifications in the future.
// This field is required and should be set to CURRENT_VERSION above.
DWORD dwVersion;
// Identifier for the User. This field is required.
DWORD cbId;
_Field_size_bytes_(cbId)
PBYTE pbId;
// Contains a detailed name for this account, such as "john.p.smith@example.com".
PCWSTR pwszName;
// Optional URL that can be used to retrieve an image containing the user's current avatar,
// or a data URI that contains the image data.
PCWSTR pwszIcon;
// For User: Contains the friendly name associated with the user account by the Relying Party, such as "John P. Smith".
PCWSTR pwszDisplayName;
} WEBAUTHN_USER_ENTITY_INFORMATION, *PWEBAUTHN_USER_ENTITY_INFORMATION;
typedef const WEBAUTHN_USER_ENTITY_INFORMATION *PCWEBAUTHN_USER_ENTITY_INFORMATION;
//+------------------------------------------------------------------------------------------
// Information about client data.
//-------------------------------------------------------------------------------------------
#define WEBAUTHN_HASH_ALGORITHM_SHA_256 L"SHA-256"
#define WEBAUTHN_HASH_ALGORITHM_SHA_384 L"SHA-384"
#define WEBAUTHN_HASH_ALGORITHM_SHA_512 L"SHA-512"
#define WEBAUTHN_CLIENT_DATA_CURRENT_VERSION 1
typedef struct _WEBAUTHN_CLIENT_DATA {
// Version of this structure, to allow for modifications in the future.
// This field is required and should be set to CURRENT_VERSION above.
DWORD dwVersion;
// Size of the pbClientDataJSON field.
DWORD cbClientDataJSON;
// UTF-8 encoded JSON serialization of the client data.
_Field_size_bytes_(cbClientDataJSON)
PBYTE pbClientDataJSON;
// Hash algorithm ID used to hash the pbClientDataJSON field.
LPCWSTR pwszHashAlgId;
} WEBAUTHN_CLIENT_DATA, *PWEBAUTHN_CLIENT_DATA;
typedef const WEBAUTHN_CLIENT_DATA *PCWEBAUTHN_CLIENT_DATA;
//+------------------------------------------------------------------------------------------
// Information about credential parameters.
//-------------------------------------------------------------------------------------------
#define WEBAUTHN_CREDENTIAL_TYPE_PUBLIC_KEY L"public-key"
#define WEBAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256 -7
#define WEBAUTHN_COSE_ALGORITHM_ECDSA_P384_WITH_SHA384 -35
#define WEBAUTHN_COSE_ALGORITHM_ECDSA_P521_WITH_SHA512 -36
#define WEBAUTHN_COSE_ALGORITHM_RSASSA_PKCS1_V1_5_WITH_SHA256 -257
#define WEBAUTHN_COSE_ALGORITHM_RSASSA_PKCS1_V1_5_WITH_SHA384 -258
#define WEBAUTHN_COSE_ALGORITHM_RSASSA_PKCS1_V1_5_WITH_SHA512 -259
#define WEBAUTHN_COSE_ALGORITHM_RSA_PSS_WITH_SHA256 -37
#define WEBAUTHN_COSE_ALGORITHM_RSA_PSS_WITH_SHA384 -38
#define WEBAUTHN_COSE_ALGORITHM_RSA_PSS_WITH_SHA512 -39
#define WEBAUTHN_COSE_CREDENTIAL_PARAMETER_CURRENT_VERSION 1
typedef struct _WEBAUTHN_COSE_CREDENTIAL_PARAMETER {
// Version of this structure, to allow for modifications in the future.
DWORD dwVersion;
// Well-known credential type specifying a credential to create.
LPCWSTR pwszCredentialType;
// Well-known COSE algorithm specifying the algorithm to use for the credential.
LONG lAlg;
} WEBAUTHN_COSE_CREDENTIAL_PARAMETER, *PWEBAUTHN_COSE_CREDENTIAL_PARAMETER;
typedef const WEBAUTHN_COSE_CREDENTIAL_PARAMETER *PCWEBAUTHN_COSE_CREDENTIAL_PARAMETER;
typedef struct _WEBAUTHN_COSE_CREDENTIAL_PARAMETERS {
DWORD cCredentialParameters;
_Field_size_(cCredentialParameters)
PWEBAUTHN_COSE_CREDENTIAL_PARAMETER pCredentialParameters;
} WEBAUTHN_COSE_CREDENTIAL_PARAMETERS, *PWEBAUTHN_COSE_CREDENTIAL_PARAMETERS;
typedef const WEBAUTHN_COSE_CREDENTIAL_PARAMETERS *PCWEBAUTHN_COSE_CREDENTIAL_PARAMETERS;
//+------------------------------------------------------------------------------------------
// Information about credential.
//-------------------------------------------------------------------------------------------
#define WEBAUTHN_CREDENTIAL_CURRENT_VERSION 1
typedef struct _WEBAUTHN_CREDENTIAL {
// Version of this structure, to allow for modifications in the future.
DWORD dwVersion;
// Size of pbID.
DWORD cbId;
// Unique ID for this particular credential.
_Field_size_bytes_(cbId)
PBYTE pbId;
// Well-known credential type specifying what this particular credential is.
LPCWSTR pwszCredentialType;
} WEBAUTHN_CREDENTIAL, *PWEBAUTHN_CREDENTIAL;
typedef const WEBAUTHN_CREDENTIAL *PCWEBAUTHN_CREDENTIAL;
typedef struct _WEBAUTHN_CREDENTIALS {
DWORD cCredentials;
_Field_size_(cCredentials)
PWEBAUTHN_CREDENTIAL pCredentials;
} WEBAUTHN_CREDENTIALS, *PWEBAUTHN_CREDENTIALS;
typedef const WEBAUTHN_CREDENTIALS *PCWEBAUTHN_CREDENTIALS;
//+------------------------------------------------------------------------------------------
// Information about credential with extra information, such as, dwTransports
//-------------------------------------------------------------------------------------------
#define WEBAUTHN_CTAP_TRANSPORT_USB 0x00000001
#define WEBAUTHN_CTAP_TRANSPORT_NFC 0x00000002
#define WEBAUTHN_CTAP_TRANSPORT_BLE 0x00000004
#define WEBAUTHN_CTAP_TRANSPORT_TEST 0x00000008
#define WEBAUTHN_CTAP_TRANSPORT_INTERNAL 0x00000010
#define WEBAUTHN_CTAP_TRANSPORT_FLAGS_MASK 0x0000001F
#define WEBAUTHN_CREDENTIAL_EX_CURRENT_VERSION 1
typedef struct _WEBAUTHN_CREDENTIAL_EX {
// Version of this structure, to allow for modifications in the future.
DWORD dwVersion;
// Size of pbID.
DWORD cbId;
// Unique ID for this particular credential.
_Field_size_bytes_(cbId)
PBYTE pbId;
// Well-known credential type specifying what this particular credential is.
LPCWSTR pwszCredentialType;
// Transports. 0 implies no transport restrictions.
DWORD dwTransports;
} WEBAUTHN_CREDENTIAL_EX, *PWEBAUTHN_CREDENTIAL_EX;
typedef const WEBAUTHN_CREDENTIAL_EX *PCWEBAUTHN_CREDENTIAL_EX;
//+------------------------------------------------------------------------------------------
// Information about credential list with extra information
//-------------------------------------------------------------------------------------------
typedef struct _WEBAUTHN_CREDENTIAL_LIST {
DWORD cCredentials;
_Field_size_(cCredentials)
PWEBAUTHN_CREDENTIAL_EX *ppCredentials;
} WEBAUTHN_CREDENTIAL_LIST, *PWEBAUTHN_CREDENTIAL_LIST;
typedef const WEBAUTHN_CREDENTIAL_LIST *PCWEBAUTHN_CREDENTIAL_LIST;
//+------------------------------------------------------------------------------------------
// Hmac-Secret extension
//-------------------------------------------------------------------------------------------
#define WEBAUTHN_EXTENSIONS_IDENTIFIER_HMAC_SECRET L"hmac-secret"
// Below type definitions is for WEBAUTHN_EXTENSIONS_IDENTIFIER_HMAC_SECRET
// MakeCredential Input Type: BOOL.
// - pvExtension must point to a BOOL with the value TRUE.
// - cbExtension must contain the sizeof(BOOL).
// MakeCredential Output Type: BOOL.
// - pvExtension will point to a BOOL with the value TRUE if credential
// was successfully created with HMAC_SECRET.
// - cbExtension will contain the sizeof(BOOL).
// GetAssertion Input Type: Not Supported
// GetAssertion Output Type: Not Supported
//+------------------------------------------------------------------------------------------
// credProtect extension
//-------------------------------------------------------------------------------------------
#define WEBAUTHN_USER_VERIFICATION_ANY 0
#define WEBAUTHN_USER_VERIFICATION_OPTIONAL 1
#define WEBAUTHN_USER_VERIFICATION_OPTIONAL_WITH_CREDENTIAL_ID_LIST 2
#define WEBAUTHN_USER_VERIFICATION_REQUIRED 3
typedef struct _WEBAUTHN_CRED_PROTECT_EXTENSION_IN {
// One of the above WEBAUTHN_USER_VERIFICATION_* values
DWORD dwCredProtect;
// Set the following to TRUE to require authenticator support for the credProtect extension
BOOL bRequireCredProtect;
} WEBAUTHN_CRED_PROTECT_EXTENSION_IN, *PWEBAUTHN_CRED_PROTECT_EXTENSION_IN;
typedef const WEBAUTHN_CRED_PROTECT_EXTENSION_IN *PCWEBAUTHN_CRED_PROTECT_EXTENSION_IN;
#define WEBAUTHN_EXTENSIONS_IDENTIFIER_CRED_PROTECT L"credProtect"
// Below type definitions is for WEBAUTHN_EXTENSIONS_IDENTIFIER_CRED_PROTECT
// MakeCredential Input Type: WEBAUTHN_CRED_PROTECT_EXTENSION_IN.
// - pvExtension must point to a WEBAUTHN_CRED_PROTECT_EXTENSION_IN struct
// - cbExtension will contain the sizeof(WEBAUTHN_CRED_PROTECT_EXTENSION_IN).
// MakeCredential Output Type: DWORD.
// - pvExtension will point to a DWORD with one of the above WEBAUTHN_USER_VERIFICATION_* values
// if credential was successfully created with CRED_PROTECT.
// - cbExtension will contain the sizeof(DWORD).
// GetAssertion Input Type: Not Supported
// GetAssertion Output Type: Not Supported
//+------------------------------------------------------------------------------------------
// credBlob extension
//-------------------------------------------------------------------------------------------
typedef struct _WEBAUTHN_CRED_BLOB_EXTENSION {
// Size of pbCredBlob.
DWORD cbCredBlob;
_Field_size_bytes_(cbCredBlob)
PBYTE pbCredBlob;
} WEBAUTHN_CRED_BLOB_EXTENSION, *PWEBAUTHN_CRED_BLOB_EXTENSION;
typedef const WEBAUTHN_CRED_BLOB_EXTENSION *PCWEBAUTHN_CRED_BLOB_EXTENSION;
#define WEBAUTHN_EXTENSIONS_IDENTIFIER_CRED_BLOB L"credBlob"
// Below type definitions is for WEBAUTHN_EXTENSIONS_IDENTIFIER_CRED_BLOB
// MakeCredential Input Type: WEBAUTHN_CRED_BLOB_EXTENSION.
// - pvExtension must point to a WEBAUTHN_CRED_BLOB_EXTENSION struct
// - cbExtension must contain the sizeof(WEBAUTHN_CRED_BLOB_EXTENSION).
// MakeCredential Output Type: BOOL.
// - pvExtension will point to a BOOL with the value TRUE if credBlob was successfully created
// - cbExtension will contain the sizeof(BOOL).
// GetAssertion Input Type: BOOL.
// - pvExtension must point to a BOOL with the value TRUE to request the credBlob.
// - cbExtension must contain the sizeof(BOOL).
// GetAssertion Output Type: WEBAUTHN_CRED_BLOB_EXTENSION.
// - pvExtension will point to a WEBAUTHN_CRED_BLOB_EXTENSION struct if the authenticator
// returns the credBlob in the signed extensions
// - cbExtension will contain the sizeof(WEBAUTHN_CRED_BLOB_EXTENSION).
//+------------------------------------------------------------------------------------------
// minPinLength extension
//-------------------------------------------------------------------------------------------
#define WEBAUTHN_EXTENSIONS_IDENTIFIER_MIN_PIN_LENGTH L"minPinLength"
// Below type definitions is for WEBAUTHN_EXTENSIONS_IDENTIFIER_MIN_PIN_LENGTH
// MakeCredential Input Type: BOOL.
// - pvExtension must point to a BOOL with the value TRUE to request the minPinLength.
// - cbExtension must contain the sizeof(BOOL).
// MakeCredential Output Type: DWORD.
// - pvExtension will point to a DWORD with the minimum pin length if returned by the authenticator
// - cbExtension will contain the sizeof(DWORD).
// GetAssertion Input Type: Not Supported
// GetAssertion Output Type: Not Supported
//+------------------------------------------------------------------------------------------
// Information about Extensions.
//-------------------------------------------------------------------------------------------
typedef struct _WEBAUTHN_EXTENSION {
LPCWSTR pwszExtensionIdentifier;
DWORD cbExtension;
PVOID pvExtension;
} WEBAUTHN_EXTENSION, *PWEBAUTHN_EXTENSION;
typedef const WEBAUTHN_EXTENSION *PCWEBAUTHN_EXTENSION;
typedef struct _WEBAUTHN_EXTENSIONS {
DWORD cExtensions;
_Field_size_(cExtensions)
PWEBAUTHN_EXTENSION pExtensions;
} WEBAUTHN_EXTENSIONS, *PWEBAUTHN_EXTENSIONS;
typedef const WEBAUTHN_EXTENSIONS *PCWEBAUTHN_EXTENSIONS;
//+------------------------------------------------------------------------------------------
// Options.
//-------------------------------------------------------------------------------------------
#define WEBAUTHN_AUTHENTICATOR_ATTACHMENT_ANY 0
#define WEBAUTHN_AUTHENTICATOR_ATTACHMENT_PLATFORM 1
#define WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM 2
#define WEBAUTHN_AUTHENTICATOR_ATTACHMENT_CROSS_PLATFORM_U2F_V2 3
#define WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY 0
#define WEBAUTHN_USER_VERIFICATION_REQUIREMENT_REQUIRED 1
#define WEBAUTHN_USER_VERIFICATION_REQUIREMENT_PREFERRED 2
#define WEBAUTHN_USER_VERIFICATION_REQUIREMENT_DISCOURAGED 3
#define WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_ANY 0
#define WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_NONE 1
#define WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_INDIRECT 2
#define WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT 3
#define WEBAUTHN_ENTERPRISE_ATTESTATION_NONE 0
#define WEBAUTHN_ENTERPRISE_ATTESTATION_VENDOR_FACILITATED 1
#define WEBAUTHN_ENTERPRISE_ATTESTATION_PLATFORM_MANAGED 2
#define WEBAUTHN_LARGE_BLOB_SUPPORT_NONE 0
#define WEBAUTHN_LARGE_BLOB_SUPPORT_REQUIRED 1
#define WEBAUTHN_LARGE_BLOB_SUPPORT_PREFERRED 2
#define WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_1 1
#define WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_2 2
#define WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_3 3
#define WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_4 4
#define WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_CURRENT_VERSION WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_4
typedef struct _WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS {
// Version of this structure, to allow for modifications in the future.
DWORD dwVersion;
// Time that the operation is expected to complete within.
// This is used as guidance, and can be overridden by the platform.
DWORD dwTimeoutMilliseconds;
// Credentials used for exclusion.
WEBAUTHN_CREDENTIALS CredentialList;
// Optional extensions to parse when performing the operation.
WEBAUTHN_EXTENSIONS Extensions;
// Optional. Platform vs Cross-Platform Authenticators.
DWORD dwAuthenticatorAttachment;
// Optional. Require key to be resident or not. Defaulting to FALSE.
BOOL bRequireResidentKey;
// User Verification Requirement.
DWORD dwUserVerificationRequirement;
// Attestation Conveyance Preference.
DWORD dwAttestationConveyancePreference;
// Reserved for future Use
DWORD dwFlags;
//
// The following fields have been added in WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_2
//
// Cancellation Id - Optional - See WebAuthNGetCancellationId
GUID *pCancellationId;
//
// The following fields have been added in WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_3
//
// Exclude Credential List. If present, "CredentialList" will be ignored.
PWEBAUTHN_CREDENTIAL_LIST pExcludeCredentialList;
//
// The following fields have been added in WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_4
//
// Enterprise Attestation
DWORD dwEnterpriseAttestation;
// Large Blob Support: none, required or preferred
//
// NTE_INVALID_PARAMETER when large blob required or preferred and
// both bRequireResidentKey and bPreferResidentKey are set to FALSE.
DWORD dwLargeBlobSupport;
// Optional. Prefer key to be resident. Defaulting to FALSE. When TRUE,
// overrides the above bRequireResidentKey.
BOOL bPreferResidentKey;
} WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS, *PWEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS;
typedef const WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS *PCWEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS;
#define WEBAUTHN_CRED_LARGE_BLOB_OPERATION_NONE 0
#define WEBAUTHN_CRED_LARGE_BLOB_OPERATION_GET 1
#define WEBAUTHN_CRED_LARGE_BLOB_OPERATION_SET 2
#define WEBAUTHN_CRED_LARGE_BLOB_OPERATION_DELETE 3
#define WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_1 1
#define WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_2 2
#define WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_3 3
#define WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_4 4
#define WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_5 5
#define WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_CURRENT_VERSION WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_5
typedef struct _WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS {
// Version of this structure, to allow for modifications in the future.
DWORD dwVersion;
// Time that the operation is expected to complete within.
// This is used as guidance, and can be overridden by the platform.
DWORD dwTimeoutMilliseconds;
// Allowed Credentials List.
WEBAUTHN_CREDENTIALS CredentialList;
// Optional extensions to parse when performing the operation.
WEBAUTHN_EXTENSIONS Extensions;
// Optional. Platform vs Cross-Platform Authenticators.
DWORD dwAuthenticatorAttachment;
// User Verification Requirement.
DWORD dwUserVerificationRequirement;
// Reserved for future Use
DWORD dwFlags;
//
// The following fields have been added in WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_2
//
// Optional identifier for the U2F AppId. Converted to UTF8 before being hashed. Not lower cased.
PCWSTR pwszU2fAppId;
// If the following is non-NULL, then, set to TRUE if the above pwszU2fAppid was used instead of
// PCWSTR pwszRpId;
BOOL *pbU2fAppId;
//
// The following fields have been added in WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_3
//
// Cancellation Id - Optional - See WebAuthNGetCancellationId
GUID *pCancellationId;
//
// The following fields have been added in WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_4
//
// Allow Credential List. If present, "CredentialList" will be ignored.
PWEBAUTHN_CREDENTIAL_LIST pAllowCredentialList;
//
// The following fields have been added in WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_5
//
DWORD dwCredLargeBlobOperation;
// Size of pbCredLargeBlob
DWORD cbCredLargeBlob;
_Field_size_bytes_(cbCredLargeBlob)
PBYTE pbCredLargeBlob;
} WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS, *PWEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS;
typedef const WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS *PCWEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS;
//+------------------------------------------------------------------------------------------
// Attestation Info.
//
//-------------------------------------------------------------------------------------------
#define WEBAUTHN_ATTESTATION_DECODE_NONE 0
#define WEBAUTHN_ATTESTATION_DECODE_COMMON 1
// WEBAUTHN_ATTESTATION_DECODE_COMMON supports format types
// L"packed"
// L"fido-u2f"
#define WEBAUTHN_ATTESTATION_VER_TPM_2_0 L"2.0"
typedef struct _WEBAUTHN_X5C {
// Length of X.509 encoded certificate
DWORD cbData;
// X.509 encoded certificate bytes
_Field_size_bytes_(cbData)
PBYTE pbData;
} WEBAUTHN_X5C, *PWEBAUTHN_X5C;
// Supports either Self or Full Basic Attestation
// Note, new fields will be added to the following data structure to
// support additional attestation format types, such as, TPM.
// When fields are added, the dwVersion will be incremented.
//
// Therefore, your code must make the following check:
// "if (dwVersion >= WEBAUTHN_COMMON_ATTESTATION_CURRENT_VERSION)"
#define WEBAUTHN_COMMON_ATTESTATION_CURRENT_VERSION 1
typedef struct _WEBAUTHN_COMMON_ATTESTATION {
// Version of this structure, to allow for modifications in the future.
DWORD dwVersion;
// Hash and Padding Algorithm
//
// The following won't be set for "fido-u2f" which assumes "ES256".
PCWSTR pwszAlg;
LONG lAlg; // COSE algorithm
// Signature that was generated for this attestation.
DWORD cbSignature;
_Field_size_bytes_(cbSignature)
PBYTE pbSignature;
// Following is set for Full Basic Attestation. If not, set then, this is Self Attestation.
// Array of X.509 DER encoded certificates. The first certificate is the signer, leaf certificate.
DWORD cX5c;
_Field_size_(cX5c)
PWEBAUTHN_X5C pX5c;
// Following are also set for tpm
PCWSTR pwszVer; // L"2.0"
DWORD cbCertInfo;
_Field_size_bytes_(cbCertInfo)
PBYTE pbCertInfo;
DWORD cbPubArea;
_Field_size_bytes_(cbPubArea)
PBYTE pbPubArea;
} WEBAUTHN_COMMON_ATTESTATION, *PWEBAUTHN_COMMON_ATTESTATION;
typedef const WEBAUTHN_COMMON_ATTESTATION *PCWEBAUTHN_COMMON_ATTESTATION;
#define WEBAUTHN_ATTESTATION_TYPE_PACKED L"packed"
#define WEBAUTHN_ATTESTATION_TYPE_U2F L"fido-u2f"
#define WEBAUTHN_ATTESTATION_TYPE_TPM L"tpm"
#define WEBAUTHN_ATTESTATION_TYPE_NONE L"none"
#define WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_1 1
#define WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_2 2
#define WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_3 3
#define WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_4 4
#define WEBAUTHN_CREDENTIAL_ATTESTATION_CURRENT_VERSION WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_4
typedef struct _WEBAUTHN_CREDENTIAL_ATTESTATION {
// Version of this structure, to allow for modifications in the future.
DWORD dwVersion;
// Attestation format type
PCWSTR pwszFormatType;
// Size of cbAuthenticatorData.
DWORD cbAuthenticatorData;
// Authenticator data that was created for this credential.
_Field_size_bytes_(cbAuthenticatorData)
PBYTE pbAuthenticatorData;
// Size of CBOR encoded attestation information
//0 => encoded as CBOR null value.
DWORD cbAttestation;
//Encoded CBOR attestation information
_Field_size_bytes_(cbAttestation)
PBYTE pbAttestation;
DWORD dwAttestationDecodeType;
// Following depends on the dwAttestationDecodeType
// WEBAUTHN_ATTESTATION_DECODE_NONE
// NULL - not able to decode the CBOR attestation information
// WEBAUTHN_ATTESTATION_DECODE_COMMON
// PWEBAUTHN_COMMON_ATTESTATION;
PVOID pvAttestationDecode;
// The CBOR encoded Attestation Object to be returned to the RP.
DWORD cbAttestationObject;
_Field_size_bytes_(cbAttestationObject)
PBYTE pbAttestationObject;
// The CredentialId bytes extracted from the Authenticator Data.
// Used by Edge to return to the RP.
DWORD cbCredentialId;
_Field_size_bytes_(cbCredentialId)
PBYTE pbCredentialId;
//
// Following fields have been added in WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_2
//
WEBAUTHN_EXTENSIONS Extensions;
//
// Following fields have been added in WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_3
//
// One of the WEBAUTHN_CTAP_TRANSPORT_* bits will be set corresponding to
// the transport that was used.
DWORD dwUsedTransport;
//
// Following fields have been added in WEBAUTHN_CREDENTIAL_ATTESTATION_VERSION_4
//
BOOL bEpAtt;
BOOL bLargeBlobSupported;
BOOL bResidentKey;
} WEBAUTHN_CREDENTIAL_ATTESTATION, *PWEBAUTHN_CREDENTIAL_ATTESTATION;
typedef const WEBAUTHN_CREDENTIAL_ATTESTATION *PCWEBAUTHN_CREDENTIAL_ATTESTATION;
//+------------------------------------------------------------------------------------------
// authenticatorGetAssertion output.
//-------------------------------------------------------------------------------------------
#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_NONE 0
#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_SUCCESS 1
#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_NOT_SUPPORTED 2
#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_INVALID_DATA 3
#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_INVALID_PARAMETER 4
#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_NOT_FOUND 5
#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_MULTIPLE_CREDENTIALS 6
#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_LACK_OF_SPACE 7
#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_PLATFORM_ERROR 8
#define WEBAUTHN_CRED_LARGE_BLOB_STATUS_AUTHENTICATOR_ERROR 9
#define WEBAUTHN_ASSERTION_VERSION_1 1
#define WEBAUTHN_ASSERTION_VERSION_2 2
#define WEBAUTHN_ASSERTION_CURRENT_VERSION WEBAUTHN_ASSERTION_VERSION_2
typedef struct _WEBAUTHN_ASSERTION {
// Version of this structure, to allow for modifications in the future.
DWORD dwVersion;
// Size of cbAuthenticatorData.
DWORD cbAuthenticatorData;
// Authenticator data that was created for this assertion.
_Field_size_bytes_(cbAuthenticatorData)
PBYTE pbAuthenticatorData;
// Size of pbSignature.
DWORD cbSignature;
// Signature that was generated for this assertion.
_Field_size_bytes_(cbSignature)
PBYTE pbSignature;
// Credential that was used for this assertion.
WEBAUTHN_CREDENTIAL Credential;
// Size of User Id
DWORD cbUserId;
// UserId
_Field_size_bytes_(cbUserId)
PBYTE pbUserId;
//
// Following fields have been added in WEBAUTHN_ASSERTION_VERSION_2
//
WEBAUTHN_EXTENSIONS Extensions;
// Size of pbCredLargeBlob
DWORD cbCredLargeBlob;
_Field_size_bytes_(cbCredLargeBlob)
PBYTE pbCredLargeBlob;
DWORD dwCredLargeBlobStatus;
} WEBAUTHN_ASSERTION, *PWEBAUTHN_ASSERTION;
typedef const WEBAUTHN_ASSERTION *PCWEBAUTHN_ASSERTION;
//+------------------------------------------------------------------------------------------
// APIs.
//-------------------------------------------------------------------------------------------
DWORD
WINAPI
WebAuthNGetApiVersionNumber();
HRESULT
WINAPI
WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable(
_Out_ BOOL *pbIsUserVerifyingPlatformAuthenticatorAvailable);
HRESULT
WINAPI
WebAuthNAuthenticatorMakeCredential(
_In_ HWND hWnd,
_In_ PCWEBAUTHN_RP_ENTITY_INFORMATION pRpInformation,
_In_ PCWEBAUTHN_USER_ENTITY_INFORMATION pUserInformation,
_In_ PCWEBAUTHN_COSE_CREDENTIAL_PARAMETERS pPubKeyCredParams,
_In_ PCWEBAUTHN_CLIENT_DATA pWebAuthNClientData,
_In_opt_ PCWEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS pWebAuthNMakeCredentialOptions,
_Outptr_result_maybenull_ PWEBAUTHN_CREDENTIAL_ATTESTATION *ppWebAuthNCredentialAttestation);
HRESULT
WINAPI
WebAuthNAuthenticatorGetAssertion(
_In_ HWND hWnd,
_In_ LPCWSTR pwszRpId,
_In_ PCWEBAUTHN_CLIENT_DATA pWebAuthNClientData,
_In_opt_ PCWEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS pWebAuthNGetAssertionOptions,
_Outptr_result_maybenull_ PWEBAUTHN_ASSERTION *ppWebAuthNAssertion);
void
WINAPI
WebAuthNFreeCredentialAttestation(
_In_opt_ PWEBAUTHN_CREDENTIAL_ATTESTATION pWebAuthNCredentialAttestation);
void
WINAPI
WebAuthNFreeAssertion(
_In_ PWEBAUTHN_ASSERTION pWebAuthNAssertion);
HRESULT
WINAPI
WebAuthNGetCancellationId(
_Out_ GUID* pCancellationId);
HRESULT
WINAPI
WebAuthNCancelCurrentOperation(
_In_ const GUID* pCancellationId);
//
// Returns the following Error Names:
// L"Success" - S_OK
// L"InvalidStateError" - NTE_EXISTS
// L"ConstraintError" - HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED),
// NTE_NOT_SUPPORTED,
// NTE_TOKEN_KEYSET_STORAGE_FULL
// L"NotSupportedError" - NTE_INVALID_PARAMETER
// L"NotAllowedError" - NTE_DEVICE_NOT_FOUND,
// NTE_NOT_FOUND,
// HRESULT_FROM_WIN32(ERROR_CANCELLED),
// NTE_USER_CANCELLED,
// HRESULT_FROM_WIN32(ERROR_TIMEOUT)
// L"UnknownError" - All other hr values
//
PCWSTR
WINAPI
WebAuthNGetErrorName(
_In_ HRESULT hr);
HRESULT
WINAPI
WebAuthNGetW3CExceptionDOMError(
_In_ HRESULT hr);
#ifdef __cplusplus
} // Balance extern "C" above
#endif
#endif // WINAPI_FAMILY_PARTITION
#pragma endregion
#endif // __WEBAUTHN_H_

View File

@ -8,9 +8,9 @@
#include <stdlib.h>
#include <windows.h>
#include <webauthn.h>
#include "fido.h"
#include "webauthn.h"
#define MAXCHARS 128
#define MAXCREDS 128
@ -40,6 +40,87 @@ struct winhello_cred {
wchar_t *display_name;
};
static TLS BOOL webauthn_loaded;
static TLS HMODULE webauthn_handle;
static TLS DWORD (*webauthn_get_api_version)(void);
static TLS PCWSTR (*webauthn_strerr)(HRESULT);
static TLS HRESULT (*webauthn_get_assert)(HWND, LPCWSTR,
PCWEBAUTHN_CLIENT_DATA,
PCWEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS,
PWEBAUTHN_ASSERTION *);
static TLS HRESULT (*webauthn_make_cred)(HWND,
PCWEBAUTHN_RP_ENTITY_INFORMATION,
PCWEBAUTHN_USER_ENTITY_INFORMATION,
PCWEBAUTHN_COSE_CREDENTIAL_PARAMETERS,
PCWEBAUTHN_CLIENT_DATA,
PCWEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS,
PWEBAUTHN_CREDENTIAL_ATTESTATION *);
static TLS void (*webauthn_free_assert)(PWEBAUTHN_ASSERTION);
static TLS void (*webauthn_free_attest)(PWEBAUTHN_CREDENTIAL_ATTESTATION);
static int
webauthn_load(void)
{
if (webauthn_loaded || webauthn_handle != NULL) {
fido_log_debug("%s: already loaded", __func__);
return -1;
}
if ((webauthn_handle = LoadLibrary("webauthn.dll")) == NULL) {
fido_log_debug("%s: LoadLibrary", __func__);
return -1;
}
if ((webauthn_get_api_version = (void *)GetProcAddress(webauthn_handle,
"WebAuthNGetApiVersionNumber")) == NULL) {
fido_log_debug("%s: WebAuthNGetApiVersionNumber", __func__);
goto fail;
}
if ((webauthn_strerr = (void *)GetProcAddress(webauthn_handle,
"WebAuthNGetErrorName")) == NULL) {
fido_log_debug("%s: WebAuthNGetErrorName", __func__);
goto fail;
}
if ((webauthn_get_assert = (void *)GetProcAddress(webauthn_handle,
"WebAuthNAuthenticatorGetAssertion")) == NULL) {
fido_log_debug("%s: WebAuthNAuthenticatorGetAssertion",
__func__);
goto fail;
}
if ((webauthn_make_cred = (void *)GetProcAddress(webauthn_handle,
"WebAuthNAuthenticatorMakeCredential")) == NULL) {
fido_log_debug("%s: WebAuthNAuthenticatorMakeCredential",
__func__);
goto fail;
}
if ((webauthn_free_assert = (void *)GetProcAddress(webauthn_handle,
"WebAuthNFreeAssertion")) == NULL) {
fido_log_debug("%s: WebAuthNFreeAssertion", __func__);
goto fail;
}
if ((webauthn_free_attest = (void *)GetProcAddress(webauthn_handle,
"WebAuthNFreeCredentialAttestation")) == NULL) {
fido_log_debug("%s: WebAuthNFreeCredentialAttestation",
__func__);
goto fail;
}
webauthn_loaded = true;
return 0;
fail:
fido_log_debug("%s: GetProcAddress", __func__);
webauthn_get_api_version = NULL;
webauthn_strerr = NULL;
webauthn_get_assert = NULL;
webauthn_make_cred = NULL;
webauthn_free_assert = NULL;
webauthn_free_attest = NULL;
FreeLibrary(webauthn_handle);
webauthn_handle = NULL;
return -1;
}
static wchar_t *
to_utf16(const char *utf8)
{
@ -97,24 +178,6 @@ to_utf8(const wchar_t *utf16)
return utf8;
}
static int
to_fido_str_array(fido_str_array_t *sa, const char **v, size_t n)
{
if ((sa->ptr = calloc(n, sizeof(char *))) == NULL) {
fido_log_debug("%s: calloc", __func__);
return -1;
}
for (size_t i = 0; i < n; i++) {
if ((sa->ptr[i] = strdup(v[i])) == NULL) {
fido_log_debug("%s: strdup", __func__);
return -1;
}
sa->len++;
}
return 0;
}
static int
to_fido(HRESULT hr)
{
@ -210,7 +273,7 @@ set_uv(DWORD *out, fido_opt_t uv, const char *pin)
static int
pack_rp(wchar_t **id, wchar_t **name, WEBAUTHN_RP_ENTITY_INFORMATION *out,
fido_rp_t *in)
const fido_rp_t *in)
{
/* keep non-const copies of pwsz* for free() */
out->dwVersion = WEBAUTHN_RP_ENTITY_INFORMATION_CURRENT_VERSION;
@ -227,7 +290,7 @@ pack_rp(wchar_t **id, wchar_t **name, WEBAUTHN_RP_ENTITY_INFORMATION *out,
static int
pack_user(wchar_t **name, wchar_t **icon, wchar_t **display_name,
WEBAUTHN_USER_ENTITY_INFORMATION *out, fido_user_t *in)
WEBAUTHN_USER_ENTITY_INFORMATION *out, const fido_user_t *in)
{
if (in->id.ptr == NULL || in->id.len > ULONG_MAX) {
fido_log_debug("%s: id", __func__);
@ -287,7 +350,7 @@ pack_cose(WEBAUTHN_COSE_CREDENTIAL_PARAMETER *alg,
}
static int
pack_cred_ext(WEBAUTHN_EXTENSIONS *out, fido_cred_ext_t *in)
pack_cred_ext(WEBAUTHN_EXTENSIONS *out, const fido_cred_ext_t *in)
{
WEBAUTHN_EXTENSION *e;
WEBAUTHN_CRED_PROTECT_EXTENSION_IN *p;
@ -342,94 +405,7 @@ pack_cred_ext(WEBAUTHN_EXTENSIONS *out, fido_cred_ext_t *in)
}
static int
unpack_fmt(fido_cred_t *cred, WEBAUTHN_CREDENTIAL_ATTESTATION *att)
{
char *fmt;
int r;
if ((fmt = to_utf8(att->pwszFormatType)) == NULL) {
fido_log_debug("%s: fmt", __func__);
return -1;
}
r = fido_cred_set_fmt(cred, fmt);
free(fmt);
fmt = NULL;
if (r != FIDO_OK) {
fido_log_debug("%s: fido_cred_set_fmt: %s", __func__,
fido_strerr(r));
return -1;
}
return 0;
}
static int
unpack_cred_authdata(fido_cred_t *cred, WEBAUTHN_CREDENTIAL_ATTESTATION *att)
{
int r;
if (att->cbAuthenticatorData > SIZE_MAX) {
fido_log_debug("%s: cbAuthenticatorData", __func__);
return -1;
}
if ((r = fido_cred_set_authdata_raw(cred, att->pbAuthenticatorData,
(size_t)att->cbAuthenticatorData)) != FIDO_OK) {
fido_log_debug("%s: fido_cred_set_authdata_raw: %s", __func__,
fido_strerr(r));
return -1;
}
return 0;
}
static int
unpack_cred_sig(fido_cred_t *cred, WEBAUTHN_COMMON_ATTESTATION *attr)
{
int r;
if (attr->cbSignature > SIZE_MAX) {
fido_log_debug("%s: cbSignature", __func__);
return -1;
}
if ((r = fido_cred_set_sig(cred, attr->pbSignature,
(size_t)attr->cbSignature)) != FIDO_OK) {
fido_log_debug("%s: fido_cred_set_sig: %s", __func__,
fido_strerr(r));
return -1;
}
return 0;
}
static int
unpack_x5c(fido_cred_t *cred, WEBAUTHN_COMMON_ATTESTATION *attr)
{
int r;
fido_log_debug("%s: %u cert(s)", __func__, attr->cX5c);
if (attr->cX5c == 0)
return 0; /* self-attestation */
if (attr->lAlg != WEBAUTHN_COSE_ALGORITHM_ECDSA_P256_WITH_SHA256) {
fido_log_debug("%s: lAlg %d", __func__, attr->lAlg);
return -1;
}
if (attr->pX5c[0].cbData > SIZE_MAX) {
fido_log_debug("%s: cbData", __func__);
return -1;
}
if ((r = fido_cred_set_x509(cred, attr->pX5c[0].pbData,
(size_t)attr->pX5c[0].cbData)) != FIDO_OK) {
fido_log_debug("%s: fido_cred_set_x509: %s", __func__,
fido_strerr(r));
return -1;
}
return 0;
}
static int
unpack_assert_authdata(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
unpack_assert_authdata(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa)
{
int r;
@ -448,7 +424,7 @@ unpack_assert_authdata(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
}
static int
unpack_assert_sig(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
unpack_assert_sig(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa)
{
int r;
@ -467,7 +443,7 @@ unpack_assert_sig(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
}
static int
unpack_cred_id(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
unpack_cred_id(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa)
{
if (wa->Credential.cbId > SIZE_MAX) {
fido_log_debug("%s: Credential.cbId", __func__);
@ -483,7 +459,7 @@ unpack_cred_id(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
}
static int
unpack_user_id(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
unpack_user_id(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa)
{
if (wa->cbUserId == 0)
return 0; /* user id absent */
@ -501,8 +477,8 @@ unpack_user_id(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
}
static int
translate_fido_assert(struct winhello_assert *ctx, fido_assert_t *assert,
const char *pin)
translate_fido_assert(struct winhello_assert *ctx, const fido_assert_t *assert,
const char *pin, int ms)
{
WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS *opt;
@ -527,7 +503,7 @@ translate_fido_assert(struct winhello_assert *ctx, fido_assert_t *assert,
/* options */
opt = &ctx->opt;
opt->dwVersion = WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_1;
opt->dwTimeoutMilliseconds = MAXMSEC;
opt->dwTimeoutMilliseconds = ms < 0 ? MAXMSEC : (DWORD)ms;
if (pack_credlist(&opt->CredentialList, &assert->allow_list) < 0) {
fido_log_debug("%s: pack_credlist", __func__);
return FIDO_ERR_INTERNAL;
@ -541,7 +517,7 @@ translate_fido_assert(struct winhello_assert *ctx, fido_assert_t *assert,
}
static int
translate_winhello_assert(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
translate_winhello_assert(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa)
{
int r;
@ -575,8 +551,8 @@ translate_winhello_assert(fido_assert_t *assert, WEBAUTHN_ASSERTION *wa)
}
static int
translate_fido_cred(struct winhello_cred *ctx, fido_cred_t *cred,
const char *pin)
translate_fido_cred(struct winhello_cred *ctx, const fido_cred_t *cred,
const char *pin, int ms)
{
WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS *opt;
@ -600,7 +576,9 @@ translate_fido_cred(struct winhello_cred *ctx, fido_cred_t *cred,
/* options */
opt = &ctx->opt;
opt->dwVersion = WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS_VERSION_1;
opt->dwTimeoutMilliseconds = MAXMSEC;
opt->dwTimeoutMilliseconds = ms < 0 ? MAXMSEC : (DWORD)ms;
opt->dwAttestationConveyancePreference =
WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_DIRECT;
if (pack_credlist(&opt->CredentialList, &cred->excl) < 0) {
fido_log_debug("%s: pack_credlist", __func__);
return FIDO_ERR_INTERNAL;
@ -609,7 +587,8 @@ translate_fido_cred(struct winhello_cred *ctx, fido_cred_t *cred,
fido_log_debug("%s: pack_cred_ext", __func__);
return FIDO_ERR_UNSUPPORTED_EXTENSION;
}
if (set_uv(&opt->dwUserVerificationRequirement, cred->uv, pin) < 0) {
if (set_uv(&opt->dwUserVerificationRequirement, (cred->ext.mask &
FIDO_EXT_CRED_PROTECT) ? FIDO_OPT_TRUE : cred->uv, pin) < 0) {
fido_log_debug("%s: set_uv", __func__);
return FIDO_ERR_INTERNAL;
}
@ -621,67 +600,94 @@ translate_fido_cred(struct winhello_cred *ctx, fido_cred_t *cred,
}
static int
translate_winhello_cred(fido_cred_t *cred, WEBAUTHN_CREDENTIAL_ATTESTATION *att)
decode_attobj(const cbor_item_t *key, const cbor_item_t *val, void *arg)
{
if (unpack_fmt(cred, att) < 0) {
fido_log_debug("%s: unpack_fmt", __func__);
return FIDO_ERR_INTERNAL;
}
if (unpack_cred_authdata(cred, att) < 0) {
fido_log_debug("%s: unpack_cred_authdata", __func__);
return FIDO_ERR_INTERNAL;
fido_cred_t *cred = arg;
char *name = NULL;
int ok = -1;
if (cbor_string_copy(key, &name) < 0) {
fido_log_debug("%s: cbor type", __func__);
ok = 0; /* ignore */
goto fail;
}
switch (att->dwAttestationDecodeType) {
case WEBAUTHN_ATTESTATION_DECODE_NONE:
if (att->pvAttestationDecode != NULL) {
fido_log_debug("%s: pvAttestationDecode", __func__);
return FIDO_ERR_INTERNAL;
if (!strcmp(name, "fmt")) {
if (cbor_decode_fmt(val, &cred->fmt) < 0) {
fido_log_debug("%s: cbor_decode_fmt", __func__);
goto fail;
}
break;
case WEBAUTHN_ATTESTATION_DECODE_COMMON:
if (att->pvAttestationDecode == NULL) {
fido_log_debug("%s: pvAttestationDecode", __func__);
return FIDO_ERR_INTERNAL;
} else if (!strcmp(name, "attStmt")) {
if (cbor_decode_attstmt(val, &cred->attstmt) < 0) {
fido_log_debug("%s: cbor_decode_attstmt", __func__);
goto fail;
}
if (unpack_cred_sig(cred, att->pvAttestationDecode) < 0) {
fido_log_debug("%s: unpack_cred_sig", __func__);
return FIDO_ERR_INTERNAL;
} else if (!strcmp(name, "authData")) {
if (cbor_decode_cred_authdata(val, cred->type,
&cred->authdata_cbor, &cred->authdata, &cred->attcred,
&cred->authdata_ext) < 0) {
fido_log_debug("%s: cbor_decode_cred_authdata",
__func__);
goto fail;
}
if (unpack_x5c(cred, att->pvAttestationDecode) < 0) {
fido_log_debug("%s: unpack_x5c", __func__);
return FIDO_ERR_INTERNAL;
}
break;
default:
fido_log_debug("%s: dwAttestationDecodeType: %u", __func__,
att->dwAttestationDecodeType);
return FIDO_ERR_INTERNAL;
}
return FIDO_OK;
ok = 0;
fail:
free(name);
return (ok);
}
static int
winhello_manifest(BOOL *present)
translate_winhello_cred(fido_cred_t *cred, const WEBAUTHN_CREDENTIAL_ATTESTATION *att)
{
cbor_item_t *item = NULL;
struct cbor_load_result cbor;
int r = FIDO_ERR_INTERNAL;
if (att->pbAttestationObject == NULL ||
att->cbAttestationObject > SIZE_MAX) {
fido_log_debug("%s: pbAttestationObject", __func__);
goto fail;
}
if ((item = cbor_load(att->pbAttestationObject,
(size_t)att->cbAttestationObject, &cbor)) == NULL) {
fido_log_debug("%s: cbor_load", __func__);
goto fail;
}
if (cbor_isa_map(item) == false ||
cbor_map_is_definite(item) == false ||
cbor_map_iter(item, cred, decode_attobj) < 0) {
fido_log_debug("%s: cbor type", __func__);
goto fail;
}
r = FIDO_OK;
fail:
if (item != NULL)
cbor_decref(&item);
return r;
}
static int
winhello_manifest(void)
{
DWORD n;
HRESULT hr;
int r = FIDO_OK;
if ((n = WebAuthNGetApiVersionNumber()) < 1) {
if (!webauthn_loaded && webauthn_load() < 0) {
fido_log_debug("%s: webauthn_load", __func__);
return FIDO_ERR_INTERNAL;
}
if ((n = webauthn_get_api_version()) < 1) {
fido_log_debug("%s: unsupported api %u", __func__, n);
return FIDO_ERR_INTERNAL;
}
fido_log_debug("%s: api version %u", __func__, n);
hr = WebAuthNIsUserVerifyingPlatformAuthenticatorAvailable(present);
if (hr != S_OK) {
r = to_fido(hr);
fido_log_debug("%s: %ls -> %s", __func__,
WebAuthNGetErrorName(hr), fido_strerr(r));
}
return r;
return FIDO_OK;
}
static int
@ -690,12 +696,11 @@ winhello_get_assert(HWND w, struct winhello_assert *ctx)
HRESULT hr;
int r = FIDO_OK;
hr = WebAuthNAuthenticatorGetAssertion(w, ctx->rp_id, &ctx->cd,
&ctx->opt, &ctx->assert);
if (hr != S_OK) {
if ((hr = webauthn_get_assert(w, ctx->rp_id, &ctx->cd, &ctx->opt,
&ctx->assert)) != S_OK) {
r = to_fido(hr);
fido_log_debug("%s: %ls -> %s", __func__,
WebAuthNGetErrorName(hr), fido_strerr(r));
fido_log_debug("%s: %ls -> %s", __func__, webauthn_strerr(hr),
fido_strerr(r));
}
return r;
@ -707,12 +712,11 @@ winhello_make_cred(HWND w, struct winhello_cred *ctx)
HRESULT hr;
int r = FIDO_OK;
hr = WebAuthNAuthenticatorMakeCredential(w, &ctx->rp, &ctx->user,
&ctx->cose, &ctx->cd, &ctx->opt, &ctx->att);
if (hr != S_OK) {
if ((hr = webauthn_make_cred(w, &ctx->rp, &ctx->user, &ctx->cose,
&ctx->cd, &ctx->opt, &ctx->att)) != S_OK) {
r = to_fido(hr);
fido_log_debug("%s: %ls -> %s", __func__,
WebAuthNGetErrorName(hr), fido_strerr(r));
fido_log_debug("%s: %ls -> %s", __func__, webauthn_strerr(hr),
fido_strerr(r));
}
return r;
@ -724,7 +728,7 @@ winhello_assert_free(struct winhello_assert *ctx)
if (ctx == NULL)
return;
if (ctx->assert != NULL)
WebAuthNFreeAssertion(ctx->assert);
webauthn_free_assert(ctx->assert);
free(ctx->rp_id);
free(ctx->opt.CredentialList.pCredentials);
@ -737,7 +741,7 @@ winhello_cred_free(struct winhello_cred *ctx)
if (ctx == NULL)
return;
if (ctx->att != NULL)
WebAuthNFreeCredentialAttestation(ctx->att);
webauthn_free_attest(ctx->att);
free(ctx->rp_id);
free(ctx->rp_name);
@ -758,7 +762,6 @@ int
fido_winhello_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
{
int r;
BOOL present;
fido_dev_info_t *di;
if (ilen == 0) {
@ -767,14 +770,10 @@ fido_winhello_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
if (devlist == NULL) {
return FIDO_ERR_INVALID_ARGUMENT;
}
if ((r = winhello_manifest(&present)) != FIDO_OK) {
if ((r = winhello_manifest()) != FIDO_OK) {
fido_log_debug("%s: winhello_manifest", __func__);
return r;
}
if (present == false) {
fido_log_debug("%s: not present", __func__);
return FIDO_OK;
}
di = &devlist[*olen];
memset(di, 0, sizeof(*di));
@ -799,9 +798,12 @@ fido_winhello_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
int
fido_winhello_open(fido_dev_t *dev)
{
if (!webauthn_loaded && webauthn_load() < 0) {
fido_log_debug("%s: webauthn_load", __func__);
return FIDO_ERR_INTERNAL;
}
if (dev->flags != 0)
return FIDO_ERR_INVALID_ARGUMENT;
dev->attr.flags = FIDO_CAP_CBOR | FIDO_CAP_WINK;
dev->flags = FIDO_DEV_WINHELLO | FIDO_DEV_CRED_PROT | FIDO_DEV_PIN_SET;
@ -826,7 +828,7 @@ fido_winhello_cancel(fido_dev_t *dev)
int
fido_winhello_get_assert(fido_dev_t *dev, fido_assert_t *assert,
const char *pin)
const char *pin, int ms)
{
HWND w;
struct winhello_assert *ctx;
@ -834,6 +836,8 @@ fido_winhello_get_assert(fido_dev_t *dev, fido_assert_t *assert,
(void)dev;
fido_assert_reset_rx(assert);
if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
fido_log_debug("%s: calloc", __func__);
goto fail;
@ -842,7 +846,7 @@ fido_winhello_get_assert(fido_dev_t *dev, fido_assert_t *assert,
fido_log_debug("%s: GetForegroundWindow", __func__);
goto fail;
}
if ((r = translate_fido_assert(ctx, assert, pin)) != FIDO_OK) {
if ((r = translate_fido_assert(ctx, assert, pin, ms)) != FIDO_OK) {
fido_log_debug("%s: translate_fido_assert", __func__);
goto fail;
}
@ -873,10 +877,10 @@ fido_winhello_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci)
fido_cbor_info_reset(ci);
if (to_fido_str_array(&ci->versions, v, nitems(v)) < 0 ||
to_fido_str_array(&ci->extensions, e, nitems(e)) < 0 ||
to_fido_str_array(&ci->transports, t, nitems(t)) < 0) {
fido_log_debug("%s: to_fido_str_array", __func__);
if (fido_str_array_pack(&ci->versions, v, nitems(v)) < 0 ||
fido_str_array_pack(&ci->extensions, e, nitems(e)) < 0 ||
fido_str_array_pack(&ci->transports, t, nitems(t)) < 0) {
fido_log_debug("%s: fido_str_array_pack", __func__);
return FIDO_ERR_INTERNAL;
}
if ((ci->options.name = calloc(nitems(o), sizeof(char *))) == NULL ||
@ -897,7 +901,8 @@ fido_winhello_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci)
}
int
fido_winhello_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
fido_winhello_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
int ms)
{
HWND w;
struct winhello_cred *ctx;
@ -905,6 +910,8 @@ fido_winhello_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
(void)dev;
fido_cred_reset_rx(cred);
if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
fido_log_debug("%s: calloc", __func__);
goto fail;
@ -913,7 +920,7 @@ fido_winhello_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
fido_log_debug("%s: GetForegroundWindow", __func__);
goto fail;
}
if ((r = translate_fido_cred(ctx, cred, pin)) != FIDO_OK) {
if ((r = translate_fido_cred(ctx, cred, pin, ms)) != FIDO_OK) {
fido_log_debug("%s: translate_fido_cred", __func__);
goto fail;
}

View File

@ -3,10 +3,13 @@
# license that can be found in the LICENSE file.
list(APPEND COMPAT_SOURCES
../openbsd-compat/bsd-getpagesize.c
../openbsd-compat/explicit_bzero.c
../openbsd-compat/freezero.c
../openbsd-compat/recallocarray.c
../openbsd-compat/strlcat.c
../openbsd-compat/strlcpy.c
../openbsd-compat/strsep.c
)
if(WIN32 AND NOT CYGWIN AND NOT MSYS)

View File

@ -147,3 +147,51 @@ config_force_pin_change(char *path)
exit(ok);
}
int
config_pin_minlen_rpid(char *path, const char *rpids)
{
fido_dev_t *dev;
char *otmp, *tmp, *cp;
char *pin = NULL, **rpid = NULL;
int r, ok = 1;
size_t n;
if ((tmp = strdup(rpids)) == NULL)
err(1, "strdup");
otmp = tmp;
for (n = 0; (cp = strsep(&tmp, ",")) != NULL; n++) {
if (n == SIZE_MAX || (rpid = recallocarray(rpid, n, n + 1,
sizeof(*rpid))) == NULL)
err(1, "recallocarray");
if ((rpid[n] = strdup(cp)) == NULL)
err(1, "strdup");
if (*rpid[n] == '\0')
errx(1, "empty rpid");
}
free(otmp);
if (rpid == NULL || n == 0)
errx(1, "could not parse rp_id");
dev = open_dev(path);
if ((r = fido_dev_set_pin_minlen_rpid(dev, (const char * const *)rpid,
n, NULL)) != FIDO_OK && should_retry_with_pin(dev, r)) {
if ((pin = get_pin(path)) == NULL)
goto out;
r = fido_dev_set_pin_minlen_rpid(dev, (const char * const *)rpid,
n, pin);
freezero(pin, PINBUF_LEN);
pin = NULL;
}
if (r != FIDO_OK) {
warnx("fido_dev_set_pin_minlen_rpid: %s (0x%x)",
fido_strerr(r), r);
goto out;
}
ok = 0;
out:
fido_dev_close(dev);
fido_dev_free(&dev);
exit(ok);
}

View File

@ -20,7 +20,7 @@ struct blob {
size_t len;
};
#define TOKEN_OPT "CDGILPRSVabcdefi:k:l:n:p:ru"
#define TOKEN_OPT "CDGILPRSVabcdefi:k:l:m:n:p:ru"
#define FLAG_DEBUG 0x01
#define FLAG_QUIET 0x02
@ -62,6 +62,7 @@ int config_always_uv(char *, int);
int config_entattest(char *);
int config_force_pin_change(char *);
int config_pin_minlen(char *, const char *);
int config_pin_minlen_rpid(char *, const char *);
int cose_type(const char *, int *);
int cred_make(int, char **);
int cred_verify(int, char **);

View File

@ -28,6 +28,7 @@ usage(void)
" fido2-token -S [-adefu] [-l pin_length] [-i template_id -n template_name] device\n"
" fido2-token -Sb [-k key_path] [-i cred_id -n rp_id] blob_path device\n"
" fido2-token -Sc -i cred_id -k user_id -n name -p display_name device\n"
" fido2-token -Sm rp_id device\n"
" fido2-token -V\n"
);
@ -59,6 +60,7 @@ main(int argc, char **argv)
case 'i':
case 'k':
case 'l':
case 'm':
case 'n':
case 'p':
case 'r':

View File

@ -352,6 +352,7 @@ token_set(int argc, char **argv, char *path)
char *len = NULL;
char *display_name = NULL;
char *name = NULL;
char *rpid = NULL;
int blob = 0;
int cred = 0;
int ch;
@ -391,6 +392,9 @@ token_set(int argc, char **argv, char *path)
case 'p':
display_name = optarg;
break;
case 'm':
rpid = optarg;
break;
case 'n':
name = optarg;
break;
@ -440,6 +444,8 @@ token_set(int argc, char **argv, char *path)
if (len)
return (config_pin_minlen(path, len));
if (rpid)
return (config_pin_minlen_rpid(path, rpid));
if (force)
return (config_force_pin_change(path));
if (uv)

View File

@ -1,140 +1,136 @@
# Copyright (c) 2021 Yubico AB. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
param(
[string]$CMakePath = "C:\Program Files\CMake\bin\cmake.exe",
[string]$GitPath = "C:\Program Files\Git\bin\git.exe",
[string]$SevenZPath = "C:\Program Files\7-Zip\7z.exe",
[string]$GPGPath = "C:\Program Files (x86)\GnuPG\bin\gpg.exe",
[string]$WinSDK = "",
[string]$Config = "Release",
[string]$Arch = "x64",
[string]$Type = "dynamic",
[string]$Fido2Flags = ""
)
$ErrorActionPreference = "Continue"
$ErrorActionPreference = "Stop"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# LibreSSL coordinates.
New-Variable -Name 'LIBRESSL_URL' `
-Value 'https://fastly.cdn.openbsd.org/pub/OpenBSD/LibreSSL' -Option Constant
New-Variable -Name 'LIBRESSL' -Value 'libressl-3.2.5' -Option Constant
. "$PSScriptRoot\const.ps1"
# libcbor coordinates.
New-Variable -Name 'LIBCBOR' -Value 'libcbor-0.8.0' -Option Constant
New-Variable -Name 'LIBCBOR_BRANCH' -Value 'v0.8.0' -Option Constant
New-Variable -Name 'LIBCBOR_GIT' -Value 'https://github.com/pjk/libcbor' `
-Option Constant
Function ExitOnError() {
if ($LastExitCode -ne 0) {
throw "A command exited with status $LastExitCode"
}
}
# zlib coordinates.
New-Variable -Name 'ZLIB' -Value 'zlib-1.2.11' -Option Constant
New-Variable -Name 'ZLIB_BRANCH' -Value 'v1.2.11' -Option Constant
New-Variable -Name 'ZLIB_GIT' -Value 'https://github.com/madler/zlib' `
-Option Constant
# Work directories.
New-Variable -Name 'BUILD' -Value "$PSScriptRoot\..\build" -Option Constant
New-Variable -Name 'OUTPUT' -Value "$PSScriptRoot\..\output" -Option Constant
# Find CMake.
$CMake = $(Get-Command cmake -ErrorAction Ignore | Select-Object -ExpandProperty Source)
if([string]::IsNullOrEmpty($CMake)) {
$CMake = $CMakePath
Function GitClone(${REPO}, ${BRANCH}, ${DIR}) {
Write-Host "Cloning ${REPO}..."
& $Git -c advice.detachedHead=false clone --quiet --depth=1 `
--branch "${BRANCH}" "${REPO}" "${DIR}"
Write-Host "${REPO}'s ${BRANCH} HEAD is:"
& $Git -C "${DIR}" show -s HEAD
}
# Find Git.
$Git = $(Get-Command git -ErrorAction Ignore | Select-Object -ExpandProperty Source)
if([string]::IsNullOrEmpty($Git)) {
$Git = $(Get-Command git -ErrorAction Ignore | `
Select-Object -ExpandProperty Source)
if ([string]::IsNullOrEmpty($Git)) {
$Git = $GitPath
}
if (-Not (Test-Path $Git)) {
throw "Unable to find Git at $Git"
}
# Find CMake.
$CMake = $(Get-Command cmake -ErrorAction Ignore | `
Select-Object -ExpandProperty Source)
if ([string]::IsNullOrEmpty($CMake)) {
$CMake = $CMakePath
}
if (-Not (Test-Path $CMake)) {
throw "Unable to find CMake at $CMake"
}
# Find 7z.
$SevenZ = $(Get-Command 7z -ErrorAction Ignore | Select-Object -ExpandProperty Source)
if([string]::IsNullOrEmpty($SevenZ)) {
$SevenZ = $(Get-Command 7z -ErrorAction Ignore | `
Select-Object -ExpandProperty Source)
if ([string]::IsNullOrEmpty($SevenZ)) {
$SevenZ = $SevenZPath
}
if (-Not (Test-Path $SevenZ)) {
throw "Unable to find 7z at $SevenZ"
}
# Find GPG.
$GPG = $(Get-Command gpg -ErrorAction Ignore | Select-Object -ExpandProperty Source)
if([string]::IsNullOrEmpty($GPG)) {
$GPG = $(Get-Command gpg -ErrorAction Ignore | `
Select-Object -ExpandProperty Source)
if ([string]::IsNullOrEmpty($GPG)) {
$GPG = $GPGPath
}
if (-Not (Test-Path $GPG)) {
throw "Unable to find GPG at $GPG"
}
# Override CMAKE_SYSTEM_VERSION if $WinSDK is set.
if(-Not ([string]::IsNullOrEmpty($WinSDK))) {
if (-Not ([string]::IsNullOrEmpty($WinSDK))) {
$CMAKE_SYSTEM_VERSION = "-DCMAKE_SYSTEM_VERSION='$WinSDK'"
} else {
$CMAKE_SYSTEM_VERSION = ''
}
if(-Not (Test-Path $CMake)) {
throw "Unable to find CMake at $CMake"
}
if(-Not (Test-Path $Git)) {
throw "Unable to find Git at $Git"
}
if(-Not (Test-Path $SevenZ)) {
throw "Unable to find 7z at $SevenZ"
}
if(-Not (Test-Path $GPG)) {
throw "Unable to find GPG at $GPG"
}
Write-Host "WinSDK: $WinSDK"
Write-Host "Config: $Config"
Write-Host "Arch: $Arch"
Write-Host "Type: $Type"
Write-Host "Git: $Git"
Write-Host "CMake: $CMake"
Write-Host "7z: $SevenZ"
Write-Host "GPG: $GPG"
New-Item -Type Directory ${BUILD}
New-Item -Type Directory ${BUILD}\32
New-Item -Type Directory ${BUILD}\32\dynamic
New-Item -Type Directory ${BUILD}\32\static
New-Item -Type Directory ${BUILD}\64
New-Item -Type Directory ${BUILD}\64\dynamic
New-Item -Type Directory ${BUILD}\64\static
New-Item -Type Directory ${OUTPUT}
New-Item -Type Directory ${OUTPUT}\pkg\Win64\Release\v142\dynamic
New-Item -Type Directory ${OUTPUT}\pkg\Win32\Release\v142\dynamic
New-Item -Type Directory ${OUTPUT}\pkg\Win64\Release\v142\static
New-Item -Type Directory ${OUTPUT}\pkg\Win32\Release\v142\static
# Create build directories.
New-Item -Type Directory "${BUILD}" -Force
New-Item -Type Directory "${BUILD}\${Arch}" -Force
New-Item -Type Directory "${BUILD}\${Arch}\${Type}" -Force
New-Item -Type Directory "${STAGE}\${LIBRESSL}" -Force
New-Item -Type Directory "${STAGE}\${LIBCBOR}" -Force
New-Item -Type Directory "${STAGE}\${ZLIB}" -Force
# Create output directories.
New-Item -Type Directory "${OUTPUT}" -Force
New-Item -Type Directory "${OUTPUT}\${Arch}" -Force
New-Item -Type Directory "${OUTPUT}\${Arch}\${Type}" -force
# Fetch and verify dependencies.
Push-Location ${BUILD}
try {
if (Test-Path .\${LIBRESSL}) {
Remove-Item .\${LIBRESSL} -Recurse -ErrorAction Stop
}
if (-Not (Test-Path .\${LIBRESSL})) {
if (-Not (Test-Path .\${LIBRESSL}.tar.gz -PathType leaf)) {
Invoke-WebRequest ${LIBRESSL_URL}/${LIBRESSL}.tar.gz `
-OutFile .\${LIBRESSL}.tar.gz
}
if (-Not (Test-Path .\${LIBRESSL}.tar.gz.asc -PathType leaf)) {
Invoke-WebRequest ${LIBRESSL_URL}/${LIBRESSL}.tar.gz.asc `
-OutFile .\${LIBRESSL}.tar.gz.asc
}
if(-Not (Test-Path .\${LIBRESSL}.tar.gz -PathType leaf)) {
Invoke-WebRequest ${LIBRESSL_URL}/${LIBRESSL}.tar.gz `
-OutFile .\${LIBRESSL}.tar.gz
Copy-Item "$PSScriptRoot\libressl.gpg" -Destination "${BUILD}"
& $GPG --list-keys
& $GPG --quiet --no-default-keyring --keyring ./libressl.gpg `
--verify .\${LIBRESSL}.tar.gz.asc .\${LIBRESSL}.tar.gz
if ($LastExitCode -ne 0) {
throw "GPG signature verification failed"
}
& $SevenZ e .\${LIBRESSL}.tar.gz
& $SevenZ x .\${LIBRESSL}.tar
Remove-Item -Force .\${LIBRESSL}.tar
}
if(-Not (Test-Path .\${LIBRESSL}.tar.gz.asc -PathType leaf)) {
Invoke-WebRequest ${LIBRESSL_URL}/${LIBRESSL}.tar.gz.asc `
-OutFile .\${LIBRESSL}.tar.gz.asc
if (-Not (Test-Path .\${LIBCBOR})) {
GitClone "${LIBCBOR_GIT}" "${LIBCBOR_BRANCH}" ".\${LIBCBOR}"
}
Copy-Item "$PSScriptRoot\libressl.gpg" -Destination "${BUILD}"
& $GPG --list-keys
& $GPG -v --no-default-keyring --keyring ./libressl.gpg `
--verify .\${LIBRESSL}.tar.gz.asc .\${LIBRESSL}.tar.gz
if ($LastExitCode -ne 0) {
throw "GPG signature verification failed"
}
& $SevenZ e .\${LIBRESSL}.tar.gz
& $SevenZ x .\${LIBRESSL}.tar
Remove-Item -Force .\${LIBRESSL}.tar
if(-Not (Test-Path .\${LIBCBOR})) {
Write-Host "Cloning ${LIBCBOR}..."
& $Git clone --branch ${LIBCBOR_BRANCH} ${LIBCBOR_GIT} `
.\${LIBCBOR}
}
if(-Not (Test-Path .\${ZLIB})) {
Write-Host "Cloning ${ZLIB}..."
& $Git clone --branch ${ZLIB_BRANCH} ${ZLIB_GIT} `
.\${ZLIB}
if (-Not (Test-Path .\${ZLIB})) {
GitClone "${ZLIB_GIT}" "${ZLIB_BRANCH}" ".\${ZLIB}"
}
} catch {
throw "Failed to fetch and verify dependencies"
@ -142,131 +138,103 @@ try {
Pop-Location
}
Function Build(${OUTPUT}, ${GENERATOR}, ${ARCH}, ${SHARED}, ${FLAGS}) {
if (-Not (Test-Path .\${LIBRESSL})) {
New-Item -Type Directory .\${LIBRESSL} -ErrorAction Stop
}
Push-Location .\${LIBRESSL}
& $CMake ..\..\..\${LIBRESSL} -G "${GENERATOR}" -A "${ARCH}" `
-DBUILD_SHARED_LIBS="${SHARED}" -DLIBRESSL_TESTS=OFF `
-DCMAKE_C_FLAGS_RELEASE="${FLAGS} /Zi /guard:cf /sdl" `
-DCMAKE_INSTALL_PREFIX="${OUTPUT}" "${CMAKE_SYSTEM_VERSION}"
& $CMake --build . --config Release --verbose
& $CMake --build . --config Release --target install --verbose
# Build LibreSSL.
Push-Location ${STAGE}\${LIBRESSL}
try {
& $CMake ..\..\..\${LIBRESSL} -A "${Arch}" `
-DBUILD_SHARED_LIBS="${SHARED}" -DLIBRESSL_TESTS=OFF `
-DCMAKE_C_FLAGS_DEBUG="${CFLAGS_DEBUG}" `
-DCMAKE_C_FLAGS_RELEASE="${CFLAGS_RELEASE}" `
-DCMAKE_INSTALL_PREFIX="${PREFIX}" "${CMAKE_SYSTEM_VERSION}"; `
ExitOnError
& $CMake --build . --config ${Config} --verbose; ExitOnError
& $CMake --build . --config ${Config} --target install --verbose; `
ExitOnError
} catch {
throw "Failed to build LibreSSL"
} finally {
Pop-Location
}
if (-Not (Test-Path .\${LIBCBOR})) {
New-Item -Type Directory .\${LIBCBOR} -ErrorAction Stop
}
Push-Location .\${LIBCBOR}
& $CMake ..\..\..\${LIBCBOR} -G "${GENERATOR}" -A "${ARCH}" `
-DBUILD_SHARED_LIBS="${SHARED}" `
-DCMAKE_C_FLAGS_RELEASE="${FLAGS} /Zi /guard:cf /sdl" `
-DCMAKE_INSTALL_PREFIX="${OUTPUT}" "${CMAKE_SYSTEM_VERSION}"
& $CMake --build . --config Release --verbose
& $CMake --build . --config Release --target install --verbose
# Build libcbor.
Push-Location ${STAGE}\${LIBCBOR}
try {
& $CMake ..\..\..\${LIBCBOR} -A "${Arch}" `
-DWITH_EXAMPLES=OFF `
-DBUILD_SHARED_LIBS="${SHARED}" `
-DCMAKE_C_FLAGS_DEBUG="${CFLAGS_DEBUG}" `
-DCMAKE_C_FLAGS_RELEASE="${CFLAGS_RELEASE}" `
-DCMAKE_INSTALL_PREFIX="${PREFIX}" "${CMAKE_SYSTEM_VERSION}"; `
ExitOnError
& $CMake --build . --config ${Config} --verbose; ExitOnError
& $CMake --build . --config ${Config} --target install --verbose; `
ExitOnError
} catch {
throw "Failed to build libcbor"
} finally {
Pop-Location
}
if(-Not (Test-Path .\${ZLIB})) {
New-Item -Type Directory .\${ZLIB} -ErrorAction Stop
# Build zlib.
Push-Location ${STAGE}\${ZLIB}
try {
& $CMake ..\..\..\${ZLIB} -A "${Arch}" `
-DBUILD_SHARED_LIBS="${SHARED}" `
-DCMAKE_C_FLAGS_DEBUG="${CFLAGS_DEBUG}" `
-DCMAKE_C_FLAGS_RELEASE="${CFLAGS_RELEASE}" `
-DCMAKE_INSTALL_PREFIX="${PREFIX}" "${CMAKE_SYSTEM_VERSION}"; `
ExitOnError
& $CMake --build . --config ${Config} --verbose; ExitOnError
& $CMake --build . --config ${Config} --target install --verbose; `
ExitOnError
# Patch up zlib's resulting names when built with --config Debug.
if ("${Config}" -eq "Debug") {
if ("${Type}" -eq "Dynamic") {
Copy-Item "${PREFIX}/lib/zlibd.lib" `
-Destination "${PREFIX}/lib/zlib.lib" -Force
Copy-Item "${PREFIX}/bin/zlibd1.dll" `
-Destination "${PREFIX}/bin/zlib1.dll" -Force
} else {
Copy-Item "${PREFIX}/lib/zlibstaticd.lib" `
-Destination "${PREFIX}/lib/zlib.lib" -Force
}
}
Push-Location .\${ZLIB}
& $CMake ..\..\..\${ZLIB} -G "${GENERATOR}" -A "${ARCH}" `
-DBUILD_SHARED_LIBS="${SHARED}" `
-DCMAKE_C_FLAGS_RELEASE="${FLAGS} /Zi /guard:cf /sdl" `
-DCMAKE_INSTALL_PREFIX="${OUTPUT}" "${CMAKE_SYSTEM_VERSION}"
& $CMake --build . --config Release --verbose
& $CMake --build . --config Release --target install --verbose
} catch {
throw "Failed to build zlib"
} finally {
Pop-Location
}
& $CMake ..\..\.. -G "${GENERATOR}" -A "${ARCH}" `
-DBUILD_SHARED_LIBS="${SHARED}" `
-DCBOR_INCLUDE_DIRS="${OUTPUT}\include" `
-DCBOR_LIBRARY_DIRS="${OUTPUT}\lib" `
-DZLIB_INCLUDE_DIRS="${OUTPUT}\include" `
-DZLIB_LIBRARY_DIRS="${OUTPUT}\lib" `
-DCRYPTO_INCLUDE_DIRS="${OUTPUT}\include" `
-DCRYPTO_LIBRARY_DIRS="${OUTPUT}\lib" `
-DCMAKE_C_FLAGS_RELEASE="${FLAGS} /Zi /guard:cf /sdl ${Fido2Flags}" `
-DCMAKE_INSTALL_PREFIX="${OUTPUT}" "${CMAKE_SYSTEM_VERSION}"
& $CMake --build . --config Release --verbose
& $CMake --build . --config Release --target install --verbose
# Build libfido2.
Push-Location ${STAGE}
try {
& $CMake ..\..\.. -A "${Arch}" `
-DCMAKE_BUILD_TYPE="${Config}" `
-DBUILD_SHARED_LIBS="${SHARED}" `
-DCBOR_INCLUDE_DIRS="${PREFIX}\include" `
-DCBOR_LIBRARY_DIRS="${PREFIX}\lib" `
-DCBOR_BIN_DIRS="${PREFIX}\bin" `
-DZLIB_INCLUDE_DIRS="${PREFIX}\include" `
-DZLIB_LIBRARY_DIRS="${PREFIX}\lib" `
-DZLIB_BIN_DIRS="${PREFIX}\bin" `
-DCRYPTO_INCLUDE_DIRS="${PREFIX}\include" `
-DCRYPTO_LIBRARY_DIRS="${PREFIX}\lib" `
-DCRYPTO_BIN_DIRS="${PREFIX}\bin" `
-DCMAKE_C_FLAGS_DEBUG="${CFLAGS_DEBUG} ${Fido2Flags}" `
-DCMAKE_C_FLAGS_RELEASE="${CFLAGS_RELEASE} ${Fido2Flags}" `
-DCMAKE_INSTALL_PREFIX="${PREFIX}" "${CMAKE_SYSTEM_VERSION}"; `
ExitOnError
& $CMake --build . --config ${Config} --verbose; ExitOnError
& $CMake --build . --config ${Config} --target install --verbose; `
ExitOnError
# Copy DLLs.
if ("${SHARED}" -eq "ON") {
"cbor.dll", "crypto-46.dll", "zlib1.dll" | %{ Copy-Item "${OUTPUT}\bin\$_" `
-Destination "examples\Release" }
"cbor.dll", "crypto-46.dll", "zlib1.dll" | `
%{ Copy-Item "${PREFIX}\bin\$_" `
-Destination "examples\${Config}" }
}
} catch {
throw "Failed to build libfido2"
} finally {
Pop-Location
}
Function Package-Headers() {
Copy-Item "${OUTPUT}\64\dynamic\include" -Destination "${OUTPUT}\pkg" `
-Recurse -ErrorAction Stop
}
Function Package-Dynamic(${SRC}, ${DEST}) {
Copy-Item "${SRC}\bin\cbor.dll" "${DEST}" -ErrorAction Stop
Copy-Item "${SRC}\lib\cbor.lib" "${DEST}" -ErrorAction Stop
Copy-Item "${SRC}\bin\zlib1.dll" "${DEST}" -ErrorAction Stop
Copy-Item "${SRC}\lib\zlib.lib" "${DEST}" -ErrorAction Stop
Copy-Item "${SRC}\bin\crypto-46.dll" "${DEST}" -ErrorAction Stop
Copy-Item "${SRC}\lib\crypto-46.lib" "${DEST}" -ErrorAction Stop
Copy-Item "${SRC}\bin\fido2.dll" "${DEST}" -ErrorAction Stop
Copy-Item "${SRC}\lib\fido2.lib" "${DEST}" -ErrorAction Stop
}
Function Package-Static(${SRC}, ${DEST}) {
Copy-Item "${SRC}/lib/cbor.lib" "${DEST}" -ErrorAction Stop
Copy-Item "${SRC}/lib/zlib.lib" "${DEST}" -ErrorAction Stop
Copy-Item "${SRC}/lib/crypto-46.lib" "${DEST}" -ErrorAction Stop
Copy-Item "${SRC}/lib/fido2_static.lib" "${DEST}/fido2.lib" `
-ErrorAction Stop
}
Function Package-PDBs(${SRC}, ${DEST}) {
Copy-Item "${SRC}\${LIBRESSL}\crypto\crypto.dir\Release\vc142.pdb" `
"${DEST}\crypto-46.pdb" -ErrorAction Stop
Copy-Item "${SRC}\${LIBCBOR}\src\cbor.dir\Release\vc142.pdb" `
"${DEST}\cbor.pdb" -ErrorAction Stop
Copy-Item "${SRC}\${ZLIB}\zlib.dir\Release\vc142.pdb" `
"${DEST}\zlib.pdb" -ErrorAction Stop
Copy-Item "${SRC}\src\fido2_shared.dir\Release\vc142.pdb" `
"${DEST}\fido2.pdb" -ErrorAction Stop
}
Function Package-Tools(${SRC}, ${DEST}) {
Copy-Item "${SRC}\tools\Release\fido2-assert.exe" `
"${DEST}\fido2-assert.exe" -ErrorAction stop
Copy-Item "${SRC}\tools\Release\fido2-cred.exe" `
"${DEST}\fido2-cred.exe" -ErrorAction stop
Copy-Item "${SRC}\tools\Release\fido2-token.exe" `
"${DEST}\fido2-token.exe" -ErrorAction stop
}
Push-Location ${BUILD}\64\dynamic
Build ${OUTPUT}\64\dynamic "Visual Studio 16 2019" "x64" "ON" "/MD"
Pop-Location
Push-Location ${BUILD}\32\dynamic
Build ${OUTPUT}\32\dynamic "Visual Studio 16 2019" "Win32" "ON" "/MD"
Pop-Location
Push-Location ${BUILD}\64\static
Build ${OUTPUT}\64\static "Visual Studio 16 2019" "x64" "OFF" "/MT"
Pop-Location
Push-Location ${BUILD}\32\static
Build ${OUTPUT}\32\static "Visual Studio 16 2019" "Win32" "OFF" "/MT"
Pop-Location
Package-Headers
Package-Dynamic ${OUTPUT}\64\dynamic ${OUTPUT}\pkg\Win64\Release\v142\dynamic
Package-PDBs ${BUILD}\64\dynamic ${OUTPUT}\pkg\Win64\Release\v142\dynamic
Package-Tools ${BUILD}\64\dynamic ${OUTPUT}\pkg\Win64\Release\v142\dynamic
Package-Dynamic ${OUTPUT}\32\dynamic ${OUTPUT}\pkg\Win32\Release\v142\dynamic
Package-PDBs ${BUILD}\32\dynamic ${OUTPUT}\pkg\Win32\Release\v142\dynamic
Package-Tools ${BUILD}\32\dynamic ${OUTPUT}\pkg\Win32\Release\v142\dynamic
Package-Static ${OUTPUT}\64\static ${OUTPUT}\pkg\Win64\Release\v142\static
Package-Static ${OUTPUT}\32\static ${OUTPUT}\pkg\Win32\Release\v142\static

42
windows/const.ps1 Normal file
View File

@ -0,0 +1,42 @@
# Copyright (c) 2021 Yubico AB. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# LibreSSL coordinates.
New-Variable -Name 'LIBRESSL_URL' `
-Value 'https://fastly.cdn.openbsd.org/pub/OpenBSD/LibreSSL' `
-Option Constant
New-Variable -Name 'LIBRESSL' -Value 'libressl-3.3.4' -Option Constant
# libcbor coordinates.
New-Variable -Name 'LIBCBOR' -Value 'libcbor-0.8.0' -Option Constant
New-Variable -Name 'LIBCBOR_BRANCH' -Value 'v0.8.0' -Option Constant
New-Variable -Name 'LIBCBOR_GIT' -Value 'https://github.com/pjk/libcbor' `
-Option Constant
# zlib coordinates.
New-Variable -Name 'ZLIB' -Value 'zlib-1.2.11' -Option Constant
New-Variable -Name 'ZLIB_BRANCH' -Value 'v1.2.11' -Option Constant
New-Variable -Name 'ZLIB_GIT' -Value 'https://github.com/madler/zlib' `
-Option Constant
# Work directories.
New-Variable -Name 'BUILD' -Value "$PSScriptRoot\..\build" -Option Constant
New-Variable -Name 'OUTPUT' -Value "$PSScriptRoot\..\output" -Option Constant
# Prefixes.
New-Variable -Name 'STAGE' -Value "${BUILD}\${Arch}\${Type}" -Option Constant
New-Variable -Name 'PREFIX' -Value "${OUTPUT}\${Arch}\${Type}" -Option Constant
# Build flags.
if ("${Type}" -eq "dynamic") {
New-Variable -Name 'RUNTIME' -Value '/MD' -Option Constant
New-Variable -Name 'SHARED' -Value 'ON' -Option Constant
} else {
New-Variable -Name 'RUNTIME' -Value '/MT' -Option Constant
New-Variable -Name 'SHARED' -Value 'OFF' -Option Constant
}
New-Variable -Name 'CFLAGS_DEBUG' -Value "${RUNTIME}d /Zi /guard:cf /sdl" `
-Option Constant
New-Variable -Name 'CFLAGS_RELEASE' -Value "${RUNTIME} /Zi /guard:cf /sdl" `
-Option Constant

84
windows/release.ps1 Normal file
View File

@ -0,0 +1,84 @@
# Copyright (c) 2021 Yubico AB. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
$ErrorActionPreference = "Stop"
$Architectures = @('x64', 'Win32', 'ARM64', 'ARM')
$InstallPrefixes = @('Win64', 'Win32', 'ARM64', 'ARM')
$Types = @('dynamic', 'static')
$Config = 'Release'
$LibCrypto = '46'
$SDK = '142'
. "$PSScriptRoot\const.ps1"
foreach ($Arch in $Architectures) {
foreach ($Type in $Types) {
./build.ps1 -Arch ${Arch} -Type ${Type} -Config ${Config}
}
}
foreach ($InstallPrefix in $InstallPrefixes) {
foreach ($Type in $Types) {
New-Item -Type Directory `
"${OUTPUT}/pkg/${InstallPrefix}/${Config}/v${SDK}/${Type}"
}
}
Function Package-Headers() {
Copy-Item "${OUTPUT}\x64\dynamic\include" -Destination "${OUTPUT}\pkg" `
-Recurse -ErrorAction Stop
}
Function Package-Dynamic(${SRC}, ${DEST}) {
Copy-Item "${SRC}\bin\cbor.dll" "${DEST}"
Copy-Item "${SRC}\lib\cbor.lib" "${DEST}"
Copy-Item "${SRC}\bin\zlib1.dll" "${DEST}"
Copy-Item "${SRC}\lib\zlib.lib" "${DEST}"
Copy-Item "${SRC}\bin\crypto-${LibCrypto}.dll" "${DEST}"
Copy-Item "${SRC}\lib\crypto-${LibCrypto}.lib" "${DEST}"
Copy-Item "${SRC}\bin\fido2.dll" "${DEST}"
Copy-Item "${SRC}\lib\fido2.lib" "${DEST}"
}
Function Package-Static(${SRC}, ${DEST}) {
Copy-Item "${SRC}/lib/cbor.lib" "${DEST}"
Copy-Item "${SRC}/lib/zlib.lib" "${DEST}"
Copy-Item "${SRC}/lib/crypto-${LibCrypto}.lib" "${DEST}"
Copy-Item "${SRC}/lib/fido2_static.lib" "${DEST}/fido2.lib"
}
Function Package-PDBs(${SRC}, ${DEST}) {
Copy-Item "${SRC}\${LIBRESSL}\crypto\crypto.dir\${Config}\vc${SDK}.pdb" `
"${DEST}\crypto-${LibCrypto}.pdb"
Copy-Item "${SRC}\${LIBCBOR}\src\cbor.dir\${Config}\vc${SDK}.pdb" `
"${DEST}\cbor.pdb"
Copy-Item "${SRC}\${ZLIB}\zlib.dir\${Config}\vc${SDK}.pdb" `
"${DEST}\zlib.pdb"
Copy-Item "${SRC}\src\fido2_shared.dir\${Config}\vc${SDK}.pdb" `
"${DEST}\fido2.pdb"
}
Function Package-Tools(${SRC}, ${DEST}) {
Copy-Item "${SRC}\tools\${Config}\fido2-assert.exe" `
"${DEST}\fido2-assert.exe"
Copy-Item "${SRC}\tools\${Config}\fido2-cred.exe" `
"${DEST}\fido2-cred.exe"
Copy-Item "${SRC}\tools\${Config}\fido2-token.exe" `
"${DEST}\fido2-token.exe"
}
Package-Headers
for ($i = 0; $i -lt $Architectures.Length; $i++) {
$Arch = $Architectures[$i]
$InstallPrefix = $InstallPrefixes[$i]
Package-Dynamic "${OUTPUT}\${Arch}\dynamic" `
"${OUTPUT}\pkg\${InstallPrefix}\${Config}\v${SDK}\dynamic"
Package-PDBs "${BUILD}\${Arch}\dynamic" `
"${OUTPUT}\pkg\${InstallPrefix}\${Config}\v${SDK}\dynamic"
Package-Tools "${BUILD}\${Arch}\dynamic" `
"${OUTPUT}\pkg\${InstallPrefix}\${Config}\v${SDK}\dynamic"
Package-Static "${OUTPUT}\${Arch}\static" `
"${OUTPUT}\pkg\${InstallPrefix}\${Config}\v${SDK}\static"
}