11use base64:: { prelude:: BASE64_URL_SAFE_NO_PAD , Engine } ;
22use ctap_hid_fido2:: {
3- fidokey:: { AssertionExtension , GetAssertionArgsBuilder } ,
4- Cfg , FidoKeyHidFactory ,
3+ Cfg , FidoKeyHid , FidoKeyHidFactory , fidokey:: { AssertionExtension , GetAssertionArgsBuilder , get_assertion:: get_assertion_params:: GetAssertionArgs }
54} ;
65use pinentry:: PassphraseInput ;
76use secrecy:: ExposeSecret ;
@@ -28,6 +27,24 @@ pub fn available() -> bool {
2827 true
2928}
3029
30+ fn make_assertion ( options : AssertionOptions , client_data_json : String , credential : Option < & [ u8 ] > , pin : Option < String > ) -> Result < GetAssertionArgs , Fido2ClientError > {
31+ let mut get_assertion_args =
32+ GetAssertionArgsBuilder :: new ( options. rpid . as_str ( ) , client_data_json. as_bytes ( ) )
33+ . extensions ( & [ AssertionExtension :: HmacSecret ( Some ( prf_to_hmac (
34+ & options. prf_eval_first ,
35+ ) ) ) ] ) ;
36+
37+ if pin. is_some ( ) {
38+ get_assertion_args = get_assertion_args. pin ( pin. as_ref ( ) . unwrap ( ) ) ;
39+ }
40+
41+ if let Some ( cred) = credential {
42+ get_assertion_args = get_assertion_args. credential_id ( cred) ;
43+ }
44+
45+ Ok ( get_assertion_args. build ( ) )
46+ }
47+
3148pub fn get ( options : AssertionOptions ) -> Result < PublicKeyCredential , Fido2ClientError > {
3249 let device = FidoKeyHidFactory :: create ( & Cfg :: init ( ) ) . map_err ( |_| Fido2ClientError :: NoDevice ) ?;
3350
@@ -37,24 +54,32 @@ pub fn get(options: AssertionOptions) -> Result<PublicKeyCredential, Fido2Client
3754 options. rpid
3855 ) ;
3956
40- let mut get_assertion_args =
41- GetAssertionArgsBuilder :: new ( options. rpid . as_str ( ) , client_data_json. as_bytes ( ) )
42- . extensions ( & [ AssertionExtension :: HmacSecret ( Some ( prf_to_hmac (
43- & options. prf_eval_first ,
44- ) ) ) ] ) ;
45-
46- let mut pin: Option < String > = None ;
57+ let pin: Option < String > ;
4758 if options. user_verification == crate :: UserVerification :: Required
4859 || options. user_verification == crate :: UserVerification :: Preferred
4960 {
5061 pin = Some ( get_pin ( ) . ok_or ( Fido2ClientError :: WrongPin ) ?) ;
51- get_assertion_args = get_assertion_args. pin ( pin. as_ref ( ) . unwrap ( ) ) ;
5262 }
63+
5364
5465 let assertions = device
5566 . get_assertion_with_args ( & get_assertion_args. build ( ) )
56- . map_err ( |_e| Fido2ClientError :: AssertionError ) ?;
57- let assertion = assertions. get ( 0 ) . ok_or ( Fido2ClientError :: AssertionError ) ?;
67+ . map_err ( |_e| {
68+ Fido2ClientError :: AssertionError
69+ } ) ?;
70+
71+ let assertion = if assertions. len ( ) > 1 {
72+ let first_assertion = & assertions[ 0 ] ;
73+ let mut get_assertion_args = get_assertion_args. credential_id ( & first_assertion. credential_id ) ;
74+ let assertions = device
75+ . get_assertion_with_args ( & get_assertion_args. build ( ) )
76+ . map_err ( |_e| {
77+ Fido2ClientError :: AssertionError
78+ } ) ?;
79+ assertions. get ( 0 ) . ok_or ( Fido2ClientError :: AssertionError ) ?
80+ } else {
81+ assertions. get ( 0 ) . ok_or ( Fido2ClientError :: AssertionError ) ?
82+ } ;
5883
5984 let prf_extension = assertion
6085 . extensions
@@ -93,7 +118,7 @@ mod tests {
93118 get ( AssertionOptions {
94119 challenge : vec ! [ ] ,
95120 timeout : 0 ,
96- rpid : "example.com " . to_string ( ) ,
121+ rpid : "vault.usdev.bitwarden.pw " . to_string ( ) ,
97122 user_verification : crate :: UserVerification :: Required ,
98123 allow_credentials : vec ! [ ] ,
99124 prf_eval_first : [ 0u8 ; 32 ] ,
0 commit comments