Hi,

This syncs libfido2 with the current state of upstream. It includes
a few new APIs that I want to use in OpenSSH to improve FIDO token
support (require-PIN and fixing some corner-case bugs around multiple
inserted tokens).

ok?

(major crank for ABI change)

Index: Makefile
===================================================================
RCS file: /cvs/src/lib/libfido2/Makefile,v
retrieving revision 1.5
diff -u -p -r1.5 Makefile
--- Makefile    7 Feb 2020 00:57:49 -0000       1.5
+++ Makefile    10 Aug 2020 02:02:50 -0000
@@ -30,7 +30,7 @@ MAN+= fido_cbor_info_new.3 fido_cred_exc
 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 \
Index: README.openbsd
===================================================================
RCS file: /cvs/src/lib/libfido2/README.openbsd,v
retrieving revision 1.2
diff -u -p -r1.2 README.openbsd
--- README.openbsd      7 Feb 2020 00:57:49 -0000       1.2
+++ README.openbsd      10 Aug 2020 02:02:50 -0000
@@ -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 2fa20b889c (20200810)
 
 Local changes:
 
Index: shlib_version
===================================================================
RCS file: /cvs/src/lib/libfido2/shlib_version,v
retrieving revision 1.3
diff -u -p -r1.3 shlib_version
--- shlib_version       7 Feb 2020 00:57:49 -0000       1.3
+++ shlib_version       10 Aug 2020 02:02:50 -0000
@@ -1,2 +1,2 @@
-major=2
+major=3
 minor=0
Index: man/fido_assert_new.3
===================================================================
RCS file: /cvs/src/lib/libfido2/man/fido_assert_new.3,v
retrieving revision 1.3
diff -u -p -r1.3 fido_assert_new.3
--- man/fido_assert_new.3       7 Feb 2020 00:57:49 -0000       1.3
+++ man/fido_assert_new.3       10 Aug 2020 02:02:50 -0000
@@ -9,6 +9,7 @@
 .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 statement
 .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,14 +156,22 @@ 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
 The
 .Fn fido_assert_sigcount
 function can be used to obtain the signature counter of statement
+.Fa idx
+in
+.Fa assert .
+.Pp
+The
+.Fn fido_assert_flags
+function returns the authenticator data flags of statement
 .Fa idx
 in
 .Fa assert .
Index: man/fido_bio_dev_get_info.3
===================================================================
RCS file: /cvs/src/lib/libfido2/man/fido_bio_dev_get_info.3,v
retrieving revision 1.3
diff -u -p -r1.3 fido_bio_dev_get_info.3
--- man/fido_bio_dev_get_info.3 7 Feb 2020 00:57:49 -0000       1.3
+++ man/fido_bio_dev_get_info.3 10 Aug 2020 02:02:50 -0000
@@ -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.
Index: man/fido_bio_template.3
===================================================================
RCS file: /cvs/src/lib/libfido2/man/fido_bio_template.3,v
retrieving revision 1.4
diff -u -p -r1.4 fido_bio_template.3
--- man/fido_bio_template.3     7 Feb 2020 00:57:49 -0000       1.4
+++ man/fido_bio_template.3     10 Aug 2020 02:02:50 -0000
@@ -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 r
 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.
Index: man/fido_cbor_info_new.3
===================================================================
RCS file: /cvs/src/lib/libfido2/man/fido_cbor_info_new.3,v
retrieving revision 1.2
diff -u -p -r1.2 fido_cbor_info_new.3
--- man/fido_cbor_info_new.3    7 Feb 2020 00:57:49 -0000       1.2
+++ man/fido_cbor_info_new.3    10 Aug 2020 02:02:50 -0000
@@ -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 retur
 .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
Index: man/fido_cred_new.3
===================================================================
RCS file: /cvs/src/lib/libfido2/man/fido_cred_new.3,v
retrieving revision 1.3
diff -u -p -r1.3 fido_cred_new.3
--- man/fido_cred_new.3 7 Feb 2020 00:57:49 -0000       1.3
+++ man/fido_cred_new.3 10 Aug 2020 02:02:50 -0000
@@ -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
 .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
