@@ -66,7 +66,84 @@ 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 < crate :: Result < crate :: RegisterResult > > ,
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 ( errors:: AuthenticatorError :: U2FToken (
118+ errors:: U2FTokenError :: InvalidState ,
119+ ) ) ) ;
120+ break ;
121+ }
122+ } else if let Ok ( bytes) = apdu_register ( dev, & challenge, & application) {
123+ let dev_info = dev. get_device_info ( ) ;
124+ send_status (
125+ & status_mutex,
126+ crate :: StatusUpdate :: Success {
127+ dev_info : dev. get_device_info ( ) ,
128+ } ,
129+ ) ;
130+ callback. call ( Ok ( ( bytes, dev_info) ) ) ;
131+ break ;
132+ }
133+
134+ // Sleep a bit before trying again.
135+ thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
136+ }
137+
138+ send_status (
139+ & status_mutex,
140+ crate :: StatusUpdate :: DeviceUnavailable {
141+ dev_info : dev. get_device_info ( ) ,
142+ } ,
143+ ) ;
144+ }
145+
146+ pub fn _register (
70147 & mut self ,
71148 flags : crate :: RegisterFlags ,
72149 timeout : u64 ,
@@ -89,75 +166,119 @@ impl StateMachine {
89166 _ => return ,
90167 } ;
91168
92- // Try initializing it.
93- if !dev. is_u2f ( ) || !dev. init_apdu ( ) . is_ok ( ) {
169+ if !dev. is_u2f ( ) {
94170 return ;
95171 }
96172
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- }
173+ StateMachine :: register ( dev, flags, & challenge, & application, & key_handles, & status_mutex, & callback, alive) ;
174+ } ) ;
175+
176+ self . transaction = Some ( try_or ! ( transaction, |e| cbc. call( Err ( e) ) ) ) ;
177+ }
178+
179+ pub fn sign < T > (
180+ dev : & mut T ,
181+ flags : crate :: SignFlags ,
182+ challenge : & Vec < u8 > ,
183+ app_ids : & Vec < crate :: AppId > ,
184+ key_handles : & Vec < crate :: KeyHandle > ,
185+ status_mutex : & Mutex < Sender < crate :: StatusUpdate > > ,
186+ callback : & StateCallback < crate :: Result < crate :: SignResult > > ,
187+ alive : & dyn Fn ( ) -> bool ,
188+ ) where
189+ T : APDUDevice + U2FInfoQueryable ,
190+ {
191+ // Try initializing it.
192+ if !dev. init_apdu ( ) . is_ok ( ) {
193+ return ;
194+ }
195+
196+ // We currently don't support user verification because we can't
197+ // ask tokens whether they do support that. If the flag is set,
198+ // ignore all tokens for now.
199+ //
200+ // Technically, this is a ConstraintError because we shouldn't talk
201+ // to this authenticator in the first place. But the result is the
202+ // same anyway.
203+ if !flags. is_empty ( ) {
204+ return ;
205+ }
107206
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 */
207+ // For each appId, try all key handles. If there's at least one
208+ // valid key handle for an appId, we'll use that appId below.
209+ let ( app_id, valid_handles) =
210+ find_valid_key_handles ( & app_ids, & key_handles, |app_id, key_handle| {
211+ apdu_is_keyhandle_valid ( dev, & challenge, app_id, & key_handle. credential )
212+ . unwrap_or ( false ) /* no match on failure */
122213 } ) ;
123214
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 ( errors:: AuthenticatorError :: U2FToken (
129- errors:: U2FTokenError :: InvalidState ,
215+ // Aggregate distinct transports from all given credentials.
216+ let transports = key_handles
217+ . iter ( )
218+ . fold ( crate :: AuthenticatorTransports :: empty ( ) , |t, k| {
219+ t | k. transports
220+ } ) ;
221+
222+ // We currently only support USB. If the RP specifies transports
223+ // and doesn't include USB it's probably lying.
224+ if !is_valid_transport ( transports) {
225+ return ;
226+ }
227+
228+ send_status (
229+ & status_mutex,
230+ crate :: StatusUpdate :: DeviceAvailable {
231+ dev_info : dev. get_device_info ( ) ,
232+ } ,
233+ ) ;
234+
235+ ' outer: while alive ( ) {
236+ // If the device matches none of the given key handles
237+ // then just make it blink with bogus data.
238+ if valid_handles. is_empty ( ) {
239+ let blank = vec ! [ 0u8 ; PARAMETER_SIZE ] ;
240+ if apdu_register ( dev, & blank, & blank) . is_ok ( ) {
241+ callback. call ( Err ( errors:: AuthenticatorError :: U2FToken (
242+ errors:: U2FTokenError :: InvalidState ,
243+ ) ) ) ;
244+ break ;
245+ }
246+ } else {
247+ // Otherwise, try to sign.
248+ for key_handle in & valid_handles {
249+ if let Ok ( bytes) = apdu_sign ( dev, & challenge, app_id, & key_handle. credential )
250+ {
251+ let dev_info = dev. get_device_info ( ) ;
252+ send_status (
253+ & status_mutex,
254+ crate :: StatusUpdate :: Success {
255+ dev_info : dev. get_device_info ( ) ,
256+ } ,
257+ ) ;
258+ callback. call ( Ok ( (
259+ app_id. clone ( ) ,
260+ key_handle. credential . clone ( ) ,
261+ bytes,
262+ dev_info,
130263 ) ) ) ;
131- break ;
264+ break ' outer ;
132265 }
133- } else if let Ok ( bytes) = apdu_register ( dev, & challenge, & application) {
134- let dev_info = dev. get_device_info ( ) ;
135- send_status (
136- & status_mutex,
137- crate :: StatusUpdate :: Success {
138- dev_info : dev. get_device_info ( ) ,
139- } ,
140- ) ;
141- callback. call ( Ok ( ( bytes, dev_info) ) ) ;
142- break ;
143266 }
144-
145- // Sleep a bit before trying again.
146- thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
147267 }
148268
149- send_status (
150- & status_mutex,
151- crate :: StatusUpdate :: DeviceUnavailable {
152- dev_info : dev. get_device_info ( ) ,
153- } ,
154- ) ;
155- } ) ;
269+ // Sleep a bit before trying again.
270+ thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
271+ }
156272
157- self . transaction = Some ( try_or ! ( transaction, |e| cbc. call( Err ( e) ) ) ) ;
273+ send_status (
274+ & status_mutex,
275+ crate :: StatusUpdate :: DeviceUnavailable {
276+ dev_info : dev. get_device_info ( ) ,
277+ } ,
278+ ) ;
158279 }
159280
160- pub fn sign (
281+ pub fn _sign (
161282 & mut self ,
162283 flags : crate :: SignFlags ,
163284 timeout : u64 ,
@@ -181,94 +302,11 @@ impl StateMachine {
181302 _ => return ,
182303 } ;
183304
184- // Try initializing it.
185- if !dev. is_u2f ( ) || !dev. init_apdu ( ) . is_ok ( ) {
305+ if !dev. is_u2f ( ) {
186306 return ;
187307 }
188308
189- // We currently don't support user verification because we can't
190- // ask tokens whether they do support that. If the flag is set,
191- // ignore all tokens for now.
192- //
193- // Technically, this is a ConstraintError because we shouldn't talk
194- // to this authenticator in the first place. But the result is the
195- // same anyway.
196- if !flags. is_empty ( ) {
197- return ;
198- }
199-
200- // For each appId, try all key handles. If there's at least one
201- // valid key handle for an appId, we'll use that appId below.
202- let ( app_id, valid_handles) =
203- find_valid_key_handles ( & app_ids, & key_handles, |app_id, key_handle| {
204- apdu_is_keyhandle_valid ( dev, & challenge, app_id, & key_handle. credential )
205- . unwrap_or ( false ) /* no match on failure */
206- } ) ;
207-
208- // Aggregate distinct transports from all given credentials.
209- let transports = key_handles
210- . iter ( )
211- . fold ( crate :: AuthenticatorTransports :: empty ( ) , |t, k| {
212- t | k. transports
213- } ) ;
214-
215- // We currently only support USB. If the RP specifies transports
216- // and doesn't include USB it's probably lying.
217- if !is_valid_transport ( transports) {
218- return ;
219- }
220-
221- send_status (
222- & status_mutex,
223- crate :: StatusUpdate :: DeviceAvailable {
224- dev_info : dev. get_device_info ( ) ,
225- } ,
226- ) ;
227-
228- ' outer: while alive ( ) {
229- // If the device matches none of the given key handles
230- // then just make it blink with bogus data.
231- if valid_handles. is_empty ( ) {
232- let blank = vec ! [ 0u8 ; PARAMETER_SIZE ] ;
233- if apdu_register ( dev, & blank, & blank) . is_ok ( ) {
234- callback. call ( Err ( errors:: AuthenticatorError :: U2FToken (
235- errors:: U2FTokenError :: InvalidState ,
236- ) ) ) ;
237- break ;
238- }
239- } else {
240- // Otherwise, try to sign.
241- for key_handle in & valid_handles {
242- if let Ok ( bytes) = apdu_sign ( dev, & challenge, app_id, & key_handle. credential )
243- {
244- let dev_info = dev. get_device_info ( ) ;
245- send_status (
246- & status_mutex,
247- crate :: StatusUpdate :: Success {
248- dev_info : dev. get_device_info ( ) ,
249- } ,
250- ) ;
251- callback. call ( Ok ( (
252- app_id. clone ( ) ,
253- key_handle. credential . clone ( ) ,
254- bytes,
255- dev_info,
256- ) ) ) ;
257- break ' outer;
258- }
259- }
260- }
261-
262- // Sleep a bit before trying again.
263- thread:: sleep ( Duration :: from_millis ( 100 ) ) ;
264- }
265-
266- send_status (
267- & status_mutex,
268- crate :: StatusUpdate :: DeviceUnavailable {
269- dev_info : dev. get_device_info ( ) ,
270- } ,
271- ) ;
309+ StateMachine :: sign ( dev, flags, & challenge, & app_ids, & key_handles, & status_mutex, & callback, alive) ;
272310 } ) ;
273311
274312 self . transaction = Some ( try_or ! ( transaction, |e| cbc. call( Err ( e) ) ) ) ;
0 commit comments