summaryrefslogtreecommitdiff
path: root/lib/libfido2
diff options
context:
space:
mode:
authorDamien Miller <djm@cvs.openbsd.org>2020-08-11 08:44:54 +0000
committerDamien Miller <djm@cvs.openbsd.org>2020-08-11 08:44:54 +0000
commit7886f296005bdefcb8545a01f5abf60e52c60bed (patch)
tree70da8aea067f6f6ddf8c4b5162eb6532f492ce47 /lib/libfido2
parenta0af9b1d67134f47c6a7629600f71533bc344040 (diff)
sync with upstream libfido2 rev 2fa20b889, picking up ~7 months
of fixes and a few new APIs that we'd like to use in OpenSSH ok deraadt@
Diffstat (limited to 'lib/libfido2')
-rw-r--r--lib/libfido2/Makefile4
-rw-r--r--lib/libfido2/README.openbsd2
-rw-r--r--lib/libfido2/man/fido_assert_new.337
-rw-r--r--lib/libfido2/man/fido_bio_dev_get_info.312
-rw-r--r--lib/libfido2/man/fido_bio_template.324
-rw-r--r--lib/libfido2/man/fido_cbor_info_new.336
-rw-r--r--lib/libfido2/man/fido_cred_new.367
-rw-r--r--lib/libfido2/man/fido_credman_metadata_new.313
-rw-r--r--lib/libfido2/man/fido_dev_get_touch_begin.367
-rw-r--r--lib/libfido2/man/fido_dev_open.324
-rw-r--r--lib/libfido2/man/fido_dev_set_io_functions.371
-rw-r--r--lib/libfido2/shlib_version2
-rw-r--r--lib/libfido2/src/assert.c10
-rw-r--r--lib/libfido2/src/bio.c4
-rw-r--r--lib/libfido2/src/blob.h8
-rw-r--r--lib/libfido2/src/cbor.c35
-rw-r--r--lib/libfido2/src/cred.c64
-rw-r--r--lib/libfido2/src/credman.c8
-rw-r--r--lib/libfido2/src/dev.c225
-rw-r--r--lib/libfido2/src/eddsa.c8
-rw-r--r--lib/libfido2/src/err.c4
-rw-r--r--lib/libfido2/src/es256.c49
-rw-r--r--lib/libfido2/src/export.llvm10
-rw-r--r--lib/libfido2/src/extern.h29
-rw-r--r--lib/libfido2/src/fido.h28
-rw-r--r--lib/libfido2/src/fido/bio.h8
-rw-r--r--lib/libfido2/src/fido/credman.h8
-rw-r--r--lib/libfido2/src/fido/eddsa.h8
-rw-r--r--lib/libfido2/src/fido/err.h10
-rw-r--r--lib/libfido2/src/fido/es256.h8
-rw-r--r--lib/libfido2/src/fido/param.h18
-rw-r--r--lib/libfido2/src/fido/rs256.h8
-rw-r--r--lib/libfido2/src/fido/types.h64
-rw-r--r--lib/libfido2/src/hid_openbsd.c66
-rw-r--r--lib/libfido2/src/info.c24
-rw-r--r--lib/libfido2/src/io.c102
-rw-r--r--lib/libfido2/src/iso7816.c6
-rw-r--r--lib/libfido2/src/iso7816.h8
-rw-r--r--lib/libfido2/src/pin.c10
-rw-r--r--lib/libfido2/src/u2f.c101
40 files changed, 1066 insertions, 224 deletions
diff --git a/lib/libfido2/Makefile b/lib/libfido2/Makefile
index 6b22371cb91..9a8153d007f 100644
--- a/lib/libfido2/Makefile
+++ b/lib/libfido2/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.5 2020/02/07 00:57:49 djm Exp $
+# $OpenBSD: Makefile,v 1.6 2020/08/11 08:44:53 djm Exp $
.PATH: ${.CURDIR}/man ${.CURDIR}/src
@@ -30,7 +30,7 @@ MAN+= fido_cbor_info_new.3 fido_cred_exclude.3 fido_cred_new.3
MAN+= fido_cred_set_authdata.3 fido_cred_verify.3 fido_credman_metadata_new.3
MAN+= fido_dev_get_assert.3 fido_dev_info_manifest.3 fido_dev_make_cred.3
MAN+= fido_dev_open.3 fido_dev_set_io_functions.3 fido_dev_set_pin.3
-MAN+= fido_init.3 fido_strerr.3 rs256_pk_new.3
+MAN+= fido_init.3 fido_strerr.3 rs256_pk_new.3 fido_dev_get_touch_begin.3
includes:
@for i in $(HDRS); do \
diff --git a/lib/libfido2/README.openbsd b/lib/libfido2/README.openbsd
index 6144ef2a03b..dbfcfc1ecf1 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 780ad3c25 (20120123)
+This is an import of https://github.com/Yubico/libfido2 2fa20b889 (20200810)
Local changes:
diff --git a/lib/libfido2/man/fido_assert_new.3 b/lib/libfido2/man/fido_assert_new.3
index b58a7fe121f..f04bdbcba07 100644
--- a/lib/libfido2/man/fido_assert_new.3
+++ b/lib/libfido2/man/fido_assert_new.3
@@ -2,13 +2,14 @@
.\" 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 11 2020 $
.Dt FIDO_ASSERT_NEW 3
.Os
.Sh NAME
.Nm fido_assert_new ,
.Nm fido_assert_free ,
.Nm fido_assert_count ,
+.Nm fido_assert_rp_id ,
.Nm fido_assert_user_display_name ,
.Nm fido_assert_user_icon ,
.Nm fido_assert_user_name ,
@@ -17,12 +18,15 @@
.Nm fido_assert_hmac_secret_ptr ,
.Nm fido_assert_user_id_ptr ,
.Nm fido_assert_sig_ptr ,
+.Nm fido_assert_id_ptr ,
.Nm fido_assert_authdata_len ,
.Nm fido_assert_clientdata_hash_len ,
.Nm fido_assert_hmac_secret_len ,
.Nm fido_assert_user_id_len ,
.Nm fido_assert_sig_len ,
-.Nm fido_assert_sigcount
+.Nm fido_assert_id_len ,
+.Nm fido_assert_sigcount ,
+.Nm fido_assert_flags
.Nd FIDO 2 assertion API
.Sh SYNOPSIS
.In fido.h
@@ -33,6 +37,8 @@
.Ft size_t
.Fn fido_assert_count "const fido_assert_t *assert"
.Ft const char *
+.Fn fido_assert_rp_id "const fido_assert_t *assert"
+.Ft const char *
.Fn fido_assert_user_display_name "const fido_assert_t *assert" "size_t idx"
.Ft const char *
.Fn fido_assert_user_icon "const fido_assert_t *assert" "size_t idx"
@@ -48,6 +54,8 @@
.Fn fido_assert_user_id_ptr "const fido_assert_t *assert" "size_t idx"
.Ft const unsigned char *
.Fn fido_assert_sig_ptr "const fido_assert_t *assert" "size_t idx"
+.Ft const unsigned char *
+.Fn fido_assert_id_ptr "const fido_assert_t *assert" "size_t idx"
.Ft size_t
.Fn fido_assert_authdata_len "const fido_assert_t *assert" "size_t idx"
.Ft size_t
@@ -58,8 +66,12 @@
.Fn fido_assert_user_id_len "const fido_assert_t *assert" "size_t idx"
.Ft size_t
.Fn fido_assert_sig_len "const fido_assert_t *assert" "size_t idx"
+.Ft size_t
+.Fn fido_assert_id_len "const fido_assert_t *assert" "size_t idx"
.Ft uint32_t
.Fn fido_assert_sigcount "const fido_assert_t *assert" "size_t idx"
+.Ft uint8_t
+.Fn fido_assert_flags "const fido_assert_t *assert" "size_t idx"
.Sh DESCRIPTION
FIDO 2 assertions are abstracted in
.Em libfido2
@@ -110,6 +122,12 @@ function returns the number of statements in
.Fa assert .
.Pp
The
+.Fn fido_assert_rp_id
+function returns a pointer to a NUL-terminated string holding the
+relying party ID of
+.Fa assert .
+.Pp
+The
.Fn fido_assert_user_display_name ,
.Fn fido_assert_user_icon ,
and
@@ -126,10 +144,11 @@ The
.Fn fido_assert_user_id_ptr ,
.Fn fido_assert_authdata_ptr ,
.Fn fido_assert_hmac_secret_ptr ,
+.Fn fido_assert_sig_ptr ,
and
-.Fn fido_assert_sig_ptr
+.Fn fido_assert_id_ptr
functions return pointers to the user ID, authenticator data,
-hmac-secret, and signature attributes of statement
+hmac-secret, signature, and credential ID attributes of statement
.Fa idx
in
.Fa assert .
@@ -137,8 +156,9 @@ The
.Fn fido_assert_user_id_len ,
.Fn fido_assert_authdata_len ,
.Fn fido_assert_hmac_secret_len ,
+.Fn fido_assert_sig_len ,
and
-.Fn fido_assert_sig_len
+.Fn fido_assert_id_len
functions can be used to retrieve the corresponding length of a
specific attribute.
.Pp
@@ -149,6 +169,13 @@ function can be used to obtain the signature counter of statement
in
.Fa assert .
.Pp
+The
+.Fn fido_assert_flags
+function returns the authenticator data flags of statement
+.Fa idx
+in
+.Fa assert .
+.Pp
Please note that the first statement in
.Fa assert
has an
diff --git a/lib/libfido2/man/fido_bio_dev_get_info.3 b/lib/libfido2/man/fido_bio_dev_get_info.3
index c7551701158..7338d7f04d4 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: February 7 2020 $
+.Dd $Mdocdate: August 11 2020 $
.Dt FIDO_BIO_DEV_GET_INFO 3
.Os
.Sh NAME
@@ -35,6 +35,8 @@
The functions described in this page allow biometric
templates on a FIDO2 authenticator to be listed, created,
removed, and customised.
+Please note that not all FIDO2 authenticators support biometric
+enrollment.
For a description of the types involved, please refer to
.Xr fido_bio_info_new 3 ,
.Xr fido_bio_enroll_new 3 ,
@@ -118,3 +120,11 @@ is returned.
.Xr fido_bio_enroll_new 3 ,
.Xr fido_bio_info_new 3 ,
.Xr fido_bio_template 3
+.Sh CAVEATS
+Biometric enrollment is a tentative feature of FIDO 2.1.
+Applications willing to strictly abide by FIDO 2.0 should refrain
+from using biometric enrollment.
+Applications using biometric enrollment should ensure it is
+supported by the authenticator prior to using the API.
+Since FIDO 2.1 hasn't been finalised, there is a chance the
+functionality and associated data structures may change.
diff --git a/lib/libfido2/man/fido_bio_template.3 b/lib/libfido2/man/fido_bio_template.3
index c66a1b092d5..f13bf231c5b 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: February 7 2020 $
+.Dd $Mdocdate: August 11 2020 $
.Dt FIDO_BIO_TEMPLATE 3
.Os
.Sh NAME
@@ -38,11 +38,11 @@
.Ft fido_bio_template_array_t *
.Fn fido_bio_template_array_new "void"
.Ft void
-.Fn fido_bio_template_array_free "fido_bio_template_array_t **template_array_p"
+.Fn fido_bio_template_array_free "fido_bio_template_array_t **array_p"
.Ft size_t
-.Fn fido_bio_template_array_count "const fido_bio_template_array_t *template_array"
+.Fn fido_bio_template_array_count "const fido_bio_template_array_t *array"
.Ft const fido_bio_template_t *
-.Fn fido_bio_template "const fido_bio_template_array_t *template_array" "size_t idx"
+.Fn fido_bio_template "const fido_bio_template_array_t *array" "size_t idx"
.Sh DESCRIPTION
Existing FIDO 2 biometric enrollments are abstracted in
.Em libfido2
@@ -132,18 +132,18 @@ If memory cannot be allocated, NULL is returned.
The
.Fn fido_bio_template_array_free
function releases the memory backing
-.Fa *template_array_p ,
+.Fa *array_p ,
where
-.Fa *template_array_p
+.Fa *array_p
must have been previously allocated by
.Fn fido_bio_template_array_new .
On return,
-.Fa *template_array_p
+.Fa *array_p
is set to NULL.
Either
-.Fa template_array_p
+.Fa array_p
or
-.Fa *template_array_p
+.Fa *array_p
may be NULL, in which case
.Fn fido_bio_template_array_free
is a NOP.
@@ -151,16 +151,16 @@ is a NOP.
The
.Fn fido_bio_template_array_count
function returns the number of templates in
-.Fa template_array .
+.Fa array .
.Pp
The
.Fn fido_bio_template
function returns a pointer to the template at index
.Fa idx
in
-.Fa template_array .
+.Fa array .
Please note that the first template in
-.Fa template_array
+.Fa array
has an
.Fa idx
(index) value of 0.
diff --git a/lib/libfido2/man/fido_cbor_info_new.3 b/lib/libfido2/man/fido_cbor_info_new.3
index 6f71f9d3ded..755182a5d75 100644
--- a/lib/libfido2/man/fido_cbor_info_new.3
+++ b/lib/libfido2/man/fido_cbor_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 11 2020 $
.Dt FIDO_CBOR_INFO_NEW 3
.Os
.Sh NAME
@@ -20,7 +20,10 @@
.Nm fido_cbor_info_protocols_len ,
.Nm fido_cbor_info_versions_len ,
.Nm fido_cbor_info_options_len ,
-.Nm fido_cbor_info_maxmsgsiz
+.Nm fido_cbor_info_maxmsgsiz ,
+.Nm fido_cbor_info_maxcredcntlst ,
+.Nm fido_cbor_info_maxcredidlen ,
+.Nm fido_cbor_info_fwversion
.Nd FIDO 2 CBOR Info API
.Sh SYNOPSIS
.In fido.h
@@ -54,6 +57,12 @@
.Fn fido_cbor_info_options_len "const fido_cbor_info_t *ci"
.Ft uint64_t
.Fn fido_cbor_info_maxmsgsiz "const fido_cbor_info_t *ci"
+.Ft uint64_t
+.Fn fido_cbor_info_maxcredcntlst "const fido_cbor_info_t *ci"
+.Ft uint64_t
+.Fn fido_cbor_info_maxcredidlen "const fido_cbor_info_t *ci"
+.Ft uint64_t
+.Fn fido_cbor_info_fwversion "const fido_cbor_info_t *ci"
.Sh DESCRIPTION
The
.Fn fido_cbor_info_new
@@ -100,8 +109,8 @@ The
.Fn fido_cbor_info_protocols_ptr ,
and
.Fn fido_cbor_info_versions_ptr
-functions return pointers to the AAGUID, supported extensions,
-PIN protocol and CTAP version strings of
+functions return pointers to the authenticator attestation GUID,
+supported extensions, PIN protocol and CTAP version strings of
.Fa ci .
The corresponding length of a given attribute can be
obtained by
@@ -124,7 +133,24 @@ The length of the options array is returned by
.Pp
The
.Fn fido_cbor_info_maxmsgsiz
-function returns the maximum message size of
+function returns the maximum message size attribute of
+.Fa ci .
+.Pp
+The
+.Fn fido_cbor_info_maxcredcntlst
+function returns the maximum supported number of credentials in
+a single credential ID list as reported in
+.Fa ci .
+.Pp
+The
+.Fn fido_cbor_info_maxcredidlen
+function returns the maximum supported length of a credential ID
+as reported in
+.Fa ci .
+.Pp
+The
+.Fn fido_cbor_info_fwversion
+function returns the firmware version attribute of
.Fa ci .
.Pp
A complete example of how to use these functions can be found in the
diff --git a/lib/libfido2/man/fido_cred_new.3 b/lib/libfido2/man/fido_cred_new.3
index 77650ed5d78..d5d8f2f0922 100644
--- a/lib/libfido2/man/fido_cred_new.3
+++ b/lib/libfido2/man/fido_cred_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 11 2020 $
.Dt FIDO_CRED_NEW 3
.Os
.Sh NAME
@@ -10,18 +10,28 @@
.Nm fido_cred_free ,
.Nm fido_cred_prot ,
.Nm fido_cred_fmt ,
+.Nm fido_cred_rp_id ,
+.Nm fido_cred_rp_name ,
+.Nm fido_cred_user_name ,
+.Nm fido_cred_display_name ,
.Nm fido_cred_authdata_ptr ,
.Nm fido_cred_clientdata_hash_ptr ,
.Nm fido_cred_id_ptr ,
+.Nm fido_cred_aaguid_ptr ,
.Nm fido_cred_pubkey_ptr ,
.Nm fido_cred_sig_ptr ,
+.Nm fido_cred_user_id_ptr ,
.Nm fido_cred_x5c_ptr ,
.Nm fido_cred_authdata_len ,
.Nm fido_cred_clientdata_hash_len ,
.Nm fido_cred_id_len ,
+.Nm fido_cred_aaguid_len ,
.Nm fido_cred_pubkey_len ,
.Nm fido_cred_sig_len ,
-.Nm fido_cred_x5c_len
+.Nm fido_cred_user_id_len ,
+.Nm fido_cred_x5c_len ,
+.Nm fido_cred_type ,
+.Nm fido_cred_flags
.Nd FIDO 2 credential API
.Sh SYNOPSIS
.In fido.h
@@ -33,6 +43,14 @@
.Fn fido_cred_prot "fido_cred_t *cred"
.Ft const char *
.Fn fido_cred_fmt "const fido_cred_t *cred"
+.Ft const char *
+.Fn fido_cred_rp_id "const fido_cred_t *cred"
+.Ft const char *
+.Fn fido_cred_rp_name "const fido_cred_t *cred"
+.Ft const char *
+.Fn fido_cred_user_name "const fido_cred_t *cred"
+.Ft const char *
+.Fn fido_cred_display_name "const fido_cred_t *cred"
.Ft const unsigned char *
.Fn fido_cred_authdata_ptr "const fido_cred_t *cred"
.Ft const unsigned char *
@@ -40,10 +58,14 @@
.Ft const unsigned char *
.Fn fido_cred_id_ptr "const fido_cred_t *cred"
.Ft const unsigned char *
+.Fn fido_cred_aaguid_ptr "const fido_cred_t *cred"
+.Ft const unsigned char *
.Fn fido_cred_pubkey_ptr "const fido_cred_t *cred"
.Ft const unsigned char *
.Fn fido_cred_sig_ptr "const fido_cred_t *cred"
.Ft const unsigned char *
+.Fn fido_cred_user_id_ptr "const fido_cred_t *cred"
+.Ft const unsigned char *
.Fn fido_cred_x5c_ptr "const fido_cred_t *cred"
.Ft size_t
.Fn fido_cred_authdata_len "const fido_cred_t *cred"
@@ -52,11 +74,19 @@
.Ft size_t
.Fn fido_cred_id_len "const fido_cred_t *cred"
.Ft size_t
+.Fn fido_cred_aaguid_len "const fido_cred_t *cred"
+.Ft size_t
.Fn fido_cred_pubkey_len "const fido_cred_t *cred"
.Ft size_t
.Fn fido_cred_sig_len "const fido_cred_t *cred"
.Ft size_t
+.Fn fido_cred_user_id_len "const fido_cred_t *cred"
+.Ft size_t
.Fn fido_cred_x5c_len "const fido_cred_t *cred"
+.Ft int
+.Fn fido_cred_type "const fido_cred_t *cred"
+.Ft uint8_t
+.Fn fido_cred_flags "const fido_cred_t *cred"
.Sh DESCRIPTION
FIDO 2 credentials are abstracted in
.Em libfido2
@@ -120,15 +150,30 @@ or NULL if
does not have a format set.
.Pp
The
+.Fn fido_cred_rp_id ,
+.Fn fido_cred_rp_name ,
+.Fn fido_cred_user_name ,
+and
+.Fn fido_cred_display_name
+functions return pointers to NUL-terminated strings holding the
+relying party ID, relying party name, user name, and user display
+name attributes of
+.Fa cred ,
+or NULL if the respective entry is not set.
+.Pp
+The
.Fn fido_cred_authdata_ptr ,
.Fn fido_cred_clientdata_hash_ptr ,
.Fn fido_cred_id_ptr ,
+.Fn fido_cred_aaguid_ptr ,
.Fn fido_cred_pubkey_ptr ,
.Fn fido_cred_sig_ptr ,
+.Fn fido_cred_user_id_ptr ,
and
.Fn fido_cred_x5c_ptr
functions return pointers to the authenticator data, client data
-hash, ID, public key, signature and x509 certificate parts of
+hash, ID, authenticator attestation GUID, public key, signature,
+user ID, and x509 certificate parts of
.Fa cred ,
or NULL if the respective entry is not set.
.Pp
@@ -136,12 +181,25 @@ The corresponding length can be obtained by
.Fn fido_cred_authdata_len ,
.Fn fido_cred_clientdata_hash_len ,
.Fn fido_cred_id_len ,
+.Fn fido_cred_aaguid_len ,
.Fn fido_cred_pubkey_len ,
+.Fn fido_cred_sig_len ,
+.Fn fido_cred_user_id_len ,
and
-.Fn fido_cred_sig_len .
+.Fn fido_cred_x5c_len .
.Pp
The authenticator data, x509 certificate, and signature parts of a
credential are typically passed to a FIDO 2 server for verification.
+.Pp
+The
+.Fn fido_cred_type
+function returns the COSE algorithm of
+.Fa cred .
+.Pp
+The
+.Fn fido_cred_flags
+function returns the authenticator data flags of
+.Fa cred .
.Sh RETURN VALUES
The authenticator data returned by
.Fn fido_cred_authdata_ptr
@@ -152,6 +210,7 @@ If not NULL, pointers returned by
.Fn fido_cred_authdata_ptr ,
.Fn fido_cred_clientdata_hash_ptr ,
.Fn fido_cred_id_ptr ,
+.Fn fido_cred_aaguid_ptr ,
.Fn fido_cred_pubkey_ptr ,
.Fn fido_cred_sig_ptr ,
and
diff --git a/lib/libfido2/man/fido_credman_metadata_new.3 b/lib/libfido2/man/fido_credman_metadata_new.3
index 09b0bf8a76f..4e62c807e03 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: February 7 2020 $
+.Dd $Mdocdate: August 11 2020 $
.Dt FIDO_CREDMAN_METADATA_NEW 3
.Os
.Sh NAME
@@ -72,7 +72,8 @@ The credential management API of
.Em libfido2
allows resident credentials on a FIDO2 authenticator to be listed,
inspected, and removed.
-Please note that not all authenticators support credential management.
+Please note that not all FIDO2 authenticators support credential
+management.
To obtain information on what an authenticator supports, please
refer to
.Xr fido_cbor_info_new 3 .
@@ -297,3 +298,11 @@ should have their return values checked for NULL.
.Sh SEE ALSO
.Xr fido_cbor_info_new 3 ,
.Xr fido_cred_new 3
+.Sh CAVEATS
+Credential management is a tentative feature of FIDO 2.1.
+Applications willing to strictly abide by FIDO 2.0 should refrain
+from using credential management.
+Applications using credential management should ensure it is
+supported by the authenticator prior to using the API.
+Since FIDO 2.1 hasn't been finalised, there is a chance the
+functionality and associated data structures may change.
diff --git a/lib/libfido2/man/fido_dev_get_touch_begin.3 b/lib/libfido2/man/fido_dev_get_touch_begin.3
new file mode 100644
index 00000000000..a1c5ce635c3
--- /dev/null
+++ b/lib/libfido2/man/fido_dev_get_touch_begin.3
@@ -0,0 +1,67 @@
+.\" Copyright (c) 2020 Yubico AB. All rights reserved.
+.\" Use of this source code is governed by a BSD-style
+.\" license that can be found in the LICENSE file.
+.\"
+.Dd $Mdocdate: August 11 2020 $
+.Dt FIDO_DEV_GET_TOUCH_BEGIN 3
+.Os
+.Sh NAME
+.Nm fido_dev_get_touch_begin ,
+.Nm fido_dev_get_touch_status
+.Nd asynchronously wait for touch on a FIDO 2 authenticator
+.Sh SYNOPSIS
+.In fido.h
+.Ft int
+.Fn fido_dev_get_touch_begin "fido_dev_t *dev"
+.Ft int
+.Fn fido_dev_get_touch_status "fido_dev_t *dev" "int *touched" "int *pin_set" "int ms"
+.Sh DESCRIPTION
+The functions described in this page allow an application to
+asynchronously wait for touch on a FIDO authenticator.
+This is useful when multiple authenticators are present and
+the application needs to know which one to use.
+.Pp
+The
+.Fn fido_dev_get_touch_begin
+function initiates a touch request on
+.Fa dev .
+.Pp
+The
+.Fn fido_dev_get_touch_status
+function continues an ongoing touch request on
+.Fa dev ,
+blocking up to
+.Fa ms
+milliseconds.
+On success,
+.Fa touched
+will be updated to reflect the touch request status.
+If
+.Fa touched
+is 1, the device was touched, and the touch request is
+terminated.
+If
+.Fa touched
+is 0, the application may call
+.Fn fido_dev_get_touch_status
+to continue the touch request, or
+.Fn fido_dev_cancel
+to terminate it.
+.Sh RETURN VALUES
+The error codes returned by
+.Fn fido_dev_get_touch_begin
+and
+.Fn fido_dev_get_touch_status
+are defined in
+.In fido/err.h .
+On success,
+.Dv FIDO_OK
+is returned.
+.Sh EXAMPLES
+Please refer to
+.Em examples/select.c
+in
+.Em libfido2's
+source tree.
+.Sh SEE ALSO
+.Xr fido_dev_cancel 3
diff --git a/lib/libfido2/man/fido_dev_open.3 b/lib/libfido2/man/fido_dev_open.3
index fd472ed63ef..22f7baa1f58 100644
--- a/lib/libfido2/man/fido_dev_open.3
+++ b/lib/libfido2/man/fido_dev_open.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 11 2020 $
.Dt FIDO_DEV_OPEN 3
.Os
.Sh NAME
@@ -14,6 +14,8 @@
.Nm fido_dev_force_fido2 ,
.Nm fido_dev_force_u2f ,
.Nm fido_dev_is_fido2 ,
+.Nm fido_dev_supports_cred_prot ,
+.Nm fido_dev_supports_pin ,
.Nm fido_dev_protocol ,
.Nm fido_dev_build ,
.Nm fido_dev_flags ,
@@ -38,6 +40,10 @@
.Fn fido_dev_force_u2f "fido_dev_t *dev"
.Ft bool
.Fn fido_dev_is_fido2 "const fido_dev_t *dev"
+.Ft bool
+.Fn fido_dev_supports_cred_prot "const fido_dev_t *dev"
+.Ft bool
+.Fn fido_dev_supports_pin "const fido_dev_t *dev"
.Ft uint8_t
.Fn fido_dev_protocol "const fido_dev_t *dev"
.Ft uint8_t
@@ -117,6 +123,22 @@ if
is a FIDO 2 device.
.Pp
The
+.Fn fido_dev_supports_cred_prot
+function returns
+.Dv true
+if
+.Fa dev
+supports FIDO 2.1 Credential Protection.
+.Pp
+The
+.Fn fido_dev_supports_pin
+function returns
+.Dv true
+if
+.Fa dev
+supports FIDO 2.0 Client PINs.
+.Pp
+The
.Fn fido_dev_protocol
function returns the CTAPHID protocol version identifier of
.Fa dev .
diff --git a/lib/libfido2/man/fido_dev_set_io_functions.3 b/lib/libfido2/man/fido_dev_set_io_functions.3
index de3b618c25b..ad02286ca09 100644
--- a/lib/libfido2/man/fido_dev_set_io_functions.3
+++ b/lib/libfido2/man/fido_dev_set_io_functions.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 11 2020 $
.Dt FIDO_DEV_SET_IO_FUNCTIONS 3
.Os
.Sh NAME
@@ -15,12 +15,16 @@ typedef void *fido_dev_io_open_t(const char *);
typedef void fido_dev_io_close_t(void *);
typedef int fido_dev_io_read_t(void *, unsigned char *, size_t, int);
typedef int fido_dev_io_write_t(void *, const unsigned char *, size_t);
+typedef int fido_dev_io_rx_t(struct fido_dev *, uint8_t, unsigned char *, size_t, int);
+typedef int fido_dev_io_tx_t(struct fido_dev *, uint8_t, const unsigned char *, size_t);
typedef struct fido_dev_io {
fido_dev_io_open_t *open;
fido_dev_io_close_t *close;
fido_dev_io_read_t *read;
fido_dev_io_write_t *write;
+ fido_dev_io_rx_t *rx;
+ fido_dev_io_tx_t *tx;
} fido_dev_io_t;
.Ed
.Ft int
@@ -28,12 +32,12 @@ typedef struct fido_dev_io {
.Sh DESCRIPTION
The
.Nm
-interface defines the I/O handlers used to talk to
+interface defines the I/O and transmission handlers used to talk to
.Fa dev .
Its usage is optional.
By default,
.Em libfido2
-will use the operating system's native HID interface to talk to
+will use the operating system's native HID interface to talk CTAP2 to
a FIDO device.
.Pp
A
@@ -51,13 +55,13 @@ It is not expected to be idempotent.
.Pp
A
.Vt fido_dev_io_read_t
-function reads from
+function reads a single HID report from
.Fa dev .
The first parameter taken is the opaque handle obtained from
.Vt fido_dev_io_open_t .
The read buffer is pointed to by the second parameter, and the
third parameter holds its size.
-Finally, the last argument passed to
+The last argument passed to
.Vt fido_dev_io_read_t
is the number of milliseconds the caller is willing to sleep,
should the call need to block.
@@ -67,9 +71,9 @@ may block indefinitely.
The number of bytes read is returned.
On error, -1 is returned.
.Pp
-Conversely, a
+A
.Vt fido_dev_io_write_t
-function writes to
+function writes a single HID report to
.Fa dev .
The first parameter taken is the opaque handle returned by
.Vt fido_dev_io_open_t .
@@ -81,6 +85,59 @@ function may block.
The number of bytes written is returned.
On error, -1 is returned.
.Pp
+A
+.Vt fido_dev_io_rx_t
+function receives a complete CTAP2 message from
+.Fa dev .
+The first parameter taken is a pointer to
+.Fa dev .
+The second parameter holds the expected CTAP2 command byte.
+The read buffer is pointed to by the third parameter, and the
+fourth parameter holds its size.
+The last argument passed to
+.Vt fido_dev_io_rx_t
+is the number of milliseconds the caller is willing to sleep,
+should the call need to block.
+If this value holds -1,
+.Vt fido_dev_io_rx_t
+may block indefinitely.
+The number of bytes read is returned.
+On error, -1 is returned.
+.Pp
+A
+.Vt fido_dev_io_tx_t
+function transmits a complete CTAP2 message to
+.Fa dev .
+The first parameter taken is a pointer to
+.Fa dev .
+The second parameter holds the CTAP2 command byte.
+The write buffer is pointed to by the third parameter, and the
+fourth parameter holds its size.
+A
+.Vt fido_dev_io_tx_t
+function may block.
+On success, 0 is returned.
+On error, -1 is returned.
+.Pp
+When calling
+.Fn fido_dev_set_io_functions ,
+the
+.Fa open ,
+.Fa close ,
+.Fa read
+and
+.Fa write
+fields of
+.Fa io
+may not be NULL.
+Either
+.Fa rx
+or
+.Fa tx
+may be NULL, in which case
+.Em libfido2
+uses its corresponding CTAP2 HID transport method.
+.Pp
No references to
.Fa io
are held by
diff --git a/lib/libfido2/shlib_version b/lib/libfido2/shlib_version
index b52599a164f..012c14171d3 100644
--- a/lib/libfido2/shlib_version
+++ b/lib/libfido2/shlib_version
@@ -1,2 +1,2 @@
-major=2
+major=3
minor=0
diff --git a/lib/libfido2/src/assert.c b/lib/libfido2/src/assert.c
index d1ad2b0f5f7..17463878d28 100644
--- a/lib/libfido2/src/assert.c
+++ b/lib/libfido2/src/assert.c
@@ -313,7 +313,7 @@ fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin)
goto fail;
}
}
-
+
r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, -1);
if (r == FIDO_OK && assert->ext & FIDO_EXT_HMAC_SECRET)
if (decrypt_hmac_secrets(assert, ecdh) < 0) {
@@ -362,8 +362,8 @@ check_extensions(int authdata_ext, int ext)
return (0);
}
-static int
-get_signed_hash(int cose_alg, fido_blob_t *dgst, const fido_blob_t *clientdata,
+int
+fido_get_signed_hash(int cose_alg, fido_blob_t *dgst, const fido_blob_t *clientdata,
const fido_blob_t *authdata_cbor)
{
cbor_item_t *item = NULL;
@@ -578,9 +578,9 @@ fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg,
goto out;
}
- if (get_signed_hash(cose_alg, &dgst, &assert->cdh,
+ if (fido_get_signed_hash(cose_alg, &dgst, &assert->cdh,
&stmt->authdata_cbor) < 0) {
- fido_log_debug("%s: get_signed_hash", __func__);
+ fido_log_debug("%s: fido_get_signed_hash", __func__);
r = FIDO_ERR_INTERNAL;
goto out;
}
diff --git a/lib/libfido2/src/bio.c b/lib/libfido2/src/bio.c
index 7f44cb18412..c1032d8db5e 100644
--- a/lib/libfido2/src/bio.c
+++ b/lib/libfido2/src/bio.c
@@ -407,7 +407,7 @@ bio_rx_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t,
fido_log_debug("%s: bio_parse_template_id", __func__);
return (r);
}
-
+
return (FIDO_OK);
}
@@ -500,7 +500,7 @@ bio_rx_enroll_continue(fido_dev_t *dev, fido_bio_enroll_t *e, int ms)
fido_log_debug("%s: bio_parse_enroll_status", __func__);
return (r);
}
-
+
return (FIDO_OK);
}
diff --git a/lib/libfido2/src/blob.h b/lib/libfido2/src/blob.h
index cf0b2b35c15..9e98d03b786 100644
--- a/lib/libfido2/src/blob.h
+++ b/lib/libfido2/src/blob.h
@@ -10,6 +10,10 @@
#include <cbor.h>
#include <stdlib.h>
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
typedef struct fido_blob {
unsigned char *ptr;
size_t len;
@@ -28,4 +32,8 @@ int fido_blob_set(fido_blob_t *, const unsigned char *, size_t);
void fido_blob_free(fido_blob_t **);
void fido_free_blob_array(fido_blob_array_t *);
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
#endif /* !_BLOB_H */
diff --git a/lib/libfido2/src/cbor.c b/lib/libfido2/src/cbor.c
index 1ecb4b87169..b30da508b7c 100644
--- a/lib/libfido2/src/cbor.c
+++ b/lib/libfido2/src/cbor.c
@@ -386,7 +386,7 @@ cbor_flatten_vector(cbor_item_t *argv[], size_t argc)
return (NULL);
for (i = 0; i < argc; i++)
- if (cbor_add_arg(map, i + 1, argv[i]) < 0)
+ if (cbor_add_arg(map, (uint8_t)(i + 1), argv[i]) < 0)
break;
if (i != argc) {
@@ -583,7 +583,9 @@ cbor_encode_extensions(const fido_cred_ext_t *ext)
}
}
if (ext->mask & FIDO_EXT_CRED_PROTECT) {
- if (cbor_add_uint8(item, "credProtect", ext->prot) < 0) {
+ if (ext->prot < 0 || ext->prot > UINT8_MAX ||
+ cbor_add_uint8(item, "credProtect",
+ (uint8_t)ext->prot) < 0) {
cbor_decref(&item);
return (NULL);
}
@@ -634,7 +636,7 @@ cbor_encode_pin_auth(const fido_blob_t *hmac_key, const fido_blob_t *data)
unsigned int dgst_len;
if ((md = EVP_sha256()) == NULL || HMAC(md, hmac_key->ptr,
- (int)hmac_key->len, data->ptr, (int)data->len, dgst,
+ (int)hmac_key->len, data->ptr, data->len, dgst,
&dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH)
return (NULL);
@@ -696,7 +698,6 @@ cbor_encode_change_pin_auth(const fido_blob_t *key, const fido_blob_t *new_pin,
fido_blob_t *npe = NULL; /* new pin, encrypted */
fido_blob_t *ph = NULL; /* pin hash */
fido_blob_t *phe = NULL; /* pin hash, encrypted */
- int ok = -1;
if ((npe = fido_blob_new()) == NULL ||
(ph = fido_blob_new()) == NULL ||
@@ -735,8 +736,8 @@ cbor_encode_change_pin_auth(const fido_blob_t *key, const fido_blob_t *new_pin,
if ((ctx = HMAC_CTX_new()) == NULL ||
(md = EVP_sha256()) == NULL ||
HMAC_Init_ex(ctx, key->ptr, (int)key->len, md, NULL) == 0 ||
- HMAC_Update(ctx, npe->ptr, (int)npe->len) == 0 ||
- HMAC_Update(ctx, phe->ptr, (int)phe->len) == 0 ||
+ HMAC_Update(ctx, npe->ptr, npe->len) == 0 ||
+ HMAC_Update(ctx, phe->ptr, phe->len) == 0 ||
HMAC_Final(ctx, dgst, &dgst_len) == 0 || dgst_len != 32) {
fido_log_debug("%s: HMAC", __func__);
goto fail;
@@ -748,7 +749,6 @@ cbor_encode_change_pin_auth(const fido_blob_t *key, const fido_blob_t *new_pin,
goto fail;
}
- ok = 0;
fail:
fido_blob_free(&npe);
fido_blob_free(&ph);
@@ -759,13 +759,6 @@ fail:
HMAC_CTX_free(ctx);
#endif
- if (ok < 0) {
- if (item != NULL) {
- cbor_decref(&item);
- item = NULL;
- }
- }
-
return (item);
}
@@ -787,7 +780,7 @@ cbor_encode_set_pin_auth(const fido_blob_t *key, const fido_blob_t *pin)
}
if ((md = EVP_sha256()) == NULL || key->len != 32 || HMAC(md, key->ptr,
- (int)key->len, pe->ptr, (int)pe->len, dgst, &dgst_len) == NULL ||
+ (int)key->len, pe->ptr, pe->len, dgst, &dgst_len) == NULL ||
dgst_len != SHA256_DIGEST_LENGTH) {
fido_log_debug("%s: HMAC", __func__);
goto fail;
@@ -1292,7 +1285,7 @@ cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg,
}
if (authdata_ext != NULL) {
- if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 &&
+ if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 &&
decode_extensions(&buf, &len, authdata_ext) < 0)
return (-1);
}
@@ -1366,6 +1359,7 @@ 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) {
@@ -1376,11 +1370,16 @@ decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
if (!strcmp(name, "alg")) {
if (cbor_isa_negint(val) == false ||
- cbor_int_get_width(val) != CBOR_INT_8 ||
- cbor_get_uint8(val) != -COSE_ES256 - 1) {
+ cbor_get_int(val) > UINT16_MAX) {
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);
+ goto out;
+ }
} else if (!strcmp(name, "sig")) {
if (cbor_bytestring_copy(val, &attstmt->sig.ptr,
&attstmt->sig.len) < 0) {
diff --git a/lib/libfido2/src/cred.c b/lib/libfido2/src/cred.c
index b73c390c247..9f902faf0ae 100644
--- a/lib/libfido2/src/cred.c
+++ b/lib/libfido2/src/cred.c
@@ -203,48 +203,6 @@ fido_check_rp_id(const char *id, const unsigned char *obtained_hash)
}
static int
-get_signed_hash_packed(fido_blob_t *dgst, const fido_blob_t *clientdata,
- const fido_blob_t *authdata_cbor)
-{
- cbor_item_t *item = NULL;
- unsigned char *authdata_ptr = NULL;
- size_t authdata_len;
- struct cbor_load_result cbor;
- SHA256_CTX ctx;
- int ok = -1;
-
- if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len,
- &cbor)) == NULL) {
- fido_log_debug("%s: cbor_load", __func__);
- goto fail;
- }
-
- if (cbor_isa_bytestring(item) == false ||
- cbor_bytestring_is_definite(item) == false) {
- fido_log_debug("%s: cbor type", __func__);
- goto fail;
- }
-
- authdata_ptr = cbor_bytestring_handle(item);
- authdata_len = cbor_bytestring_length(item);
-
- 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) {
- fido_log_debug("%s: sha256", __func__);
- goto fail;
- }
-
- ok = 0;
-fail:
- if (item != NULL)
- cbor_decref(&item);
-
- return (ok);
-}
-
-static int
get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id,
size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id,
const es256_pk_t *pk)
@@ -358,9 +316,9 @@ fido_cred_verify(const fido_cred_t *cred)
}
if (!strcmp(cred->fmt, "packed")) {
- if (get_signed_hash_packed(&dgst, &cred->cdh,
+ if (fido_get_signed_hash(COSE_ES256, &dgst, &cred->cdh,
&cred->authdata_cbor) < 0) {
- fido_log_debug("%s: get_signed_hash_packed", __func__);
+ fido_log_debug("%s: fido_get_signed_hash", __func__);
r = FIDO_ERR_INTERNAL;
goto out;
}
@@ -390,7 +348,7 @@ out:
int
fido_cred_verify_self(const fido_cred_t *cred)
{
- unsigned char buf[SHA256_DIGEST_LENGTH];
+ unsigned char buf[1024]; /* XXX */
fido_blob_t dgst;
int ok = -1;
int r;
@@ -433,9 +391,9 @@ fido_cred_verify_self(const fido_cred_t *cred)
}
if (!strcmp(cred->fmt, "packed")) {
- if (get_signed_hash_packed(&dgst, &cred->cdh,
+ if (fido_get_signed_hash(cred->attcred.type, &dgst, &cred->cdh,
&cred->authdata_cbor) < 0) {
- fido_log_debug("%s: get_signed_hash_packed", __func__);
+ fido_log_debug("%s: fido_get_signed_hash", __func__);
r = FIDO_ERR_INTERNAL;
goto out;
}
@@ -1009,6 +967,18 @@ fido_cred_id_len(const fido_cred_t *cred)
return (cred->attcred.id.len);
}
+const unsigned char *
+fido_cred_aaguid_ptr(const fido_cred_t *cred)
+{
+ return (cred->attcred.aaguid);
+}
+
+size_t
+fido_cred_aaguid_len(const fido_cred_t *cred)
+{
+ return (sizeof(cred->attcred.aaguid));
+}
+
int
fido_cred_prot(const fido_cred_t *cred)
{
diff --git a/lib/libfido2/src/credman.c b/lib/libfido2/src/credman.c
index a382185dec2..4219807ce48 100644
--- a/lib/libfido2/src/credman.c
+++ b/lib/libfido2/src/credman.c
@@ -230,7 +230,8 @@ fido_credman_get_dev_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata
static int
credman_parse_rk(const cbor_item_t *key, const cbor_item_t *val, void *arg)
{
- fido_cred_t *cred = arg;
+ fido_cred_t *cred = arg;
+ uint64_t prot;
if (cbor_isa_uint(key) == false ||
cbor_int_get_width(key) != CBOR_INT_8) {
@@ -249,6 +250,11 @@ credman_parse_rk(const cbor_item_t *key, const cbor_item_t *val, void *arg)
return (-1);
cred->type = cred->attcred.type; /* XXX */
return (0);
+ case 10:
+ if (cbor_decode_uint64(val, &prot) < 0 || prot > INT_MAX ||
+ fido_cred_set_prot(cred, (int)prot) != FIDO_OK)
+ return (-1);
+ return (0);
default:
fido_log_debug("%s: cbor type", __func__);
return (0); /* ignore */
diff --git a/lib/libfido2/src/dev.c b/lib/libfido2/src/dev.c
index 1440bd385d7..6cc861909e6 100644
--- a/lib/libfido2/src/dev.c
+++ b/lib/libfido2/src/dev.c
@@ -10,6 +10,8 @@
#include <sys/random.h>
#endif
+#include <openssl/sha.h>
+
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
@@ -106,10 +108,52 @@ find_manifest_func_node(dev_manifest_func_t f, dev_manifest_func_node_t **curr,
}
}
+#ifdef FIDO_FUZZ
+static void
+set_random_report_len(fido_dev_t *dev)
+{
+ dev->rx_len = CTAP_MIN_REPORT_LEN +
+ uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1);
+ dev->tx_len = CTAP_MIN_REPORT_LEN +
+ uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1);
+}
+#endif
+
+static void
+fido_dev_set_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
+{
+ char * const *ptr;
+ size_t len;
+
+ ptr = fido_cbor_info_extensions_ptr(info);
+ len = fido_cbor_info_extensions_len(info);
+
+ for (size_t i = 0; i < len; i++) {
+ if (strcmp(ptr[i], "credProtect") == 0) {
+ dev->flags |= FIDO_DEV_SUPPORTS_CRED_PROT;
+ }
+ }
+
+ ptr = fido_cbor_info_options_name_ptr(info);
+ len = fido_cbor_info_options_len(info);
+
+ for (size_t i = 0; i < len; i++) {
+ /*
+ * clientPin: PIN supported and set;
+ * noclientPin: PIN supported but not set.
+ */
+ if (strcmp(ptr[i], "clientPin") == 0 ||
+ strcmp(ptr[i], "noclientPin") == 0) {
+ dev->flags |= FIDO_DEV_SUPPORTS_PIN;
+ }
+ }
+}
+
static int
fido_dev_open_tx(fido_dev_t *dev, const char *path)
{
- const uint8_t cmd = CTAP_CMD_INIT;
+ const uint8_t cmd = CTAP_CMD_INIT;
+ int r;
if (dev->io_handle != NULL) {
fido_log_debug("%s: handle=%p", __func__, dev->io_handle);
@@ -131,14 +175,44 @@ fido_dev_open_tx(fido_dev_t *dev, const char *path)
return (FIDO_ERR_INTERNAL);
}
+ if (dev->io_own) {
+ dev->rx_len = CTAP_MAX_REPORT_LEN;
+ dev->tx_len = CTAP_MAX_REPORT_LEN;
+ } else {
+ dev->rx_len = fido_hid_report_in_len(dev->io_handle);
+ dev->tx_len = fido_hid_report_out_len(dev->io_handle);
+ }
+
+#ifdef FIDO_FUZZ
+ set_random_report_len(dev);
+#endif
+
+ if (dev->rx_len < CTAP_MIN_REPORT_LEN ||
+ dev->rx_len > CTAP_MAX_REPORT_LEN) {
+ fido_log_debug("%s: invalid rx_len %zu", __func__, dev->rx_len);
+ r = FIDO_ERR_RX;
+ goto fail;
+ }
+
+ if (dev->tx_len < CTAP_MIN_REPORT_LEN ||
+ dev->tx_len > CTAP_MAX_REPORT_LEN) {
+ fido_log_debug("%s: invalid tx_len %zu", __func__, dev->tx_len);
+ r = FIDO_ERR_TX;
+ goto fail;
+ }
+
if (fido_tx(dev, cmd, &dev->nonce, sizeof(dev->nonce)) < 0) {
fido_log_debug("%s: fido_tx", __func__);
- dev->io.close(dev->io_handle);
- dev->io_handle = NULL;
- return (FIDO_ERR_TX);
+ r = FIDO_ERR_TX;
+ goto fail;
}
return (FIDO_OK);
+fail:
+ dev->io.close(dev->io_handle);
+ dev->io_handle = NULL;
+
+ return (r);
}
static int
@@ -166,6 +240,7 @@ fido_dev_open_rx(fido_dev_t *dev, int ms)
goto fail;
}
+ dev->flags = 0;
dev->cid = dev->attr.cid;
if (fido_dev_is_fido2(dev)) {
@@ -177,6 +252,8 @@ fido_dev_open_rx(fido_dev_t *dev, int ms)
if (fido_dev_get_cbor_info_wait(dev, info, ms) != FIDO_OK) {
fido_log_debug("%s: falling back to u2f", __func__);
fido_dev_force_u2f(dev);
+ } else {
+ fido_dev_set_flags(dev, info);
}
}
@@ -303,6 +380,9 @@ fido_dev_close(fido_dev_t *dev)
int
fido_dev_cancel(fido_dev_t *dev)
{
+ if (fido_dev_is_fido2(dev) == false)
+ return (FIDO_ERR_INVALID_ARGUMENT);
+
if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0) < 0)
return (FIDO_ERR_TX);
@@ -310,10 +390,111 @@ fido_dev_cancel(fido_dev_t *dev)
}
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()) == 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 *pin_set, int ms)
+{
+ int r;
+
+ *touched = 0;
+ *pin_set = 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_INVALID:
+ case FIDO_ERR_PIN_AUTH_INVALID:
+ *pin_set = 1;
+ /* FALLTHROUGH */
+ case FIDO_ERR_PIN_NOT_SET:
+ *touched = 1;
+ break;
+ case FIDO_ERR_RX:
+ /* ignore */
+ break;
+ default:
+ fido_log_debug("%s: fido_rx_cbor_status", __func__);
+ return (r);
+ }
+
+ return (FIDO_OK);
+}
+
+int
fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
{
if (dev->io_handle != NULL) {
- fido_log_debug("%s: NULL handle", __func__);
+ fido_log_debug("%s: non-NULL handle", __func__);
return (FIDO_ERR_INVALID_ARGUMENT);
}
@@ -324,6 +505,21 @@ fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
}
dev->io = *io;
+ dev->io_own = true;
+
+ return (FIDO_OK);
+}
+
+int
+fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t)
+{
+ if (dev->io_handle != NULL) {
+ fido_log_debug("%s: non-NULL handle", __func__);
+ return (FIDO_ERR_INVALID_ARGUMENT);
+ }
+
+ dev->transport = *t;
+ dev->io_own = true;
return (FIDO_OK);
}
@@ -349,8 +545,6 @@ fido_dev_new(void)
&fido_hid_close,
&fido_hid_read,
&fido_hid_write,
- NULL,
- NULL,
};
return (dev);
@@ -374,6 +568,8 @@ fido_dev_new_with_info(const fido_dev_info_t *di)
}
dev->io = di->io;
+ dev->transport = di->transport;
+
if ((dev->path = strdup(di->path)) == NULL) {
fido_log_debug("%s: strdup", __func__);
fido_dev_free(&dev);
@@ -433,10 +629,23 @@ fido_dev_is_fido2(const fido_dev_t *dev)
return (dev->attr.flags & FIDO_CAP_CBOR);
}
+bool
+fido_dev_supports_pin(const fido_dev_t *dev)
+{
+ return (dev->flags & FIDO_DEV_SUPPORTS_PIN);
+}
+
+bool
+fido_dev_supports_cred_prot(const fido_dev_t *dev)
+{
+ return (dev->flags & FIDO_DEV_SUPPORTS_CRED_PROT);
+}
+
void
fido_dev_force_u2f(fido_dev_t *dev)
{
- dev->attr.flags &= ~FIDO_CAP_CBOR;
+ dev->attr.flags &= (uint8_t)~FIDO_CAP_CBOR;
+ dev->flags = 0;
}
void
diff --git a/lib/libfido2/src/eddsa.c b/lib/libfido2/src/eddsa.c
index 92a022288aa..44a556319bd 100644
--- a/lib/libfido2/src/eddsa.c
+++ b/lib/libfido2/src/eddsa.c
@@ -23,6 +23,8 @@ EVP_PKEY_new_raw_public_key(int type, ENGINE *e, const unsigned char *key,
(void)key;
(void)keylen;
+ fido_log_debug("%s: unimplemented", __func__);
+
return (NULL);
}
@@ -34,6 +36,8 @@ EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub,
(void)pub;
(void)len;
+ fido_log_debug("%s: unimplemented", __func__);
+
return (0);
}
@@ -47,6 +51,8 @@ EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen,
(void)tbs;
(void)tbslen;
+ fido_log_debug("%s: unimplemented", __func__);
+
return (0);
}
#endif /* LIBRESSL_VERSION_NUMBER || OPENSSL_VERSION_NUMBER < 0x10101000L */
@@ -55,6 +61,8 @@ EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen,
EVP_MD_CTX *
EVP_MD_CTX_new(void)
{
+ fido_log_debug("%s: unimplemented", __func__);
+
return (NULL);
}
diff --git a/lib/libfido2/src/err.c b/lib/libfido2/src/err.c
index 6261bfc468c..19cda2111d2 100644
--- a/lib/libfido2/src/err.c
+++ b/lib/libfido2/src/err.c
@@ -38,6 +38,8 @@ fido_strerr(int n)
return "FIDO_ERR_LIMIT_EXCEEDED";
case FIDO_ERR_UNSUPPORTED_EXTENSION:
return "FIDO_ERR_UNSUPPORTED_EXTENSION";
+ case FIDO_ERR_FP_DATABASE_FULL:
+ return "FIDO_ERR_FP_DATABASE_FULL";
case FIDO_ERR_CREDENTIAL_EXCLUDED:
return "FIDO_ERR_CREDENTIAL_EXCLUDED";
case FIDO_ERR_PROCESSING:
@@ -94,6 +96,8 @@ fido_strerr(int n)
return "FIDO_ERR_ACTION_TIMEOUT";
case FIDO_ERR_UP_REQUIRED:
return "FIDO_ERR_UP_REQUIRED";
+ case FIDO_ERR_UV_BLOCKED:
+ return "FIDO_ERR_UV_BLOCKED";
case FIDO_ERR_ERR_OTHER:
return "FIDO_ERR_ERR_OTHER";
case FIDO_ERR_SPEC_LAST:
diff --git a/lib/libfido2/src/es256.c b/lib/libfido2/src/es256.c
index 7c751d814bf..5b4e6d663d7 100644
--- a/lib/libfido2/src/es256.c
+++ b/lib/libfido2/src/es256.c
@@ -92,7 +92,7 @@ es256_pk_encode(const es256_pk_t *pk, int ecdh)
/* alg */
if ((argv[1].key = cbor_build_uint8(3)) == NULL ||
- (argv[1].value = cbor_build_negint8(-alg - 1)) == NULL ||
+ (argv[1].value = cbor_build_negint8((uint8_t)(-alg - 1))) == NULL ||
!cbor_map_add(item, argv[1]))
goto fail;
@@ -267,8 +267,12 @@ es256_pk_to_EVP_PKEY(const es256_pk_t *k)
const int nid = NID_X9_62_prime256v1;
int ok = -1;
- if ((bnctx = BN_CTX_new()) == NULL ||
- (x = BN_CTX_get(bnctx)) == NULL ||
+ if ((bnctx = BN_CTX_new()) == NULL)
+ goto fail;
+
+ BN_CTX_start(bnctx);
+
+ if ((x = BN_CTX_get(bnctx)) == NULL ||
(y = BN_CTX_get(bnctx)) == NULL)
goto fail;
@@ -301,12 +305,16 @@ es256_pk_to_EVP_PKEY(const es256_pk_t *k)
ok = 0;
fail:
- if (bnctx != NULL)
+ if (bnctx != NULL) {
+ BN_CTX_end(bnctx);
BN_CTX_free(bnctx);
+ }
+
if (ec != NULL)
EC_KEY_free(ec);
if (q != NULL)
EC_POINT_free(q);
+
if (ok < 0 && pkey != NULL) {
EVP_PKEY_free(pkey);
pkey = NULL;
@@ -318,7 +326,7 @@ fail:
int
es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec)
{
- BN_CTX *ctx = NULL;
+ BN_CTX *bnctx = NULL;
BIGNUM *x = NULL;
BIGNUM *y = NULL;
const EC_POINT *q = NULL;
@@ -327,15 +335,17 @@ es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec)
int n;
if ((q = EC_KEY_get0_public_key(ec)) == NULL ||
- (g = EC_KEY_get0_group(ec)) == NULL)
+ (g = EC_KEY_get0_group(ec)) == NULL ||
+ (bnctx = BN_CTX_new()) == NULL)
goto fail;
- if ((ctx = BN_CTX_new()) == NULL ||
- (x = BN_CTX_get(ctx)) == NULL ||
- (y = BN_CTX_get(ctx)) == NULL)
+ BN_CTX_start(bnctx);
+
+ if ((x = BN_CTX_get(bnctx)) == NULL ||
+ (y = BN_CTX_get(bnctx)) == NULL)
goto fail;
- if (EC_POINT_get_affine_coordinates_GFp(g, q, x, y, ctx) == 0 ||
+ 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)) {
fido_log_debug("%s: EC_POINT_get_affine_coordinates_GFp",
@@ -351,8 +361,10 @@ es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec)
ok = FIDO_OK;
fail:
- if (ctx != NULL)
- BN_CTX_free(ctx);
+ if (bnctx != NULL) {
+ BN_CTX_end(bnctx);
+ BN_CTX_free(bnctx);
+ }
return (ok);
}
@@ -367,7 +379,12 @@ es256_sk_to_EVP_PKEY(const es256_sk_t *k)
const int nid = NID_X9_62_prime256v1;
int ok = -1;
- if ((bnctx = BN_CTX_new()) == NULL || (d = BN_CTX_get(bnctx)) == NULL ||
+ if ((bnctx = BN_CTX_new()) == NULL)
+ goto fail;
+
+ BN_CTX_start(bnctx);
+
+ if ((d = BN_CTX_get(bnctx)) == NULL ||
BN_bin2bn(k->d, sizeof(k->d), d) == NULL) {
fido_log_debug("%s: BN_bin2bn", __func__);
goto fail;
@@ -389,10 +406,14 @@ es256_sk_to_EVP_PKEY(const es256_sk_t *k)
ok = 0;
fail:
- if (bnctx != NULL)
+ if (bnctx != NULL) {
+ BN_CTX_end(bnctx);
BN_CTX_free(bnctx);
+ }
+
if (ec != NULL)
EC_KEY_free(ec);
+
if (ok < 0 && pkey != NULL) {
EVP_PKEY_free(pkey);
pkey = NULL;
diff --git a/lib/libfido2/src/export.llvm b/lib/libfido2/src/export.llvm
index d8ae0290939..e04ad0658b5 100644
--- a/lib/libfido2/src/export.llvm
+++ b/lib/libfido2/src/export.llvm
@@ -74,6 +74,9 @@ _fido_cbor_info_extensions_len
_fido_cbor_info_extensions_ptr
_fido_cbor_info_free
_fido_cbor_info_maxmsgsiz
+_fido_cbor_info_maxcredcntlst
+_fido_cbor_info_maxcredidlen
+_fido_cbor_info_fwversion
_fido_cbor_info_new
_fido_cbor_info_options_len
_fido_cbor_info_options_name_ptr
@@ -93,6 +96,8 @@ _fido_cred_fmt
_fido_cred_free
_fido_cred_id_len
_fido_cred_id_ptr
+_fido_cred_aaguid_len
+_fido_cred_aaguid_ptr
_fido_credman_del_dev_rk
_fido_credman_get_dev_metadata
_fido_credman_get_dev_rk
@@ -152,6 +157,8 @@ _fido_dev_free
_fido_dev_get_assert
_fido_dev_get_cbor_info
_fido_dev_get_retry_count
+_fido_dev_get_touch_begin
+_fido_dev_get_touch_status
_fido_dev_info_free
_fido_dev_info_manifest
_fido_dev_info_manufacturer_string
@@ -171,6 +178,9 @@ _fido_dev_protocol
_fido_dev_reset
_fido_dev_set_io_functions
_fido_dev_set_pin
+_fido_dev_set_transport_functions
+_fido_dev_supports_cred_prot
+_fido_dev_supports_pin
_fido_init
_fido_set_log_handler
_fido_strerr
diff --git a/lib/libfido2/src/extern.h b/lib/libfido2/src/extern.h
index e3cc315d101..62acadfef84 100644
--- a/lib/libfido2/src/extern.h
+++ b/lib/libfido2/src/extern.h
@@ -12,6 +12,10 @@
#include "fido/types.h"
#include "blob.h"
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
/* aes256 */
int aes256_cbc_dec(const fido_blob_t *, const fido_blob_t *, fido_blob_t *);
int aes256_cbc_enc(const fido_blob_t *, const fido_blob_t *, fido_blob_t *);
@@ -84,6 +88,8 @@ void *fido_hid_open(const char *);
void fido_hid_close(void *);
int fido_hid_read(void *, unsigned char *, size_t, int);
int fido_hid_write(void *, const unsigned char *, size_t);
+size_t fido_hid_report_in_len(void *);
+size_t fido_hid_report_out_len(void *);
/* generic i/o */
int fido_rx_cbor_status(fido_dev_t *, int);
@@ -111,6 +117,8 @@ void fido_log_xxd(const void *, size_t);
/* 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);
/* unexposed fido ops */
int fido_dev_authkey(fido_dev_t *, es256_pk_t *);
@@ -134,6 +142,8 @@ int fido_verify_sig_rs256(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 *,
const fido_blob_t *);
+int fido_get_signed_hash(int, fido_blob_t *, const fido_blob_t *,
+ const fido_blob_t *);
/* hid device manifest */
int fido_hid_manifest(fido_dev_info_t *, size_t, size_t *);
@@ -143,4 +153,23 @@ 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);
+/* fuzzing instrumentation */
+#ifdef FIDO_FUZZ
+uint32_t uniform_random(uint32_t);
+#endif
+
+/* internal device capability flags */
+#define FIDO_DEV_SUPPORTS_PIN 0x01
+#define FIDO_DEV_SUPPORTS_CRED_PROT 0x02
+
+/* miscellanea */
+#define FIDO_DUMMY_CLIENTDATA ""
+#define FIDO_DUMMY_RP_ID "localhost"
+#define FIDO_DUMMY_USER_NAME "dummy"
+#define FIDO_DUMMY_USER_ID 1
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
#endif /* !_EXTERN_H */
diff --git a/lib/libfido2/src/fido.h b/lib/libfido2/src/fido.h
index b818759da0c..edca4d9de20 100644
--- a/lib/libfido2/src/fido.h
+++ b/lib/libfido2/src/fido.h
@@ -28,6 +28,18 @@
#include "fido/param.h"
#include "fido/types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if defined(_MSC_VER)
+#define FIDO_DEPRECATED(reason) __declspec(deprecated(reason))
+#elif defined(__OpenBSD__)
+#define FIDO_DEPRECATED(reason)
+#else
+#define FIDO_DEPRECATED(reason) __attribute__((__deprecated__(reason)))
+#endif
+
fido_assert_t *fido_assert_new(void);
fido_cred_t *fido_cred_new(void);
fido_dev_t *fido_dev_new(void);
@@ -78,6 +90,7 @@ const unsigned char *fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *);
const unsigned char *fido_cred_authdata_ptr(const fido_cred_t *);
const unsigned char *fido_cred_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_pubkey_ptr(const fido_cred_t *);
const unsigned char *fido_cred_sig_ptr(const fido_cred_t *);
@@ -93,6 +106,7 @@ int fido_assert_set_clientdata_hash(fido_assert_t *, const unsigned char *,
int fido_assert_set_count(fido_assert_t *, size_t);
int fido_assert_set_extensions(fido_assert_t *, int);
int fido_assert_set_hmac_salt(fido_assert_t *, const unsigned char *, size_t);
+FIDO_DEPRECATED("use fido_assert_set_up/fido_assert_set_uv")
int fido_assert_set_options(fido_assert_t *, bool, bool);
int fido_assert_set_rp(fido_assert_t *, const char *);
int fido_assert_set_up(fido_assert_t *, fido_opt_t);
@@ -106,6 +120,7 @@ int fido_cred_set_authdata_raw(fido_cred_t *, const unsigned char *, size_t);
int fido_cred_set_clientdata_hash(fido_cred_t *, const unsigned char *, size_t);
int fido_cred_set_extensions(fido_cred_t *, int);
int fido_cred_set_fmt(fido_cred_t *, const char *);
+FIDO_DEPRECATED("use fido_cred_set_rk/fido_cred_set_uv")
int fido_cred_set_options(fido_cred_t *, bool, bool);
int fido_cred_set_prot(fido_cred_t *, int);
int fido_cred_set_rk(fido_cred_t *, fido_opt_t);
@@ -124,6 +139,8 @@ int fido_dev_close(fido_dev_t *);
int fido_dev_get_assert(fido_dev_t *, fido_assert_t *, const char *);
int fido_dev_get_cbor_info(fido_dev_t *, fido_cbor_info_t *);
int fido_dev_get_retry_count(fido_dev_t *, int *);
+int fido_dev_get_touch_begin(fido_dev_t *);
+int fido_dev_get_touch_status(fido_dev_t *, int *, int *, int);
int fido_dev_info_manifest(fido_dev_info_t *, size_t, size_t *);
int fido_dev_make_cred(fido_dev_t *, fido_cred_t *, const char *);
int fido_dev_open_with_info(fido_dev_t *);
@@ -131,6 +148,7 @@ int fido_dev_open(fido_dev_t *, const char *);
int fido_dev_reset(fido_dev_t *);
int fido_dev_set_io_functions(fido_dev_t *, const fido_dev_io_t *);
int fido_dev_set_pin(fido_dev_t *, const char *, const char *);
+int fido_dev_set_transport_functions(fido_dev_t *, const fido_dev_transport_t *);
size_t fido_assert_authdata_len(const fido_assert_t *, size_t);
size_t fido_assert_clientdata_hash_len(const fido_assert_t *);
@@ -147,6 +165,7 @@ size_t fido_cbor_info_versions_len(const fido_cbor_info_t *);
size_t fido_cred_authdata_len(const fido_cred_t *);
size_t fido_cred_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_pubkey_len(const fido_cred_t *);
size_t fido_cred_sig_len(const fido_cred_t *);
@@ -163,7 +182,16 @@ 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_maxcredcntlst(const fido_cbor_info_t *ci);
+uint64_t fido_cbor_info_maxcredidlen(const fido_cbor_info_t *);
+uint64_t fido_cbor_info_fwversion(const fido_cbor_info_t *);
bool fido_dev_is_fido2(const fido_dev_t *);
+bool fido_dev_supports_pin(const fido_dev_t *);
+bool fido_dev_supports_cred_prot(const fido_dev_t *);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
#endif /* !_FIDO_H */
diff --git a/lib/libfido2/src/fido/bio.h b/lib/libfido2/src/fido/bio.h
index 49301de1e6b..afe9ca4752b 100644
--- a/lib/libfido2/src/fido/bio.h
+++ b/lib/libfido2/src/fido/bio.h
@@ -21,6 +21,10 @@
#include <fido/param.h>
#endif
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
#ifdef _FIDO_INTERNAL
struct fido_bio_template {
fido_blob_t id;
@@ -100,4 +104,8 @@ void fido_bio_info_free(fido_bio_info_t **);
void fido_bio_template_array_free(fido_bio_template_array_t **);
void fido_bio_template_free(fido_bio_template_t **);
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
#endif /* !_FIDO_BIO_H */
diff --git a/lib/libfido2/src/fido/credman.h b/lib/libfido2/src/fido/credman.h
index ed110a2cbb5..eaffd65ac0c 100644
--- a/lib/libfido2/src/fido/credman.h
+++ b/lib/libfido2/src/fido/credman.h
@@ -21,6 +21,10 @@
#include <fido/param.h>
#endif
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
#ifdef _FIDO_INTERNAL
struct fido_credman_metadata {
uint64_t rk_existing;
@@ -79,4 +83,8 @@ void fido_credman_metadata_free(fido_credman_metadata_t **);
void fido_credman_rk_free(fido_credman_rk_t **);
void fido_credman_rp_free(fido_credman_rp_t **);
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
#endif /* !_FIDO_CREDMAN_H */
diff --git a/lib/libfido2/src/fido/eddsa.h b/lib/libfido2/src/fido/eddsa.h
index 3362d55f735..4a810179b6f 100644
--- a/lib/libfido2/src/fido/eddsa.h
+++ b/lib/libfido2/src/fido/eddsa.h
@@ -18,6 +18,10 @@
#include <fido.h>
#endif
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
eddsa_pk_t *eddsa_pk_new(void);
void eddsa_pk_free(eddsa_pk_t **);
EVP_PKEY *eddsa_pk_to_EVP_PKEY(const eddsa_pk_t *);
@@ -43,4 +47,8 @@ void EVP_MD_CTX_free(EVP_MD_CTX *);
#endif /* _FIDO_INTERNAL */
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
#endif /* !_FIDO_EDDSA_H */
diff --git a/lib/libfido2/src/fido/err.h b/lib/libfido2/src/fido/err.h
index 11f52bcff92..253914f7e50 100644
--- a/lib/libfido2/src/fido/err.h
+++ b/lib/libfido2/src/fido/err.h
@@ -21,6 +21,7 @@
#define FIDO_ERR_MISSING_PARAMETER 0x14
#define FIDO_ERR_LIMIT_EXCEEDED 0x15
#define FIDO_ERR_UNSUPPORTED_EXTENSION 0x16
+#define FIDO_ERR_FP_DATABASE_FULL 0x17
#define FIDO_ERR_CREDENTIAL_EXCLUDED 0x19
#define FIDO_ERR_PROCESSING 0x21
#define FIDO_ERR_INVALID_CREDENTIAL 0x22
@@ -49,6 +50,7 @@
#define FIDO_ERR_REQUEST_TOO_LARGE 0x39
#define FIDO_ERR_ACTION_TIMEOUT 0x3a
#define FIDO_ERR_UP_REQUIRED 0x3b
+#define FIDO_ERR_UV_BLOCKED 0x3c
#define FIDO_ERR_ERR_OTHER 0x7f
#define FIDO_ERR_SPEC_LAST 0xdf
@@ -64,6 +66,14 @@
#define FIDO_ERR_USER_PRESENCE_REQUIRED -8
#define FIDO_ERR_INTERNAL -9
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
const char *fido_strerr(int);
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
#endif /* _FIDO_ERR_H */
diff --git a/lib/libfido2/src/fido/es256.h b/lib/libfido2/src/fido/es256.h
index 65fda998e1f..80f4db39c7b 100644
--- a/lib/libfido2/src/fido/es256.h
+++ b/lib/libfido2/src/fido/es256.h
@@ -18,6 +18,10 @@
#include <fido.h>
#endif
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
es256_pk_t *es256_pk_new(void);
void es256_pk_free(es256_pk_t **);
EVP_PKEY *es256_pk_to_EVP_PKEY(const es256_pk_t *);
@@ -37,4 +41,8 @@ int es256_pk_set_x(es256_pk_t *, const unsigned char *);
int es256_pk_set_y(es256_pk_t *, const unsigned char *);
#endif
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
#endif /* !_FIDO_ES256_H */
diff --git a/lib/libfido2/src/fido/param.h b/lib/libfido2/src/fido/param.h
index 7d3c0cc20c3..763e364a966 100644
--- a/lib/libfido2/src/fido/param.h
+++ b/lib/libfido2/src/fido/param.h
@@ -50,8 +50,20 @@
/* HID Broadcast channel ID. */
#define CTAP_CID_BROADCAST 0xffffffff
-/* Expected size of a HID report in bytes. */
-#define CTAP_RPT_SIZE 64
+#define CTAP_INIT_HEADER_LEN 7
+#define CTAP_CONT_HEADER_LEN 5
+
+/*
+ * Maximal length of a CTAP HID report in bytes, excluding report ID (if
+ * required on the given platform).
+ */
+#define CTAP_MAX_REPORT_LEN 64
+
+/*
+ * Minimal HID report length needed to transmit an INIT header + one byte of
+ * payload data.
+ */
+#define CTAP_MIN_REPORT_LEN (CTAP_INIT_HEADER_LEN + 1)
/* Randomness device on UNIX-like platforms. */
#ifndef FIDO_RANDOM_DEV
@@ -60,7 +72,7 @@
/* Maximum message size in bytes. */
#ifndef FIDO_MAXMSG
-#define FIDO_MAXMSG 1200
+#define FIDO_MAXMSG 2048
#endif
/* CTAP capability bits. */
diff --git a/lib/libfido2/src/fido/rs256.h b/lib/libfido2/src/fido/rs256.h
index 017f4e7afdf..2b08d59980c 100644
--- a/lib/libfido2/src/fido/rs256.h
+++ b/lib/libfido2/src/fido/rs256.h
@@ -18,6 +18,10 @@
#include <fido.h>
#endif
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
rs256_pk_t *rs256_pk_new(void);
void rs256_pk_free(rs256_pk_t **);
EVP_PKEY *rs256_pk_to_EVP_PKEY(const rs256_pk_t *);
@@ -25,4 +29,8 @@ EVP_PKEY *rs256_pk_to_EVP_PKEY(const rs256_pk_t *);
int rs256_pk_from_RSA(rs256_pk_t *, const RSA *);
int rs256_pk_from_ptr(rs256_pk_t *, const void *, size_t);
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
#endif /* !_FIDO_RS256_H */
diff --git a/lib/libfido2/src/fido/types.h b/lib/libfido2/src/fido/types.h
index 815270187b3..cce1a44ddc8 100644
--- a/lib/libfido2/src/fido/types.h
+++ b/lib/libfido2/src/fido/types.h
@@ -10,24 +10,31 @@
#include <stddef.h>
#include <stdint.h>
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
struct fido_dev;
typedef void *fido_dev_io_open_t(const char *);
typedef void fido_dev_io_close_t(void *);
typedef int fido_dev_io_read_t(void *, unsigned char *, size_t, int);
typedef int fido_dev_io_write_t(void *, const unsigned char *, size_t);
-typedef int fido_dev_io_rx_t(struct fido_dev *, uint8_t, unsigned char *, size_t, int);
-typedef int fido_dev_io_tx_t(struct fido_dev *, uint8_t, const unsigned char *, size_t);
+typedef int fido_dev_rx_t(struct fido_dev *, uint8_t, unsigned char *, size_t, int);
+typedef int fido_dev_tx_t(struct fido_dev *, uint8_t, const unsigned char *, size_t);
typedef struct fido_dev_io {
fido_dev_io_open_t *open;
fido_dev_io_close_t *close;
fido_dev_io_read_t *read;
fido_dev_io_write_t *write;
- fido_dev_io_rx_t *rx;
- fido_dev_io_tx_t *tx;
} fido_dev_io_t;
+typedef struct fido_dev_transport {
+ fido_dev_rx_t *rx;
+ fido_dev_tx_t *tx;
+} fido_dev_transport_t;
+
typedef enum {
FIDO_OPT_OMIT = 0, /* use authenticator's default */
FIDO_OPT_FALSE, /* explicitly set option to false */
@@ -168,21 +175,25 @@ typedef struct fido_byte_array {
} 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_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 */
+ uint64_t maxcredcntlst; /* max number of credentials in list */
+ uint64_t maxcredidlen; /* max credential ID length */
+ uint64_t fwversion; /* firmware version */
} fido_cbor_info_t;
typedef struct fido_dev_info {
- char *path; /* device path */
- int16_t vendor_id; /* 2-byte vendor id */
- int16_t product_id; /* 2-byte product id */
- char *manufacturer; /* manufacturer string */
- char *product; /* product string */
- fido_dev_io_t io; /* i/o functions */
+ char *path; /* device path */
+ int16_t vendor_id; /* 2-byte vendor id */
+ int16_t product_id; /* 2-byte product id */
+ char *manufacturer; /* manufacturer string */
+ char *product; /* product string */
+ fido_dev_io_t io; /* i/o functions */
+ fido_dev_transport_t transport; /* transport functions */
} fido_dev_info_t;
PACKED_TYPE(fido_ctap_info_t,
@@ -198,12 +209,17 @@ struct fido_ctap_info {
})
typedef struct fido_dev {
- uint64_t nonce; /* issued nonce */
- fido_ctap_info_t attr; /* device attributes */
- uint32_t cid; /* assigned channel id */
- char *path; /* device path */
- void *io_handle; /* abstract i/o handle */
- fido_dev_io_t io; /* i/o functions */
+ uint64_t nonce; /* issued nonce */
+ fido_ctap_info_t attr; /* device attributes */
+ uint32_t cid; /* assigned channel id */
+ char *path; /* device path */
+ void *io_handle; /* abstract i/o handle */
+ fido_dev_io_t io; /* i/o functions */
+ bool io_own; /* device has own io/transport */
+ size_t rx_len; /* length of HID input reports */
+ size_t tx_len; /* length of HID output reports */
+ int flags; /* internal flags; see FIDO_DEV_* */
+ fido_dev_transport_t transport; /* transport functions */
} fido_dev_t;
#else
@@ -218,4 +234,8 @@ typedef struct rs256_pk rs256_pk_t;
typedef struct eddsa_pk eddsa_pk_t;
#endif /* _FIDO_INTERNAL */
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
#endif /* !_FIDO_TYPES_H */
diff --git a/lib/libfido2/src/hid_openbsd.c b/lib/libfido2/src/hid_openbsd.c
index 7f35bff8b56..7ba0fc53cda 100644
--- a/lib/libfido2/src/hid_openbsd.c
+++ b/lib/libfido2/src/hid_openbsd.c
@@ -7,6 +7,7 @@
#include <sys/types.h>
#include <sys/ioctl.h>
+#include <sys/time.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>
@@ -80,8 +81,6 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
fido_hid_close,
fido_hid_read,
fido_hid_write,
- NULL,
- NULL,
};
(*olen)++;
}
@@ -182,18 +181,61 @@ fido_hid_close(void *handle)
}
int
+waitfd(int fd, int ms)
+{
+ struct timespec ts_start, ts_now, ts_delta;
+ struct pollfd pfd;
+ int ms_remain, r;
+
+ if (ms < 0)
+ return 0;
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts_start) != 0) {
+ fido_log_debug("%s: clock_gettime: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+ for (ms_remain = ms; ms_remain > 0;) {
+ if ((r = poll(&pfd, 1, ms_remain)) > 0)
+ return 0;
+ else if (r == 0)
+ break;
+ else if (r != EINTR) {
+ fido_log_debug("%s: poll: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+ /* poll interrupted - subtract time already waited */
+ if (clock_gettime(CLOCK_MONOTONIC, &ts_now) != 0) {
+ fido_log_debug("%s: clock_gettime: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+ timespecsub(&ts_now, &ts_start, &ts_delta);
+ ms_remain = ms - ((ts_delta.tv_sec * 1000) +
+ (ts_delta.tv_nsec / 1000000));
+ }
+ return -1;
+}
+
+int
fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
{
struct hid_openbsd *ctx = (struct hid_openbsd *)handle;
ssize_t r;
- (void)ms; /* XXX */
-
+ fido_log_debug("%s: %zu timeout %d", __func__, len, ms);
if (len != ctx->report_in_len) {
fido_log_debug("%s: invalid len: got %zu, want %zu", __func__,
len, ctx->report_in_len);
return (-1);
}
+ if (waitfd(ctx->fd, ms) != 0) {
+ fido_log_debug("%s: fd not ready", __func__);
+ return (-1);
+ }
if ((r = read(ctx->fd, buf, len)) == -1 || (size_t)r != len) {
fido_log_debug("%s: read: %s", __func__, strerror(errno));
return (-1);
@@ -219,3 +261,19 @@ fido_hid_write(void *handle, const unsigned char *buf, size_t len)
}
return ((int)len);
}
+
+size_t
+fido_hid_report_in_len(void *handle)
+{
+ struct hid_openbsd *ctx = handle;
+
+ return (ctx->report_in_len);
+}
+
+size_t
+fido_hid_report_out_len(void *handle)
+{
+ struct hid_openbsd *ctx = handle;
+
+ return (ctx->report_out_len);
+}
diff --git a/lib/libfido2/src/info.c b/lib/libfido2/src/info.c
index 18f5abea1c7..3199ac2dbef 100644
--- a/lib/libfido2/src/info.c
+++ b/lib/libfido2/src/info.c
@@ -217,6 +217,12 @@ parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg)
return (cbor_decode_uint64(val, &ci->maxmsgsiz));
case 6: /* pinProtocols */
return (decode_protocols(val, &ci->protocols));
+ case 7: /* maxCredentialCountInList */
+ return (cbor_decode_uint64(val, &ci->maxcredcntlst));
+ case 8: /* maxCredentialIdLength */
+ return (cbor_decode_uint64(val, &ci->maxcredidlen));
+ case 14: /* fwVersion */
+ return (cbor_decode_uint64(val, &ci->fwversion));
default: /* ignore */
fido_log_debug("%s: cbor type", __func__);
return (0);
@@ -396,6 +402,24 @@ fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci)
return (ci->maxmsgsiz);
}
+uint64_t
+fido_cbor_info_maxcredcntlst(const fido_cbor_info_t *ci)
+{
+ return (ci->maxcredcntlst);
+}
+
+uint64_t
+fido_cbor_info_maxcredidlen(const fido_cbor_info_t *ci)
+{
+ return (ci->maxcredidlen);
+}
+
+uint64_t
+fido_cbor_info_fwversion(const fido_cbor_info_t *ci)
+{
+ return (ci->fwversion);
+}
+
const uint8_t *
fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci)
{
diff --git a/lib/libfido2/src/io.c b/lib/libfido2/src/io.c
index fe9c49ade49..9d2de884bf1 100644
--- a/lib/libfido2/src/io.c
+++ b/lib/libfido2/src/io.c
@@ -20,11 +20,11 @@ struct frame {
uint8_t cmd;
uint8_t bcnth;
uint8_t bcntl;
- uint8_t data[CTAP_RPT_SIZE - 7];
+ uint8_t data[CTAP_MAX_REPORT_LEN - CTAP_INIT_HEADER_LEN];
} init;
struct {
uint8_t seq;
- uint8_t data[CTAP_RPT_SIZE - 5];
+ uint8_t data[CTAP_MAX_REPORT_LEN - CTAP_CONT_HEADER_LEN];
} cont;
} body;
})
@@ -38,6 +38,7 @@ tx_empty(fido_dev_t *d, uint8_t cmd)
{
struct frame *fp;
unsigned char pkt[sizeof(*fp) + 1];
+ const size_t len = d->tx_len + 1;
int n;
memset(&pkt, 0, sizeof(pkt));
@@ -45,8 +46,8 @@ tx_empty(fido_dev_t *d, uint8_t cmd)
fp->cid = d->cid;
fp->body.init.cmd = CTAP_FRAME_INIT | cmd;
- n = d->io.write(d->io_handle, pkt, sizeof(pkt));
- if (n < 0 || (size_t)n != sizeof(pkt))
+ if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt,
+ len)) < 0 || (size_t)n != len)
return (-1);
return (0);
@@ -57,19 +58,23 @@ tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
{
struct frame *fp;
unsigned char pkt[sizeof(*fp) + 1];
+ const size_t len = d->tx_len + 1;
int n;
+ if (d->tx_len - CTAP_INIT_HEADER_LEN > sizeof(fp->body.init.data))
+ return (0);
+
memset(&pkt, 0, sizeof(pkt));
fp = (struct frame *)(pkt + 1);
fp->cid = d->cid;
fp->body.init.cmd = CTAP_FRAME_INIT | cmd;
fp->body.init.bcnth = (count >> 8) & 0xff;
fp->body.init.bcntl = count & 0xff;
- count = MIN(count, sizeof(fp->body.init.data));
+ count = MIN(count, d->tx_len - CTAP_INIT_HEADER_LEN);
memcpy(&fp->body.init.data, buf, count);
- n = d->io.write(d->io_handle, pkt, sizeof(pkt));
- if (n < 0 || (size_t)n != sizeof(pkt))
+ if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt,
+ len)) < 0 || (size_t)n != len)
return (0);
return (count);
@@ -80,17 +85,21 @@ tx_frame(fido_dev_t *d, uint8_t seq, const void *buf, size_t count)
{
struct frame *fp;
unsigned char pkt[sizeof(*fp) + 1];
+ const size_t len = d->tx_len + 1;
int n;
+ if (d->tx_len - CTAP_CONT_HEADER_LEN > sizeof(fp->body.cont.data))
+ return (0);
+
memset(&pkt, 0, sizeof(pkt));
fp = (struct frame *)(pkt + 1);
fp->cid = d->cid;
fp->body.cont.seq = seq;
- count = MIN(count, sizeof(fp->body.cont.data));
+ count = MIN(count, d->tx_len - CTAP_CONT_HEADER_LEN);
memcpy(&fp->body.cont.data, buf, count);
- n = d->io.write(d->io_handle, pkt, sizeof(pkt));
- if (n < 0 || (size_t)n != sizeof(pkt))
+ if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt,
+ len)) < 0 || (size_t)n != len)
return (0);
return (count);
@@ -127,18 +136,14 @@ fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
(void *)d, cmd, (const void *)buf, count);
fido_log_xxd(buf, count);
- if (d->io.tx != NULL)
- return (d->io.tx(d, cmd, buf, count));
-
+ if (d->transport.tx != NULL)
+ return (d->transport.tx(d, cmd, buf, count));
if (d->io_handle == NULL || d->io.write == NULL || count > UINT16_MAX) {
fido_log_debug("%s: invalid argument", __func__);
return (-1);
}
- if (count == 0)
- return (tx_empty(d, cmd));
-
- return (tx(d, cmd, buf, count));
+ return (count == 0 ? tx_empty(d, cmd) : tx(d, cmd, buf, count));
}
static int
@@ -146,8 +151,10 @@ rx_frame(fido_dev_t *d, struct frame *fp, int ms)
{
int n;
- n = d->io.read(d->io_handle, (unsigned char *)fp, sizeof(*fp), ms);
- if (n < 0 || (size_t)n != sizeof(*fp))
+ memset(fp, 0, sizeof(*fp));
+
+ if (d->rx_len > sizeof(*fp) || (n = d->io.read(d->io_handle,
+ (unsigned char *)fp, d->rx_len, ms)) < 0 || (size_t)n != d->rx_len)
return (-1);
return (0);
@@ -165,8 +172,11 @@ rx_preamble(fido_dev_t *d, uint8_t cmd, struct frame *fp, int ms)
} while (fp->cid == d->cid &&
fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE));
+ if (d->rx_len > sizeof(*fp))
+ return (-1);
+
fido_log_debug("%s: initiation frame at %p", __func__, (void *)fp);
- fido_log_xxd(fp, sizeof(*fp));
+ fido_log_xxd(fp, d->rx_len);
#ifdef FIDO_FUZZ
fp->body.init.cmd = (CTAP_FRAME_INIT | cmd);
@@ -185,30 +195,41 @@ static int
rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms)
{
struct frame f;
- uint16_t r, payload_len;
+ size_t r, payload_len, init_data_len, cont_data_len;
+
+ if (d->rx_len <= CTAP_INIT_HEADER_LEN ||
+ d->rx_len <= CTAP_CONT_HEADER_LEN)
+ return (-1);
+
+ init_data_len = d->rx_len - CTAP_INIT_HEADER_LEN;
+ cont_data_len = d->rx_len - CTAP_CONT_HEADER_LEN;
+
+ if (init_data_len > sizeof(f.body.init.data) ||
+ cont_data_len > sizeof(f.body.cont.data))
+ return (-1);
if (rx_preamble(d, cmd, &f, ms) < 0) {
fido_log_debug("%s: rx_preamble", __func__);
return (-1);
}
- payload_len = (f.body.init.bcnth << 8) | f.body.init.bcntl;
- fido_log_debug("%s: payload_len=%zu", __func__, (size_t)payload_len);
+ payload_len = (size_t)((f.body.init.bcnth << 8) | f.body.init.bcntl);
+ fido_log_debug("%s: payload_len=%zu", __func__, payload_len);
- if (count < (size_t)payload_len) {
+ if (count < payload_len) {
fido_log_debug("%s: count < payload_len", __func__);
return (-1);
}
- if (payload_len < sizeof(f.body.init.data)) {
+ if (payload_len < init_data_len) {
memcpy(buf, f.body.init.data, payload_len);
- return (payload_len);
+ return ((int)payload_len);
}
- memcpy(buf, f.body.init.data, sizeof(f.body.init.data));
- r = sizeof(f.body.init.data);
+ memcpy(buf, f.body.init.data, init_data_len);
+ r = init_data_len;
- for (int seq = 0; (size_t)r < payload_len; seq++) {
+ for (int seq = 0; r < payload_len; seq++) {
if (rx_frame(d, &f, ms) < 0) {
fido_log_debug("%s: rx_frame", __func__);
return (-1);
@@ -216,11 +237,11 @@ rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms)
fido_log_debug("%s: continuation frame at %p", __func__,
(void *)&f);
- fido_log_xxd(&f, sizeof(f));
+ fido_log_xxd(&f, d->rx_len);
#ifdef FIDO_FUZZ
f.cid = d->cid;
- f.body.cont.seq = seq;
+ f.body.cont.seq = (uint8_t)seq;
#endif
if (f.cid != d->cid || f.body.cont.seq != seq) {
@@ -229,17 +250,16 @@ rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms)
return (-1);
}
- if ((size_t)(payload_len - r) > sizeof(f.body.cont.data)) {
- memcpy(buf + r, f.body.cont.data,
- sizeof(f.body.cont.data));
- r += sizeof(f.body.cont.data);
+ if (payload_len - r > cont_data_len) {
+ memcpy(buf + r, f.body.cont.data, cont_data_len);
+ r += cont_data_len;
} else {
memcpy(buf + r, f.body.cont.data, payload_len - r);
- r += (payload_len - r); /* break */
+ r += payload_len - r; /* break */
}
}
- return (r);
+ return ((int)r);
}
int
@@ -250,17 +270,15 @@ fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms)
fido_log_debug("%s: d=%p, cmd=0x%02x, buf=%p, count=%zu, ms=%d",
__func__, (void *)d, cmd, (const void *)buf, count, ms);
- if (d->io.rx != NULL)
- return (d->io.rx(d, cmd, buf, count, ms));
-
+ if (d->transport.rx != NULL)
+ return (d->transport.rx(d, cmd, buf, count, ms));
if (d->io_handle == NULL || d->io.read == NULL || count > UINT16_MAX) {
fido_log_debug("%s: invalid argument", __func__);
return (-1);
}
-
if ((n = rx(d, cmd, buf, count, ms)) >= 0) {
fido_log_debug("%s: buf=%p, len=%d", __func__, (void *)buf, n);
- fido_log_xxd(buf, n);
+ fido_log_xxd(buf, (size_t)n);
}
return (n);
diff --git a/lib/libfido2/src/iso7816.c b/lib/libfido2/src/iso7816.c
index a3fd280f537..4fe6329a9d5 100644
--- a/lib/libfido2/src/iso7816.c
+++ b/lib/libfido2/src/iso7816.c
@@ -23,8 +23,8 @@ iso7816_new(uint8_t ins, uint8_t p1, uint16_t payload_len)
apdu->payload_ptr = apdu->payload;
apdu->header.ins = ins;
apdu->header.p1 = p1;
- apdu->header.lc2 = (payload_len >> 8) & 0xff;
- apdu->header.lc3 = payload_len & 0xff;
+ apdu->header.lc2 = (uint8_t)((payload_len >> 8) & 0xff);
+ apdu->header.lc3 = (uint8_t)(payload_len & 0xff);
return (apdu);
}
@@ -51,7 +51,7 @@ iso7816_add(iso7816_apdu_t *apdu, const void *buf, size_t cnt)
memcpy(apdu->payload_ptr, buf, cnt);
apdu->payload_ptr += cnt;
- apdu->payload_len -= (uint16_t)cnt;
+ apdu->payload_len = (uint16_t)(apdu->payload_len - cnt);
return (0);
}
diff --git a/lib/libfido2/src/iso7816.h b/lib/libfido2/src/iso7816.h
index eaf213ccc33..563243fa01f 100644
--- a/lib/libfido2/src/iso7816.h
+++ b/lib/libfido2/src/iso7816.h
@@ -12,6 +12,10 @@
#include "packed.h"
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
PACKED_TYPE(iso7816_header_t,
struct iso7816_header {
uint8_t cla;
@@ -38,4 +42,8 @@ iso7816_apdu_t *iso7816_new(uint8_t, uint8_t, uint16_t);
size_t iso7816_len(const iso7816_apdu_t *);
void iso7816_free(iso7816_apdu_t **);
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
#endif /* !_ISO7816_H */
diff --git a/lib/libfido2/src/pin.c b/lib/libfido2/src/pin.c
index 36acbe4d14b..8b23ae33415 100644
--- a/lib/libfido2/src/pin.c
+++ b/lib/libfido2/src/pin.c
@@ -53,7 +53,7 @@ fido_dev_get_pin_token_tx(fido_dev_t *dev, const char *pin,
if ((argv[0] = cbor_build_uint8(1)) == NULL ||
(argv[1] = cbor_build_uint8(5)) == NULL ||
- (argv[2] = es256_pk_encode(pk, 0)) == NULL ||
+ (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
(argv[5] = cbor_encode_pin_hash_enc(ecdh, p)) == NULL) {
fido_log_debug("%s: cbor encode", __func__);
r = FIDO_ERR_INTERNAL;
@@ -89,7 +89,7 @@ fido_dev_get_uv_token_tx(fido_dev_t *dev, const es256_pk_t *pk)
if ((argv[0] = cbor_build_uint8(1)) == NULL ||
(argv[1] = cbor_build_uint8(6)) == NULL ||
- (argv[2] = es256_pk_encode(pk, 0)) == NULL) {
+ (argv[2] = es256_pk_encode(pk, 1)) == NULL) {
fido_log_debug("%s: cbor encode", __func__);
r = FIDO_ERR_INTERNAL;
goto fail;
@@ -240,7 +240,7 @@ pad64(const char *pin, fido_blob_t **ppin)
if ((*ppin = fido_blob_new()) == NULL)
return (FIDO_ERR_INTERNAL);
- ppin_len = (pin_len + 63) & ~63;
+ ppin_len = (pin_len + 63U) & ~63U;
if (ppin_len < pin_len || ((*ppin)->ptr = calloc(1, ppin_len)) == NULL) {
fido_blob_free(ppin);
return (FIDO_ERR_INTERNAL);
@@ -285,7 +285,7 @@ fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin)
if ((argv[0] = cbor_build_uint8(1)) == NULL ||
(argv[1] = cbor_build_uint8(4)) == NULL ||
- (argv[2] = es256_pk_encode(pk, 0)) == NULL ||
+ (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
(argv[3] = cbor_encode_change_pin_auth(ecdh, ppin, opin)) == NULL ||
(argv[4] = cbor_encode_pin_enc(ecdh, ppin)) == NULL ||
(argv[5] = cbor_encode_pin_hash_enc(ecdh, opin)) == NULL) {
@@ -339,7 +339,7 @@ fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin)
if ((argv[0] = cbor_build_uint8(1)) == NULL ||
(argv[1] = cbor_build_uint8(3)) == NULL ||
- (argv[2] = es256_pk_encode(pk, 0)) == NULL ||
+ (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
(argv[3] = cbor_encode_set_pin_auth(ecdh, ppin)) == NULL ||
(argv[4] = cbor_encode_pin_enc(ecdh, ppin)) == NULL) {
fido_log_debug("%s: cbor encode", __func__);
diff --git a/lib/libfido2/src/u2f.c b/lib/libfido2/src/u2f.c
index 19a959d6dc0..406186a51b0 100644
--- a/lib/libfido2/src/u2f.c
+++ b/lib/libfido2/src/u2f.c
@@ -122,6 +122,7 @@ authdata_fake(const char *rp_id, uint8_t flags, uint32_t sigcount,
return (0);
}
+/* TODO: use u2f_get_touch_begin & u2f_get_touch_status instead */
static int
send_dummy_register(fido_dev_t *dev, int ms)
{
@@ -160,7 +161,7 @@ send_dummy_register(fido_dev_t *dev, int ms)
r = FIDO_ERR_RX;
goto fail;
}
- if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) {
+ if (usleep((unsigned)(ms == -1 ? 100 : ms) * 1000) < 0) {
fido_log_debug("%s: usleep", __func__);
r = FIDO_ERR_RX;
goto fail;
@@ -204,8 +205,8 @@ key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id,
key_id_len = (uint8_t)key_id->len;
- if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_CHECK, 2 *
- SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len)) == NULL ||
+ if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_CHECK, (uint16_t)(2 *
+ SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL ||
iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 ||
iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 ||
iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 ||
@@ -312,8 +313,8 @@ do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id,
key_id_len = (uint8_t)key_id->len;
- if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_SIGN, 2 *
- SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len)) == NULL ||
+ if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_SIGN, (uint16_t)(2 *
+ SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL ||
iso7816_add(apdu, cdh->ptr, cdh->len) < 0 ||
iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 ||
iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 ||
@@ -336,7 +337,7 @@ do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id,
r = FIDO_ERR_RX;
goto fail;
}
- if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) {
+ if (usleep((unsigned)(ms == -1 ? 100 : ms) * 1000) < 0) {
fido_log_debug("%s: usleep", __func__);
r = FIDO_ERR_RX;
goto fail;
@@ -643,7 +644,7 @@ u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms)
r = FIDO_ERR_RX;
goto fail;
}
- if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) {
+ if (usleep((unsigned)(ms == -1 ? 100 : ms) * 1000) < 0) {
fido_log_debug("%s: usleep", __func__);
r = FIDO_ERR_RX;
goto fail;
@@ -726,8 +727,8 @@ fail:
int
u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms)
{
- int nfound = 0;
- int nauth_ok = 0;
+ size_t nfound = 0;
+ size_t nauth_ok = 0;
int r;
if (fa->uv == FIDO_OPT_TRUE || fa->allow_list.ptr == NULL) {
@@ -769,3 +770,85 @@ u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms)
return (FIDO_OK);
}
+
+int
+u2f_get_touch_begin(fido_dev_t *dev)
+{
+ iso7816_apdu_t *apdu = NULL;
+ const char *clientdata = FIDO_DUMMY_CLIENTDATA;
+ const char *rp_id = FIDO_DUMMY_RP_ID;
+ unsigned char clientdata_hash[SHA256_DIGEST_LENGTH];
+ unsigned char rp_id_hash[SHA256_DIGEST_LENGTH];
+ unsigned char reply[FIDO_MAXMSG];
+ int r;
+
+ memset(&clientdata_hash, 0, sizeof(clientdata_hash));
+ memset(&rp_id_hash, 0, sizeof(rp_id_hash));
+
+ if (SHA256((const void *)clientdata, strlen(clientdata),
+ clientdata_hash) != clientdata_hash || SHA256((const void *)rp_id,
+ strlen(rp_id), rp_id_hash) != rp_id_hash) {
+ fido_log_debug("%s: sha256", __func__);
+ return (FIDO_ERR_INTERNAL);
+ }
+
+ if ((apdu = iso7816_new(U2F_CMD_REGISTER, 0, 2 *
+ SHA256_DIGEST_LENGTH)) == NULL ||
+ iso7816_add(apdu, clientdata_hash, sizeof(clientdata_hash)) < 0 ||
+ iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) {
+ fido_log_debug("%s: iso7816", __func__);
+ r = FIDO_ERR_INTERNAL;
+ goto fail;
+ }
+
+ if (dev->attr.flags & FIDO_CAP_WINK) {
+ fido_tx(dev, CTAP_CMD_WINK, NULL, 0);
+ fido_rx(dev, CTAP_CMD_WINK, &reply, sizeof(reply), 200);
+ }
+
+ if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
+ iso7816_len(apdu)) < 0) {
+ fido_log_debug("%s: fido_tx", __func__);
+ r = FIDO_ERR_TX;
+ goto fail;
+ }
+
+ r = FIDO_OK;
+fail:
+ iso7816_free(&apdu);
+
+ return (r);
+}
+
+int
+u2f_get_touch_status(fido_dev_t *dev, int *touched, int ms)
+{
+ unsigned char reply[FIDO_MAXMSG];
+ int reply_len;
+ int r;
+
+ if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, &reply, sizeof(reply),
+ ms)) < 2) {
+ fido_log_debug("%s: fido_rx", __func__);
+ return (FIDO_OK); /* ignore */
+ }
+
+ switch ((reply[reply_len - 2] << 8) | reply[reply_len - 1]) {
+ case SW_CONDITIONS_NOT_SATISFIED:
+ usleep(200 * 1000); /* per spec (Chrome) */
+ if ((r = u2f_get_touch_begin(dev)) != FIDO_OK) {
+ fido_log_debug("%s: u2f_get_touch_begin", __func__);
+ return (r);
+ }
+ *touched = 0;
+ break;
+ case SW_NO_ERROR:
+ *touched = 1;
+ break;
+ default:
+ fido_log_debug("%s: unexpected sw", __func__);
+ return (FIDO_ERR_RX);
+ }
+
+ return (FIDO_OK);
+}