@@ -66,7 +66,82 @@ impl StateMachine {
6666 Default :: default ( )
6767 }
6868
69- pub fn register (
69+ pub fn register < T > (
70+ dev : & mut T ,
71+ flags : crate :: RegisterFlags ,
72+ challenge : & Vec < u8 > ,
73+ application : & crate :: AppId ,
74+ key_handles : & Vec < crate :: KeyHandle > ,
75+ status_mutex : & Mutex < Sender < crate :: StatusUpdate > > ,
76+ callback : & StateCallback < Result < crate :: RegisterResult , crate :: Error > > ,
77+ alive : & dyn Fn ( ) -> bool ,
78+ ) where
79+ T : APDUDevice + U2FInfoQueryable ,
80+ {
81+ // Try initializing it.
82+ if !dev. init_apdu ( ) . is_ok ( ) {
83+ return ;
84+ }
85+
86+ // We currently support none of the authenticator selection
87+ // criteria because we can't ask tokens whether they do support
88+ // those features. If flags are set, ignore all tokens for now.
89+ //
90+ // Technically, this is a ConstraintError because we shouldn't talk
91+ // to this authenticator in the first place. But the result is the
92+ // same anyway.
93+ if !flags. is_empty ( ) {
94+ return ;
95+ }
96+
97+ send_status (
98+ & status_mutex,
99+ crate :: StatusUpdate :: DeviceAvailable {
100+ dev_info : dev. get_device_info ( ) ,
101+ } ,
102+ ) ;
103+
104+ // Iterate the exclude list and see if there are any matches.
105+ // If so, we'll keep polling the device anyway to test for user
106+ // consent, to be consistent with CTAP2 device behavior.
107+ let excluded = key_handles. iter ( ) . any ( |key_handle| {
108+ is_valid_transport ( key_handle. transports )
109+ && apdu_is_keyhandle_valid ( dev, & challenge, & application, & key_handle. credential )
110+ . unwrap_or ( false ) /* no match on failure */
111+ } ) ;
112+
113+ while alive ( ) {
114+ if excluded {
115+ let blank = vec ! [ 0u8 ; PARAMETER_SIZE ] ;
116+ if apdu_register ( dev, & blank, & blank) . is_ok ( ) {
117+ callback. call ( Err ( crate :: Error :: InvalidState ) ) ;
118+ break ;
119+ }
120+ } else if let Ok ( bytes) = apdu_register ( dev, & challenge, & application) {
121+ let dev_info = dev. get_device_info ( ) ;
122+ send_status (
123+ & status_mutex,
124+ crate :: StatusUpdate :: Success {
125+ dev_info : dev. get_device_info ( ) ,
126+ } ,
127+ ) ;
128+ callback. call ( Ok ( ( bytes, dev_info) ) ) ;
129+ break ;
130+ }
131+
132+ // Sleep a bit before trying again.
133+ thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
134+ }
135+
136+ send_status (
137+ & status_mutex,
138+ crate :: StatusUpdate :: DeviceUnavailable {
139+ dev_info : dev. get_device_info ( ) ,
140+ } ,
141+ ) ;
142+ }
143+
144+ pub fn _register (
70145 & mut self ,
71146 flags : crate :: RegisterFlags ,
72147 timeout : u64 ,
@@ -89,73 +164,117 @@ impl StateMachine {
89164 _ => return ,
90165 } ;
91166
92- // Try initializing it.
93- if !dev. is_u2f ( ) || !dev. init_apdu ( ) . is_ok ( ) {
167+ if !dev. is_u2f ( ) {
94168 return ;
95169 }
96170
97- // We currently support none of the authenticator selection
98- // criteria because we can't ask tokens whether they do support
99- // those features. If flags are set, ignore all tokens for now.
100- //
101- // Technically, this is a ConstraintError because we shouldn't talk
102- // to this authenticator in the first place. But the result is the
103- // same anyway.
104- if !flags. is_empty ( ) {
105- return ;
106- }
171+ StateMachine :: register ( dev, flags, & challenge, & application, & key_handles, & status_mutex, & callback, alive) ;
172+ } ) ;
173+
174+ self . transaction = Some ( try_or ! ( transaction, |e| cbc. call( Err ( e) ) ) ) ;
175+ }
107176
108- send_status (
109- & status_mutex,
110- crate :: StatusUpdate :: DeviceAvailable {
111- dev_info : dev. get_device_info ( ) ,
112- } ,
113- ) ;
114-
115- // Iterate the exclude list and see if there are any matches.
116- // If so, we'll keep polling the device anyway to test for user
117- // consent, to be consistent with CTAP2 device behavior.
118- let excluded = key_handles. iter ( ) . any ( |key_handle| {
119- is_valid_transport ( key_handle. transports )
120- && apdu_is_keyhandle_valid ( dev, & challenge, & application, & key_handle. credential )
121- . unwrap_or ( false ) /* no match on failure */
177+ pub fn sign < T > (
178+ dev : & mut T ,
179+ flags : crate :: SignFlags ,
180+ challenge : & Vec < u8 > ,
181+ app_ids : & Vec < crate :: AppId > ,
182+ key_handles : & Vec < crate :: KeyHandle > ,
183+ status_mutex : & Mutex < Sender < crate :: StatusUpdate > > ,
184+ callback : & StateCallback < Result < crate :: SignResult , crate :: Error > > ,
185+ alive : & dyn Fn ( ) -> bool ,
186+ ) where
187+ T : APDUDevice + U2FInfoQueryable ,
188+ {
189+ // Try initializing it.
190+ if !dev. init_apdu ( ) . is_ok ( ) {
191+ return ;
192+ }
193+
194+ // We currently don't support user verification because we can't
195+ // ask tokens whether they do support that. If the flag is set,
196+ // ignore all tokens for now.
197+ //
198+ // Technically, this is a ConstraintError because we shouldn't talk
199+ // to this authenticator in the first place. But the result is the
200+ // same anyway.
201+ if !flags. is_empty ( ) {
202+ return ;
203+ }
204+
205+ // For each appId, try all key handles. If there's at least one
206+ // valid key handle for an appId, we'll use that appId below.
207+ let ( app_id, valid_handles) =
208+ find_valid_key_handles ( & app_ids, & key_handles, |app_id, key_handle| {
209+ apdu_is_keyhandle_valid ( dev, & challenge, app_id, & key_handle. credential )
210+ . unwrap_or ( false ) /* no match on failure */
122211 } ) ;
123212
124- while alive ( ) {
125- if excluded {
126- let blank = vec ! [ 0u8 ; PARAMETER_SIZE ] ;
127- if apdu_register ( dev, & blank, & blank) . is_ok ( ) {
128- callback. call ( Err ( crate :: Error :: InvalidState ) ) ;
129- break ;
130- }
131- } else if let Ok ( bytes) = apdu_register ( dev, & challenge, & application) {
132- let dev_info = dev. get_device_info ( ) ;
133- send_status (
134- & status_mutex,
135- crate :: StatusUpdate :: Success {
136- dev_info : dev. get_device_info ( ) ,
137- } ,
138- ) ;
139- callback. call ( Ok ( ( bytes, dev_info) ) ) ;
213+ // Aggregate distinct transports from all given credentials.
214+ let transports = key_handles
215+ . iter ( )
216+ . fold ( crate :: AuthenticatorTransports :: empty ( ) , |t, k| {
217+ t | k. transports
218+ } ) ;
219+
220+ // We currently only support USB. If the RP specifies transports
221+ // and doesn't include USB it's probably lying.
222+ if !is_valid_transport ( transports) {
223+ return ;
224+ }
225+
226+ send_status (
227+ & status_mutex,
228+ crate :: StatusUpdate :: DeviceAvailable {
229+ dev_info : dev. get_device_info ( ) ,
230+ } ,
231+ ) ;
232+
233+ ' outer: while alive ( ) {
234+ // If the device matches none of the given key handles
235+ // then just make it blink with bogus data.
236+ if valid_handles. is_empty ( ) {
237+ let blank = vec ! [ 0u8 ; PARAMETER_SIZE ] ;
238+ if apdu_register ( dev, & blank, & blank) . is_ok ( ) {
239+ callback. call ( Err ( crate :: Error :: InvalidState ) ) ;
140240 break ;
141241 }
142-
143- // Sleep a bit before trying again.
144- thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
242+ } else {
243+ // Otherwise, try to sign.
244+ for key_handle in & valid_handles {
245+ if let Ok ( bytes) = apdu_sign ( dev, & challenge, app_id, & key_handle. credential )
246+ {
247+ let dev_info = dev. get_device_info ( ) ;
248+ send_status (
249+ & status_mutex,
250+ crate :: StatusUpdate :: Success {
251+ dev_info : dev. get_device_info ( ) ,
252+ } ,
253+ ) ;
254+ callback. call ( Ok ( (
255+ app_id. clone ( ) ,
256+ key_handle. credential . clone ( ) ,
257+ bytes,
258+ dev_info,
259+ ) ) ) ;
260+ break ' outer;
261+ }
262+ }
145263 }
146264
147- send_status (
148- & status_mutex,
149- crate :: StatusUpdate :: DeviceUnavailable {
150- dev_info : dev. get_device_info ( ) ,
151- } ,
152- ) ;
153- } ) ;
265+ // Sleep a bit before trying again.
266+ thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
267+ }
154268
155- self . transaction = Some ( try_or ! ( transaction, |e| cbc. call( Err ( e) ) ) ) ;
269+ send_status (
270+ & status_mutex,
271+ crate :: StatusUpdate :: DeviceUnavailable {
272+ dev_info : dev. get_device_info ( ) ,
273+ } ,
274+ ) ;
156275 }
157276
158- pub fn sign (
277+ pub fn _sign (
159278 & mut self ,
160279 flags : crate :: SignFlags ,
161280 timeout : u64 ,
@@ -179,92 +298,11 @@ impl StateMachine {
179298 _ => return ,
180299 } ;
181300
182- // Try initializing it.
183- if !dev. is_u2f ( ) || !dev. init_apdu ( ) . is_ok ( ) {
184- return ;
185- }
186-
187- // We currently don't support user verification because we can't
188- // ask tokens whether they do support that. If the flag is set,
189- // ignore all tokens for now.
190- //
191- // Technically, this is a ConstraintError because we shouldn't talk
192- // to this authenticator in the first place. But the result is the
193- // same anyway.
194- if !flags. is_empty ( ) {
195- return ;
196- }
197-
198- // For each appId, try all key handles. If there's at least one
199- // valid key handle for an appId, we'll use that appId below.
200- let ( app_id, valid_handles) =
201- find_valid_key_handles ( & app_ids, & key_handles, |app_id, key_handle| {
202- apdu_is_keyhandle_valid ( dev, & challenge, app_id, & key_handle. credential )
203- . unwrap_or ( false ) /* no match on failure */
204- } ) ;
205-
206- // Aggregate distinct transports from all given credentials.
207- let transports = key_handles
208- . iter ( )
209- . fold ( crate :: AuthenticatorTransports :: empty ( ) , |t, k| {
210- t | k. transports
211- } ) ;
212-
213- // We currently only support USB. If the RP specifies transports
214- // and doesn't include USB it's probably lying.
215- if !is_valid_transport ( transports) {
301+ if !dev. is_u2f ( ) {
216302 return ;
217303 }
218304
219- send_status (
220- & status_mutex,
221- crate :: StatusUpdate :: DeviceAvailable {
222- dev_info : dev. get_device_info ( ) ,
223- } ,
224- ) ;
225-
226- ' outer: while alive ( ) {
227- // If the device matches none of the given key handles
228- // then just make it blink with bogus data.
229- if valid_handles. is_empty ( ) {
230- let blank = vec ! [ 0u8 ; PARAMETER_SIZE ] ;
231- if apdu_register ( dev, & blank, & blank) . is_ok ( ) {
232- callback. call ( Err ( crate :: Error :: InvalidState ) ) ;
233- break ;
234- }
235- } else {
236- // Otherwise, try to sign.
237- for key_handle in & valid_handles {
238- if let Ok ( bytes) = apdu_sign ( dev, & challenge, app_id, & key_handle. credential )
239- {
240- let dev_info = dev. get_device_info ( ) ;
241- send_status (
242- & status_mutex,
243- crate :: StatusUpdate :: Success {
244- dev_info : dev. get_device_info ( ) ,
245- } ,
246- ) ;
247- callback. call ( Ok ( (
248- app_id. clone ( ) ,
249- key_handle. credential . clone ( ) ,
250- bytes,
251- dev_info,
252- ) ) ) ;
253- break ' outer;
254- }
255- }
256- }
257-
258- // Sleep a bit before trying again.
259- thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
260- }
261-
262- send_status (
263- & status_mutex,
264- crate :: StatusUpdate :: DeviceUnavailable {
265- dev_info : dev. get_device_info ( ) ,
266- } ,
267- ) ;
305+ StateMachine :: sign ( dev, flags, & challenge, & app_ids, & key_handles, & status_mutex, & callback, alive) ;
268306 } ) ;
269307
270308 self . transaction = Some ( try_or ! ( transaction, |e| cbc. call( Err ( e) ) ) ) ;
0 commit comments