Index: man/fido_credman_metadata_new.3
===================================================================
RCS file: /cvs/src/lib/libfido2/man/fido_credman_metadata_new.3,v
retrieving revision 1.3
diff -u -p -r1.3 fido_credman_metadata_new.3
--- man/fido_credman_metadata_new.3     7 Feb 2020 00:57:49 -0000       1.3
+++ man/fido_credman_metadata_new.3     10 Aug 2020 02:02:50 -0000
@@ -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 
 .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.
Index: man/fido_dev_get_touch_begin.3
===================================================================
RCS file: man/fido_dev_get_touch_begin.3
diff -N man/fido_dev_get_touch_begin.3
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ man/fido_dev_get_touch_begin.3      10 Aug 2020 02:02:50 -0000
@@ -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 5 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
Index: man/fido_dev_open.3
===================================================================
RCS file: /cvs/src/lib/libfido2/man/fido_dev_open.3,v
retrieving revision 1.3
diff -u -p -r1.3 fido_dev_open.3
--- man/fido_dev_open.3 7 Feb 2020 00:57:49 -0000       1.3
+++ man/fido_dev_open.3 10 Aug 2020 02:02:50 -0000
@@ -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
@@ -115,6 +121,22 @@ function returns
 if
 .Fa dev
 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
Index: man/fido_dev_set_io_functions.3
===================================================================
RCS file: /cvs/src/lib/libfido2/man/fido_dev_set_io_functions.3,v
retrieving revision 1.3
diff -u -p -r1.3 fido_dev_set_io_functions.3
--- man/fido_dev_set_io_functions.3     7 Feb 2020 00:57:49 -0000       1.3
+++ man/fido_dev_set_io_functions.3     10 Aug 2020 02:02:50 -0000
@@ -15,12 +15,16 @@ typedef void *fido_dev_io_open_t(const c
 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 .
@@ -80,6 +84,59 @@ A
 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
Index: src/assert.c
===================================================================
RCS file: /cvs/src/lib/libfido2/src/assert.c,v
retrieving revision 1.2
diff -u -p -r1.2 assert.c
--- src/assert.c        7 Feb 2020 00:57:49 -0000       1.2
+++ src/assert.c        10 Aug 2020 02:02:50 -0000
@@ -313,7 +313,7 @@ fido_dev_get_assert(fido_dev_t *dev, fid
                        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 e
        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 *
                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;
        }
Index: src/bio.c
===================================================================
RCS file: /cvs/src/lib/libfido2/src/bio.c,v
retrieving revision 1.2
diff -u -p -r1.2 bio.c
--- src/bio.c   7 Feb 2020 00:57:49 -0000       1.2
+++ src/bio.c   10 Aug 2020 02:02:50 -0000
@@ -407,7 +407,7 @@ bio_rx_enroll_begin(fido_dev_t *dev, fid
                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_log_debug("%s: bio_parse_enroll_status", __func__);
                return (r);
        }
-    
+
        return (FIDO_OK);
 }
 
