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