summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDamien Miller <djm@cvs.openbsd.org>2022-08-29 03:04:30 +0000
committerDamien Miller <djm@cvs.openbsd.org>2022-08-29 03:04:30 +0000
commit267fb7a2c7d3a68ad2dc5493ad2a01f45bf631fc (patch)
treea3549304739f5cfb8b2a8ae6d95c768fa72bb722 /lib
parent209e6f81de6ea3eb825178e9ab0d853ace9b4fe4 (diff)
update libfido2 to 1.11.0, taking in just over a year of upstream
development. "looks ok" miod@ ok sthen@ NB. libfido2 major bump
Diffstat (limited to 'lib')
-rw-r--r--lib/libfido2/Makefile5
-rw-r--r--lib/libfido2/NEWS226
-rw-r--r--lib/libfido2/README.openbsd2
-rw-r--r--lib/libfido2/man/eddsa_pk_new.36
-rw-r--r--lib/libfido2/man/es256_pk_new.322
-rw-r--r--lib/libfido2/man/fido_assert_allow_cred.36
-rw-r--r--lib/libfido2/man/fido_assert_new.3101
-rw-r--r--lib/libfido2/man/fido_assert_set_authdata.363
-rw-r--r--lib/libfido2/man/fido_assert_verify.38
-rw-r--r--lib/libfido2/man/fido_bio_dev_get_info.34
-rw-r--r--lib/libfido2/man/fido_bio_enroll_new.36
-rw-r--r--lib/libfido2/man/fido_bio_info_new.34
-rw-r--r--lib/libfido2/man/fido_bio_template.36
-rw-r--r--lib/libfido2/man/fido_cbor_info_new.316
-rw-r--r--lib/libfido2/man/fido_cred_exclude.34
-rw-r--r--lib/libfido2/man/fido_cred_new.358
-rw-r--r--lib/libfido2/man/fido_cred_set_authdata.375
-rw-r--r--lib/libfido2/man/fido_cred_verify.358
-rw-r--r--lib/libfido2/man/fido_credman_metadata_new.38
-rw-r--r--lib/libfido2/man/fido_dev_enable_entattest.333
-rw-r--r--lib/libfido2/man/fido_dev_get_assert.38
-rw-r--r--lib/libfido2/man/fido_dev_get_touch_begin.36
-rw-r--r--lib/libfido2/man/fido_dev_info_manifest.353
-rw-r--r--lib/libfido2/man/fido_dev_largeblob_get.312
-rw-r--r--lib/libfido2/man/fido_dev_make_cred.38
-rw-r--r--lib/libfido2/man/fido_dev_open.373
-rw-r--r--lib/libfido2/man/fido_dev_set_io_functions.3116
-rw-r--r--lib/libfido2/man/fido_dev_set_pin.34
-rw-r--r--lib/libfido2/man/fido_init.330
-rw-r--r--lib/libfido2/man/fido_strerr.34
-rw-r--r--lib/libfido2/man/rs256_pk_new.322
-rw-r--r--lib/libfido2/shlib_version2
-rw-r--r--lib/libfido2/src/assert.c168
-rw-r--r--lib/libfido2/src/authkey.c16
-rw-r--r--lib/libfido2/src/bio.c81
-rw-r--r--lib/libfido2/src/cbor.c108
-rw-r--r--lib/libfido2/src/compress.c144
-rw-r--r--lib/libfido2/src/config.c74
-rw-r--r--lib/libfido2/src/cred.c245
-rw-r--r--lib/libfido2/src/credman.c62
-rw-r--r--lib/libfido2/src/dev.c286
-rw-r--r--lib/libfido2/src/ecdh.c12
-rw-r--r--lib/libfido2/src/eddsa.c97
-rw-r--r--lib/libfido2/src/es256.c121
-rw-r--r--lib/libfido2/src/export.llvm16
-rw-r--r--lib/libfido2/src/extern.h76
-rw-r--r--lib/libfido2/src/fido.h31
-rw-r--r--lib/libfido2/src/fido/config.h2
-rw-r--r--lib/libfido2/src/fido/eddsa.h9
-rw-r--r--lib/libfido2/src/fido/es256.h3
-rw-r--r--lib/libfido2/src/fido/param.h8
-rw-r--r--lib/libfido2/src/fido/rs256.h3
-rw-r--r--lib/libfido2/src/fido/types.h49
-rw-r--r--lib/libfido2/src/hid.c56
-rw-r--r--lib/libfido2/src/hid_unix.c3
-rw-r--r--lib/libfido2/src/info.c89
-rw-r--r--lib/libfido2/src/io.c104
-rw-r--r--lib/libfido2/src/iso7816.c4
-rw-r--r--lib/libfido2/src/iso7816.h5
-rw-r--r--lib/libfido2/src/largeblob.c65
-rw-r--r--lib/libfido2/src/nfc.c320
-rw-r--r--lib/libfido2/src/pin.c72
-rw-r--r--lib/libfido2/src/reset.c12
-rw-r--r--lib/libfido2/src/rs1.c99
-rw-r--r--lib/libfido2/src/rs256.c147
-rw-r--r--lib/libfido2/src/time.c74
-rw-r--r--lib/libfido2/src/touch.c108
-rw-r--r--lib/libfido2/src/tpm.c390
-rw-r--r--lib/libfido2/src/types.c76
-rw-r--r--lib/libfido2/src/types.h171
-rw-r--r--lib/libfido2/src/u2f.c158
-rw-r--r--lib/libfido2/src/util.c30
72 files changed, 3400 insertions, 1243 deletions
diff --git a/lib/libfido2/Makefile b/lib/libfido2/Makefile
index fc699ff62d4..740e995b584 100644
--- a/lib/libfido2/Makefile
+++ b/lib/libfido2/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.7 2021/10/26 21:36:23 djm Exp $
+# $OpenBSD: Makefile,v 1.8 2022/08/29 03:04:29 djm Exp $
.PATH: ${.CURDIR}/man ${.CURDIR}/src
@@ -20,7 +20,8 @@ LIB= fido2
SRCS= aes256.c assert.c authkey.c bio.c blob.c buf.c cbor.c compress.c
SRCS+= config.c cred.c credman.c dev.c ecdh.c eddsa.c err.c es256.c
SRCS+= hid.c hid_openbsd.c hid_unix.c info.c io.c iso7816.c largeblob.c
-SRCS+= log.c pin.c random.c reset.c rs256.c u2f.c
+SRCS+= log.c nfc.c pin.c random.c reset.c rs1.c rs256.c time.c touch.c
+SRCS+= tpm.c types.c u2f.c util.c
HDRS= fido.h fido/bio.h fido/config.h fido/credman.h fido/eddsa.h fido/err.h
HDRS+= fido/es256.h fido/param.h fido/rs256.h fido/types.h
diff --git a/lib/libfido2/NEWS b/lib/libfido2/NEWS
new file mode 100644
index 00000000000..f5bd414297d
--- /dev/null
+++ b/lib/libfido2/NEWS
@@ -0,0 +1,226 @@
+* Version 1.11.0 (2022-05-03)
+ ** Experimental PCSC support; enable with -DUSE_PCSC.
+ ** Improved OpenSSL 3.0 compatibility.
+ ** Use RFC1951 raw deflate to compress CTAP 2.1 largeBlobs.
+ ** winhello: advertise "uv" instead of "clientPin".
+ ** winhello: support hmac-secret in fido_dev_get_assert().
+ ** New API calls:
+ - fido_cbor_info_maxlargeblob.
+ ** Documentation and reliability fixes.
+ ** Separate build and regress targets.
+
+* Version 1.10.0 (2022-01-17)
+ ** hid_osx: handle devices with paths > 511 bytes; gh#462.
+ ** bio: fix CTAP2 canonical CBOR encoding in fido_bio_dev_enroll_*(); gh#480.
+ ** winhello: fallback to GetTopWindow() if GetForegroundWindow() fails.
+ ** winhello: fallback to hid_win.c if webauthn.dll isn't available.
+ ** New API calls:
+ - fido_dev_info_set;
+ - fido_dev_io_handle;
+ - fido_dev_new_with_info;
+ - fido_dev_open_with_info.
+ ** Cygwin and NetBSD build fixes.
+ ** Documentation and reliability fixes.
+ ** Support for TPM 2.0 attestation of COSE_ES256 credentials.
+
+* Version 1.9.0 (2021-10-27)
+ ** Enabled NFC support on Linux.
+ ** Added OpenSSL 3.0 compatibility.
+ ** Removed OpenSSL 1.0 compatibility.
+ ** Support for FIDO 2.1 "minPinLength" extension.
+ ** Support for COSE_EDDSA, COSE_ES256, and COSE_RS1 attestation.
+ ** Support for TPM 2.0 attestation.
+ ** Support for device timeouts; see fido_dev_set_timeout().
+ ** New API calls:
+ - es256_pk_from_EVP_PKEY;
+ - fido_cred_attstmt_len;
+ - fido_cred_attstmt_ptr;
+ - fido_cred_pin_minlen;
+ - fido_cred_set_attstmt;
+ - fido_cred_set_pin_minlen;
+ - fido_dev_set_pin_minlen_rpid;
+ - fido_dev_set_timeout;
+ - rs256_pk_from_EVP_PKEY.
+ ** Reliability and portability fixes.
+ ** Better handling of HID devices without identification strings; gh#381.
+ ** Fixed detection of Windows's native webauthn API; gh#382.
+
+* Version 1.8.0 (2021-07-22)
+ ** Dropped 'Requires.private' entry from pkg-config file.
+ ** Better support for FIDO 2.1 authenticators.
+ ** Support for Windows's native webauthn API.
+ ** Support for attestation format 'none'.
+ ** New API calls:
+ - fido_assert_set_clientdata;
+ - fido_cbor_info_algorithm_cose;
+ - fido_cbor_info_algorithm_count;
+ - fido_cbor_info_algorithm_type;
+ - fido_cbor_info_transports_len;
+ - fido_cbor_info_transports_ptr;
+ - fido_cred_set_clientdata;
+ - fido_cred_set_id;
+ - fido_credman_set_dev_rk;
+ - fido_dev_is_winhello.
+ ** fido2-token: new -Sc option to update a resident credential.
+ ** Documentation and reliability fixes.
+ ** HID access serialisation on Linux.
+
+* Version 1.7.0 (2021-03-29)
+ ** New dependency on zlib.
+ ** Fixed musl build; gh#259.
+ ** hid_win: detect devices with vendor or product IDs > 0x7fff; gh#264.
+ ** Support for FIDO 2.1 authenticator configuration.
+ ** Support for FIDO 2.1 UV token permissions.
+ ** Support for FIDO 2.1 "credBlobs" and "largeBlobs" extensions.
+ ** New API calls:
+ - fido_assert_blob_len;
+ - fido_assert_blob_ptr;
+ - fido_assert_largeblob_key_len;
+ - fido_assert_largeblob_key_ptr;
+ - fido_assert_set_hmac_secret;
+ - fido_cbor_info_maxcredbloblen;
+ - fido_cred_largeblob_key_len;
+ - fido_cred_largeblob_key_ptr;
+ - fido_cred_set_blob;
+ - fido_dev_enable_entattest;
+ - fido_dev_force_pin_change;
+ - fido_dev_has_uv;
+ - fido_dev_largeblob_get;
+ - fido_dev_largeblob_get_array;
+ - fido_dev_largeblob_remove;
+ - fido_dev_largeblob_set;
+ - fido_dev_largeblob_set_array;
+ - fido_dev_set_pin_minlen;
+ - fido_dev_set_sigmask;
+ - fido_dev_supports_credman;
+ - fido_dev_supports_permissions;
+ - fido_dev_supports_uv;
+ - fido_dev_toggle_always_uv.
+ ** New fido_init flag to disable fido_dev_open's U2F fallback; gh#282.
+ ** Experimental NFC support on Linux; enable with -DNFC_LINUX.
+
+* Version 1.6.0 (2020-12-22)
+ ** Fix OpenSSL 1.0 and Cygwin builds.
+ ** hid_linux: fix build on 32-bit systems.
+ ** hid_osx: allow reads from spawned threads.
+ ** Documentation and reliability fixes.
+ ** New API calls:
+ - fido_cred_authdata_raw_len;
+ - fido_cred_authdata_raw_ptr;
+ - fido_cred_sigcount;
+ - fido_dev_get_uv_retry_count;
+ - fido_dev_supports_credman.
+ ** Hardened Windows build.
+ ** Native FreeBSD and NetBSD support.
+ ** Use CTAP2 canonical CBOR when combining hmac-secret and credProtect.
+
+* Version 1.5.0 (2020-09-01)
+ ** hid_linux: return FIDO_OK if no devices are found.
+ ** hid_osx:
+ - repair communication with U2F tokens, gh#166;
+ - reliability fixes.
+ ** fido2-{assert,cred}: new options to explicitly toggle UP, UV.
+ ** Support for configurable report lengths.
+ ** New API calls:
+ - fido_cbor_info_maxcredcntlst;
+ - fido_cbor_info_maxcredidlen;
+ - fido_cred_aaguid_len;
+ - fido_cred_aaguid_ptr;
+ - fido_dev_get_touch_begin;
+ - fido_dev_get_touch_status.
+ ** Use COSE_ECDH_ES256 with CTAP_CBOR_CLIENT_PIN; gh#154.
+ ** Allow CTAP messages up to 2048 bytes; gh#171.
+ ** Ensure we only list USB devices by default.
+
+* Version 1.4.0 (2020-04-15)
+ ** hid_hidapi: hidapi backend; enable with -DUSE_HIDAPI=1.
+ ** Fall back to U2F if the key claims to, but does not support FIDO2.
+ ** FIDO2 credential protection (credprot) support.
+ ** New API calls:
+ - fido_cbor_info_fwversion;
+ - fido_cred_prot;
+ - fido_cred_set_prot;
+ - fido_dev_set_transport_functions;
+ - fido_set_log_handler.
+ ** Support for FreeBSD.
+ ** Support for C++.
+ ** Support for MSYS.
+ ** Fixed EdDSA and RSA self-attestation.
+
+* Version 1.3.1 (2020-02-19)
+ ** fix zero-ing of le1 and le2 when talking to a U2F device.
+ ** dropping sk-libfido2 middleware, please find it in the openssh tree.
+
+* Version 1.3.0 (2019-11-28)
+ ** assert/hmac: encode public key as per spec, gh#60.
+ ** fido2-cred: fix creation of resident keys.
+ ** fido2-{assert,cred}: support for hmac-secret extension.
+ ** hid_osx: detect device removal, gh#56.
+ ** hid_osx: fix device detection in MacOS Catalina.
+ ** New API calls:
+ - fido_assert_set_authdata_raw;
+ - fido_assert_sigcount;
+ - fido_cred_set_authdata_raw;
+ - fido_dev_cancel.
+ ** Middleware library for use by OpenSSH.
+ ** Support for biometric enrollment.
+ ** Support for OpenBSD.
+ ** Support for self-attestation.
+
+* Version 1.2.0 (released 2019-07-26)
+ ** Credential management support.
+ ** New API reflecting FIDO's 3-state booleans (true, false, absent):
+ - fido_assert_set_up;
+ - fido_assert_set_uv;
+ - fido_cred_set_rk;
+ - fido_cred_set_uv.
+ ** Command-line tools for Windows.
+ ** Documentation and reliability fixes.
+ ** fido_{assert,cred}_set_options() are now marked as deprecated.
+
+* Version 1.1.0 (released 2019-05-08)
+ ** MacOS: fix IOKit crash on HID read.
+ ** Windows: fix contents of release file.
+ ** EdDSA (Ed25519) support.
+ ** fido_dev_make_cred: fix order of CBOR map keys.
+ ** fido_dev_get_assert: plug memory leak when operating on U2F devices.
+
+* Version 1.0.0 (released 2019-03-21)
+ ** Native HID support on Linux, MacOS, and Windows.
+ ** fido2-{assert,cred}: new -u option to force U2F on dual authenticators.
+ ** fido2-assert: support for multiple resident keys with the same RP.
+ ** Strict checks for CTAP2 compliance on received CBOR payloads.
+ ** Better fuzzing harnesses.
+ ** Documentation and reliability fixes.
+
+* Version 0.4.0 (released 2019-01-07)
+ ** fido2-assert: print the user id for resident credentials.
+ ** Fix encoding of COSE algorithms when making a credential.
+ ** Rework purpose of fido_cred_set_type; no ABI change.
+ ** Minor documentation and code fixes.
+
+* Version 0.3.0 (released 2018-09-11)
+ ** Various reliability fixes.
+ ** Merged fuzzing instrumentation.
+ ** Added regress tests.
+ ** Added support for FIDO 2's hmac-secret extension.
+ ** New API calls:
+ - fido_assert_hmac_secret_len;
+ - fido_assert_hmac_secret_ptr;
+ - fido_assert_set_extensions;
+ - fido_assert_set_hmac_salt;
+ - fido_cred_set_extensions;
+ - fido_dev_force_fido2.
+ ** Support for native builds with Microsoft Visual Studio 17.
+
+* Version 0.2.0 (released 2018-06-20)
+ ** Added command-line tools.
+ ** Added a couple of missing get functions.
+
+* Version 0.1.1 (released 2018-06-05)
+ ** Added documentation.
+ ** Added OpenSSL 1.0 support.
+ ** Minor fixes.
+
+* Version 0.1.0 (released 2018-05-18)
+ ** First beta release.
diff --git a/lib/libfido2/README.openbsd b/lib/libfido2/README.openbsd
index 90f48bcae32..7b632008281 100644
--- a/lib/libfido2/README.openbsd
+++ b/lib/libfido2/README.openbsd
@@ -1,4 +1,4 @@
-This is an import of https://github.com/Yubico/libfido2 1.8.0 (20210722)
+This is an import of https://github.com/Yubico/libfido2 1.11.0 (2022-05-03)
Local changes:
diff --git a/lib/libfido2/man/eddsa_pk_new.3 b/lib/libfido2/man/eddsa_pk_new.3
index 09dacc7d750..8a956b29285 100644
--- a/lib/libfido2/man/eddsa_pk_new.3
+++ b/lib/libfido2/man/eddsa_pk_new.3
@@ -2,7 +2,7 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: February 7 2020 $
+.Dd $Mdocdate: August 29 2022 $
.Dt EDDSA_PK_NEW 3
.Os
.Sh NAME
@@ -11,7 +11,7 @@
.Nm eddsa_pk_from_EVP_PKEY ,
.Nm eddsa_pk_from_ptr ,
.Nm eddsa_pk_to_EVP_PKEY
-.Nd FIDO 2 COSE EDDSA API
+.Nd FIDO2 COSE EDDSA API
.Sh SYNOPSIS
.In openssl/evp.h
.In fido/eddsa.h
@@ -106,7 +106,7 @@ If an error occurs,
returns NULL.
.Sh RETURN VALUES
The
-.Fn eddsa_pk_from_EC_KEY
+.Fn eddsa_pk_from_EVP_PKEY
and
.Fn eddsa_pk_from_ptr
functions return
diff --git a/lib/libfido2/man/es256_pk_new.3 b/lib/libfido2/man/es256_pk_new.3
index 6f46e0d813c..0bfd0344d9c 100644
--- a/lib/libfido2/man/es256_pk_new.3
+++ b/lib/libfido2/man/es256_pk_new.3
@@ -1,17 +1,18 @@
-.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\" Copyright (c) 2018-2021 Yubico AB. All rights reserved.
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: February 7 2020 $
+.Dd $Mdocdate: August 29 2022 $
.Dt ES256_PK_NEW 3
.Os
.Sh NAME
.Nm es256_pk_new ,
.Nm es256_pk_free ,
.Nm es256_pk_from_EC_KEY ,
+.Nm es256_pk_from_EVP_PKEY ,
.Nm es256_pk_from_ptr ,
.Nm es256_pk_to_EVP_PKEY
-.Nd FIDO 2 COSE ES256 API
+.Nd FIDO2 COSE ES256 API
.Sh SYNOPSIS
.In openssl/ec.h
.In fido/es256.h
@@ -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_PKEY
+function fills
+.Fa pk
+with the contents of
+.Fa pkey .
+No references to
+.Fa pkey
+are kept.
+.Pp
+The
.Fn es256_pk_from_ptr
function fills
.Fa pk
@@ -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_PKEY ,
and
.Fn es256_pk_from_ptr
functions return
diff --git a/lib/libfido2/man/fido_assert_allow_cred.3 b/lib/libfido2/man/fido_assert_allow_cred.3
index e5b8b180a91..8beea2faa85 100644
--- a/lib/libfido2/man/fido_assert_allow_cred.3
+++ b/lib/libfido2/man/fido_assert_allow_cred.3
@@ -2,12 +2,12 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: February 7 2020 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_ASSERT_ALLOW_CRED 3
.Os
.Sh NAME
.Nm fido_assert_allow_cred
-.Nd appends a credential ID to the list of credentials allowed in an assertion
+.Nd allow a credential in a FIDO2 assertion
.Sh SYNOPSIS
.In fido.h
.Ft int
@@ -31,7 +31,7 @@ If
.Fn fido_assert_allow_cred
fails, the existing list of allowed credentials is preserved.
.Pp
-For the format of a FIDO 2 credential ID, please refer to the
+For the format of a FIDO2 credential ID, please refer to the
Web Authentication (webauthn) standard.
.Sh RETURN VALUES
The error codes returned by
diff --git a/lib/libfido2/man/fido_assert_new.3 b/lib/libfido2/man/fido_assert_new.3
index d14fd01d68e..32be4ac4efd 100644
--- a/lib/libfido2/man/fido_assert_new.3
+++ b/lib/libfido2/man/fido_assert_new.3
@@ -1,8 +1,8 @@
-.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved.
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: October 26 2021 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_ASSERT_NEW 3
.Os
.Sh NAME
@@ -31,7 +31,7 @@
.Nm fido_assert_id_len ,
.Nm fido_assert_sigcount ,
.Nm fido_assert_flags
-.Nd FIDO 2 assertion API
+.Nd FIDO2 assertion API
.Sh SYNOPSIS
.In fido.h
.Ft fido_assert_t *
@@ -85,9 +85,12 @@
.Ft uint8_t
.Fn fido_assert_flags "const fido_assert_t *assert" "size_t idx"
.Sh DESCRIPTION
-FIDO 2 assertions are abstracted in
-.Em libfido2
-by the
+A FIDO2 assertion is a collection of statements, each statement a
+map between a challenge, a credential, a signature, and ancillary
+attributes.
+In
+.Em libfido2 ,
+a FIDO2 assertion is abstracted by the
.Vt fido_assert_t
type.
The functions described in this page allow a
@@ -153,47 +156,63 @@ If not NULL, the values returned by these functions point to
NUL-terminated UTF-8 strings.
.Pp
The
-.Fn fido_assert_user_id_ptr ,
.Fn fido_assert_authdata_ptr ,
-.Fn fido_assert_blob_ptr ,
-.Fn fido_assert_hmac_secret_ptr ,
-.Fn fido_assert_largeblob_key_ptr ,
+.Fn fido_assert_clientdata_hash_ptr ,
+.Fn fido_assert_id_ptr ,
+.Fn fido_assert_user_id_ptr ,
.Fn fido_assert_sig_ptr ,
+.Fn fido_assert_sigcount ,
and
-.Fn fido_assert_id_ptr
-functions return pointers to the user ID, CBOR-encoded
-authenticator data, cred blob, hmac-secret,
-.Dq largeBlobKey ,
-signature, and credential ID attributes of statement
+.Fn fido_assert_flags
+functions return pointers to the CBOR-encoded authenticator data,
+client data hash, credential ID, user ID, signature, signature
+count, and authenticator data flags of statement
.Fa idx
in
.Fa assert .
.Pp
The
-.Fn fido_assert_user_id_len ,
-.Fn fido_assert_authdata_len ,
-.Fn fido_assert_blob_len ,
-.Fn fido_assert_hmac_secret_len ,
-.Fn fido_assert_largeblob_key_len ,
-.Fn fido_assert_sig_len ,
-and
-.Fn fido_assert_id_len
-functions can be used to retrieve the corresponding length of a
-specific attribute.
-.Pp
-The
-.Fn fido_assert_sigcount
-function can be used to obtain the signature counter of statement
+.Fn fido_assert_hmac_secret_ptr
+function returns a pointer to the hmac-secret attribute of statement
.Fa idx
in
.Fa assert .
+The HMAC Secret Extension
+.Pq hmac-secret
+is a CTAP 2.0 extension.
+Note that the resulting hmac-secret varies according to whether
+user verification was performed by the authenticator.
.Pp
The
-.Fn fido_assert_flags
-function returns the authenticator data flags of statement
+.Fn fido_assert_blob_ptr
+and
+.Fn fido_assert_largeblob_key_ptr
+functions return pointers to the
+.Dq credBlob
+and
+.Dq largeBlobKey
+attributes of statement
.Fa idx
in
.Fa assert .
+Credential Blob
+.Pq credBlob
+and
+Large Blob Key
+.Pq largeBlobKey
+are CTAP 2.1 extensions.
+.Pp
+The
+.Fn fido_assert_authdata_len ,
+.Fn fido_assert_clientdata_hash_len ,
+.Fn fido_assert_id_len ,
+.Fn fido_assert_user_id_len ,
+.Fn fido_assert_sig_len ,
+.Fn fido_assert_hmac_secret_len ,
+.Fn fido_assert_blob_len ,
+and
+.Fn fido_assert_largeblob_key_len
+functions return the length of a given attribute.
.Pp
Please note that the first statement in
.Fa assert
@@ -202,31 +221,27 @@ has an
(index) value of 0.
.Pp
The authenticator data and signature parts of an assertion
-statement are typically passed to a FIDO 2 server for verification.
-.Pp
-The
-.Fn fido_assert_clientdata_hash_ptr
-function returns a pointer to the client data hash of
-.Fa assert .
-The corresponding length can be obtained by
-.Fn fido_assert_clientdata_hash_len .
+statement are typically passed to a FIDO2 server for verification.
.Sh RETURN VALUES
The authenticator data returned by
.Fn fido_assert_authdata_ptr
is a CBOR-encoded byte string, as obtained from the authenticator.
.Pp
The
+.Fn fido_assert_rp_id ,
.Fn fido_assert_user_display_name ,
.Fn fido_assert_user_icon ,
.Fn fido_assert_user_name ,
.Fn fido_assert_authdata_ptr ,
.Fn fido_assert_clientdata_hash_ptr ,
-.Fn fido_assert_hmac_secret_ptr ,
-.Fn fido_assert_largeblob_key_ptr ,
+.Fn fido_assert_id_ptr ,
.Fn fido_assert_user_id_ptr ,
+.Fn fido_assert_sig_ptr ,
+.Fn fido_assert_hmac_secret_ptr ,
+.Fn fido_assert_blob_ptr ,
and
-.Fn fido_assert_sig_ptr
-functions return NULL if the respective field in
+.Fn fido_assert_largeblob_key_ptr
+functions may return NULL if the respective field in
.Fa assert
is not set.
If not NULL, returned pointers are guaranteed to exist until any API
diff --git a/lib/libfido2/man/fido_assert_set_authdata.3 b/lib/libfido2/man/fido_assert_set_authdata.3
index b5d070f5f1f..d4ee263439d 100644
--- a/lib/libfido2/man/fido_assert_set_authdata.3
+++ b/lib/libfido2/man/fido_assert_set_authdata.3
@@ -1,8 +1,8 @@
-.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved.
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: October 26 2021 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_ASSERT_SET_AUTHDATA 3
.Os
.Sh NAME
@@ -18,7 +18,7 @@
.Nm fido_assert_set_uv ,
.Nm fido_assert_set_rp ,
.Nm fido_assert_set_sig
-.Nd set parameters of a FIDO 2 assertion
+.Nd set parameters of a FIDO2 assertion
.Sh SYNOPSIS
.In fido.h
.Bd -literal
@@ -29,9 +29,9 @@ typedef enum {
} fido_opt_t;
.Ed
.Ft int
-.Fn fido_assert_set_authdata "fido_assert_t *assert" " size_t idx" "const unsigned char *ptr" "size_t len"
+.Fn fido_assert_set_authdata "fido_assert_t *assert" "size_t idx" "const unsigned char *ptr" "size_t len"
.Ft int
-.Fn fido_assert_set_authdata_raw "fido_assert_t *assert" " size_t idx" "const unsigned char *ptr" "size_t len"
+.Fn fido_assert_set_authdata_raw "fido_assert_t *assert" "size_t idx" "const unsigned char *ptr" "size_t len"
.Ft int
.Fn fido_assert_set_clientdata "fido_assert_t *assert" "const unsigned char *ptr" "size_t len"
.Ft int
@@ -43,7 +43,7 @@ typedef enum {
.Ft int
.Fn fido_assert_set_hmac_salt "fido_assert_t *assert" "const unsigned char *ptr" "size_t len"
.Ft int
-.Fn fido_assert_set_hmac_secret "fido_assert_t *assert" "const unsigned char *ptr" "size_t len"
+.Fn fido_assert_set_hmac_secret "fido_assert_t *assert" "size_t idx" "const unsigned char *ptr" "size_t len"
.Ft int
.Fn fido_assert_set_up "fido_assert_t *assert" "fido_opt_t up"
.Ft int
@@ -55,14 +55,14 @@ typedef enum {
.Sh DESCRIPTION
The
.Nm
-set of functions define the various parameters of a FIDO 2
+set of functions define the various parameters of a FIDO2
assertion, allowing a
.Fa fido_assert_t
type to be prepared for a subsequent call to
.Xr fido_dev_get_assert 3
or
.Xr fido_assert_verify 3 .
-For the complete specification of a FIDO 2 assertion and the format
+For the complete specification of a FIDO2 assertion and the format
of its constituent parts, please refer to the Web Authentication
(webauthn) standard.
.Pp
@@ -106,11 +106,8 @@ Alternatively, a raw binary blob may be passed to
.Fn fido_assert_set_authdata_raw .
.Pp
The
-.Fn fido_assert_set_clientdata_hash ,
-.Fn fido_assert_set_hmac_salt ,
-and
-.Fn fido_assert_set_hmac_secret
-functions set the client data hash and hmac-salt parts of
+.Fn fido_assert_set_clientdata_hash
+function sets the client data hash of
.Fa assert
to
.Fa ptr ,
@@ -167,6 +164,31 @@ is zero, the extensions of
are cleared.
.Pp
The
+.Fn fido_assert_set_hmac_salt
+and
+.Fn fido_assert_set_hmac_secret
+functions set the hmac-salt and hmac-secret parts of
+.Fa assert
+to
+.Fa ptr ,
+where
+.Fa ptr
+points to
+.Fa len
+bytes.
+A copy of
+.Fa ptr
+is made, and no references to the passed pointer are kept.
+The HMAC Secret
+.Pq hmac-secret
+Extension is a CTAP 2.0 extension.
+Note that the resulting hmac-secret varies according to whether
+user verification was performed by the authenticator.
+The
+.Fn fido_assert_set_hmac_secret
+function is normally only useful when writing tests.
+.Pp
+The
.Fn fido_assert_set_up
and
.Fn fido_assert_set_uv
@@ -184,27 +206,22 @@ by default, allowing the authenticator to use its default settings.
Use of the
.Nm
set of functions may happen in two distinct situations:
-when asking a FIDO device to produce a series of assertion
+when asking a FIDO2 device to produce a series of assertion
statements, prior to
.Xr fido_dev_get_assert 3
-(i.e, in the context of a FIDO client), or when verifying assertion
+(i.e, in the context of a FIDO2 client), or when verifying assertion
statements using
.Xr fido_assert_verify 3
-(i.e, in the context of a FIDO server).
+(i.e, in the context of a FIDO2 server).
.Pp
-For a complete description of the generation of a FIDO 2 assertion
-and its verification, please refer to the FIDO 2 specification.
+For a complete description of the generation of a FIDO2 assertion
+and its verification, please refer to the FIDO2 specification.
An example of how to use the
.Nm
set of functions can be found in the
.Pa examples/assert.c
file shipped with
.Em libfido2 .
-.Pp
-.Fn fido_assert_set_hmac_secret
-is not normally useful in a FIDO client or server \(em it is provided
-to enable testing other functionality that relies on retrieving the
-HMAC secret from an assertion obtained from an authenticator.
.Sh RETURN VALUES
The
.Nm
diff --git a/lib/libfido2/man/fido_assert_verify.3 b/lib/libfido2/man/fido_assert_verify.3
index 04380b224d6..1e004b9a218 100644
--- a/lib/libfido2/man/fido_assert_verify.3
+++ b/lib/libfido2/man/fido_assert_verify.3
@@ -2,16 +2,16 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: February 7 2020 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_ASSERT_VERIFY 3
.Os
.Sh NAME
.Nm fido_assert_verify
-.Nd verifies the signature of a FIDO 2 assertion statement
+.Nd verifies the signature of a FIDO2 assertion statement
.Sh SYNOPSIS
.In fido.h
.Ft int
-.Fn fido_assert_verify "fido_assert_t *assert" "size_t idx" "int cose_alg" "const void *pk"
+.Fn fido_assert_verify "const fido_assert_t *assert" "size_t idx" "int cose_alg" "const void *pk"
.Sh DESCRIPTION
The
.Fn fido_assert_verify
@@ -23,7 +23,7 @@ matches the parameters of the assertion.
Before using
.Fn fido_assert_verify
in a sensitive context, the reader is strongly encouraged to make
-herself familiar with the FIDO 2 assertion statement process
+herself familiar with the FIDO2 assertion statement process
as defined in the Web Authentication (webauthn) standard.
.Pp
A brief description follows:
diff --git a/lib/libfido2/man/fido_bio_dev_get_info.3 b/lib/libfido2/man/fido_bio_dev_get_info.3
index df0fb692514..1054ff7fed2 100644
--- a/lib/libfido2/man/fido_bio_dev_get_info.3
+++ b/lib/libfido2/man/fido_bio_dev_get_info.3
@@ -2,7 +2,7 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: October 26 2021 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_BIO_DEV_GET_INFO 3
.Os
.Sh NAME
@@ -13,7 +13,7 @@
.Nm fido_bio_dev_enroll_remove ,
.Nm fido_bio_dev_get_template_array ,
.Nm fido_bio_dev_set_template_name
-.Nd FIDO 2 biometric authenticator API
+.Nd FIDO2 biometric authenticator API
.Sh SYNOPSIS
.In fido.h
.In fido/bio.h
diff --git a/lib/libfido2/man/fido_bio_enroll_new.3 b/lib/libfido2/man/fido_bio_enroll_new.3
index 603421abcdf..d5f488905af 100644
--- a/lib/libfido2/man/fido_bio_enroll_new.3
+++ b/lib/libfido2/man/fido_bio_enroll_new.3
@@ -2,7 +2,7 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: February 7 2020 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_BIO_ENROLL_NEW 3
.Os
.Sh NAME
@@ -10,7 +10,7 @@
.Nm fido_bio_enroll_free ,
.Nm fido_bio_enroll_last_status ,
.Nm fido_bio_enroll_remaining_samples
-.Nd FIDO 2 biometric enrollment API
+.Nd FIDO2 biometric enrollment API
.Sh SYNOPSIS
.In fido.h
.In fido/bio.h
@@ -40,7 +40,7 @@
.Ft uint8_t
.Fn fido_bio_enroll_remaining_samples "const fido_bio_enroll_t *enroll"
.Sh DESCRIPTION
-Ongoing FIDO 2 biometric enrollments are abstracted in
+Ongoing FIDO2 biometric enrollments are abstracted in
.Em libfido2
by the
.Vt fido_bio_enroll_t
diff --git a/lib/libfido2/man/fido_bio_info_new.3 b/lib/libfido2/man/fido_bio_info_new.3
index 5712db298f6..41320365b07 100644
--- a/lib/libfido2/man/fido_bio_info_new.3
+++ b/lib/libfido2/man/fido_bio_info_new.3
@@ -2,7 +2,7 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: February 7 2020 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_BIO_INFO_NEW 3
.Os
.Sh NAME
@@ -10,7 +10,7 @@
.Nm fido_bio_info_free ,
.Nm fido_bio_info_type ,
.Nm fido_bio_info_max_samples
-.Nd FIDO 2 biometric sensor information API
+.Nd FIDO2 biometric sensor information API
.Sh SYNOPSIS
.In fido.h
.In fido/bio.h
diff --git a/lib/libfido2/man/fido_bio_template.3 b/lib/libfido2/man/fido_bio_template.3
index da012b4fb2c..603747458e2 100644
--- a/lib/libfido2/man/fido_bio_template.3
+++ b/lib/libfido2/man/fido_bio_template.3
@@ -2,7 +2,7 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: October 26 2021 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_BIO_TEMPLATE 3
.Os
.Sh NAME
@@ -17,7 +17,7 @@
.Nm fido_bio_template_new ,
.Nm fido_bio_template_set_id ,
.Nm fido_bio_template_set_name
-.Nd FIDO 2 biometric template API
+.Nd FIDO2 biometric template API
.Sh SYNOPSIS
.In fido.h
.In fido/bio.h
@@ -44,7 +44,7 @@
.Ft const fido_bio_template_t *
.Fn fido_bio_template "const fido_bio_template_array_t *array" "size_t idx"
.Sh DESCRIPTION
-Existing FIDO 2 biometric enrollments are abstracted in
+Existing FIDO2 biometric enrollments are abstracted in
.Em libfido2
by the
.Vt fido_bio_template_t
diff --git a/lib/libfido2/man/fido_cbor_info_new.3 b/lib/libfido2/man/fido_cbor_info_new.3
index 93a4affd426..b70249aea6b 100644
--- a/lib/libfido2/man/fido_cbor_info_new.3
+++ b/lib/libfido2/man/fido_cbor_info_new.3
@@ -1,8 +1,8 @@
-.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\" Copyright (c) 2018-2022 Yubico AB. All rights reserved.
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: October 26 2021 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_CBOR_INFO_NEW 3
.Os
.Sh NAME
@@ -26,10 +26,12 @@
.Nm fido_cbor_info_versions_len ,
.Nm fido_cbor_info_options_len ,
.Nm fido_cbor_info_maxmsgsiz ,
+.Nm fido_cbor_info_maxcredbloblen ,
.Nm fido_cbor_info_maxcredcntlst ,
.Nm fido_cbor_info_maxcredidlen ,
+.Nm fido_cbor_info_maxlargeblob ,
.Nm fido_cbor_info_fwversion
-.Nd FIDO 2 CBOR Info API
+.Nd FIDO2 CBOR Info API
.Sh SYNOPSIS
.In fido.h
.Ft fido_cbor_info_t *
@@ -79,6 +81,8 @@
.Ft uint64_t
.Fn fido_cbor_info_maxcredidlen "const fido_cbor_info_t *ci"
.Ft uint64_t
+.Fn fido_cbor_info_maxlargeblob "const fido_cbor_info_t *ci"
+.Ft uint64_t
.Fn fido_cbor_info_fwversion "const fido_cbor_info_t *ci"
.Sh DESCRIPTION
The
@@ -200,6 +204,12 @@ as reported in
.Fa ci .
.Pp
The
+.Fn fido_cbor_info_maxlargeblob
+function returns the maximum length in bytes of an authenticator's
+serialized largeBlob array as reported in
+.Fa ci .
+.Pp
+The
.Fn fido_cbor_info_fwversion
function returns the firmware version attribute of
.Fa ci .
diff --git a/lib/libfido2/man/fido_cred_exclude.3 b/lib/libfido2/man/fido_cred_exclude.3
index d27c0aabc8b..f42411cf9cf 100644
--- a/lib/libfido2/man/fido_cred_exclude.3
+++ b/lib/libfido2/man/fido_cred_exclude.3
@@ -2,7 +2,7 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: February 7 2020 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_CRED_EXCLUDE 3
.Os
.Sh NAME
@@ -44,7 +44,7 @@ then
.Xr fido_dev_make_cred 3
will fail.
.Pp
-For the format of a FIDO 2 credential ID, please refer to the
+For the format of a FIDO2 credential ID, please refer to the
Web Authentication (webauthn) standard.
.Sh RETURN VALUES
The error codes returned by
diff --git a/lib/libfido2/man/fido_cred_new.3 b/lib/libfido2/man/fido_cred_new.3
index f78f6a6f04c..6e25c25ba0e 100644
--- a/lib/libfido2/man/fido_cred_new.3
+++ b/lib/libfido2/man/fido_cred_new.3
@@ -1,13 +1,14 @@
-.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\" Copyright (c) 2018-2021 Yubico AB. All rights reserved.
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: October 26 2021 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_CRED_NEW 3
.Os
.Sh NAME
.Nm fido_cred_new ,
.Nm fido_cred_free ,
+.Nm fido_cred_pin_minlen ,
.Nm fido_cred_prot ,
.Nm fido_cred_fmt ,
.Nm fido_cred_rp_id ,
@@ -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,18 +36,21 @@
.Nm fido_cred_sig_len ,
.Nm fido_cred_user_id_len ,
.Nm fido_cred_x5c_len ,
+.Nm fido_cred_attstmt_len ,
.Nm fido_cred_type ,
.Nm fido_cred_flags ,
.Nm fido_cred_sigcount
-.Nd FIDO 2 credential API
+.Nd FIDO2 credential API
.Sh SYNOPSIS
.In fido.h
.Ft fido_cred_t *
.Fn fido_cred_new "void"
.Ft void
.Fn fido_cred_free "fido_cred_t **cred_p"
+.Ft size_t
+.Fn fido_cred_pin_minlen "const fido_cred_t *cred"
.Ft int
-.Fn fido_cred_prot "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
@@ -103,7 +112,7 @@
.Ft uint32_t
.Fn fido_cred_sigcount "const fido_cred_t *cred"
.Sh DESCRIPTION
-FIDO 2 credentials are abstracted in
+FIDO2 credentials are abstracted in
.Em libfido2
by the
.Vt fido_cred_t
@@ -146,13 +155,35 @@ may be NULL, in which case
.Fn fido_cred_free
is a NOP.
.Pp
-The
+If the CTAP 2.1
+.Dv FIDO_EXT_MINPINLEN
+extension is enabled on
+.Fa cred ,
+then the
+.Fn fido_cred_pin_minlen
+function returns the minimum PIN length of
+.Fa cred .
+Otherwise,
+.Fn fido_cred_pin_minlen
+returns zero.
+See
+.Xr fido_cred_set_pin_minlen 3
+on how to enable this extension.
+.Pp
+If the CTAP 2.1
+.Dv FIDO_EXT_CRED_PROTECT
+extension is enabled on
+.Fa cred ,
+then the
.Fn fido_cred_prot
function returns the protection of
.Fa cred .
+Otherwise,
+.Fn fido_cred_prot
+returns zero.
See
.Xr fido_cred_set_prot 3
-for the 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,11 +238,12 @@ 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.
+credential are typically passed to a FIDO2 server for verification.
.Pp
The
.Fn fido_cred_type
@@ -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 ,
diff --git a/lib/libfido2/man/fido_cred_set_authdata.3 b/lib/libfido2/man/fido_cred_set_authdata.3
index dea4b7dec0a..39359e9a45c 100644
--- a/lib/libfido2/man/fido_cred_set_authdata.3
+++ b/lib/libfido2/man/fido_cred_set_authdata.3
@@ -1,13 +1,14 @@
-.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\" Copyright (c) 2018-2021 Yubico AB. All rights reserved.
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: October 26 2021 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_CRED_SET_AUTHDATA 3
.Os
.Sh NAME
.Nm fido_cred_set_authdata ,
.Nm fido_cred_set_authdata_raw ,
+.Nm fido_cred_set_attstmt ,
.Nm fido_cred_set_x509 ,
.Nm fido_cred_set_sig ,
.Nm fido_cred_set_id ,
@@ -17,12 +18,13 @@
.Nm fido_cred_set_user ,
.Nm fido_cred_set_extensions ,
.Nm fido_cred_set_blob ,
+.Nm fido_cred_set_pin_minlen ,
.Nm fido_cred_set_prot ,
.Nm fido_cred_set_rk ,
.Nm fido_cred_set_uv ,
.Nm fido_cred_set_fmt ,
.Nm fido_cred_set_type
-.Nd set parameters of a FIDO 2 credential
+.Nd set parameters of a FIDO2 credential
.Sh SYNOPSIS
.In fido.h
.Bd -literal
@@ -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"
@@ -67,26 +73,28 @@ typedef enum {
.Sh DESCRIPTION
The
.Nm
-set of functions define the various parameters of a FIDO 2
+set of functions define the various parameters of a FIDO2
credential, allowing a
.Fa fido_cred_t
type to be prepared for a subsequent call to
.Xr fido_dev_make_cred 3
or
.Xr fido_cred_verify 3 .
-For the complete specification of a FIDO 2 credential and the format
+For the complete specification of a FIDO2 credential and the format
of its constituent parts, please refer to the Web Authentication
(webauthn) standard.
.Pp
The
.Fn fido_cred_set_authdata ,
+.Fn fido_cred_set_attstmt ,
.Fn fido_cred_set_x509 ,
.Fn fido_cred_set_sig ,
.Fn fido_cred_set_id ,
and
.Fn fido_cred_set_clientdata_hash
-functions set the authenticator data, attestation 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 CTAP 2.1
+.Dv FIDO_EXT_MINPINLEN
+extension on
+.Fa cred
+and sets the expected minimum PIN length of
+.Fa cred
+to
+.Fa len ,
+where
+.Fa len
+is greater than zero.
+If
+.Fa len
+is zero, the
+.Dv FIDO_EXT_MINPINLEN
+extension is disabled on
+.Fa cred .
+.Pp
+The
.Fn fido_cred_set_prot
-function sets the protection of
+function enables the CTAP 2.1
+.Dv FIDO_EXT_CRED_PROTECT
+extension on
+.Fa cred
+and sets the protection of
.Fa cred
to the scalar
.Fa prot .
@@ -278,15 +325,15 @@ Note that not all authenticators support COSE_RS256 or COSE_EDDSA.
Use of the
.Nm
set of functions may happen in two distinct situations:
-when generating a new credential on a FIDO device, prior to
+when generating a new credential on a FIDO2 device, prior to
.Xr fido_dev_make_cred 3
-(i.e, in the context of a FIDO client), or when validating
+(i.e, in the context of a FIDO2 client), or when validating
a generated credential using
.Xr fido_cred_verify 3
-(i.e, in the context of a FIDO server).
+(i.e, in the context of a FIDO2 server).
.Pp
-For a complete description of the generation of a FIDO 2 credential
-and its verification, please refer to the FIDO 2 specification.
+For a complete description of the generation of a FIDO2 credential
+and its verification, please refer to the FIDO2 specification.
A concrete utilisation example of the
.Nm
set of functions can be found in the
diff --git a/lib/libfido2/man/fido_cred_verify.3 b/lib/libfido2/man/fido_cred_verify.3
index 47c14948e94..9db299e64cf 100644
--- a/lib/libfido2/man/fido_cred_verify.3
+++ b/lib/libfido2/man/fido_cred_verify.3
@@ -1,36 +1,41 @@
-.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\" Copyright (c) 2018-2021 Yubico AB. All rights reserved.
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: October 26 2021 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_CRED_VERIFY 3
.Os
.Sh NAME
-.Nm fido_cred_verify
-.Nd verifies the attestation signature of a FIDO 2 credential
+.Nm fido_cred_verify ,
+.Nm fido_cred_verify_self
+.Nd verify the attestation signature of a FIDO2 credential
.Sh SYNOPSIS
.In fido.h
.Ft int
.Fn fido_cred_verify "const fido_cred_t *cred"
+.Ft int
+.Fn fido_cred_verify_self "const fido_cred_t *cred"
.Sh DESCRIPTION
The
.Fn fido_cred_verify
-function verifies whether the attestation signature contained in
+and
+.Fn fido_cred_verify_self
+functions verify whether the attestation signature contained in
.Fa cred
matches the attributes of the credential.
Before using
.Fn fido_cred_verify
+or
+.Fn fido_cred_verify_self
in a sensitive context, the reader is strongly encouraged to make
-herself familiar with the FIDO 2 credential attestation process
+herself familiar with the FIDO2 credential attestation process
as defined in the Web Authentication (webauthn) standard.
.Pp
-A brief description follows:
-.Pp
The
.Fn fido_cred_verify
function verifies whether the client data hash, relying party ID,
-credential ID, type, and resident/discoverable key and user verification
-attributes of
+credential ID, type, protection policy, minimum PIN length, and
+resident/discoverable key and user verification attributes of
.Fa cred
have been attested by the holder of the private counterpart of
the public key contained in the credential's x509 certificate.
@@ -40,27 +45,44 @@ 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.
+.Pp
+The
+.Fn fido_cred_verify_self
+function verifies whether the client data hash, relying party ID,
+credential ID, type, protection policy, minimum PIN length, and
+resident/discoverable key and user verification attributes of
+.Fa cred
+have been attested by the holder of the credential's private key.
+.Pp
+The attestation statement formats supported by
+.Fn fido_cred_verify_self
+are
+.Em packed
+and
+.Em fido-u2f .
+The attestation type implemented by
+.Fn fido_cred_verify_self
+is
+.Em Self Attestation .
+.Pp
Other attestation formats and types are not supported.
.Sh RETURN VALUES
The error codes returned by
.Fn fido_cred_verify
+and
+.Fn fido_cred_verify_self
are defined in
.In fido/err.h .
If
.Fa cred
-does not contain attestation data, then
-.Dv FIDO_ERR_INVALID_ARGUMENT
-is returned.
-If
-.Fa cred
passes verification, then
.Dv FIDO_OK
is returned.
diff --git a/lib/libfido2/man/fido_credman_metadata_new.3 b/lib/libfido2/man/fido_credman_metadata_new.3
index 7fb310909fd..a414b44c8b0 100644
--- a/lib/libfido2/man/fido_credman_metadata_new.3
+++ b/lib/libfido2/man/fido_credman_metadata_new.3
@@ -2,7 +2,7 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: October 26 2021 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_CREDMAN_METADATA_NEW 3
.Os
.Sh NAME
@@ -26,7 +26,7 @@
.Nm fido_credman_set_dev_rk ,
.Nm fido_credman_del_dev_rk ,
.Nm fido_credman_get_dev_rp
-.Nd FIDO 2 credential management API
+.Nd FIDO2 credential management API
.Sh SYNOPSIS
.In fido.h
.In fido/credman.h
@@ -307,7 +307,7 @@ The
.Fn fido_credman_set_dev_rk ,
.Fn fido_credman_del_dev_rk ,
and
-.Fn fido_credman_get_dev_rp
+.Fn fido_credman_get_dev_rp
functions return
.Dv FIDO_OK
on success.
@@ -323,4 +323,4 @@ should have their return values checked for NULL.
.Sh CAVEATS
Resident credentials are called
.Dq discoverable credentials
-in FIDO 2.1.
+in CTAP 2.1.
diff --git a/lib/libfido2/man/fido_dev_enable_entattest.3 b/lib/libfido2/man/fido_dev_enable_entattest.3
index c059fa10fd4..65acddfd3ec 100644
--- a/lib/libfido2/man/fido_dev_enable_entattest.3
+++ b/lib/libfido2/man/fido_dev_enable_entattest.3
@@ -2,15 +2,16 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: March 29 2022 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_DEV_ENABLE_ENTATTEST 3
.Os
.Sh NAME
.Nm fido_dev_enable_entattest ,
.Nm fido_dev_toggle_always_uv ,
.Nm fido_dev_force_pin_change ,
-.Nm fido_dev_set_pin_minlen
-.Nd FIDO 2.1 configuration authenticator API
+.Nm fido_dev_set_pin_minlen ,
+.Nm fido_dev_set_pin_minlen_rpid
+.Nd CTAP 2.1 configuration authenticator API
.Sh SYNOPSIS
.In fido.h
.In fido/config.h
@@ -22,9 +23,11 @@
.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.
+CTAP 2.1 authenticator.
.Pp
The
.Fn fido_dev_enable_entattest
@@ -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 CTAP 2.1
+.Dv FIDO_EXT_MINPINLEN
+extension.
+The list of RP identifiers is denoted by
+.Fa rpid ,
+a vector of
+.Fa n
+NUL-terminated UTF-8 strings.
+A copy of
+.Fa rpid
+is made, and no reference to it or its contents is kept.
+.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
diff --git a/lib/libfido2/man/fido_dev_get_assert.3 b/lib/libfido2/man/fido_dev_get_assert.3
index 3ea8157c5db..e0b7eca79d1 100644
--- a/lib/libfido2/man/fido_dev_get_assert.3
+++ b/lib/libfido2/man/fido_dev_get_assert.3
@@ -2,20 +2,20 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: February 7 2020 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_DEV_GET_ASSERT 3
.Os
.Sh NAME
.Nm fido_dev_get_assert
-.Nd obtains an assertion from a FIDO device
+.Nd obtains an assertion from a FIDO2 device
.Sh SYNOPSIS
.In fido.h
.Ft int
-.Fn fido_dev_get_assert "fido_dev_t *dev" " fido_assert_t *assert" "const char *pin"
+.Fn fido_dev_get_assert "fido_dev_t *dev" "fido_assert_t *assert" "const char *pin"
.Sh DESCRIPTION
The
.Fn fido_dev_get_assert
-function asks the FIDO device represented by
+function asks the FIDO2 device represented by
.Fa dev
for an assertion according to the following parameters defined in
.Fa assert :
diff --git a/lib/libfido2/man/fido_dev_get_touch_begin.3 b/lib/libfido2/man/fido_dev_get_touch_begin.3
index 4a9b9908cbd..3329cb27dea 100644
--- a/lib/libfido2/man/fido_dev_get_touch_begin.3
+++ b/lib/libfido2/man/fido_dev_get_touch_begin.3
@@ -2,13 +2,13 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: September 7 2020 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_DEV_GET_TOUCH_BEGIN 3
.Os
.Sh NAME
.Nm fido_dev_get_touch_begin ,
.Nm fido_dev_get_touch_status
-.Nd asynchronously wait for touch on a FIDO 2 authenticator
+.Nd asynchronously wait for touch on a FIDO2 authenticator
.Sh SYNOPSIS
.In fido.h
.Ft int
@@ -17,7 +17,7 @@
.Fn fido_dev_get_touch_status "fido_dev_t *dev" "int *touched" "int ms"
.Sh DESCRIPTION
The functions described in this page allow an application to
-asynchronously wait for touch on a FIDO authenticator.
+asynchronously wait for touch on a FIDO2 authenticator.
This is useful when multiple authenticators are present and
the application needs to know which one to use.
.Pp
diff --git a/lib/libfido2/man/fido_dev_info_manifest.3 b/lib/libfido2/man/fido_dev_info_manifest.3
index 7e0389ca621..adfb6eff098 100644
--- a/lib/libfido2/man/fido_dev_info_manifest.3
+++ b/lib/libfido2/man/fido_dev_info_manifest.3
@@ -2,7 +2,7 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: March 29 2022 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_DEV_INFO_MANIFEST 3
.Os
.Sh NAME
@@ -14,8 +14,9 @@
.Nm fido_dev_info_product ,
.Nm fido_dev_info_vendor ,
.Nm fido_dev_info_manufacturer_string ,
-.Nm fido_dev_info_product_string
-.Nd FIDO 2 device discovery functions
+.Nm fido_dev_info_product_string ,
+.Nm fido_dev_info_set
+.Nd FIDO2 device discovery functions
.Sh SYNOPSIS
.In fido.h
.Ft int
@@ -36,6 +37,8 @@
.Fn fido_dev_info_manufacturer_string "const fido_dev_info_t *di"
.Ft const char *
.Fn fido_dev_info_product_string "const fido_dev_info_t *di"
+.Ft int
+.Fn fido_dev_info_set "fido_dev_info_t *devlist" "size_t i" "const char *path" "const char *manufacturer" "const char *product" "const fido_dev_io_t *io" "const fido_dev_transport_t *transport"
.Sh DESCRIPTION
The
.Fn fido_dev_info_manifest
@@ -43,7 +46,7 @@ function fills
.Fa devlist
with up to
.Fa ilen
-FIDO devices found by the underlying operating system.
+FIDO2 devices found by the underlying operating system.
Currently only USB HID devices are supported.
The number of discovered devices is returned in
.Fa olen ,
@@ -112,17 +115,51 @@ The
.Fn fido_dev_info_manufacturer_string
function returns the manufacturer string of
.Fa di .
+If
+.Fa di
+does not have an associated manufacturer string,
+.Fn fido_dev_info_manufacturer_string
+returns an empty string.
.Pp
The
.Fn fido_dev_info_product_string
function returns the product string of
.Fa di .
+If
+.Fa di
+does not have an associated product string,
+.Fn fido_dev_info_product_string
+returns an empty string.
.Pp
An example of how to use the functions described in this document
can be found in the
.Pa examples/manifest.c
file shipped with
.Em libfido2 .
+.Pp
+The
+.Fn fido_dev_info_set
+function initializes an entry in a device list allocated by
+.Fn fido_dev_info_new
+with the specified path, manufacturer, and product strings, and with
+the specified I/O handlers and, optionally, transport functions, as
+described in
+.Xr fido_dev_set_io_functions 3 .
+The
+.Fa io
+argument must be specified; the
+.Fa transport
+argument may be
+.Dv NULL .
+The path, I/O handlers, and transport functions will be used
+automatically by
+.Xr fido_dev_new_with_info 3
+and
+.Xr fido_dev_open_with_info 3 .
+An application can use this, for example, to substitute mock FIDO2
+devices in testing for the real ones that
+.Fn fido_dev_info_manifest
+would discover.
.Sh RETURN VALUES
The
.Fn fido_dev_info_manifest
@@ -132,6 +169,14 @@ If a discovery error occurs, the
.Fa olen
pointer is set to 0.
.Pp
+On success, the
+.Fn fido_dev_info_set
+function returns
+.Dv FIDO_OK .
+On error, a different error code defined in
+.In fido/err.h
+is returned.
+.Pp
The pointers returned by
.Fn fido_dev_info_ptr ,
.Fn fido_dev_info_path ,
diff --git a/lib/libfido2/man/fido_dev_largeblob_get.3 b/lib/libfido2/man/fido_dev_largeblob_get.3
index cd9d0cce2bf..9bcfe48efe6 100644
--- a/lib/libfido2/man/fido_dev_largeblob_get.3
+++ b/lib/libfido2/man/fido_dev_largeblob_get.3
@@ -2,7 +2,7 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: October 26 2021 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_LARGEBLOB_GET 3
.Os
.Sh NAME
@@ -11,7 +11,7 @@
.Nm fido_dev_largeblob_remove ,
.Nm fido_dev_largeblob_get_array ,
.Nm fido_dev_largeblob_set_array
-.Nd FIDO 2 large blob API
+.Nd FIDO2 large blob API
.Sh SYNOPSIS
.In fido.h
.Ft int
@@ -29,10 +29,10 @@ The
.Dq largeBlobs
API of
.Em libfido2
-allows binary blobs residing on a FIDO 2.1 authenticator to be
+allows binary blobs residing on a CTAP 2.1 authenticator to be
read, written, and inspected.
.Dq largeBlobs
-is a FIDO 2.1 extension.
+is a CTAP 2.1 extension.
.Pp
.Dq largeBlobs
are stored as elements of a CBOR array.
@@ -58,9 +58,9 @@ The
.Dq largeBlobs
CBOR array is opaque to the authenticator.
Management of the array is left at the discretion of FIDO2 clients.
-For further details on FIDO 2.1's
+For further details on CTAP 2.1's
.Dq largeBlobs
-extension, please refer to the FIDO 2.1 spec.
+extension, please refer to the CTAP 2.1 spec.
.Pp
The
.Fn fido_dev_largeblob_get
diff --git a/lib/libfido2/man/fido_dev_make_cred.3 b/lib/libfido2/man/fido_dev_make_cred.3
index 158f5ea5a8e..da1d035644c 100644
--- a/lib/libfido2/man/fido_dev_make_cred.3
+++ b/lib/libfido2/man/fido_dev_make_cred.3
@@ -2,20 +2,20 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: October 26 2021 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_DEV_MAKE_CRED 3
.Os
.Sh NAME
.Nm fido_dev_make_cred
-.Nd generates a new credential on a FIDO device
+.Nd generates a new credential on a FIDO2 device
.Sh SYNOPSIS
.In fido.h
.Ft int
-.Fn fido_dev_make_cred "fido_dev_t *dev" " fido_cred_t *cred" "const char *pin"
+.Fn fido_dev_make_cred "fido_dev_t *dev" "fido_cred_t *cred" "const char *pin"
.Sh DESCRIPTION
The
.Fn fido_dev_make_cred
-function asks the FIDO device represented by
+function asks the FIDO2 device represented by
.Fa dev
to generate a new credential according to the following parameters
defined in
diff --git a/lib/libfido2/man/fido_dev_open.3 b/lib/libfido2/man/fido_dev_open.3
index def6a997941..ff6e16fe6f5 100644
--- a/lib/libfido2/man/fido_dev_open.3
+++ b/lib/libfido2/man/fido_dev_open.3
@@ -2,14 +2,16 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: October 26 2021 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_DEV_OPEN 3
.Os
.Sh NAME
.Nm fido_dev_open ,
+.Nm fido_dev_open_with_info ,
.Nm fido_dev_close ,
.Nm fido_dev_cancel ,
.Nm fido_dev_new ,
+.Nm fido_dev_new_with_info ,
.Nm fido_dev_free ,
.Nm fido_dev_force_fido2 ,
.Nm fido_dev_force_u2f ,
@@ -17,26 +19,31 @@
.Nm fido_dev_is_winhello ,
.Nm fido_dev_supports_credman ,
.Nm fido_dev_supports_cred_prot ,
+.Nm fido_dev_supports_permissions ,
.Nm fido_dev_supports_pin ,
-.Nm fido_dev_has_pin ,
.Nm fido_dev_supports_uv ,
+.Nm fido_dev_has_pin ,
.Nm fido_dev_has_uv ,
.Nm fido_dev_protocol ,
.Nm fido_dev_build ,
.Nm fido_dev_flags ,
.Nm fido_dev_major ,
.Nm fido_dev_minor
-.Nd FIDO 2 device open/close and related functions
+.Nd FIDO2 device open/close and related functions
.Sh SYNOPSIS
.In fido.h
.Ft int
.Fn fido_dev_open "fido_dev_t *dev" "const char *path"
.Ft int
+.Fn fido_dev_open_with_info "fido_dev_t *dev"
+.Ft int
.Fn fido_dev_close "fido_dev_t *dev"
.Ft int
.Fn fido_dev_cancel "fido_dev_t *dev"
.Ft fido_dev_t *
.Fn fido_dev_new "void"
+.Ft fido_dev_t *
+.Fn fido_dev_new_with_info "const fido_dev_info_t *"
.Ft void
.Fn fido_dev_free "fido_dev_t **dev_p"
.Ft void
@@ -52,12 +59,14 @@
.Ft bool
.Fn fido_dev_supports_cred_prot "const fido_dev_t *dev"
.Ft bool
-.Fn fido_dev_supports_pin "const fido_dev_t *dev"
+.Fn fido_dev_supports_permissions "const fido_dev_t *dev"
.Ft bool
-.Fn fido_dev_has_pin "const fido_dev_t *dev"
+.Fn fido_dev_supports_pin "const fido_dev_t *dev"
.Ft bool
.Fn fido_dev_supports_uv "const fido_dev_t *dev"
.Ft bool
+.Fn fido_dev_has_pin "const fido_dev_t *dev"
+.Ft bool
.Fn fido_dev_has_uv "const fido_dev_t *dev"
.Ft uint8_t
.Fn fido_dev_protocol "const fido_dev_t *dev"
@@ -92,6 +101,13 @@ flag was set in
.Xr fido_init 3 .
.Pp
The
+.Fn fido_dev_open_with_info
+function opens
+.Fa dev
+as previously allocated using
+.Fn fido_dev_new_with_info .
+.Pp
+The
.Fn fido_dev_close
function closes the device represented by
.Fa dev .
@@ -113,6 +129,18 @@ function returns a pointer to a newly allocated, empty
If memory cannot be allocated, NULL is returned.
.Pp
The
+.Fn fido_dev_new_with_info
+function returns a pointer to a newly allocated
+.Vt fido_dev_t
+with
+.Vt fido_dev_info_t
+parameters, for use with
+.Xr fido_dev_info_manifest 3
+and
+.Fn fido_dev_open_with_info .
+If memory cannot be allocated, NULL is returned.
+.Pp
+The
.Fn fido_dev_free
function releases the memory backing
.Fa *dev_p ,
@@ -134,12 +162,18 @@ is a NOP.
The
.Fn fido_dev_force_fido2
function can be used to force CTAP2 communication with
-.Fa dev .
+.Fa dev ,
+where
+.Fa dev
+is an open device.
.Pp
The
.Fn fido_dev_force_u2f
function can be used to force CTAP1 (U2F) communication with
-.Fa dev .
+.Fa dev ,
+where
+.Fa dev
+is an open device.
.Pp
The
.Fn fido_dev_is_fido2
@@ -147,7 +181,7 @@ function returns
.Dv true
if
.Fa dev
-is a FIDO 2 device.
+is a FIDO2 device.
.Pp
The
.Fn fido_dev_is_winhello
@@ -163,7 +197,7 @@ function returns
.Dv true
if
.Fa dev
-supports FIDO 2.1 Credential Management.
+supports CTAP 2.1 Credential Management.
.Pp
The
.Fn fido_dev_supports_cred_prot
@@ -171,23 +205,23 @@ function returns
.Dv true
if
.Fa dev
-supports FIDO 2.1 Credential Protection.
+supports CTAP 2.1 Credential Protection.
.Pp
The
-.Fn fido_dev_supports_pin
+.Fn fido_dev_supports_permissions
function returns
.Dv true
if
.Fa dev
-supports FIDO 2.0 Client PINs.
+supports CTAP 2.1 UV token permissions.
.Pp
The
-.Fn fido_dev_has_pin
+.Fn fido_dev_supports_pin
function returns
.Dv true
if
.Fa dev
-has a FIDO 2.0 Client PIN set.
+supports CTAP 2.0 Client PINs.
.Pp
The
.Fn fido_dev_supports_uv
@@ -198,6 +232,14 @@ if
supports a built-in user verification method.
.Pp
The
+.Fn fido_dev_has_pin
+function returns
+.Dv true
+if
+.Fa dev
+has a CTAP 2.0 Client PIN set.
+.Pp
+The
.Fn fido_dev_has_uv
function returns
.Dv true
@@ -236,7 +278,8 @@ functions above, please refer to the FIDO Client to Authenticator
Protocol (CTAP) specification.
.Sh RETURN VALUES
On success,
-.Fn fido_dev_open
+.Fn fido_dev_open ,
+.Fn fido_dev_open_with_info ,
and
.Fn fido_dev_close
return
diff --git a/lib/libfido2/man/fido_dev_set_io_functions.3 b/lib/libfido2/man/fido_dev_set_io_functions.3
index 6775b73c1da..cf0680b5024 100644
--- a/lib/libfido2/man/fido_dev_set_io_functions.3
+++ b/lib/libfido2/man/fido_dev_set_io_functions.3
@@ -1,14 +1,17 @@
-.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\" Copyright (c) 2018-2021 Yubico AB. All rights reserved.
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: October 26 2021 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_DEV_SET_IO_FUNCTIONS 3
.Os
.Sh NAME
.Nm fido_dev_set_io_functions ,
-.Nm fido_dev_set_sigmask
-.Nd FIDO 2 device I/O interface
+.Nm fido_dev_set_sigmask ,
+.Nm fido_dev_set_timeout ,
+.Nm fido_dev_set_transport_functions ,
+.Nm fido_dev_io_handle
+.Nd FIDO2 device I/O interface
.Sh SYNOPSIS
.In fido.h
.Bd -literal
@@ -29,11 +32,28 @@ typedef int fido_sigset_t;
#else
typedef sigset_t fido_sigset_t;
#endif
+
+typedef int fido_dev_rx_t(struct fido_dev *,
+ uint8_t, unsigned char *, size_t, int);
+typedef int fido_dev_tx_t(struct fido_dev *,
+ uint8_t, const unsigned char *, size_t);
+
+typedef struct fido_dev_transport {
+ fido_dev_rx_t *rx;
+ fido_dev_tx_t *tx;
+} fido_dev_transport_t;
.Ed
+.Pp
.Ft int
.Fn fido_dev_set_io_functions "fido_dev_t *dev" "const fido_dev_io_t *io"
.Ft int
.Fn fido_dev_set_sigmask "fido_dev_t *dev" "const fido_sigset_t *sigmask"
+.Ft int
+.Fn fido_dev_set_timeout "fido_dev_t *dev" "int ms"
+.Ft int
+.Fn fido_dev_set_transport_functions "fido_dev_t *dev" "const fido_dev_transport_t *t"
+.Ft void *
+.Fn fido_dev_io_handle "const fido_dev_t *dev"
.Sh DESCRIPTION
The
.Fn fido_dev_set_io_functions
@@ -122,13 +142,97 @@ No references to
.Fa sigmask
are held by
.Fn fido_dev_set_sigmask .
+.Pp
+The
+.Fn fido_dev_set_timeout
+function informs
+.Em libfido2
+not to block for more than
+.Fa ms
+milliseconds while communicating with
+.Fa dev .
+If a timeout occurs, the corresponding
+.Em fido_dev_*
+function will fail with
+.Dv FIDO_ERR_RX .
+If
+.Fa ms
+is -1,
+then
+.Em libfido2
+may block indefinitely.
+This is the default behaviour.
+When using the Windows Hello backend,
+.Fa ms
+is used as a guidance and may be overwritten by the platform.
+.Pp
+The
+.Fn fido_dev_set_transport_functions
+function sets the transport functions used by
+.Em libfido2
+to talk to
+.Fa dev .
+While the I/O handlers are responsible for sending and receiving
+transmission units of initialization and continuation packets already
+formatted by
+.Em libfido2 ,
+the transport handlers are responsible for sending and receiving
+the CTAPHID commands and data directly, as defined in the FIDO Client
+to Authenticator Protocol (CTAP) standard.
+They are defined as follows:
+.Bl -tag -width Ds
+.It Vt fido_dev_tx_t
+Receives a device, a CTAPHID command to transmit, a data buffer to
+transmit, and the length of the data buffer.
+On success, 0 is returned.
+On error, -1 is returned.
+.It Vt fido_dev_rx_t
+Receives a device, a CTAPHID command whose response the caller expects
+to receive, a data buffer to receive into, the size of the data buffer
+determining the maximum length of a response, and the maximum number of
+milliseconds to wait for a response.
+On success, the number of bytes read into the data buffer is returned.
+On error, -1 is returned.
+.El
+.Pp
+When transport functions are specified,
+.Em libfido2
+will use them instead of the
+.Dv read
+and
+.Dv write
+functions of the I/O handlers.
+However, the I/O handlers must still be specified to open and close the
+device.
+.Pp
+The
+.Fn fido_dev_io_handle
+function returns the opaque pointer returned by the
+.Dv open
+function of the I/O handlers.
+This is useful mainly for the transport functions, which unlike the I/O
+handlers are passed the
+.Vt fido_dev_t
+pointer instead of the opaque I/O handle.
.Sh RETURN VALUES
On success,
-.Fn fido_dev_set_io_functions
+.Fn fido_dev_set_io_functions ,
+.Fn fido_dev_set_transport_functions ,
+.Fn fido_dev_set_sigmask ,
and
-.Fn fido_dev_set_sigmask
+.Fn fido_dev_set_timeout
return
.Dv FIDO_OK .
On error, a different error code defined in
.In fido/err.h
is returned.
+.Sh SEE ALSO
+.Xr fido_dev_info_manifest 3 ,
+.Xr fido_dev_open 3
+.Rs
+.%D 2021-06-15
+.%O Proposed Standard, Version 2.1
+.%Q FIDO Alliance
+.%R Client to Authenticator Protocol (CTAP)
+.%U https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html
+.Re
diff --git a/lib/libfido2/man/fido_dev_set_pin.3 b/lib/libfido2/man/fido_dev_set_pin.3
index a269541b2fb..50244fbb247 100644
--- a/lib/libfido2/man/fido_dev_set_pin.3
+++ b/lib/libfido2/man/fido_dev_set_pin.3
@@ -2,7 +2,7 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: October 26 2021 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_DEV_SET_PIN 3
.Os
.Sh NAME
@@ -10,7 +10,7 @@
.Nm fido_dev_get_retry_count ,
.Nm fido_dev_get_uv_retry_count ,
.Nm fido_dev_reset
-.Nd FIDO 2 device management functions
+.Nd FIDO2 device management functions
.Sh SYNOPSIS
.In fido.h
.Ft int
diff --git a/lib/libfido2/man/fido_init.3 b/lib/libfido2/man/fido_init.3
index cd95c15d158..a54dcbc6427 100644
--- a/lib/libfido2/man/fido_init.3
+++ b/lib/libfido2/man/fido_init.3
@@ -2,16 +2,23 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: October 26 2021 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_INIT 3
.Os
.Sh NAME
-.Nm fido_init
-.Nd initialise the FIDO 2 library
+.Nm fido_init ,
+.Nm fido_set_log_handler
+.Nd initialise the FIDO2 library
.Sh SYNOPSIS
.In fido.h
+.Bd -literal
+typedef void fido_log_handler_t(const char *);
+.Ed
+.Pp
.Ft void
.Fn fido_init "int flags"
+.Ft void
+.Fn fido_set_log_handler "fido_log_handler_t *handler"
.Sh DESCRIPTION
The
.Fn fido_init
@@ -43,8 +50,21 @@ then
.Em libfido2
will not fallback to U2F in
.Xr fido_dev_open 3
-if a device claims to be FIDO2 but fails to respond to a
-FIDO2 command.
+if a device claims to support FIDO2 but fails to respond to
+a CTAP 2.0 greeting.
+.Pp
+The
+.Fn fido_set_log_handler
+function causes
+.Fa handler
+to be called for each log line generated in the context of the
+executing thread.
+Lines passed to
+.Fa handler
+include a trailing newline character and are not printed by
+.Em libfido2
+on
+.Em stderr .
.Sh SEE ALSO
.Xr fido_assert_new 3 ,
.Xr fido_cred_new 3 ,
diff --git a/lib/libfido2/man/fido_strerr.3 b/lib/libfido2/man/fido_strerr.3
index fa1919b3a92..3ab956faa38 100644
--- a/lib/libfido2/man/fido_strerr.3
+++ b/lib/libfido2/man/fido_strerr.3
@@ -2,12 +2,12 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: February 7 2020 $
+.Dd $Mdocdate: August 29 2022 $
.Dt FIDO_STRERR 3
.Os
.Sh NAME
.Nm fido_strerr
-.Nd FIDO 2 error codes
+.Nd FIDO2 error codes
.Sh SYNOPSIS
.In fido.h
.Ft const char *
diff --git a/lib/libfido2/man/rs256_pk_new.3 b/lib/libfido2/man/rs256_pk_new.3
index a11e012229d..580ee513155 100644
--- a/lib/libfido2/man/rs256_pk_new.3
+++ b/lib/libfido2/man/rs256_pk_new.3
@@ -1,17 +1,18 @@
-.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\" Copyright (c) 2018-2021 Yubico AB. All rights reserved.
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: February 7 2020 $
+.Dd $Mdocdate: August 29 2022 $
.Dt RS256_PK_NEW 3
.Os
.Sh NAME
.Nm rs256_pk_new ,
.Nm rs256_pk_free ,
.Nm rs256_pk_from_RSA ,
+.Nm rs256_pk_from_EVP_PKEY ,
.Nm rs256_pk_from_ptr ,
.Nm rs256_pk_to_EVP_PKEY
-.Nd FIDO 2 COSE RS256 API
+.Nd FIDO2 COSE RS256 API
.Sh SYNOPSIS
.In openssl/rsa.h
.In fido/rs256.h
@@ -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
diff --git a/lib/libfido2/shlib_version b/lib/libfido2/shlib_version
index 3066b9771e7..9c1551636c5 100644
--- a/lib/libfido2/shlib_version
+++ b/lib/libfido2/shlib_version
@@ -1,2 +1,2 @@
-major=5
+major=6
minor=0
diff --git a/lib/libfido2/src/assert.c b/lib/libfido2/src/assert.c
index b36f8e32466..949af919d25 100644
--- a/lib/libfido2/src/assert.c
+++ b/lib/libfido2/src/assert.c
@@ -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 @@ fail:
}
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 @@ fail:
if (item != NULL)
cbor_decref(&item);
- return (ok);
-}
-
-int
-fido_verify_sig_es256(const fido_blob_t *dgst, const es256_pk_t *pk,
- const fido_blob_t *sig)
-{
- EVP_PKEY *pkey = NULL;
- EC_KEY *ec = NULL;
- int ok = -1;
-
- /* ECDSA_verify needs ints */
- if (dgst->len > INT_MAX || sig->len > INT_MAX) {
- fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
- dgst->len, sig->len);
- return (-1);
- }
-
- if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL ||
- (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) {
- fido_log_debug("%s: pk -> ec", __func__);
- goto fail;
- }
-
- if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr,
- (int)sig->len, ec) != 1) {
- fido_log_debug("%s: ECDSA_verify", __func__);
- goto fail;
- }
-
- ok = 0;
-fail:
- if (pkey != NULL)
- EVP_PKEY_free(pkey);
-
- return (ok);
-}
-
-int
-fido_verify_sig_rs256(const fido_blob_t *dgst, const rs256_pk_t *pk,
- const fido_blob_t *sig)
-{
- EVP_PKEY *pkey = NULL;
- RSA *rsa = NULL;
- int ok = -1;
-
- /* RSA_verify needs unsigned ints */
- if (dgst->len > UINT_MAX || sig->len > UINT_MAX) {
- fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
- dgst->len, sig->len);
- return (-1);
- }
-
- if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL ||
- (rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) {
- fido_log_debug("%s: pk -> ec", __func__);
- goto fail;
- }
-
- if (RSA_verify(NID_sha256, dgst->ptr, (unsigned int)dgst->len, sig->ptr,
- (unsigned int)sig->len, rsa) != 1) {
- fido_log_debug("%s: RSA_verify", __func__);
- goto fail;
- }
-
- ok = 0;
-fail:
- if (pkey != NULL)
- EVP_PKEY_free(pkey);
-
- return (ok);
-}
-
-int
-fido_verify_sig_eddsa(const fido_blob_t *dgst, const eddsa_pk_t *pk,
- const fido_blob_t *sig)
-{
- EVP_PKEY *pkey = NULL;
- EVP_MD_CTX *mdctx = NULL;
- int ok = -1;
-
- /* EVP_DigestVerify needs ints */
- if (dgst->len > INT_MAX || sig->len > INT_MAX) {
- fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
- dgst->len, sig->len);
- return (-1);
- }
-
- if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
- fido_log_debug("%s: pk -> pkey", __func__);
- goto fail;
- }
-
- if ((mdctx = EVP_MD_CTX_new()) == NULL) {
- fido_log_debug("%s: EVP_MD_CTX_new", __func__);
- goto fail;
- }
-
- if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) {
- fido_log_debug("%s: EVP_DigestVerifyInit", __func__);
- goto fail;
- }
-
- if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr,
- dgst->len) != 1) {
- fido_log_debug("%s: EVP_DigestVerify", __func__);
- goto fail;
- }
-
- ok = 0;
-fail:
- if (mdctx != NULL)
- EVP_MD_CTX_free(mdctx);
-
- if (pkey != NULL)
- EVP_PKEY_free(pkey);
+ EVP_MD_CTX_free(ctx);
return (ok);
}
@@ -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__,
diff --git a/lib/libfido2/src/authkey.c b/lib/libfido2/src/authkey.c
index c3474ccafc0..33e0a8d44bd 100644
--- a/lib/libfido2/src/authkey.c
+++ b/lib/libfido2/src/authkey.c
@@ -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 @@ fail:
}
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));
}
diff --git a/lib/libfido2/src/bio.c b/lib/libfido2/src/bio.c
index 06bc32eea7e..8c52de5d76c 100644
--- a/lib/libfido2/src/bio.c
+++ b/lib/libfido2/src/bio.c
@@ -58,7 +58,7 @@ fail:
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;
@@ -419,12 +424,12 @@ bio_enroll_begin_wait(fido_dev_t *dev, fido_bio_template_t *t,
memset(&argv, 0, sizeof(argv));
- if ((argv[2] = cbor_build_uint32(timo_ms)) == NULL) {
+ if ((argv[2] = cbor_build_uint(timo_ms)) == NULL) {
fido_log_debug("%s: cbor encode", __func__);
goto fail;
}
- if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token)) != 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 @@ fail:
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;
@@ -514,12 +520,12 @@ bio_enroll_continue_wait(fido_dev_t *dev, const fido_bio_template_t *t,
memset(&argv, 0, sizeof(argv));
if ((argv[0] = fido_blob_encode(&t->id)) == NULL ||
- (argv[2] = cbor_build_uint32(timo_ms)) == NULL) {
+ (argv[2] = cbor_build_uint(timo_ms)) == NULL) {
fido_log_debug("%s: cbor encode", __func__);
goto fail;
}
- if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token)) != 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 *
diff --git a/lib/libfido2/src/cbor.c b/lib/libfido2/src/cbor.c
index 5c1b11583e7..8b7edece3d8 100644
--- a/lib/libfido2/src/cbor.c
+++ b/lib/libfido2/src/cbor.c
@@ -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 @@ fail:
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);
}
@@ -662,7 +696,6 @@ cbor_encode_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret,
uint8_t prot;
fido_blob_t key;
-
key.ptr = secret->ptr;
key.len = secret->len;
@@ -706,11 +739,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 +755,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 +765,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 +774,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 +787,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 +814,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 +915,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 +1160,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 +1392,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 +1406,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 +1425,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 +1447,8 @@ out:
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 +1456,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);
}
diff --git a/lib/libfido2/src/compress.c b/lib/libfido2/src/compress.c
index ee5501b4a4a..074bca87648 100644
--- a/lib/libfido2/src/compress.c
+++ b/lib/libfido2/src/compress.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Yubico AB. All rights reserved.
+ * Copyright (c) 2020-2022 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
@@ -9,41 +9,159 @@
#define BOUND (1024UL * 1024UL)
+/* zlib inflate (raw + headers) */
static int
-do_compress(fido_blob_t *out, const fido_blob_t *in, size_t origsiz, int decomp)
+rfc1950_inflate(fido_blob_t *out, const fido_blob_t *in, size_t origsiz)
{
u_long ilen, olen;
- int r;
+ int z;
memset(out, 0, sizeof(*out));
+
if (in->len > ULONG_MAX || (ilen = (u_long)in->len) > BOUND ||
- origsiz > ULONG_MAX || (olen = decomp ? (u_long)origsiz :
- compressBound(ilen)) > BOUND)
+ origsiz > ULONG_MAX || (olen = (u_long)origsiz) > BOUND) {
+ fido_log_debug("%s: in->len=%zu, origsiz=%zu", __func__,
+ in->len, origsiz);
return FIDO_ERR_INVALID_ARGUMENT;
+ }
+
if ((out->ptr = calloc(1, olen)) == NULL)
return FIDO_ERR_INTERNAL;
out->len = olen;
- if (decomp)
- r = uncompress(out->ptr, &olen, in->ptr, ilen);
- else
- r = compress(out->ptr, &olen, in->ptr, ilen);
- if (r != Z_OK || olen > SIZE_MAX || olen > out->len) {
+
+ if ((z = uncompress(out->ptr, &olen, in->ptr, ilen)) != Z_OK ||
+ olen > SIZE_MAX || olen != out->len) {
+ fido_log_debug("%s: uncompress: %d, olen=%lu, out->len=%zu",
+ __func__, z, olen, out->len);
fido_blob_reset(out);
return FIDO_ERR_COMPRESS;
}
- out->len = olen;
return FIDO_OK;
}
+/* raw inflate */
+static int
+rfc1951_inflate(fido_blob_t *out, const fido_blob_t *in, size_t origsiz)
+{
+ z_stream zs;
+ u_int ilen, olen;
+ int r, z;
+
+ memset(&zs, 0, sizeof(zs));
+ memset(out, 0, sizeof(*out));
+
+ if (in->len > UINT_MAX || (ilen = (u_int)in->len) > BOUND ||
+ origsiz > UINT_MAX || (olen = (u_int)origsiz) > BOUND) {
+ fido_log_debug("%s: in->len=%zu, origsiz=%zu", __func__,
+ in->len, origsiz);
+ return FIDO_ERR_INVALID_ARGUMENT;
+ }
+ if ((z = inflateInit2(&zs, -MAX_WBITS)) != Z_OK) {
+ fido_log_debug("%s: inflateInit2: %d", __func__, z);
+ return FIDO_ERR_COMPRESS;
+ }
+
+ if ((out->ptr = calloc(1, olen)) == NULL) {
+ r = FIDO_ERR_INTERNAL;
+ goto fail;
+ }
+ out->len = olen;
+ zs.next_in = in->ptr;
+ zs.avail_in = ilen;
+ zs.next_out = out->ptr;
+ zs.avail_out = olen;
+
+ if ((z = inflate(&zs, Z_FINISH)) != Z_STREAM_END) {
+ fido_log_debug("%s: inflate: %d", __func__, z);
+ r = FIDO_ERR_COMPRESS;
+ goto fail;
+ }
+ if (zs.avail_out != 0) {
+ fido_log_debug("%s: %u != 0", __func__, zs.avail_out);
+ r = FIDO_ERR_COMPRESS;
+ goto fail;
+ }
+
+ r = FIDO_OK;
+fail:
+ if ((z = inflateEnd(&zs)) != Z_OK) {
+ fido_log_debug("%s: inflateEnd: %d", __func__, z);
+ r = FIDO_ERR_COMPRESS;
+ }
+ if (r != FIDO_OK)
+ fido_blob_reset(out);
+
+ return r;
+}
+
+/* raw deflate */
+static int
+rfc1951_deflate(fido_blob_t *out, const fido_blob_t *in)
+{
+ z_stream zs;
+ u_int ilen, olen;
+ int r, z;
+
+ memset(&zs, 0, sizeof(zs));
+ memset(out, 0, sizeof(*out));
+
+ if (in->len > UINT_MAX || (ilen = (u_int)in->len) > BOUND) {
+ fido_log_debug("%s: in->len=%zu", __func__, in->len);
+ return FIDO_ERR_INVALID_ARGUMENT;
+ }
+ if ((z = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
+ -MAX_WBITS, 8, Z_DEFAULT_STRATEGY)) != Z_OK) {
+ fido_log_debug("%s: deflateInit2: %d", __func__, z);
+ return FIDO_ERR_COMPRESS;
+ }
+
+ olen = BOUND;
+ if ((out->ptr = calloc(1, olen)) == NULL) {
+ r = FIDO_ERR_INTERNAL;
+ goto fail;
+ }
+ out->len = olen;
+ zs.next_in = in->ptr;
+ zs.avail_in = ilen;
+ zs.next_out = out->ptr;
+ zs.avail_out = olen;
+
+ if ((z = deflate(&zs, Z_FINISH)) != Z_STREAM_END) {
+ fido_log_debug("%s: inflate: %d", __func__, z);
+ r = FIDO_ERR_COMPRESS;
+ goto fail;
+ }
+ if (zs.avail_out >= out->len) {
+ fido_log_debug("%s: %u > %zu", __func__, zs.avail_out,
+ out->len);
+ r = FIDO_ERR_COMPRESS;
+ goto fail;
+ }
+ out->len -= zs.avail_out;
+
+ r = FIDO_OK;
+fail:
+ if ((z = deflateEnd(&zs)) != Z_OK) {
+ fido_log_debug("%s: deflateEnd: %d", __func__, z);
+ r = FIDO_ERR_COMPRESS;
+ }
+ if (r != FIDO_OK)
+ fido_blob_reset(out);
+
+ return r;
+}
+
int
fido_compress(fido_blob_t *out, const fido_blob_t *in)
{
- return do_compress(out, in, 0, 0);
+ return rfc1951_deflate(out, in);
}
int
fido_uncompress(fido_blob_t *out, const fido_blob_t *in, size_t origsiz)
{
- return do_compress(out, in, origsiz, 1);
+ if (rfc1950_inflate(out, in, origsiz) == FIDO_OK)
+ return FIDO_OK; /* backwards compat with libfido2 < 1.11 */
+ return rfc1951_inflate(out, in, origsiz);
}
diff --git a/lib/libfido2/src/config.c b/lib/libfido2/src/config.c
index 0dda16163bc..2baaab0fd62 100644
--- a/lib/libfido2/src/config.c
+++ b/lib/libfido2/src/config.c
@@ -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 @@ fail:
}
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 @@ fail:
}
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;
}
diff --git a/lib/libfido2/src/cred.c b/lib/libfido2/src/cred.c
index 5e65b08293b..6da502c8d90 100644
--- a/lib/libfido2/src/cred.c
+++ b/lib/libfido2/src/cred.c
@@ -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 @@ fail:
}
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) {
+ const uint8_t zero = 0;
+ const uint8_t four = 4; /* uncompressed point */
+ const EVP_MD *md = NULL;
+ EVP_MD_CTX *ctx = NULL;
+ int ok = -1;
+
+ if (dgst->len != SHA256_DIGEST_LENGTH ||
+ (md = EVP_sha256()) == NULL ||
+ (ctx = EVP_MD_CTX_new()) == NULL ||
+ EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
+ EVP_DigestUpdate(ctx, &zero, sizeof(zero)) != 1 ||
+ EVP_DigestUpdate(ctx, rp_id, rp_id_len) != 1 ||
+ EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 ||
+ EVP_DigestUpdate(ctx, id->ptr, id->len) != 1 ||
+ EVP_DigestUpdate(ctx, &four, sizeof(four)) != 1 ||
+ EVP_DigestUpdate(ctx, pk->x, sizeof(pk->x)) != 1 ||
+ EVP_DigestUpdate(ctx, pk->y, sizeof(pk->y)) != 1 ||
+ EVP_DigestFinal_ex(ctx, dgst->ptr, NULL) != 1) {
fido_log_debug("%s: sha256", __func__);
- return (-1);
+ goto fail;
}
- return (0);
+ ok = 0;
+fail:
+ EVP_MD_CTX_free(ctx);
+
+ return (ok);
}
static int
-verify_sig(const fido_blob_t *dgst, const fido_blob_t *x5c,
- const fido_blob_t *sig)
+verify_attstmt(const fido_blob_t *dgst, const fido_attstmt_t *attstmt)
{
BIO *rawcert = NULL;
X509 *cert = NULL;
EVP_PKEY *pkey = NULL;
- EC_KEY *ec;
int ok = -1;
/* openssl needs ints */
- if (dgst->len > INT_MAX || x5c->len > INT_MAX || sig->len > INT_MAX) {
- fido_log_debug("%s: dgst->len=%zu, x5c->len=%zu, sig->len=%zu",
- __func__, dgst->len, x5c->len, sig->len);
+ if (attstmt->x5c.len > INT_MAX) {
+ fido_log_debug("%s: x5c.len=%zu", __func__, attstmt->x5c.len);
return (-1);
}
/* fetch key from x509 */
- if ((rawcert = BIO_new_mem_buf(x5c->ptr, (int)x5c->len)) == NULL ||
+ if ((rawcert = BIO_new_mem_buf(attstmt->x5c.ptr,
+ (int)attstmt->x5c.len)) == NULL ||
(cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
- (pkey = X509_get_pubkey(cert)) == NULL ||
- (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) {
+ (pkey = X509_get_pubkey(cert)) == NULL) {
fido_log_debug("%s: x509 key", __func__);
goto fail;
}
- if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr,
- (int)sig->len, ec) != 1) {
- fido_log_debug("%s: ECDSA_verify", __func__);
- goto fail;
+ switch (attstmt->alg) {
+ case COSE_UNSPEC:
+ case COSE_ES256:
+ ok = es256_verify_sig(dgst, pkey, &attstmt->sig);
+ break;
+ case COSE_RS256:
+ ok = rs256_verify_sig(dgst, pkey, &attstmt->sig);
+ break;
+ case COSE_RS1:
+ ok = rs1_verify_sig(dgst, pkey, &attstmt->sig);
+ break;
+ case COSE_EDDSA:
+ ok = eddsa_verify_sig(dgst, pkey, &attstmt->sig);
+ break;
+ default:
+ fido_log_debug("%s: unknown alg %d", __func__, attstmt->alg);
+ break;
}
- ok = 0;
fail:
- if (rawcert != NULL)
- BIO_free(rawcert);
- if (cert != NULL)
- X509_free(cert);
- if (pkey != NULL)
- EVP_PKEY_free(pkey);
+ BIO_free(rawcert);
+ X509_free(cert);
+ EVP_PKEY_free(pkey);
return (ok);
}
@@ -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 @@ fail:
fido_cred_clean_authdata(cred);
return (r);
-
}
int
@@ -610,7 +662,6 @@ fail:
fido_cred_clean_authdata(cred);
return (r);
-
}
int
@@ -641,6 +692,39 @@ fido_cred_set_sig(fido_cred_t *cred, const unsigned char *ptr, size_t len)
}
int
+fido_cred_set_attstmt(fido_cred_t *cred, const unsigned char *ptr, size_t len)
+{
+ cbor_item_t *item = NULL;
+ struct cbor_load_result cbor;
+ int r = FIDO_ERR_INVALID_ARGUMENT;
+
+ fido_cred_clean_attstmt(&cred->attstmt);
+
+ if (ptr == NULL || len == 0)
+ goto fail;
+
+ if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
+ fido_log_debug("%s: cbor_load", __func__);
+ goto fail;
+ }
+
+ if (cbor_decode_attstmt(item, &cred->attstmt) < 0) {
+ fido_log_debug("%s: cbor_decode_attstmt", __func__);
+ goto fail;
+ }
+
+ r = FIDO_OK;
+fail:
+ if (item != NULL)
+ cbor_decref(&item);
+
+ if (r != FIDO_OK)
+ fido_cred_clean_attstmt(&cred->attstmt);
+
+ return (r);
+}
+
+int
fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len)
{
fido_blob_t id_blob;
@@ -834,6 +918,19 @@ fido_cred_set_prot(fido_cred_t *cred, int prot)
}
int
+fido_cred_set_pin_minlen(fido_cred_t *cred, size_t len)
+{
+ if (len == 0)
+ cred->ext.mask &= ~FIDO_EXT_MINPINLEN;
+ else
+ cred->ext.mask |= FIDO_EXT_MINPINLEN;
+
+ cred->ext.minpinlen = len;
+
+ return (FIDO_OK);
+}
+
+int
fido_cred_set_blob(fido_cred_t *cred, const unsigned char *ptr, size_t len)
{
if (ptr == NULL || len == 0)
@@ -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)
@@ -956,6 +1053,18 @@ fido_cred_authdata_raw_len(const fido_cred_t *cred)
}
const unsigned char *
+fido_cred_attstmt_ptr(const fido_cred_t *cred)
+{
+ return (cred->attstmt.cbor.ptr);
+}
+
+size_t
+fido_cred_attstmt_len(const fido_cred_t *cred)
+{
+ return (cred->attstmt.cbor.len);
+}
+
+const unsigned char *
fido_cred_pubkey_ptr(const fido_cred_t *cred)
{
const void *ptr;
@@ -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)
{
diff --git a/lib/libfido2/src/credman.c b/lib/libfido2/src/credman.c
index e48ca4543b1..8d2649a144f 100644
--- a/lib/libfido2/src/credman.c
+++ b/lib/libfido2/src/credman.c
@@ -112,7 +112,7 @@ fail:
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 *
diff --git a/lib/libfido2/src/dev.c b/lib/libfido2/src/dev.c
index a003854f89d..635e4171475 100644
--- a/lib/libfido2/src/dev.c
+++ b/lib/libfido2/src/dev.c
@@ -1,37 +1,17 @@
/*
- * Copyright (c) 2018 Yubico AB. All rights reserved.
+ * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
-#include <openssl/sha.h>
#include "fido.h"
#ifndef TLS
#define TLS
#endif
-typedef struct dev_manifest_func_node {
- dev_manifest_func_t manifest_func;
- struct dev_manifest_func_node *next;
-} dev_manifest_func_node_t;
-
-static TLS dev_manifest_func_node_t *manifest_funcs = NULL;
static TLS bool disable_u2f_fallback;
-static void
-find_manifest_func_node(dev_manifest_func_t f, dev_manifest_func_node_t **curr,
- dev_manifest_func_node_t **prev)
-{
- *prev = NULL;
- *curr = manifest_funcs;
-
- while (*curr != NULL && (*curr)->manifest_func != f) {
- *prev = *curr;
- *curr = (*curr)->next;
- }
-}
-
#ifdef FIDO_FUZZ
static void
set_random_report_len(fido_dev_t *dev)
@@ -63,13 +43,15 @@ fido_dev_set_option_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
for (size_t i = 0; i < len; i++)
if (strcmp(ptr[i], "clientPin") == 0) {
- dev->flags |= val[i] ? FIDO_DEV_PIN_SET : FIDO_DEV_PIN_UNSET;
+ dev->flags |= val[i] ?
+ FIDO_DEV_PIN_SET : FIDO_DEV_PIN_UNSET;
} else if (strcmp(ptr[i], "credMgmt") == 0 ||
strcmp(ptr[i], "credentialMgmtPreview") == 0) {
if (val[i])
dev->flags |= FIDO_DEV_CREDMAN;
} else if (strcmp(ptr[i], "uv") == 0) {
- dev->flags |= val[i] ? FIDO_DEV_UV_SET : FIDO_DEV_UV_UNSET;
+ dev->flags |= val[i] ?
+ FIDO_DEV_UV_SET : FIDO_DEV_UV_UNSET;
} else if (strcmp(ptr[i], "pinUvAuthToken") == 0) {
if (val[i])
dev->flags |= FIDO_DEV_TOKEN_PERMS;
@@ -106,7 +88,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 +143,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 +159,7 @@ fail:
}
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 +224,7 @@ fail:
}
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,121 +232,80 @@ 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);
return (FIDO_OK);
}
-int
-fido_dev_register_manifest_func(const dev_manifest_func_t f)
-{
- dev_manifest_func_node_t *prev, *curr, *n;
-
- find_manifest_func_node(f, &curr, &prev);
- if (curr != NULL)
- return (FIDO_OK);
-
- if ((n = calloc(1, sizeof(*n))) == NULL) {
- fido_log_debug("%s: calloc", __func__);
- return (FIDO_ERR_INTERNAL);
- }
-
- n->manifest_func = f;
- n->next = manifest_funcs;
- manifest_funcs = n;
-
- return (FIDO_OK);
-}
-
-void
-fido_dev_unregister_manifest_func(const dev_manifest_func_t f)
+static void
+run_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen,
+ const char *type, int (*manifest)(fido_dev_info_t *, size_t, size_t *))
{
- dev_manifest_func_node_t *prev, *curr;
+ size_t ndevs = 0;
+ int r;
- find_manifest_func_node(f, &curr, &prev);
- if (curr == NULL)
+ if (*olen >= ilen) {
+ fido_log_debug("%s: skipping %s", __func__, type);
return;
- if (prev != NULL)
- prev->next = curr->next;
- else
- manifest_funcs = curr->next;
-
- free(curr);
+ }
+ if ((r = manifest(devlist + *olen, ilen - *olen, &ndevs)) != FIDO_OK)
+ fido_log_debug("%s: %s: 0x%x", __func__, type, r);
+ fido_log_debug("%s: found %zu %s device%s", __func__, ndevs, type,
+ ndevs == 1 ? "" : "s");
+ *olen += ndevs;
}
int
fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
{
- dev_manifest_func_node_t *curr = NULL;
- dev_manifest_func_t m_func;
- size_t curr_olen;
- int r;
-
*olen = 0;
- if (fido_dev_register_manifest_func(fido_hid_manifest) != FIDO_OK)
- return (FIDO_ERR_INTERNAL);
-#ifdef NFC_LINUX
- if (fido_dev_register_manifest_func(fido_nfc_manifest) != FIDO_OK)
- return (FIDO_ERR_INTERNAL);
+ run_manifest(devlist, ilen, olen, "hid", fido_hid_manifest);
+#ifdef USE_NFC
+ run_manifest(devlist, ilen, olen, "nfc", fido_nfc_manifest);
+#endif
+#ifdef USE_PCSC
+ run_manifest(devlist, ilen, olen, "pcsc", fido_pcsc_manifest);
#endif
#ifdef USE_WINHELLO
- if (fido_dev_register_manifest_func(fido_winhello_manifest) != FIDO_OK)
- return (FIDO_ERR_INTERNAL);
+ run_manifest(devlist, ilen, olen, "winhello", fido_winhello_manifest);
#endif
- for (curr = manifest_funcs; curr != NULL; curr = curr->next) {
- curr_olen = 0;
- m_func = curr->manifest_func;
- r = m_func(devlist + *olen, ilen - *olen, &curr_olen);
- if (r != FIDO_OK)
- return (r);
- *olen += curr_olen;
- if (*olen == ilen)
- break;
- }
-
return (FIDO_OK);
}
int
fido_dev_open_with_info(fido_dev_t *dev)
{
+ int ms = dev->timeout_ms;
+
if (dev->path == NULL)
return (FIDO_ERR_INVALID_ARGUMENT);
- return (fido_dev_open_wait(dev, dev->path, -1));
+ return (fido_dev_open_wait(dev, dev->path, &ms));
}
int
fido_dev_open(fido_dev_t *dev, const char *path)
{
-#ifdef NFC_LINUX
- /*
- * this is a hack to get existing applications up and running with nfc;
- * it will *NOT* be part of a libfido2 release. to support nfc in your
- * application, please change it to use fido_dev_open_with_info().
- */
- if (strncmp(path, "/sys", strlen("/sys")) == 0 && strlen(path) > 4 &&
- path[strlen(path) - 4] == 'n' && path[strlen(path) - 3] == 'f' &&
- path[strlen(path) - 2] == 'c') {
- dev->io_own = true;
- dev->io = (fido_dev_io_t) {
- fido_nfc_open,
- fido_nfc_close,
- fido_nfc_read,
- fido_nfc_write,
- };
- dev->transport = (fido_dev_transport_t) {
- fido_nfc_rx,
- fido_nfc_tx,
- };
+ int ms = dev->timeout_ms;
+
+#ifdef USE_NFC
+ if (fido_is_nfc(path) && fido_dev_set_nfc(dev) < 0) {
+ fido_log_debug("%s: fido_dev_set_nfc", __func__);
+ return FIDO_ERR_INTERNAL;
+ }
+#endif
+#ifdef USE_PCSC
+ if (fido_is_pcsc(path) && fido_dev_set_pcsc(dev) < 0) {
+ fido_log_debug("%s: fido_dev_set_pcsc", __func__);
+ return FIDO_ERR_INTERNAL;
}
#endif
- return (fido_dev_open_wait(dev, path, -1));
+ return (fido_dev_open_wait(dev, path, &ms));
}
int
@@ -386,131 +328,37 @@ 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)
+#ifdef USE_NFC
+ if (dev->transport.rx == fido_nfc_rx && dev->io.read == fido_nfc_read)
return (fido_nfc_set_sigmask(dev->io_handle, sigmask));
#endif
- return (fido_hid_set_sigmask(dev->io_handle, sigmask));
+ if (dev->transport.rx == NULL && dev->io.read == fido_hid_read)
+ return (fido_hid_set_sigmask(dev->io_handle, sigmask));
+
+ return (FIDO_ERR_INVALID_ARGUMENT);
}
int
fido_dev_cancel(fido_dev_t *dev)
{
+ int ms = dev->timeout_ms;
+
#ifdef USE_WINHELLO
if (dev->flags & FIDO_DEV_WINHELLO)
return (fido_winhello_cancel(dev));
#endif
if (fido_dev_is_fido2(dev) == false)
return (FIDO_ERR_INVALID_ARGUMENT);
- if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0) < 0)
+ if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0, &ms) < 0)
return (FIDO_ERR_TX);
return (FIDO_OK);
}
int
-fido_dev_get_touch_begin(fido_dev_t *dev)
-{
- fido_blob_t f;
- cbor_item_t *argv[9];
- const char *clientdata = FIDO_DUMMY_CLIENTDATA;
- const uint8_t user_id = FIDO_DUMMY_USER_ID;
- unsigned char cdh[SHA256_DIGEST_LENGTH];
- fido_rp_t rp;
- fido_user_t user;
- int r = FIDO_ERR_INTERNAL;
-
- memset(&f, 0, sizeof(f));
- memset(argv, 0, sizeof(argv));
- memset(cdh, 0, sizeof(cdh));
- memset(&rp, 0, sizeof(rp));
- memset(&user, 0, sizeof(user));
-
- if (fido_dev_is_fido2(dev) == false)
- return (u2f_get_touch_begin(dev));
-
- if (SHA256((const void *)clientdata, strlen(clientdata), cdh) != cdh) {
- fido_log_debug("%s: sha256", __func__);
- return (FIDO_ERR_INTERNAL);
- }
-
- if ((rp.id = strdup(FIDO_DUMMY_RP_ID)) == NULL ||
- (user.name = strdup(FIDO_DUMMY_USER_NAME)) == NULL) {
- fido_log_debug("%s: strdup", __func__);
- goto fail;
- }
-
- if (fido_blob_set(&user.id, &user_id, sizeof(user_id)) < 0) {
- fido_log_debug("%s: fido_blob_set", __func__);
- goto fail;
- }
-
- if ((argv[0] = cbor_build_bytestring(cdh, sizeof(cdh))) == NULL ||
- (argv[1] = cbor_encode_rp_entity(&rp)) == NULL ||
- (argv[2] = cbor_encode_user_entity(&user)) == NULL ||
- (argv[3] = cbor_encode_pubkey_param(COSE_ES256)) == NULL) {
- fido_log_debug("%s: cbor encode", __func__);
- goto fail;
- }
-
- if (fido_dev_supports_pin(dev)) {
- if ((argv[7] = cbor_new_definite_bytestring()) == NULL ||
- (argv[8] = cbor_encode_pin_opt(dev)) == NULL) {
- fido_log_debug("%s: cbor encode", __func__);
- goto fail;
- }
- }
-
- if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, nitems(argv), &f) < 0 ||
- fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
- fido_log_debug("%s: fido_tx", __func__);
- r = FIDO_ERR_TX;
- goto fail;
- }
-
- r = FIDO_OK;
-fail:
- cbor_vector_free(argv, nitems(argv));
- free(f.ptr);
- free(rp.id);
- free(user.name);
- free(user.id.ptr);
-
- return (r);
-}
-
-int
-fido_dev_get_touch_status(fido_dev_t *dev, int *touched, int ms)
-{
- int r;
-
- *touched = 0;
-
- if (fido_dev_is_fido2(dev) == false)
- return (u2f_get_touch_status(dev, touched, ms));
-
- switch ((r = fido_rx_cbor_status(dev, ms))) {
- case FIDO_ERR_PIN_AUTH_INVALID:
- case FIDO_ERR_PIN_INVALID:
- case FIDO_ERR_PIN_NOT_SET:
- case FIDO_ERR_SUCCESS:
- *touched = 1;
- break;
- case FIDO_ERR_RX:
- /* ignore */
- break;
- default:
- fido_log_debug("%s: fido_rx_cbor_status", __func__);
- return (r);
- }
-
- return (FIDO_OK);
-}
-
-int
fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
{
if (dev->io_handle != NULL) {
@@ -544,6 +392,13 @@ fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t)
return (FIDO_OK);
}
+void *
+fido_dev_io_handle(const fido_dev_t *dev)
+{
+
+ return (dev->io_handle);
+}
+
void
fido_init(int flags)
{
@@ -562,6 +417,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 +449,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 +587,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);
+}
diff --git a/lib/libfido2/src/ecdh.c b/lib/libfido2/src/ecdh.c
index 3ea47ae6457..9c4f2b99e1a 100644
--- a/lib/libfido2/src/ecdh.c
+++ b/lib/libfido2/src/ecdh.c
@@ -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 @@ fail:
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 @@ fail:
}
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;
diff --git a/lib/libfido2/src/eddsa.c b/lib/libfido2/src/eddsa.c
index 89b84c5a6bd..a94ae302391 100644
--- a/lib/libfido2/src/eddsa.c
+++ b/lib/libfido2/src/eddsa.c
@@ -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.
*/
@@ -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)
@@ -37,7 +37,9 @@ EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub,
return (0);
}
+#endif /* LIBRESSL_VERSION_NUMBER */
+#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3040000f
int
EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen,
const unsigned char *tbs, size_t tbslen)
@@ -52,23 +54,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 < 0x3040000f */
static int
decode_coord(const cbor_item_t *item, void *xy, size_t xy_len)
@@ -136,11 +122,20 @@ eddsa_pk_free(eddsa_pk_t **pkp)
int
eddsa_pk_from_ptr(eddsa_pk_t *pk, const void *ptr, size_t len)
{
+ EVP_PKEY *pkey;
+
if (len < sizeof(*pk))
return (FIDO_ERR_INVALID_ARGUMENT);
memcpy(pk, ptr, sizeof(*pk));
+ if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
+ fido_log_debug("%s: eddsa_pk_to_EVP_PKEY", __func__);
+ return (FIDO_ERR_INVALID_ARGUMENT);
+ }
+
+ EVP_PKEY_free(pkey);
+
return (FIDO_OK);
}
@@ -161,6 +156,8 @@ eddsa_pk_from_EVP_PKEY(eddsa_pk_t *pk, const EVP_PKEY *pkey)
{
size_t len = 0;
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_ED25519)
+ return (FIDO_ERR_INVALID_ARGUMENT);
if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1 ||
len != sizeof(pk->x))
return (FIDO_ERR_INTERNAL);
@@ -170,3 +167,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);
+}
diff --git a/lib/libfido2/src/es256.c b/lib/libfido2/src/es256.c
index 9cdb48e4832..4d6e86f8a26 100644
--- a/lib/libfido2/src/es256.c
+++ b/lib/libfido2/src/es256.c
@@ -1,15 +1,24 @@
/*
- * Copyright (c) 2018 Yubico AB. All rights reserved.
+ * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
#include <openssl/bn.h>
+#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
#include "fido.h"
#include "fido/es256.h"
+#if OPENSSL_VERSION_NUMBER >= 0x30000000
+#define get0_EC_KEY(x) EVP_PKEY_get0_EC_KEY((x))
+#else
+#define get0_EC_KEY(x) EVP_PKEY_get0((x))
+#endif
+
+static const int es256_nid = NID_X9_62_prime256v1;
+
static int
decode_coord(const cbor_item_t *item, void *xy, size_t xy_len)
{
@@ -169,7 +178,8 @@ es256_pk_free(es256_pk_t **pkp)
int
es256_pk_from_ptr(es256_pk_t *pk, const void *ptr, size_t len)
{
- const uint8_t *p = ptr;
+ const uint8_t *p = ptr;
+ EVP_PKEY *pkey;
if (len < sizeof(*pk))
return (FIDO_ERR_INVALID_ARGUMENT);
@@ -179,6 +189,14 @@ es256_pk_from_ptr(es256_pk_t *pk, const void *ptr, size_t len)
else
memcpy(pk, ptr, sizeof(*pk)); /* libfido2 x||y format */
+ if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) {
+ fido_log_debug("%s: es256_pk_to_EVP_PKEY", __func__);
+ explicit_bzero(pk, sizeof(*pk));
+ return (FIDO_ERR_INVALID_ARGUMENT);
+ }
+
+ EVP_PKEY_free(pkey);
+
return (FIDO_OK);
}
@@ -207,13 +225,12 @@ es256_sk_create(es256_sk_t *key)
EVP_PKEY *k = NULL;
const EC_KEY *ec;
const BIGNUM *d;
- const int nid = NID_X9_62_prime256v1;
int n;
int ok = -1;
if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL ||
EVP_PKEY_paramgen_init(pctx) <= 0 ||
- EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) <= 0 ||
+ EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, es256_nid) <= 0 ||
EVP_PKEY_paramgen(pctx, &p) <= 0) {
fido_log_debug("%s: EVP_PKEY_paramgen", __func__);
goto fail;
@@ -257,7 +274,6 @@ es256_pk_to_EVP_PKEY(const es256_pk_t *k)
BIGNUM *x = NULL;
BIGNUM *y = NULL;
const EC_GROUP *g = NULL;
- const int nid = NID_X9_62_prime256v1;
int ok = -1;
if ((bnctx = BN_CTX_new()) == NULL)
@@ -275,7 +291,7 @@ es256_pk_to_EVP_PKEY(const es256_pk_t *k)
goto fail;
}
- if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL ||
+ if ((ec = EC_KEY_new_by_curve_name(es256_nid)) == NULL ||
(g = EC_KEY_get0_group(ec)) == NULL) {
fido_log_debug("%s: EC_KEY init", __func__);
goto fail;
@@ -323,12 +339,15 @@ es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec)
BIGNUM *x = NULL;
BIGNUM *y = NULL;
const EC_POINT *q = NULL;
- const EC_GROUP *g = NULL;
+ EC_GROUP *g = NULL;
+ size_t dx;
+ size_t dy;
int ok = FIDO_ERR_INTERNAL;
- int n;
+ int nx;
+ int ny;
if ((q = EC_KEY_get0_public_key(ec)) == NULL ||
- (g = EC_KEY_get0_group(ec)) == NULL ||
+ (g = EC_GROUP_new_by_curve_name(es256_nid)) == NULL ||
(bnctx = BN_CTX_new()) == NULL)
goto fail;
@@ -338,22 +357,33 @@ es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec)
(y = BN_CTX_get(bnctx)) == NULL)
goto fail;
+ if (EC_POINT_is_on_curve(g, q, bnctx) != 1) {
+ fido_log_debug("%s: EC_POINT_is_on_curve", __func__);
+ ok = FIDO_ERR_INVALID_ARGUMENT;
+ goto fail;
+ }
+
if (EC_POINT_get_affine_coordinates_GFp(g, q, x, y, bnctx) == 0 ||
- (n = BN_num_bytes(x)) < 0 || (size_t)n > sizeof(pk->x) ||
- (n = BN_num_bytes(y)) < 0 || (size_t)n > sizeof(pk->y)) {
+ (nx = BN_num_bytes(x)) < 0 || (size_t)nx > sizeof(pk->x) ||
+ (ny = BN_num_bytes(y)) < 0 || (size_t)ny > sizeof(pk->y)) {
fido_log_debug("%s: EC_POINT_get_affine_coordinates_GFp",
__func__);
goto fail;
}
- if ((n = BN_bn2bin(x, pk->x)) < 0 || (size_t)n > sizeof(pk->x) ||
- (n = BN_bn2bin(y, pk->y)) < 0 || (size_t)n > sizeof(pk->y)) {
+ dx = sizeof(pk->x) - (size_t)nx;
+ dy = sizeof(pk->y) - (size_t)ny;
+
+ if ((nx = BN_bn2bin(x, pk->x + dx)) < 0 || (size_t)nx > sizeof(pk->x) ||
+ (ny = BN_bn2bin(y, pk->y + dy)) < 0 || (size_t)ny > sizeof(pk->y)) {
fido_log_debug("%s: BN_bn2bin", __func__);
goto fail;
}
ok = FIDO_OK;
fail:
+ EC_GROUP_free(g);
+
if (bnctx != NULL) {
BN_CTX_end(bnctx);
BN_CTX_free(bnctx);
@@ -362,6 +392,18 @@ fail:
return (ok);
}
+int
+es256_pk_from_EVP_PKEY(es256_pk_t *pk, const EVP_PKEY *pkey)
+{
+ const EC_KEY *ec;
+
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC ||
+ (ec = get0_EC_KEY(pkey)) == NULL)
+ return (FIDO_ERR_INVALID_ARGUMENT);
+
+ return (es256_pk_from_EC_KEY(pk, ec));
+}
+
EVP_PKEY *
es256_sk_to_EVP_PKEY(const es256_sk_t *k)
{
@@ -369,7 +411,6 @@ es256_sk_to_EVP_PKEY(const es256_sk_t *k)
EC_KEY *ec = NULL;
EVP_PKEY *pkey = NULL;
BIGNUM *d = NULL;
- const int nid = NID_X9_62_prime256v1;
int ok = -1;
if ((bnctx = BN_CTX_new()) == NULL)
@@ -383,7 +424,7 @@ es256_sk_to_EVP_PKEY(const es256_sk_t *k)
goto fail;
}
- if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL ||
+ if ((ec = EC_KEY_new_by_curve_name(es256_nid)) == NULL ||
EC_KEY_set_private_key(ec, d) == 0) {
fido_log_debug("%s: EC_KEY_set_private_key", __func__);
goto fail;
@@ -422,11 +463,10 @@ es256_derive_pk(const es256_sk_t *sk, es256_pk_t *pk)
EC_KEY *ec = NULL;
EC_POINT *q = NULL;
const EC_GROUP *g = NULL;
- const int nid = NID_X9_62_prime256v1;
int ok = -1;
if ((d = BN_bin2bn(sk->d, (int)sizeof(sk->d), NULL)) == NULL ||
- (ec = EC_KEY_new_by_curve_name(nid)) == NULL ||
+ (ec = EC_KEY_new_by_curve_name(es256_nid)) == NULL ||
(g = EC_KEY_get0_group(ec)) == NULL ||
(q = EC_POINT_new(g)) == NULL) {
fido_log_debug("%s: get", __func__);
@@ -451,3 +491,50 @@ fail:
return (ok);
}
+
+int
+es256_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
+ const fido_blob_t *sig)
+{
+ EVP_PKEY_CTX *pctx = NULL;
+ int ok = -1;
+
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) {
+ fido_log_debug("%s: EVP_PKEY_base_id", __func__);
+ goto fail;
+ }
+
+ if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL ||
+ EVP_PKEY_verify_init(pctx) != 1 ||
+ EVP_PKEY_verify(pctx, sig->ptr, sig->len, dgst->ptr,
+ dgst->len) != 1) {
+ fido_log_debug("%s: EVP_PKEY_verify", __func__);
+ goto fail;
+ }
+
+ ok = 0;
+fail:
+ EVP_PKEY_CTX_free(pctx);
+
+ return (ok);
+}
+
+int
+es256_pk_verify_sig(const fido_blob_t *dgst, const es256_pk_t *pk,
+ const fido_blob_t *sig)
+{
+ EVP_PKEY *pkey;
+ int ok = -1;
+
+ if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL ||
+ es256_verify_sig(dgst, pkey, sig) < 0) {
+ fido_log_debug("%s: es256_verify_sig", __func__);
+ goto fail;
+ }
+
+ ok = 0;
+fail:
+ EVP_PKEY_free(pkey);
+
+ return (ok);
+}
diff --git a/lib/libfido2/src/export.llvm b/lib/libfido2/src/export.llvm
index 8d3810f92ce..df9a667f747 100644
--- a/lib/libfido2/src/export.llvm
+++ b/lib/libfido2/src/export.llvm
@@ -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
@@ -82,10 +83,11 @@ _fido_cbor_info_algorithm_type
_fido_cbor_info_extensions_len
_fido_cbor_info_extensions_ptr
_fido_cbor_info_free
-_fido_cbor_info_maxmsgsiz
_fido_cbor_info_maxcredbloblen
_fido_cbor_info_maxcredcntlst
_fido_cbor_info_maxcredidlen
+_fido_cbor_info_maxlargeblob
+_fido_cbor_info_maxmsgsiz
_fido_cbor_info_fwversion
_fido_cbor_info_new
_fido_cbor_info_options_len
@@ -97,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
@@ -136,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
@@ -150,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
@@ -193,20 +200,26 @@ _fido_dev_info_path
_fido_dev_info_product
_fido_dev_info_product_string
_fido_dev_info_ptr
+_fido_dev_info_set
_fido_dev_info_vendor
+_fido_dev_io_handle
_fido_dev_is_fido2
_fido_dev_is_winhello
_fido_dev_major
_fido_dev_make_cred
_fido_dev_minor
_fido_dev_new
+_fido_dev_new_with_info
_fido_dev_open
+_fido_dev_open_with_info
_fido_dev_protocol
_fido_dev_reset
_fido_dev_set_io_functions
_fido_dev_set_pin
_fido_dev_set_pin_minlen
+_fido_dev_set_pin_minlen_rpid
_fido_dev_set_sigmask
+_fido_dev_set_timeout
_fido_dev_set_transport_functions
_fido_dev_supports_cred_prot
_fido_dev_supports_credman
@@ -224,6 +237,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
diff --git a/lib/libfido2/src/extern.h b/lib/libfido2/src/extern.h
index 3be33236f2b..84536d58b6f 100644
--- a/lib/libfido2/src/extern.h
+++ b/lib/libfido2/src/extern.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018 Yubico AB. All rights reserved.
+ * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
@@ -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);
@@ -117,6 +118,7 @@ size_t fido_hid_report_in_len(void *);
size_t fido_hid_report_out_len(void *);
/* nfc i/o */
+bool fido_is_nfc(const char *);
void *fido_nfc_open(const char *);
void fido_nfc_close(void *);
int fido_nfc_read(void *, unsigned char *, size_t, int);
@@ -124,20 +126,31 @@ int fido_nfc_write(void *, const unsigned char *, size_t);
int fido_nfc_rx(fido_dev_t *, uint8_t, unsigned char *, size_t, int);
int fido_nfc_tx(fido_dev_t *, uint8_t, const unsigned char *, size_t);
int fido_nfc_set_sigmask(void *, const fido_sigset_t *);
+int fido_dev_set_nfc(fido_dev_t *);
+
+/* pcsc i/o */
+bool fido_is_pcsc(const char *);
+void *fido_pcsc_open(const char *);
+void fido_pcsc_close(void *);
+int fido_pcsc_read(void *, unsigned char *, size_t, int);
+int fido_pcsc_write(void *, const unsigned char *, size_t);
+int fido_pcsc_rx(fido_dev_t *, uint8_t, unsigned char *, size_t, int);
+int fido_pcsc_tx(fido_dev_t *, uint8_t, const unsigned char *, size_t);
+int fido_dev_set_pcsc(fido_dev_t *);
/* windows hello */
int fido_winhello_manifest(fido_dev_info_t *, size_t, size_t *);
int fido_winhello_open(fido_dev_t *);
int fido_winhello_close(fido_dev_t *);
int fido_winhello_cancel(fido_dev_t *);
-int fido_winhello_get_assert(fido_dev_t *, fido_assert_t *, const char *);
+int 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,20 +176,28 @@ 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 **);
-bool fido_dev_supports_permissions(const fido_dev_t *);
+int fido_do_ecdh(fido_dev_t *, es256_pk_t **, fido_blob_t **, int *);
+
+/* types */
+void fido_algo_array_free(fido_algo_array_t *);
+void fido_byte_array_free(fido_byte_array_t *);
+void fido_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 *);
@@ -189,25 +210,30 @@ int fido_check_flags(uint8_t, fido_opt_t, fido_opt_t);
int fido_check_rp_id(const char *, const unsigned char *);
int fido_get_random(void *, size_t);
int fido_sha256(fido_blob_t *, const u_char *, size_t);
+int fido_time_now(struct timespec *);
+int fido_time_delta(const struct timespec *, int *);
+int fido_to_uint64(const char *, int, uint64_t *);
/* crypto */
-int fido_verify_sig_es256(const fido_blob_t *, const es256_pk_t *,
+int es256_verify_sig(const fido_blob_t *, EVP_PKEY *, const fido_blob_t *);
+int rs256_verify_sig(const fido_blob_t *, EVP_PKEY *, const fido_blob_t *);
+int eddsa_verify_sig(const fido_blob_t *, EVP_PKEY *, const fido_blob_t *);
+int rs1_verify_sig(const fido_blob_t *, EVP_PKEY *, const fido_blob_t *);
+int es256_pk_verify_sig(const fido_blob_t *, const es256_pk_t *,
const fido_blob_t *);
-int fido_verify_sig_rs256(const fido_blob_t *, const rs256_pk_t *,
+int rs256_pk_verify_sig(const fido_blob_t *, const rs256_pk_t *,
const fido_blob_t *);
-int fido_verify_sig_eddsa(const fido_blob_t *, const eddsa_pk_t *,
+int eddsa_pk_verify_sig(const fido_blob_t *, const eddsa_pk_t *,
const fido_blob_t *);
int fido_get_signed_hash(int, fido_blob_t *, const fido_blob_t *,
const fido_blob_t *);
+int fido_get_signed_hash_tpm(fido_blob_t *, const fido_blob_t *,
+ const fido_blob_t *, const fido_attstmt_t *, const fido_attcred_t *);
/* device manifest functions */
int fido_hid_manifest(fido_dev_info_t *, size_t, size_t *);
int fido_nfc_manifest(fido_dev_info_t *, size_t, size_t *);
-
-/* device manifest registration */
-typedef int (*dev_manifest_func_t)(fido_dev_info_t *, size_t, size_t *);
-int fido_dev_register_manifest_func(const dev_manifest_func_t);
-void fido_dev_unregister_manifest_func(const dev_manifest_func_t);
+int fido_pcsc_manifest(fido_dev_info_t *, size_t, size_t *);
/* fuzzing instrumentation */
#ifdef FIDO_FUZZ
@@ -232,6 +258,8 @@ 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:"
+#define FIDO_PCSC_PREFIX "pcsc:"
#ifdef __cplusplus
} /* extern "C" */
diff --git a/lib/libfido2/src/fido.h b/lib/libfido2/src/fido.h
index ef98130b09e..f1cd026b1d3 100644
--- a/lib/libfido2/src/fido.h
+++ b/lib/libfido2/src/fido.h
@@ -41,6 +41,7 @@ fido_dev_t *fido_dev_new(void);
fido_dev_t *fido_dev_new_with_info(const fido_dev_info_t *);
fido_dev_info_t *fido_dev_info_new(size_t);
fido_cbor_info_t *fido_cbor_info_new(void);
+void *fido_dev_io_handle(const fido_dev_t *);
void fido_assert_free(fido_assert_t **);
void fido_cbor_info_free(fido_cbor_info_t **);
@@ -87,16 +88,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 *,
@@ -120,6 +122,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);
@@ -129,6 +132,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 *);
@@ -141,7 +145,9 @@ int fido_cred_set_user(fido_cred_t *, const unsigned char *, size_t,
int fido_cred_set_x509(fido_cred_t *, const unsigned char *, size_t);
int fido_cred_verify(const fido_cred_t *);
int fido_cred_verify_self(const fido_cred_t *);
+#ifdef _FIDO_SIGSET_DEFINED
int fido_dev_set_sigmask(fido_dev_t *, const fido_sigset_t *);
+#endif
int fido_dev_cancel(fido_dev_t *);
int fido_dev_close(fido_dev_t *);
int fido_dev_get_assert(fido_dev_t *, fido_assert_t *, const char *);
@@ -151,6 +157,8 @@ int fido_dev_get_uv_retry_count(fido_dev_t *, int *);
int fido_dev_get_touch_begin(fido_dev_t *);
int fido_dev_get_touch_status(fido_dev_t *, int *, int);
int fido_dev_info_manifest(fido_dev_info_t *, size_t, size_t *);
+int fido_dev_info_set(fido_dev_info_t *, size_t, const char *, const char *,
+ const char *, const fido_dev_io_t *, const fido_dev_transport_t *);
int fido_dev_make_cred(fido_dev_t *, fido_cred_t *, const char *);
int fido_dev_open_with_info(fido_dev_t *);
int fido_dev_open(fido_dev_t *, const char *);
@@ -158,6 +166,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 *);
@@ -175,16 +184,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);
@@ -197,19 +208,21 @@ uint8_t fido_dev_build(const fido_dev_t *);
uint8_t fido_dev_flags(const fido_dev_t *);
int16_t fido_dev_info_vendor(const fido_dev_info_t *);
int16_t fido_dev_info_product(const fido_dev_info_t *);
-uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *);
uint64_t fido_cbor_info_maxcredbloblen(const fido_cbor_info_t *);
uint64_t fido_cbor_info_maxcredcntlst(const fido_cbor_info_t *);
uint64_t fido_cbor_info_maxcredidlen(const fido_cbor_info_t *);
+uint64_t fido_cbor_info_maxlargeblob(const fido_cbor_info_t *);
+uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *);
uint64_t fido_cbor_info_fwversion(const fido_cbor_info_t *);
bool fido_dev_has_pin(const fido_dev_t *);
bool fido_dev_has_uv(const fido_dev_t *);
bool fido_dev_is_fido2(const fido_dev_t *);
bool fido_dev_is_winhello(const fido_dev_t *);
-bool fido_dev_supports_pin(const fido_dev_t *);
-bool fido_dev_supports_cred_prot(const fido_dev_t *);
bool fido_dev_supports_credman(const fido_dev_t *);
+bool fido_dev_supports_cred_prot(const fido_dev_t *);
+bool fido_dev_supports_permissions(const fido_dev_t *);
+bool fido_dev_supports_pin(const fido_dev_t *);
bool fido_dev_supports_uv(const fido_dev_t *);
int fido_dev_largeblob_get(fido_dev_t *, const unsigned char *, size_t,
diff --git a/lib/libfido2/src/fido/config.h b/lib/libfido2/src/fido/config.h
index 869927df914..d8134a3c7b6 100644
--- a/lib/libfido2/src/fido/config.h
+++ b/lib/libfido2/src/fido/config.h
@@ -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" */
diff --git a/lib/libfido2/src/fido/eddsa.h b/lib/libfido2/src/fido/eddsa.h
index 4a810179b6f..083721cc3d3 100644
--- a/lib/libfido2/src/fido/eddsa.h
+++ b/lib/libfido2/src/fido/eddsa.h
@@ -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 */
diff --git a/lib/libfido2/src/fido/es256.h b/lib/libfido2/src/fido/es256.h
index 80f4db39c7b..683494dadfe 100644
--- a/lib/libfido2/src/fido/es256.h
+++ b/lib/libfido2/src/fido/es256.h
@@ -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
diff --git a/lib/libfido2/src/fido/param.h b/lib/libfido2/src/fido/param.h
index 025bb57dd81..7c6db98cfd5 100644
--- a/lib/libfido2/src/fido/param.h
+++ b/lib/libfido2/src/fido/param.h
@@ -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 */
diff --git a/lib/libfido2/src/fido/rs256.h b/lib/libfido2/src/fido/rs256.h
index 2b08d59980c..03981619178 100644
--- a/lib/libfido2/src/fido/rs256.h
+++ b/lib/libfido2/src/fido/rs256.h
@@ -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);
diff --git a/lib/libfido2/src/fido/types.h b/lib/libfido2/src/fido/types.h
index 00b6058c7e1..593a6a6b481 100644
--- a/lib/libfido2/src/fido/types.h
+++ b/lib/libfido2/src/fido/types.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018 Yubico AB. All rights reserved.
+ * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
@@ -48,10 +48,14 @@ typedef enum {
typedef void fido_log_handler_t(const char *);
+#undef _FIDO_SIGSET_DEFINED
+#define _FIDO_SIGSET_DEFINED
#ifdef _WIN32
typedef int fido_sigset_t;
-#else
+#elif defined(SIG_BLOCK)
typedef sigset_t fido_sigset_t;
+#else
+#undef _FIDO_SIGSET_DEFINED
#endif
#ifdef _FIDO_INTERNAL
@@ -107,8 +111,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 +132,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 {
@@ -146,13 +155,13 @@ typedef struct fido_cred {
fido_attcred_t attcred; /* returned credential (key + id) */
fido_attstmt_t attstmt; /* attestation statement (x509 + sig) */
fido_blob_t largeblob_key; /* decoded large blob key */
- fido_blob_t blob; /* FIDO 2.1 credBlob */
+ fido_blob_t blob; /* CTAP 2.1 credBlob */
} fido_cred_t;
typedef struct fido_assert_extattr {
int mask; /* decoded extensions */
fido_blob_t hmac_secret_enc; /* hmac secret, encrypted */
- fido_blob_t blob; /* decoded FIDO 2.1 credBlob */
+ fido_blob_t blob; /* decoded CTAP 2.1 credBlob */
} fido_assert_extattr_t;
typedef struct _fido_assert_stmt {
@@ -211,18 +220,19 @@ typedef struct fido_algo_array {
} fido_algo_array_t;
typedef struct fido_cbor_info {
- fido_str_array_t versions; /* supported versions: fido2|u2f */
- fido_str_array_t extensions; /* list of supported extensions */
- fido_str_array_t transports; /* list of supported transports */
- unsigned char aaguid[16]; /* aaguid */
- fido_opt_array_t options; /* list of supported options */
- uint64_t maxmsgsiz; /* maximum message size */
- fido_byte_array_t protocols; /* supported pin protocols */
- fido_algo_array_t algorithms; /* list of supported algorithms */
- uint64_t maxcredcntlst; /* max number of credentials in list */
- uint64_t maxcredidlen; /* max credential ID length */
- uint64_t fwversion; /* firmware version */
+ fido_str_array_t versions; /* supported versions: fido2|u2f */
+ fido_str_array_t extensions; /* list of supported extensions */
+ fido_str_array_t transports; /* list of supported transports */
+ unsigned char aaguid[16]; /* aaguid */
+ fido_opt_array_t options; /* list of supported options */
+ uint64_t maxmsgsiz; /* maximum message size */
+ fido_byte_array_t protocols; /* supported pin protocols */
+ fido_algo_array_t algorithms; /* list of supported algorithms */
+ uint64_t maxcredcntlst; /* max credentials in list */
+ uint64_t maxcredidlen; /* max credential ID length */
+ uint64_t fwversion; /* firmware version */
uint64_t maxcredbloblen; /* max credBlob length */
+ uint64_t maxlargeblob; /* max largeBlob array length */
} fido_cbor_info_t;
typedef struct fido_dev_info {
@@ -260,6 +270,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
diff --git a/lib/libfido2/src/hid.c b/lib/libfido2/src/hid.c
index a3768ad3cae..926272b6b3e 100644
--- a/lib/libfido2/src/hid.c
+++ b/lib/libfido2/src/hid.c
@@ -121,6 +121,15 @@ fido_dev_info_new(size_t n)
return (calloc(n, sizeof(fido_dev_info_t)));
}
+static void
+fido_dev_info_reset(fido_dev_info_t *di)
+{
+ free(di->path);
+ free(di->manufacturer);
+ free(di->product);
+ memset(di, 0, sizeof(*di));
+}
+
void
fido_dev_info_free(fido_dev_info_t **devlist_p, size_t n)
{
@@ -129,13 +138,8 @@ fido_dev_info_free(fido_dev_info_t **devlist_p, size_t n)
if (devlist_p == NULL || (devlist = *devlist_p) == NULL)
return;
- for (size_t i = 0; i < n; i++) {
- const fido_dev_info_t *di;
- di = &devlist[i];
- free(di->path);
- free(di->manufacturer);
- free(di->product);
- }
+ for (size_t i = 0; i < n; i++)
+ fido_dev_info_reset(&devlist[i]);
free(devlist);
@@ -148,6 +152,44 @@ fido_dev_info_ptr(const fido_dev_info_t *devlist, size_t i)
return (&devlist[i]);
}
+int
+fido_dev_info_set(fido_dev_info_t *devlist, size_t i,
+ const char *path, const char *manufacturer, const char *product,
+ const fido_dev_io_t *io, const fido_dev_transport_t *transport)
+{
+ char *path_copy = NULL, *manu_copy = NULL, *prod_copy = NULL;
+ int r;
+
+ if (path == NULL || manufacturer == NULL || product == NULL ||
+ io == NULL) {
+ r = FIDO_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
+
+ if ((path_copy = strdup(path)) == NULL ||
+ (manu_copy = strdup(manufacturer)) == NULL ||
+ (prod_copy = strdup(product)) == NULL) {
+ r = FIDO_ERR_INTERNAL;
+ goto out;
+ }
+
+ fido_dev_info_reset(&devlist[i]);
+ devlist[i].path = path_copy;
+ devlist[i].manufacturer = manu_copy;
+ devlist[i].product = prod_copy;
+ devlist[i].io = *io;
+ if (transport)
+ devlist[i].transport = *transport;
+ r = FIDO_OK;
+out:
+ if (r != FIDO_OK) {
+ free(prod_copy);
+ free(manu_copy);
+ free(path_copy);
+ }
+ return (r);
+}
+
const char *
fido_dev_info_path(const fido_dev_info_t *di)
{
diff --git a/lib/libfido2/src/hid_unix.c b/lib/libfido2/src/hid_unix.c
index 4b2aff9d67f..946b2dc3b65 100644
--- a/lib/libfido2/src/hid_unix.c
+++ b/lib/libfido2/src/hid_unix.c
@@ -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;
diff --git a/lib/libfido2/src/info.c b/lib/libfido2/src/info.c
index 57bc8de4406..ea26f22297a 100644
--- a/lib/libfido2/src/info.c
+++ b/lib/libfido2/src/info.c
@@ -186,14 +186,6 @@ out:
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);
}
@@ -276,6 +268,8 @@ parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg)
return (decode_string_array(val, &ci->transports));
case 10: /* algorithms */
return (decode_algorithms(val, &ci->algorithms));
+ case 11: /* maxSerializedLargeBlobArray */
+ return (cbor_decode_uint64(val, &ci->maxlargeblob));
case 14: /* fwVersion */
return (cbor_decode_uint64(val, &ci->fwversion));
case 15: /* maxCredBlobLen */
@@ -287,13 +281,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 +296,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 +317,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 +325,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 +335,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 +350,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
@@ -511,6 +464,12 @@ fido_cbor_info_maxcredidlen(const fido_cbor_info_t *ci)
}
uint64_t
+fido_cbor_info_maxlargeblob(const fido_cbor_info_t *ci)
+{
+ return (ci->maxlargeblob);
+}
+
+uint64_t
fido_cbor_info_fwversion(const fido_cbor_info_t *ci)
{
return (ci->fwversion);
diff --git a/lib/libfido2/src/io.c b/lib/libfido2/src/io.c
index e2594203efb..70f777fb49a 100644
--- a/lib/libfido2/src/io.c
+++ b/lib/libfido2/src/io.c
@@ -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 (fido_time_now(&ts) != 0)
+ return (-1);
+
if (d->rx_len > sizeof(*fp) || (n = d->io.read(d->io_handle,
- (unsigned char *)fp, d->rx_len, ms)) < 0 || (size_t)n != d->rx_len)
+ (unsigned char *)fp, d->rx_len, *ms)) < 0 || (size_t)n != d->rx_len)
return (-1);
- return (0);
+ return (fido_time_delta(&ts, ms));
}
static int
-rx_preamble(fido_dev_t *d, uint8_t cmd, struct frame *fp, int ms)
+rx_preamble(fido_dev_t *d, uint8_t cmd, struct frame *fp, int *ms)
{
do {
if (rx_frame(d, fp, ms) < 0)
@@ -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;
diff --git a/lib/libfido2/src/iso7816.c b/lib/libfido2/src/iso7816.c
index a11aae3e99d..a4902277c6d 100644
--- a/lib/libfido2/src/iso7816.c
+++ b/lib/libfido2/src/iso7816.c
@@ -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));
}
diff --git a/lib/libfido2/src/iso7816.h b/lib/libfido2/src/iso7816.h
index 5f5363a63a5..9bfad1fbab9 100644
--- a/lib/libfido2/src/iso7816.h
+++ b/lib/libfido2/src/iso7816.h
@@ -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);
diff --git a/lib/libfido2/src/largeblob.c b/lib/libfido2/src/largeblob.c
index fa453f5de33..c8173170766 100644
--- a/lib/libfido2/src/largeblob.c
+++ b/lib/libfido2/src/largeblob.c
@@ -153,7 +153,7 @@ fail:
}
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 @@ fail:
}
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 @@ fail:
}
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 @@ fail:
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 @@ fail:
}
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);
diff --git a/lib/libfido2/src/nfc.c b/lib/libfido2/src/nfc.c
new file mode 100644
index 00000000000..8e1221bb505
--- /dev/null
+++ b/lib/libfido2/src/nfc.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2020-2022 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "fido.h"
+#include "fido/param.h"
+#include "iso7816.h"
+
+#define TX_CHUNK_SIZE 240
+
+static const uint8_t aid[] = { 0xa0, 0x00, 0x00, 0x06, 0x47, 0x2f, 0x00, 0x01 };
+static const uint8_t v_u2f[] = { 'U', '2', 'F', '_', 'V', '2' };
+static const uint8_t v_fido[] = { 'F', 'I', 'D', 'O', '_', '2', '_', '0' };
+
+static int
+tx_short_apdu(fido_dev_t *d, const iso7816_header_t *h, const uint8_t *payload,
+ uint8_t payload_len, uint8_t cla_flags)
+{
+ uint8_t apdu[5 + UINT8_MAX + 1];
+ uint8_t sw[2];
+ size_t apdu_len;
+ int ok = -1;
+
+ memset(&apdu, 0, sizeof(apdu));
+ apdu[0] = h->cla | cla_flags;
+ apdu[1] = h->ins;
+ apdu[2] = h->p1;
+ apdu[3] = h->p2;
+ apdu[4] = payload_len;
+ memcpy(&apdu[5], payload, payload_len);
+ apdu_len = (size_t)(5 + payload_len + 1);
+
+ if (d->io.write(d->io_handle, apdu, apdu_len) < 0) {
+ fido_log_debug("%s: write", __func__);
+ goto fail;
+ }
+
+ if (cla_flags & 0x10) {
+ if (d->io.read(d->io_handle, sw, sizeof(sw), -1) != 2) {
+ fido_log_debug("%s: read", __func__);
+ goto fail;
+ }
+ if ((sw[0] << 8 | sw[1]) != SW_NO_ERROR) {
+ fido_log_debug("%s: unexpected sw", __func__);
+ goto fail;
+ }
+ }
+
+ ok = 0;
+fail:
+ explicit_bzero(apdu, sizeof(apdu));
+
+ return ok;
+}
+
+static int
+nfc_do_tx(fido_dev_t *d, const uint8_t *apdu_ptr, size_t apdu_len)
+{
+ iso7816_header_t h;
+
+ if (fido_buf_read(&apdu_ptr, &apdu_len, &h, sizeof(h)) < 0) {
+ fido_log_debug("%s: header", __func__);
+ return -1;
+ }
+ if (apdu_len < 2) {
+ fido_log_debug("%s: apdu_len %zu", __func__, apdu_len);
+ return -1;
+ }
+
+ apdu_len -= 2; /* trim le1 le2 */
+
+ while (apdu_len > TX_CHUNK_SIZE) {
+ if (tx_short_apdu(d, &h, apdu_ptr, TX_CHUNK_SIZE, 0x10) < 0) {
+ fido_log_debug("%s: chain", __func__);
+ return -1;
+ }
+ apdu_ptr += TX_CHUNK_SIZE;
+ apdu_len -= TX_CHUNK_SIZE;
+ }
+
+ if (tx_short_apdu(d, &h, apdu_ptr, (uint8_t)apdu_len, 0) < 0) {
+ fido_log_debug("%s: tx_short_apdu", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+fido_nfc_tx(fido_dev_t *d, uint8_t cmd, const unsigned char *buf, size_t count)
+{
+ iso7816_apdu_t *apdu = NULL;
+ const uint8_t *ptr;
+ size_t len;
+ int ok = -1;
+
+ switch (cmd) {
+ case CTAP_CMD_INIT: /* select */
+ if ((apdu = iso7816_new(0, 0xa4, 0x04, sizeof(aid))) == NULL ||
+ iso7816_add(apdu, aid, sizeof(aid)) < 0) {
+ fido_log_debug("%s: iso7816", __func__);
+ goto fail;
+ }
+ break;
+ case CTAP_CMD_CBOR: /* wrap cbor */
+ if (count > UINT16_MAX || (apdu = iso7816_new(0x80, 0x10, 0x00,
+ (uint16_t)count)) == NULL ||
+ iso7816_add(apdu, buf, count) < 0) {
+ fido_log_debug("%s: iso7816", __func__);
+ goto fail;
+ }
+ break;
+ case CTAP_CMD_MSG: /* already an apdu */
+ break;
+ default:
+ fido_log_debug("%s: cmd=%02x", __func__, cmd);
+ goto fail;
+ }
+
+ if (apdu != NULL) {
+ ptr = iso7816_ptr(apdu);
+ len = iso7816_len(apdu);
+ } else {
+ ptr = buf;
+ len = count;
+ }
+
+ if (nfc_do_tx(d, ptr, len) < 0) {
+ fido_log_debug("%s: nfc_do_tx", __func__);
+ goto fail;
+ }
+
+ ok = 0;
+fail:
+ iso7816_free(&apdu);
+
+ return ok;
+}
+
+static int
+rx_init(fido_dev_t *d, unsigned char *buf, size_t count, int ms)
+{
+ fido_ctap_info_t *attr = (fido_ctap_info_t *)buf;
+ uint8_t f[64];
+ int n;
+
+ if (count != sizeof(*attr)) {
+ fido_log_debug("%s: count=%zu", __func__, count);
+ return -1;
+ }
+
+ memset(attr, 0, sizeof(*attr));
+
+ if ((n = d->io.read(d->io_handle, f, sizeof(f), ms)) < 2 ||
+ (f[n - 2] << 8 | f[n - 1]) != SW_NO_ERROR) {
+ fido_log_debug("%s: read", __func__);
+ return -1;
+ }
+
+ n -= 2;
+
+ if (n == sizeof(v_u2f) && memcmp(f, v_u2f, sizeof(v_u2f)) == 0)
+ attr->flags = FIDO_CAP_CBOR;
+ else if (n == sizeof(v_fido) && memcmp(f, v_fido, sizeof(v_fido)) == 0)
+ attr->flags = FIDO_CAP_CBOR | FIDO_CAP_NMSG;
+ else {
+ fido_log_debug("%s: unknown version string", __func__);
+#ifdef FIDO_FUZZ
+ attr->flags = FIDO_CAP_CBOR | FIDO_CAP_NMSG;
+#else
+ return -1;
+#endif
+ }
+
+ memcpy(&attr->nonce, &d->nonce, sizeof(attr->nonce)); /* XXX */
+
+ return (int)count;
+}
+
+static int
+tx_get_response(fido_dev_t *d, uint8_t count)
+{
+ uint8_t apdu[5];
+
+ memset(apdu, 0, sizeof(apdu));
+ apdu[1] = 0xc0; /* GET_RESPONSE */
+ apdu[4] = count;
+
+ if (d->io.write(d->io_handle, apdu, sizeof(apdu)) < 0) {
+ fido_log_debug("%s: write", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+rx_apdu(fido_dev_t *d, uint8_t sw[2], unsigned char **buf, size_t *count, int *ms)
+{
+ uint8_t f[256 + 2];
+ struct timespec ts;
+ int n, ok = -1;
+
+ if (fido_time_now(&ts) != 0)
+ goto fail;
+
+ if ((n = d->io.read(d->io_handle, f, sizeof(f), *ms)) < 2) {
+ fido_log_debug("%s: read", __func__);
+ goto fail;
+ }
+
+ if (fido_time_delta(&ts, ms) != 0)
+ goto fail;
+
+ if (fido_buf_write(buf, count, f, (size_t)(n - 2)) < 0) {
+ fido_log_debug("%s: fido_buf_write", __func__);
+ goto fail;
+ }
+
+ memcpy(sw, f + n - 2, 2);
+
+ ok = 0;
+fail:
+ explicit_bzero(f, sizeof(f));
+
+ return ok;
+}
+
+static int
+rx_msg(fido_dev_t *d, unsigned char *buf, size_t count, int ms)
+{
+ uint8_t sw[2];
+ const size_t bufsiz = count;
+
+ if (rx_apdu(d, sw, &buf, &count, &ms) < 0) {
+ fido_log_debug("%s: preamble", __func__);
+ return -1;
+ }
+
+ while (sw[0] == SW1_MORE_DATA)
+ if (tx_get_response(d, sw[1]) < 0 ||
+ rx_apdu(d, sw, &buf, &count, &ms) < 0) {
+ fido_log_debug("%s: chain", __func__);
+ return -1;
+ }
+
+ if (fido_buf_write(&buf, &count, sw, sizeof(sw)) < 0) {
+ fido_log_debug("%s: sw", __func__);
+ return -1;
+ }
+
+ if (bufsiz - count > INT_MAX) {
+ fido_log_debug("%s: bufsiz", __func__);
+ return -1;
+ }
+
+ return (int)(bufsiz - count);
+}
+
+static int
+rx_cbor(fido_dev_t *d, unsigned char *buf, size_t count, int ms)
+{
+ int r;
+
+ if ((r = rx_msg(d, buf, count, ms)) < 2)
+ return -1;
+
+ return r - 2;
+}
+
+int
+fido_nfc_rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms)
+{
+ switch (cmd) {
+ case CTAP_CMD_INIT:
+ return rx_init(d, buf, count, ms);
+ case CTAP_CMD_CBOR:
+ return rx_cbor(d, buf, count, ms);
+ case CTAP_CMD_MSG:
+ return rx_msg(d, buf, count, ms);
+ default:
+ fido_log_debug("%s: cmd=%02x", __func__, cmd);
+ return -1;
+ }
+}
+
+#ifdef USE_NFC
+bool
+fido_is_nfc(const char *path)
+{
+ return strncmp(path, FIDO_NFC_PREFIX, strlen(FIDO_NFC_PREFIX)) == 0;
+}
+
+int
+fido_dev_set_nfc(fido_dev_t *d)
+{
+ if (d->io_handle != NULL) {
+ fido_log_debug("%s: device open", __func__);
+ return -1;
+ }
+ d->io_own = true;
+ d->io = (fido_dev_io_t) {
+ fido_nfc_open,
+ fido_nfc_close,
+ fido_nfc_read,
+ fido_nfc_write,
+ };
+ d->transport = (fido_dev_transport_t) {
+ fido_nfc_rx,
+ fido_nfc_tx,
+ };
+
+ return 0;
+}
+#endif /* USE_NFC */
diff --git a/lib/libfido2/src/pin.c b/lib/libfido2/src/pin.c
index d3104e0ca6e..30eeb086a6e 100644
--- a/lib/libfido2/src/pin.c
+++ b/lib/libfido2/src/pin.c
@@ -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 @@ fail:
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 @@ fail:
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 @@ fail:
}
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 @@ fail:
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 @@ fail:
}
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;
}
diff --git a/lib/libfido2/src/reset.c b/lib/libfido2/src/reset.c
index 11380cea090..c5fe6dfe7ac 100644
--- a/lib/libfido2/src/reset.c
+++ b/lib/libfido2/src/reset.c
@@ -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));
}
diff --git a/lib/libfido2/src/rs1.c b/lib/libfido2/src/rs1.c
new file mode 100644
index 00000000000..134068b1674
--- /dev/null
+++ b/lib/libfido2/src/rs1.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2021 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ */
+
+#include <openssl/rsa.h>
+#include <openssl/obj_mac.h>
+
+#include "fido.h"
+
+#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050200fL
+static EVP_MD *
+rs1_get_EVP_MD(void)
+{
+ const EVP_MD *from;
+ EVP_MD *to = NULL;
+
+ if ((from = EVP_sha1()) != NULL && (to = malloc(sizeof(*to))) != NULL)
+ memcpy(to, from, sizeof(*to));
+
+ return (to);
+}
+
+static void
+rs1_free_EVP_MD(EVP_MD *md)
+{
+ freezero(md, sizeof(*md));
+}
+#elif OPENSSL_VERSION_NUMBER >= 0x30000000
+static EVP_MD *
+rs1_get_EVP_MD(void)
+{
+ return (EVP_MD_fetch(NULL, "SHA-1", NULL));
+}
+
+static void
+rs1_free_EVP_MD(EVP_MD *md)
+{
+ EVP_MD_free(md);
+}
+#else
+static EVP_MD *
+rs1_get_EVP_MD(void)
+{
+ const EVP_MD *md;
+
+ if ((md = EVP_sha1()) == NULL)
+ return (NULL);
+
+ return (EVP_MD_meth_dup(md));
+}
+
+static void
+rs1_free_EVP_MD(EVP_MD *md)
+{
+ EVP_MD_meth_free(md);
+}
+#endif /* LIBRESSL_VERSION_NUMBER */
+
+int
+rs1_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
+ const fido_blob_t *sig)
+{
+ EVP_PKEY_CTX *pctx = NULL;
+ EVP_MD *md = NULL;
+ int ok = -1;
+
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
+ fido_log_debug("%s: EVP_PKEY_base_id", __func__);
+ goto fail;
+ }
+
+ if ((md = rs1_get_EVP_MD()) == NULL) {
+ fido_log_debug("%s: rs1_get_EVP_MD", __func__);
+ goto fail;
+ }
+
+ if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL ||
+ EVP_PKEY_verify_init(pctx) != 1 ||
+ EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) != 1 ||
+ EVP_PKEY_CTX_set_signature_md(pctx, md) != 1) {
+ fido_log_debug("%s: EVP_PKEY_CTX", __func__);
+ goto fail;
+ }
+
+ if (EVP_PKEY_verify(pctx, sig->ptr, sig->len, dgst->ptr,
+ dgst->len) != 1) {
+ fido_log_debug("%s: EVP_PKEY_verify", __func__);
+ goto fail;
+ }
+
+ ok = 0;
+fail:
+ EVP_PKEY_CTX_free(pctx);
+ rs1_free_EVP_MD(md);
+
+ return (ok);
+}
diff --git a/lib/libfido2/src/rs256.c b/lib/libfido2/src/rs256.c
index c6d87a3ea22..95bae167a17 100644
--- a/lib/libfido2/src/rs256.c
+++ b/lib/libfido2/src/rs256.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018 Yubico AB. All rights reserved.
+ * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
@@ -11,31 +11,60 @@
#include "fido.h"
#include "fido/rs256.h"
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-static int
-RSA_bits(const RSA *r)
+#if OPENSSL_VERSION_NUMBER >= 0x30000000
+#define get0_RSA(x) EVP_PKEY_get0_RSA((x))
+#else
+#define get0_RSA(x) EVP_PKEY_get0((x))
+#endif
+
+#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050200fL
+static EVP_MD *
+rs256_get_EVP_MD(void)
{
- return (BN_num_bits(r->n));
+ const EVP_MD *from;
+ EVP_MD *to = NULL;
+
+ if ((from = EVP_sha256()) != NULL && (to = malloc(sizeof(*to))) != NULL)
+ memcpy(to, from, sizeof(*to));
+
+ return (to);
}
-static int
-RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
+static void
+rs256_free_EVP_MD(EVP_MD *md)
+{
+ freezero(md, sizeof(*md));
+}
+#elif OPENSSL_VERSION_NUMBER >= 0x30000000
+static EVP_MD *
+rs256_get_EVP_MD(void)
{
- r->n = n;
- r->e = e;
- r->d = d;
+ return (EVP_MD_fetch(NULL, "SHA2-256", NULL));
+}
- return (1);
+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
-RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
+rs256_free_EVP_MD(EVP_MD *md)
{
- *n = r->n;
- *e = r->e;
- *d = r->d;
+ EVP_MD_meth_free(md);
}
-#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
+#endif /* LIBRESSL_VERSION_NUMBER */
static int
decode_bignum(const cbor_item_t *item, void *ptr, size_t len)
@@ -105,11 +134,20 @@ rs256_pk_free(rs256_pk_t **pkp)
int
rs256_pk_from_ptr(rs256_pk_t *pk, const void *ptr, size_t len)
{
+ EVP_PKEY *pkey;
+
if (len < sizeof(*pk))
return (FIDO_ERR_INVALID_ARGUMENT);
memcpy(pk, ptr, sizeof(*pk));
+ if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
+ fido_log_debug("%s: rs256_pk_to_EVP_PKEY", __func__);
+ return (FIDO_ERR_INVALID_ARGUMENT);
+ }
+
+ EVP_PKEY_free(pkey);
+
return (FIDO_OK);
}
@@ -140,6 +178,11 @@ rs256_pk_to_EVP_PKEY(const rs256_pk_t *k)
n = NULL;
e = NULL;
+ if (RSA_bits(rsa) != 2048) {
+ fido_log_debug("%s: invalid key length", __func__);
+ goto fail;
+ }
+
if ((pkey = EVP_PKEY_new()) == NULL ||
EVP_PKEY_assign_RSA(pkey, rsa) == 0) {
fido_log_debug("%s: EVP_PKEY_assign_RSA", __func__);
@@ -198,3 +241,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)
+{
+ const RSA *rsa;
+
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA ||
+ (rsa = get0_RSA(pkey)) == NULL)
+ return (FIDO_ERR_INVALID_ARGUMENT);
+
+ return (rs256_pk_from_RSA(pk, rsa));
+}
+
+int
+rs256_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
+ const fido_blob_t *sig)
+{
+ EVP_PKEY_CTX *pctx = NULL;
+ EVP_MD *md = NULL;
+ int ok = -1;
+
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
+ fido_log_debug("%s: EVP_PKEY_base_id", __func__);
+ goto fail;
+ }
+
+ if ((md = rs256_get_EVP_MD()) == NULL) {
+ fido_log_debug("%s: rs256_get_EVP_MD", __func__);
+ goto fail;
+ }
+
+ if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL ||
+ EVP_PKEY_verify_init(pctx) != 1 ||
+ EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) != 1 ||
+ EVP_PKEY_CTX_set_signature_md(pctx, md) != 1) {
+ fido_log_debug("%s: EVP_PKEY_CTX", __func__);
+ goto fail;
+ }
+
+ if (EVP_PKEY_verify(pctx, sig->ptr, sig->len, dgst->ptr,
+ dgst->len) != 1) {
+ fido_log_debug("%s: EVP_PKEY_verify", __func__);
+ goto fail;
+ }
+
+ ok = 0;
+fail:
+ EVP_PKEY_CTX_free(pctx);
+ rs256_free_EVP_MD(md);
+
+ return (ok);
+}
+
+int
+rs256_pk_verify_sig(const fido_blob_t *dgst, const rs256_pk_t *pk,
+ const fido_blob_t *sig)
+{
+ EVP_PKEY *pkey;
+ int ok = -1;
+
+ if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL ||
+ rs256_verify_sig(dgst, pkey, sig) < 0) {
+ fido_log_debug("%s: rs256_verify_sig", __func__);
+ goto fail;
+ }
+
+ ok = 0;
+fail:
+ EVP_PKEY_free(pkey);
+
+ return (ok);
+}
diff --git a/lib/libfido2/src/time.c b/lib/libfido2/src/time.c
new file mode 100644
index 00000000000..b82b6187449
--- /dev/null
+++ b/lib/libfido2/src/time.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2021 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ */
+
+#include <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;
+}
diff --git a/lib/libfido2/src/touch.c b/lib/libfido2/src/touch.c
new file mode 100644
index 00000000000..66b1c3478c0
--- /dev/null
+++ b/lib/libfido2/src/touch.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ */
+
+#include <openssl/sha.h>
+#include "fido.h"
+
+int
+fido_dev_get_touch_begin(fido_dev_t *dev)
+{
+ fido_blob_t f;
+ cbor_item_t *argv[9];
+ const char *clientdata = FIDO_DUMMY_CLIENTDATA;
+ const uint8_t user_id = FIDO_DUMMY_USER_ID;
+ unsigned char cdh[SHA256_DIGEST_LENGTH];
+ fido_rp_t rp;
+ fido_user_t user;
+ int ms = dev->timeout_ms;
+ int r = FIDO_ERR_INTERNAL;
+
+ memset(&f, 0, sizeof(f));
+ memset(argv, 0, sizeof(argv));
+ memset(cdh, 0, sizeof(cdh));
+ memset(&rp, 0, sizeof(rp));
+ memset(&user, 0, sizeof(user));
+
+ if (fido_dev_is_fido2(dev) == false)
+ return (u2f_get_touch_begin(dev, &ms));
+
+ if (SHA256((const void *)clientdata, strlen(clientdata), cdh) != cdh) {
+ fido_log_debug("%s: sha256", __func__);
+ return (FIDO_ERR_INTERNAL);
+ }
+
+ if ((rp.id = strdup(FIDO_DUMMY_RP_ID)) == NULL ||
+ (user.name = strdup(FIDO_DUMMY_USER_NAME)) == NULL) {
+ fido_log_debug("%s: strdup", __func__);
+ goto fail;
+ }
+
+ if (fido_blob_set(&user.id, &user_id, sizeof(user_id)) < 0) {
+ fido_log_debug("%s: fido_blob_set", __func__);
+ goto fail;
+ }
+
+ if ((argv[0] = cbor_build_bytestring(cdh, sizeof(cdh))) == NULL ||
+ (argv[1] = cbor_encode_rp_entity(&rp)) == NULL ||
+ (argv[2] = cbor_encode_user_entity(&user)) == NULL ||
+ (argv[3] = cbor_encode_pubkey_param(COSE_ES256)) == NULL) {
+ fido_log_debug("%s: cbor encode", __func__);
+ goto fail;
+ }
+
+ if (fido_dev_supports_pin(dev)) {
+ if ((argv[7] = cbor_new_definite_bytestring()) == NULL ||
+ (argv[8] = cbor_encode_pin_opt(dev)) == NULL) {
+ fido_log_debug("%s: cbor encode", __func__);
+ goto fail;
+ }
+ }
+
+ if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, nitems(argv), &f) < 0 ||
+ fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, &ms) < 0) {
+ fido_log_debug("%s: fido_tx", __func__);
+ r = FIDO_ERR_TX;
+ goto fail;
+ }
+
+ r = FIDO_OK;
+fail:
+ cbor_vector_free(argv, nitems(argv));
+ free(f.ptr);
+ free(rp.id);
+ free(user.name);
+ free(user.id.ptr);
+
+ return (r);
+}
+
+int
+fido_dev_get_touch_status(fido_dev_t *dev, int *touched, int ms)
+{
+ int r;
+
+ *touched = 0;
+
+ if (fido_dev_is_fido2(dev) == false)
+ return (u2f_get_touch_status(dev, touched, &ms));
+
+ switch ((r = fido_rx_cbor_status(dev, &ms))) {
+ case FIDO_ERR_PIN_AUTH_INVALID:
+ case FIDO_ERR_PIN_INVALID:
+ case FIDO_ERR_PIN_NOT_SET:
+ case FIDO_ERR_SUCCESS:
+ *touched = 1;
+ break;
+ case FIDO_ERR_RX:
+ /* ignore */
+ break;
+ default:
+ fido_log_debug("%s: fido_rx_cbor_status", __func__);
+ return (r);
+ }
+
+ return (FIDO_OK);
+}
diff --git a/lib/libfido2/src/tpm.c b/lib/libfido2/src/tpm.c
new file mode 100644
index 00000000000..74244f8cbf0
--- /dev/null
+++ b/lib/libfido2/src/tpm.c
@@ -0,0 +1,390 @@
+/*
+ * 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
+#define TPM_ALG_ECC 0x0023
+
+/* Part 2, 6.4: TPM_ECC_CURVE */
+#define TPM_ECC_P256 0x0003
+
+/* Part 2, 6.9: TPM_ST_ATTEST_CERTIFY */
+#define TPM_ST_CERTIFY 0x8017
+
+/* Part 2, 8.3: TPMA_OBJECT */
+#define TPMA_RESERVED 0xfff8f309 /* reserved bits; must be zero */
+#define TPMA_FIXED 0x00000002 /* object has fixed hierarchy */
+#define TPMA_CLEAR 0x00000004 /* object persists */
+#define TPMA_FIXED_P 0x00000010 /* object has fixed parent */
+#define TPMA_SENSITIVE 0x00000020 /* data originates within tpm */
+#define TPMA_SIGN 0x00040000 /* object may sign */
+
+/* Part 2, 10.4.2: TPM2B_DIGEST */
+PACKED_TYPE(tpm_sha256_digest_t,
+struct tpm_sha256_digest {
+ uint16_t size; /* sizeof(body) */
+ uint8_t body[32];
+})
+
+/* Part 2, 10.4.3: TPM2B_DATA */
+PACKED_TYPE(tpm_sha1_data_t,
+struct tpm_sha1_data {
+ uint16_t size; /* sizeof(body */
+ uint8_t body[20];
+})
+
+/* Part 2, 10.5.3: TPM2B_NAME */
+PACKED_TYPE(tpm_sha256_name_t,
+struct tpm_sha256_name {
+ uint16_t size; /* sizeof(alg) + sizeof(body) */
+ uint16_t alg; /* TPM_ALG_SHA256 */
+ uint8_t body[32];
+})
+
+/* Part 2, 10.11.1: TPMS_CLOCK_INFO */
+PACKED_TYPE(tpm_clock_info_t,
+struct tpm_clock_info {
+ uint64_t timestamp_ms;
+ uint32_t reset_count; /* obfuscated by tpm */
+ uint32_t restart_count; /* obfuscated by tpm */
+ uint8_t safe; /* 1 if timestamp_ms is current */
+})
+
+/* Part 2, 10.12.8 TPMS_ATTEST */
+PACKED_TYPE(tpm_sha1_attest_t,
+struct tpm_sha1_attest {
+ uint32_t magic; /* TPM_MAGIC */
+ uint16_t type; /* TPM_ST_ATTEST_CERTIFY */
+ tpm_sha256_name_t signer; /* full tpm path of signing key */
+ tpm_sha1_data_t data; /* signed sha1 */
+ tpm_clock_info_t clock;
+ uint64_t fwversion; /* obfuscated by tpm */
+ tpm_sha256_name_t name; /* sha256 of tpm_rs256_pubarea_t */
+ tpm_sha256_name_t qual_name; /* full tpm path of attested key */
+})
+
+/* Part 2, 11.2.4.5: TPM2B_PUBLIC_KEY_RSA */
+PACKED_TYPE(tpm_rs256_key_t,
+struct tpm_rs256_key {
+ uint16_t size; /* sizeof(body) */
+ uint8_t body[256];
+})
+
+/* Part 2, 11.2.5.1: TPM2B_ECC_PARAMETER */
+PACKED_TYPE(tpm_es256_coord_t,
+struct tpm_es256_coord {
+ uint16_t size; /* sizeof(body) */
+ uint8_t body[32];
+})
+
+/* Part 2, 11.2.5.2: TPMS_ECC_POINT */
+PACKED_TYPE(tpm_es256_point_t,
+struct tpm_es256_point {
+ tpm_es256_coord_t x;
+ tpm_es256_coord_t y;
+})
+
+/* Part 2, 12.2.3.5: TPMS_RSA_PARMS */
+PACKED_TYPE(tpm_rs256_param_t,
+struct tpm_rs256_param {
+ uint16_t symmetric; /* TPM_ALG_NULL */
+ uint16_t scheme; /* TPM_ALG_NULL */
+ uint16_t keybits; /* 2048 */
+ uint32_t exponent; /* zero (meaning 2^16 + 1) */
+})
+
+/* Part 2, 12.2.3.6: TPMS_ECC_PARMS */
+PACKED_TYPE(tpm_es256_param_t,
+struct tpm_es256_param {
+ uint16_t symmetric; /* TPM_ALG_NULL */
+ uint16_t scheme; /* TPM_ALG_NULL */
+ uint16_t curve_id; /* TPM_ECC_P256 */
+ uint16_t kdf; /* TPM_ALG_NULL */
+})
+
+/* Part 2, 12.2.4: TPMT_PUBLIC */
+PACKED_TYPE(tpm_rs256_pubarea_t,
+struct tpm_rs256_pubarea {
+ uint16_t alg; /* TPM_ALG_RSA */
+ uint16_t hash; /* TPM_ALG_SHA256 */
+ uint32_t attr;
+ tpm_sha256_digest_t policy; /* must be present? */
+ tpm_rs256_param_t param;
+ tpm_rs256_key_t key;
+})
+
+/* Part 2, 12.2.4: TPMT_PUBLIC */
+PACKED_TYPE(tpm_es256_pubarea_t,
+struct tpm_es256_pubarea {
+ uint16_t alg; /* TPM_ALG_ECC */
+ uint16_t hash; /* TPM_ALG_SHA256 */
+ uint32_t attr;
+ tpm_sha256_digest_t policy; /* must be present? */
+ tpm_es256_param_t param;
+ tpm_es256_point_t point;
+})
+
+static int
+get_signed_sha1(tpm_sha1_data_t *dgst, const fido_blob_t *authdata,
+ const fido_blob_t *clientdata)
+{
+ const EVP_MD *md = NULL;
+ EVP_MD_CTX *ctx = NULL;
+ int ok = -1;
+
+ if ((dgst->size = sizeof(dgst->body)) != SHA_DIGEST_LENGTH ||
+ (md = EVP_sha1()) == NULL ||
+ (ctx = EVP_MD_CTX_new()) == NULL ||
+ EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
+ EVP_DigestUpdate(ctx, authdata->ptr, authdata->len) != 1 ||
+ EVP_DigestUpdate(ctx, clientdata->ptr, clientdata->len) != 1 ||
+ EVP_DigestFinal_ex(ctx, dgst->body, NULL) != 1) {
+ fido_log_debug("%s: sha1", __func__);
+ goto fail;
+ }
+
+ ok = 0;
+fail:
+ EVP_MD_CTX_free(ctx);
+
+ return (ok);
+}
+
+static int
+get_signed_name(tpm_sha256_name_t *name, const fido_blob_t *pubarea)
+{
+ name->alg = TPM_ALG_SHA256;
+ name->size = sizeof(name->alg) + sizeof(name->body);
+ if (sizeof(name->body) != SHA256_DIGEST_LENGTH ||
+ SHA256(pubarea->ptr, pubarea->len, name->body) != name->body) {
+ fido_log_debug("%s: sha256", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+bswap_rs256_pubarea(tpm_rs256_pubarea_t *x)
+{
+ x->alg = htobe16(x->alg);
+ x->hash = htobe16(x->hash);
+ x->attr = htobe32(x->attr);
+ x->policy.size = htobe16(x->policy.size);
+ x->param.symmetric = htobe16(x->param.symmetric);
+ x->param.scheme = htobe16(x->param.scheme);
+ x->param.keybits = htobe16(x->param.keybits);
+ x->key.size = htobe16(x->key.size);
+}
+
+static void
+bswap_es256_pubarea(tpm_es256_pubarea_t *x)
+{
+ x->alg = htobe16(x->alg);
+ x->hash = htobe16(x->hash);
+ x->attr = htobe32(x->attr);
+ x->policy.size = htobe16(x->policy.size);
+ x->param.symmetric = htobe16(x->param.symmetric);
+ x->param.scheme = htobe16(x->param.scheme);
+ x->param.curve_id = htobe16(x->param.curve_id);
+ x->param.kdf = htobe16(x->param.kdf);
+ x->point.x.size = htobe16(x->point.x.size);
+ x->point.y.size = htobe16(x->point.y.size);
+}
+
+static void
+bswap_sha1_certinfo(tpm_sha1_attest_t *x)
+{
+ x->magic = htobe32(x->magic);
+ x->type = htobe16(x->type);
+ x->signer.size = htobe16(x->signer.size);
+ x->data.size = htobe16(x->data.size);
+ x->name.alg = htobe16(x->name.alg);
+ x->name.size = htobe16(x->name.size);
+}
+
+static int
+check_rs256_pubarea(const fido_blob_t *buf, const rs256_pk_t *pk)
+{
+ const tpm_rs256_pubarea_t *actual;
+ tpm_rs256_pubarea_t expected;
+ int ok;
+
+ if (buf->len != sizeof(*actual)) {
+ fido_log_debug("%s: buf->len=%zu", __func__, buf->len);
+ return -1;
+ }
+ actual = (const void *)buf->ptr;
+
+ memset(&expected, 0, sizeof(expected));
+ expected.alg = TPM_ALG_RSA;
+ expected.hash = TPM_ALG_SHA256;
+ expected.attr = be32toh(actual->attr);
+ expected.attr &= ~(TPMA_RESERVED|TPMA_CLEAR);
+ expected.attr |= (TPMA_FIXED|TPMA_FIXED_P|TPMA_SENSITIVE|TPMA_SIGN);
+ expected.policy = actual->policy;
+ expected.policy.size = sizeof(expected.policy.body);
+ expected.param.symmetric = TPM_ALG_NULL;
+ expected.param.scheme = TPM_ALG_NULL;
+ expected.param.keybits = 2048;
+ expected.param.exponent = 0; /* meaning 2^16+1 */
+ expected.key.size = sizeof(expected.key.body);
+ memcpy(&expected.key.body, &pk->n, sizeof(expected.key.body));
+ bswap_rs256_pubarea(&expected);
+
+ ok = timingsafe_bcmp(&expected, actual, sizeof(expected));
+ explicit_bzero(&expected, sizeof(expected));
+
+ return ok != 0 ? -1 : 0;
+}
+
+static int
+check_es256_pubarea(const fido_blob_t *buf, const es256_pk_t *pk)
+{
+ const tpm_es256_pubarea_t *actual;
+ tpm_es256_pubarea_t expected;
+ int ok;
+
+ if (buf->len != sizeof(*actual)) {
+ fido_log_debug("%s: buf->len=%zu", __func__, buf->len);
+ return -1;
+ }
+ actual = (const void *)buf->ptr;
+
+ memset(&expected, 0, sizeof(expected));
+ expected.alg = TPM_ALG_ECC;
+ expected.hash = TPM_ALG_SHA256;
+ expected.attr = be32toh(actual->attr);
+ expected.attr &= ~(TPMA_RESERVED|TPMA_CLEAR);
+ expected.attr |= (TPMA_FIXED|TPMA_FIXED_P|TPMA_SENSITIVE|TPMA_SIGN);
+ expected.policy = actual->policy;
+ expected.policy.size = sizeof(expected.policy.body);
+ expected.param.symmetric = TPM_ALG_NULL;
+ expected.param.scheme = TPM_ALG_NULL; /* TCG Alg. Registry, 5.2.4 */
+ expected.param.curve_id = TPM_ECC_P256;
+ expected.param.kdf = TPM_ALG_NULL;
+ expected.point.x.size = sizeof(expected.point.x.body);
+ expected.point.y.size = sizeof(expected.point.y.body);
+ memcpy(&expected.point.x.body, &pk->x, sizeof(expected.point.x.body));
+ memcpy(&expected.point.y.body, &pk->y, sizeof(expected.point.y.body));
+ bswap_es256_pubarea(&expected);
+
+ ok = timingsafe_bcmp(&expected, actual, sizeof(expected));
+ explicit_bzero(&expected, sizeof(expected));
+
+ return ok != 0 ? -1 : 0;
+}
+
+static int
+check_sha1_certinfo(const fido_blob_t *buf, const fido_blob_t *clientdata_hash,
+ const fido_blob_t *authdata_raw, const fido_blob_t *pubarea)
+{
+ const tpm_sha1_attest_t *actual;
+ tpm_sha1_attest_t expected;
+ tpm_sha1_data_t signed_data;
+ tpm_sha256_name_t signed_name;
+ int ok = -1;
+
+ memset(&signed_data, 0, sizeof(signed_data));
+ memset(&signed_name, 0, sizeof(signed_name));
+
+ if (get_signed_sha1(&signed_data, authdata_raw, clientdata_hash) < 0 ||
+ get_signed_name(&signed_name, pubarea) < 0) {
+ fido_log_debug("%s: get_signed_sha1/name", __func__);
+ goto fail;
+ }
+ if (buf->len != sizeof(*actual)) {
+ fido_log_debug("%s: buf->len=%zu", __func__, buf->len);
+ goto fail;
+ }
+ actual = (const void *)buf->ptr;
+
+ memset(&expected, 0, sizeof(expected));
+ expected.magic = TPM_MAGIC;
+ expected.type = TPM_ST_CERTIFY;
+ expected.signer = actual->signer;
+ expected.signer.size = sizeof(expected.signer.alg) +
+ sizeof(expected.signer.body);
+ expected.data = signed_data;
+ expected.clock = actual->clock;
+ expected.clock.safe = 1;
+ expected.fwversion = actual->fwversion;
+ expected.name = signed_name;
+ expected.qual_name = actual->qual_name;
+ bswap_sha1_certinfo(&expected);
+
+ ok = timingsafe_bcmp(&expected, actual, sizeof(expected));
+fail:
+ explicit_bzero(&expected, sizeof(expected));
+ explicit_bzero(&signed_data, sizeof(signed_data));
+ explicit_bzero(&signed_name, sizeof(signed_name));
+
+ return ok != 0 ? -1 : 0;
+}
+
+int
+fido_get_signed_hash_tpm(fido_blob_t *dgst, const fido_blob_t *clientdata_hash,
+ const fido_blob_t *authdata_raw, const fido_attstmt_t *attstmt,
+ const fido_attcred_t *attcred)
+{
+ const fido_blob_t *pubarea = &attstmt->pubarea;
+ const fido_blob_t *certinfo = &attstmt->certinfo;
+
+ if (attstmt->alg != COSE_RS1) {
+ fido_log_debug("%s: unsupported alg %d", __func__,
+ attstmt->alg);
+ return -1;
+ }
+
+ switch (attcred->type) {
+ case COSE_ES256:
+ if (check_es256_pubarea(pubarea, &attcred->pubkey.es256) < 0) {
+ fido_log_debug("%s: check_es256_pubarea", __func__);
+ return -1;
+ }
+ break;
+ case COSE_RS256:
+ if (check_rs256_pubarea(pubarea, &attcred->pubkey.rs256) < 0) {
+ fido_log_debug("%s: check_rs256_pubarea", __func__);
+ return -1;
+ }
+ break;
+ default:
+ fido_log_debug("%s: unsupported type %d", __func__,
+ attcred->type);
+ return -1;
+ }
+
+ if (check_sha1_certinfo(certinfo, clientdata_hash, authdata_raw,
+ pubarea) < 0) {
+ fido_log_debug("%s: check_sha1_certinfo", __func__);
+ return -1;
+ }
+
+ if (dgst->len < SHA_DIGEST_LENGTH ||
+ SHA1(certinfo->ptr, certinfo->len, dgst->ptr) != dgst->ptr) {
+ fido_log_debug("%s: sha1", __func__);
+ return -1;
+ }
+ dgst->len = SHA_DIGEST_LENGTH;
+
+ return 0;
+}
diff --git a/lib/libfido2/src/types.c b/lib/libfido2/src/types.c
new file mode 100644
index 00000000000..54c0ca58286
--- /dev/null
+++ b/lib/libfido2/src/types.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018-2021 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ */
+
+#include "fido.h"
+
+void
+fido_str_array_free(fido_str_array_t *sa)
+{
+ for (size_t i = 0; i < sa->len; i++)
+ free(sa->ptr[i]);
+
+ free(sa->ptr);
+ sa->ptr = NULL;
+ sa->len = 0;
+}
+
+void
+fido_opt_array_free(fido_opt_array_t *oa)
+{
+ for (size_t i = 0; i < oa->len; i++)
+ free(oa->name[i]);
+
+ free(oa->name);
+ free(oa->value);
+ oa->name = NULL;
+ oa->value = NULL;
+}
+
+void
+fido_byte_array_free(fido_byte_array_t *ba)
+{
+ free(ba->ptr);
+
+ ba->ptr = NULL;
+ ba->len = 0;
+}
+
+void
+fido_algo_free(fido_algo_t *a)
+{
+ free(a->type);
+ a->type = NULL;
+ a->cose = 0;
+}
+
+void
+fido_algo_array_free(fido_algo_array_t *aa)
+{
+ for (size_t i = 0; i < aa->len; i++)
+ fido_algo_free(&aa->ptr[i]);
+
+ free(aa->ptr);
+ aa->ptr = NULL;
+ aa->len = 0;
+}
+
+int
+fido_str_array_pack(fido_str_array_t *sa, const char * const *v, size_t n)
+{
+ if ((sa->ptr = calloc(n, sizeof(char *))) == NULL) {
+ fido_log_debug("%s: calloc", __func__);
+ return -1;
+ }
+ for (size_t i = 0; i < n; i++) {
+ if ((sa->ptr[i] = strdup(v[i])) == NULL) {
+ fido_log_debug("%s: strdup", __func__);
+ return -1;
+ }
+ sa->len++;
+ }
+
+ return 0;
+}
diff --git a/lib/libfido2/src/types.h b/lib/libfido2/src/types.h
deleted file mode 100644
index 42ed1b7cc89..00000000000
--- a/lib/libfido2/src/types.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (c) 2018 Yubico AB. All rights reserved.
- * Use of this source code is governed by a BSD-style
- * license that can be found in the LICENSE file.
- */
-
-#ifndef _TYPES_H
-#define _TYPES_H
-
-#include "packed.h"
-
-/* COSE ES256 (ECDSA over P-256 with SHA-256) public key */
-typedef struct es256_pk {
- unsigned char x[32];
- unsigned char y[32];
-} es256_pk_t;
-
-/* COSE ES256 (ECDSA over P-256 with SHA-256) (secret) key */
-typedef struct es256_sk {
- unsigned char d[32];
-} es256_sk_t;
-
-/* COSE RS256 (2048-bit RSA with PKCS1 padding and SHA-256) public key */
-typedef struct rs256_pk {
- unsigned char n[256];
- unsigned char e[3];
-} rs256_pk_t;
-
-/* COSE EDDSA (ED25519) */
-typedef struct eddsa_pk {
- unsigned char x[32];
-} eddsa_pk_t;
-
-PACKED_TYPE(fido_authdata_t,
-struct fido_authdata {
- unsigned char rp_id_hash[32]; /* sha256 of fido_rp.id */
- uint8_t flags; /* user present/verified */
- uint32_t sigcount; /* signature counter */
- /* actually longer */
-})
-
-PACKED_TYPE(fido_attcred_raw_t,
-struct fido_attcred_raw {
- unsigned char aaguid[16]; /* credential's aaguid */
- uint16_t id_len; /* credential id length */
- uint8_t body[]; /* credential id + pubkey */
-})
-
-typedef struct fido_attcred {
- unsigned char aaguid[16]; /* credential's aaguid */
- fido_blob_t id; /* credential id */
- int type; /* credential's cose algorithm */
- union { /* credential's public key */
- es256_pk_t es256;
- rs256_pk_t rs256;
- eddsa_pk_t eddsa;
- } pubkey;
-} fido_attcred_t;
-
-typedef struct fido_attstmt {
- fido_blob_t x5c; /* attestation certificate */
- fido_blob_t sig; /* attestation signature */
-} fido_attstmt_t;
-
-typedef struct fido_rp {
- char *id; /* relying party id */
- char *name; /* relying party name */
-} fido_rp_t;
-
-typedef struct fido_user {
- fido_blob_t id; /* required */
- char *icon; /* optional */
- char *name; /* optional */
- char *display_name; /* required */
-} fido_user_t;
-
-typedef struct fido_cred {
- fido_blob_t cdh; /* client data hash */
- fido_rp_t rp; /* relying party */
- fido_user_t user; /* user entity */
- fido_blob_array_t excl; /* list of credential ids to exclude */
- fido_opt_t rk; /* resident key */
- fido_opt_t uv; /* user verification */
- int ext; /* enabled extensions */
- int type; /* cose algorithm */
- char *fmt; /* credential format */
- int authdata_ext; /* decoded extensions */
- fido_blob_t authdata_cbor; /* raw cbor payload */
- fido_authdata_t authdata; /* decoded authdata payload */
- fido_attcred_t attcred; /* returned credential (key + id) */
- fido_attstmt_t attstmt; /* attestation statement (x509 + sig) */
-} fido_cred_t;
-
-typedef struct _fido_assert_stmt {
- fido_blob_t id; /* credential id */
- fido_user_t user; /* user attributes */
- fido_blob_t hmac_secret_enc; /* hmac secret, encrypted */
- fido_blob_t hmac_secret; /* hmac secret */
- int authdata_ext; /* decoded extensions */
- fido_blob_t authdata_cbor; /* raw cbor payload */
- fido_authdata_t authdata; /* decoded authdata payload */
- fido_blob_t sig; /* signature of cdh + authdata */
-} fido_assert_stmt;
-
-typedef struct fido_assert {
- char *rp_id; /* relying party id */
- fido_blob_t cdh; /* client data hash */
- fido_blob_t hmac_salt; /* optional hmac-secret salt */
- fido_blob_array_t allow_list; /* list of allowed credentials */
- fido_opt_t up; /* user presence */
- fido_opt_t uv; /* user verification */
- int ext; /* enabled extensions */
- fido_assert_stmt *stmt; /* array of expected assertions */
- size_t stmt_cnt; /* number of allocated assertions */
- size_t stmt_len; /* number of received assertions */
-} fido_assert_t;
-
-typedef struct fido_opt_array {
- char **name;
- bool *value;
- size_t len;
-} fido_opt_array_t;
-
-typedef struct fido_str_array {
- char **ptr;
- size_t len;
-} fido_str_array_t;
-
-typedef struct fido_byte_array {
- uint8_t *ptr;
- size_t len;
-} fido_byte_array_t;
-
-typedef struct fido_cbor_info {
- fido_str_array_t versions; /* supported versions: fido2|u2f */
- fido_str_array_t extensions; /* list of supported extensions */
- unsigned char aaguid[16]; /* aaguid */
- fido_opt_array_t options; /* list of supported options */
- uint64_t maxmsgsiz; /* maximum message size */
- fido_byte_array_t protocols; /* supported pin protocols */
-} fido_cbor_info_t;
-
-typedef struct fido_dev_info {
- char *path; /* device path */
- int16_t vendor_id; /* 2-byte vendor id */
- int16_t product_id; /* 2-byte product id */
- char *manufacturer; /* manufacturer string */
- char *product; /* product string */
-} fido_dev_info_t;
-
-PACKED_TYPE(fido_ctap_info_t,
-/* defined in section 8.1.9.1.3 (CTAPHID_INIT) of the fido2 ctap spec */
-struct fido_ctap_info {
- uint64_t nonce; /* echoed nonce */
- uint32_t cid; /* channel id */
- uint8_t protocol; /* ctaphid protocol id */
- uint8_t major; /* major version number */
- uint8_t minor; /* minor version number */
- uint8_t build; /* build version number */
- uint8_t flags; /* capabilities flags; see FIDO_CAP_* */
-})
-
-typedef struct fido_dev {
- uint64_t nonce; /* issued nonce */
- fido_ctap_info_t attr; /* device attributes */
- uint32_t cid; /* assigned channel id */
- void *io_handle; /* abstract i/o handle */
- fido_dev_io_t io; /* i/o functions & data */
-} fido_dev_t;
-
-#endif /* !_TYPES_H */
diff --git a/lib/libfido2/src/u2f.c b/lib/libfido2/src/u2f.c
index c5fbe0cfbb6..6ebfcc7bb84 100644
--- a/lib/libfido2/src/u2f.c
+++ b/lib/libfido2/src/u2f.c
@@ -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)
@@ -25,6 +28,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)
{
sig->len = *len; /* consume the whole buffer */
@@ -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 @@ fail:
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;
}
@@ -391,6 +412,71 @@ fail:
}
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 @@ fail:
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 @@ fail:
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 @@ fail:
}
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 @@ fail:
}
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);
}
diff --git a/lib/libfido2/src/util.c b/lib/libfido2/src/util.c
new file mode 100644
index 00000000000..61e120cfd06
--- /dev/null
+++ b/lib/libfido2/src/util.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2022 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ */
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "fido.h"
+
+int
+fido_to_uint64(const char *str, int base, uint64_t *out)
+{
+ char *ep;
+ unsigned long long ull;
+
+ errno = 0;
+ ull = strtoull(str, &ep, base);
+ if (str == ep || *ep != '\0')
+ return -1;
+ else if (ull == ULLONG_MAX && errno == ERANGE)
+ return -1;
+ else if (ull > UINT64_MAX)
+ return -1;
+ *out = (uint64_t)ull;
+
+ return 0;
+}