Index: src/blob.h
===================================================================
RCS file: /cvs/src/lib/libfido2/src/blob.h,v
retrieving revision 1.2
diff -u -p -r1.2 blob.h
--- src/blob.h  7 Feb 2020 00:57:49 -0000       1.2
+++ src/blob.h  10 Aug 2020 02:02:50 -0000
@@ -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;
@@ -27,5 +31,9 @@ int fido_blob_is_empty(const fido_blob_t
 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 */
Index: src/cbor.c
===================================================================
RCS file: /cvs/src/lib/libfido2/src/cbor.c,v
retrieving revision 1.2
diff -u -p -r1.2 cbor.c
--- src/cbor.c  7 Feb 2020 00:57:49 -0000       1.2
+++ src/cbor.c  10 Aug 2020 02:02:50 -0000
@@ -386,7 +386,7 @@ cbor_flatten_vector(cbor_item_t *argv[],
                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_e
                }
        }
        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 *
        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_b
        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_b
        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_b
                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
        }
 
        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_ite
        }
 
        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 *
 {
        fido_attstmt_t  *attstmt = arg;
        char            *name = NULL;
+       int              cose_alg = 0;
        int              ok = -1;
 
        if (cbor_string_copy(key, &name) < 0) {
@@ -1376,9 +1370,14 @@ decode_attstmt_entry(const cbor_item_t *
 
        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")) {
Index: src/cred.c
===================================================================
RCS file: /cvs/src/lib/libfido2/src/cred.c,v
retrieving revision 1.2
diff -u -p -r1.2 cred.c
--- src/cred.c  7 Feb 2020 00:57:49 -0000       1.2
+++ src/cred.c  10 Aug 2020 02:02:50 -0000
@@ -203,48 +203,6 @@ fido_check_rp_id(const char *id, const u
 }
 
 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 
        }
 
        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;
                }
@@ -1007,6 +965,18 @@ size_t
 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
Index: src/credman.c
===================================================================
RCS file: /cvs/src/lib/libfido2/src/credman.c,v
retrieving revision 1.2
diff -u -p -r1.2 credman.c
--- src/credman.c       7 Feb 2020 00:57:49 -0000       1.2
+++ src/credman.c       10 Aug 2020 02:02:50 -0000
@@ -230,7 +230,8 @@ fido_credman_get_dev_metadata(fido_dev_t
 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) {
@@ -248,6 +249,11 @@ credman_parse_rk(const cbor_item_t *key,
                    &cred->attcred.pubkey) < 0)
                        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__);
Index: src/dev.c
===================================================================
RCS file: /cvs/src/lib/libfido2/src/dev.c,v
retrieving revision 1.2
diff -u -p -r1.2 dev.c
--- src/dev.c   7 Feb 2020 00:57:49 -0000       1.2
+++ src/dev.c   10 Aug 2020 02:02:50 -0000
@@ -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_fun
        }
 }
 
+#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 
                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 *de
        }
 
        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_in
        }
 
        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
Index: src/eddsa.c
===================================================================
RCS file: /cvs/src/lib/libfido2/src/eddsa.c,v
retrieving revision 1.2
diff -u -p -r1.2 eddsa.c
--- src/eddsa.c 7 Feb 2020 00:57:49 -0000       1.2
+++ src/eddsa.c 10 Aug 2020 02:02:50 -0000
@@ -23,6 +23,8 @@ EVP_PKEY_new_raw_public_key(int type, EN
        (void)key;
        (void)keylen;
 
+       fido_log_debug("%s: unimplemented", __func__);
+
        return (NULL);
 }
 
@@ -34,6 +36,8 @@ EVP_PKEY_get_raw_public_key(const EVP_PK
        (void)pub;
        (void)len;
 
+       fido_log_debug("%s: unimplemented", __func__);
+
        return (0);
 }
 
@@ -47,6 +51,8 @@ EVP_DigestVerify(EVP_MD_CTX *ctx, const 
        (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 
 EVP_MD_CTX *
 EVP_MD_CTX_new(void)
 {
+       fido_log_debug("%s: unimplemented", __func__);
+
        return (NULL);
 }
 
Index: src/err.c
===================================================================
RCS file: /cvs/src/lib/libfido2/src/err.c,v
retrieving revision 1.2
diff -u -p -r1.2 err.c
--- src/err.c   7 Feb 2020 00:57:49 -0000       1.2
+++ src/err.c   10 Aug 2020 02:02:50 -0000
@@ -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:
Index: src/es256.c
===================================================================
RCS file: /cvs/src/lib/libfido2/src/es256.c,v
retrieving revision 1.2
diff -u -p -r1.2 es256.c
--- src/es256.c 7 Feb 2020 00:57:49 -0000       1.2
+++ src/es256.c 10 Aug 2020 02:02:50 -0000
@@ -92,7 +92,7 @@ es256_pk_encode(const es256_pk_t *pk, in
 
        /* 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, con
        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, con
 
        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;
Index: src/export.llvm
===================================================================
RCS file: /cvs/src/lib/libfido2/src/export.llvm,v
retrieving revision 1.2
diff -u -p -r1.2 export.llvm
--- src/export.llvm     7 Feb 2020 00:57:49 -0000       1.2
+++ src/export.llvm     10 Aug 2020 02:02:50 -0000
@@ -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
Index: src/extern.h
===================================================================
RCS file: /cvs/src/lib/libfido2/src/extern.h,v
retrieving revision 1.2
diff -u -p -r1.2 extern.h
--- src/extern.h        7 Feb 2020 00:57:49 -0000       1.2
+++ src/extern.h        10 Aug 2020 02:02:50 -0000
@@ -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_blo
     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 *);
@@ -142,5 +152,24 @@ int fido_hid_manifest(fido_dev_info_t *,
 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 */
Index: src/fido.h
===================================================================
RCS file: /cvs/src/lib/libfido2/src/fido.h,v
retrieving revision 1.3
diff -u -p -r1.3 fido.h
--- src/fido.h  7 Feb 2020 06:24:08 -0000       1.3
+++ src/fido.h  10 Aug 2020 02:02:50 -0000
@@ -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_aagu
 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
 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
 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 ch
 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
 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 */
Index: src/hid_openbsd.c
===================================================================
RCS file: /cvs/src/lib/libfido2/src/hid_openbsd.c,v
retrieving revision 1.3
diff -u -p -r1.3 hid_openbsd.c
--- src/hid_openbsd.c   7 Feb 2020 00:57:49 -0000       1.3
+++ src/hid_openbsd.c   10 Aug 2020 02:02:50 -0000
@@ -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 *devli
                        fido_hid_close,
                        fido_hid_read,
                        fido_hid_write,
-                       NULL,
-                       NULL,
                };
                (*olen)++;
        }
@@ -89,62 +88,6 @@ fido_hid_manifest(fido_dev_info_t *devli
        return FIDO_OK;
 }
 
-/*
- * Workaround for OpenBSD <=6.6-current (as of 201910) bug that loses
- * sync of DATA0/DATA1 sequence bit across uhid open/close.
- * Send pings until we get a response - early pings with incorrect
- * sequence bits will be ignored as duplicate packets by the device.
- */
-static int
-terrible_ping_kludge(struct hid_openbsd *ctx)
-{
-       u_char data[256];
-       int i, n;
-       struct pollfd pfd;
-
-       if (sizeof(data) < ctx->report_out_len + 1)
-               return -1;
-       for (i = 0; i < 4; i++) {
-               memset(data, 0, sizeof(data));
-               /* broadcast channel ID */
-               data[1] = 0xff;
-               data[2] = 0xff;
-               data[3] = 0xff;
-               data[4] = 0xff;
-               /* Ping command */
-               data[5] = 0x81;
-               /* One byte ping only, Vasili */
-               data[6] = 0;
-               data[7] = 1;
-               fido_log_debug("%s: send ping %d", __func__, i);
-               if (fido_hid_write(ctx, data, ctx->report_out_len + 1) == -1)
-                       return -1;
-               fido_log_debug("%s: wait reply", __func__);
-               memset(&pfd, 0, sizeof(pfd));
-               pfd.fd = ctx->fd;
-               pfd.events = POLLIN;
-               if ((n = poll(&pfd, 1, 100)) == -1) {
-                       fido_log_debug("%s: poll: %s", __func__, 
strerror(errno));
-                       return -1;
-               } else if (n == 0) {
-                       fido_log_debug("%s: timed out", __func__);
-                       continue;
-               }
-               if (fido_hid_read(ctx, data, ctx->report_out_len, 250) == -1)
-                       return -1;
-               /*
-                * Ping isn't always supported on the broadcast channel,
-                * so we might get an error, but we don't care - we're
-                * synched now.
-                */
-               fido_log_debug("%s: got reply", __func__);
-               fido_log_xxd(data, ctx->report_out_len);
-               return 0;
-       }
-       fido_log_debug("%s: no response", __func__);
-       return -1;
-}
-
 void *
 fido_hid_open(const char *path)
 {
@@ -159,16 +102,6 @@ fido_hid_open(const char *path)
        fido_log_debug("%s: inlen = %zu outlen = %zu", __func__,
            ret->report_in_len, ret->report_out_len);
 
-       /*
-        * OpenBSD (as of 201910) has a bug that causes it to lose
-        * track of the DATA0/DATA1 sequence toggle across uhid device
-        * open and close. This is a terrible hack to work around it.
-        */
-       if (terrible_ping_kludge(ret) != 0) {
-               fido_hid_close(ret);
-               return NULL;
-       }
-
        return (ret);
 }
 
@@ -182,18 +115,60 @@ fido_hid_close(void *handle)
 }
 
 int
+waitfd(int fd, int ms)
+{
+       struct timespec ts_start, ts_now, ts_remain;
+       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_remain, &ts_now, &ts_start);
+               ms_remain = ms - ((ts_remain.tv_sec * 1000) +
+                   (ts_remain.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 */
-
        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);
@@ -218,4 +193,20 @@ fido_hid_write(void *handle, const unsig
                return (-1);
        }
        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);
 }
Index: src/info.c
===================================================================
RCS file: /cvs/src/lib/libfido2/src/info.c,v
retrieving revision 1.2
diff -u -p -r1.2 info.c
--- src/info.c  7 Feb 2020 00:57:49 -0000       1.2
+++ src/info.c  10 Aug 2020 02:02:50 -0000
@@ -217,6 +217,12 @@ parse_reply_element(const cbor_item_t *k
                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);
@@ -394,6 +400,24 @@ uint64_t
 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 *
Index: src/io.c
===================================================================
RCS file: /cvs/src/lib/libfido2/src/io.c,v
retrieving revision 1.2
diff -u -p -r1.2 io.c
--- src/io.c    7 Feb 2020 00:57:49 -0000       1.2
+++ src/io.c    10 Aug 2020 02:02:50 -0000
@@ -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, 
 {
        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, con
 {
        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, cons
            (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 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, 
        } 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 
 
                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 
                        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
        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);
Index: src/iso7816.c
===================================================================
RCS file: /cvs/src/lib/libfido2/src/iso7816.c,v
retrieving revision 1.2
diff -u -p -r1.2 iso7816.c
--- src/iso7816.c       7 Feb 2020 00:57:49 -0000       1.2
+++ src/iso7816.c       10 Aug 2020 02:02:50 -0000
@@ -23,8 +23,8 @@ iso7816_new(uint8_t ins, uint8_t p1, uin
        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 
 
        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);
 }
Index: src/iso7816.h
===================================================================
RCS file: /cvs/src/lib/libfido2/src/iso7816.h,v
retrieving revision 1.2
diff -u -p -r1.2 iso7816.h
--- src/iso7816.h       7 Feb 2020 00:57:49 -0000       1.2
+++ src/iso7816.h       10 Aug 2020 02:02:50 -0000
@@ -12,6 +12,10 @@
 
 #include "packed.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
 PACKED_TYPE(iso7816_header_t,
 struct iso7816_header {
        uint8_t cla;
@@ -37,5 +41,9 @@ int iso7816_add(iso7816_apdu_t *, const 
 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 */
Index: src/pin.c
===================================================================
RCS file: /cvs/src/lib/libfido2/src/pin.c,v
retrieving revision 1.2
diff -u -p -r1.2 pin.c
--- src/pin.c   7 Feb 2020 00:57:49 -0000       1.2
+++ src/pin.c   10 Aug 2020 02:02:50 -0000
@@ -53,7 +53,7 @@ fido_dev_get_pin_token_tx(fido_dev_t *de
 
        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
 
        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 **ppi
        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, 
 
        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, con
 
        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__);
Index: src/u2f.c
===================================================================
RCS file: /cvs/src/lib/libfido2/src/u2f.c,v
retrieving revision 1.2
diff -u -p -r1.2 u2f.c
--- src/u2f.c   7 Feb 2020 00:57:49 -0000       1.2
+++ src/u2f.c   10 Aug 2020 02:02:50 -0000
@@ -122,6 +122,7 @@ authdata_fake(const char *rp_id, uint8_t
        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
                        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 *
 
        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
 
        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
                        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_
                        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) {
@@ -766,6 +767,88 @@ u2f_authenticate(fido_dev_t *dev, fido_a
                return (FIDO_ERR_NO_CREDENTIALS);
        if (nauth_ok == 0)
                return (FIDO_ERR_USER_PRESENCE_REQUIRED);
+
+       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);
 }
Index: src/fido/bio.h
===================================================================
RCS file: /cvs/src/lib/libfido2/src/fido/bio.h,v
retrieving revision 1.2
diff -u -p -r1.2 bio.h
--- src/fido/bio.h      7 Feb 2020 00:57:49 -0000       1.2
+++ src/fido/bio.h      10 Aug 2020 02:02:50 -0000
@@ -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;
@@ -99,5 +103,9 @@ void fido_bio_enroll_free(fido_bio_enrol
 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 */
Index: src/fido/credman.h
===================================================================
RCS file: /cvs/src/lib/libfido2/src/fido/credman.h,v
retrieving revision 1.2
diff -u -p -r1.2 credman.h
--- src/fido/credman.h  7 Feb 2020 00:57:49 -0000       1.2
+++ src/fido/credman.h  10 Aug 2020 02:02:50 -0000
@@ -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;
@@ -78,5 +82,9 @@ uint64_t fido_credman_rk_remaining(const
 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 */
Index: src/fido/eddsa.h
===================================================================
RCS file: /cvs/src/lib/libfido2/src/fido/eddsa.h,v
retrieving revision 1.2
diff -u -p -r1.2 eddsa.h
--- src/fido/eddsa.h    7 Feb 2020 00:57:49 -0000       1.2
+++ src/fido/eddsa.h    10 Aug 2020 02:02:50 -0000
@@ -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 *);
@@ -42,5 +46,9 @@ void EVP_MD_CTX_free(EVP_MD_CTX *);
 #endif
 
 #endif /* _FIDO_INTERNAL */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
 
 #endif /* !_FIDO_EDDSA_H */
Index: src/fido/err.h
===================================================================
RCS file: /cvs/src/lib/libfido2/src/fido/err.h,v
retrieving revision 1.1
diff -u -p -r1.1 err.h
--- src/fido/err.h      14 Nov 2019 21:14:10 -0000      1.1
+++ src/fido/err.h      10 Aug 2020 02:02:50 -0000
@@ -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 */
Index: src/fido/es256.h
===================================================================
RCS file: /cvs/src/lib/libfido2/src/fido/es256.h,v
retrieving revision 1.2
diff -u -p -r1.2 es256.h
--- src/fido/es256.h    7 Feb 2020 00:57:49 -0000       1.2
+++ src/fido/es256.h    10 Aug 2020 02:02:50 -0000
@@ -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 *);
@@ -36,5 +40,9 @@ int es256_sk_create(es256_sk_t *);
 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 */
Index: src/fido/param.h
===================================================================
RCS file: /cvs/src/lib/libfido2/src/fido/param.h,v
retrieving revision 1.2
diff -u -p -r1.2 param.h
--- src/fido/param.h    7 Feb 2020 00:57:49 -0000       1.2
+++ src/fido/param.h    10 Aug 2020 02:02:50 -0000
@@ -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. */
Index: src/fido/rs256.h
===================================================================
RCS file: /cvs/src/lib/libfido2/src/fido/rs256.h,v
retrieving revision 1.2
diff -u -p -r1.2 rs256.h
--- src/fido/rs256.h    7 Feb 2020 00:57:49 -0000       1.2
+++ src/fido/rs256.h    10 Aug 2020 02:02:50 -0000
@@ -18,11 +18,19 @@
 #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 *);
 
 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 */
Index: src/fido/types.h
===================================================================
RCS file: /cvs/src/lib/libfido2/src/fido/types.h,v
retrieving revision 1.1
diff -u -p -r1.1 types.h
--- src/fido/types.h    7 Feb 2020 00:57:49 -0000       1.1
+++ src/fido/types.h    10 Aug 2020 02:02:50 -0000
@@ -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
@@ -217,5 +233,9 @@ typedef struct es256_sk es256_sk_t;
 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 */

Reply via email to