1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 use std::sync::{mpsc::Sender, Arc, Mutex};
6
7 use crate::consts::PARAMETER_SIZE;
8 use crate::errors::*;
9 use crate::statecallback::StateCallback;
10
11 pub trait AuthenticatorTransport {
12 /// The implementation of this method must return quickly and should
13 /// report its status via the status and callback methods
register( &mut self, flags: crate::RegisterFlags, timeout: u64, challenge: Vec<u8>, application: crate::AppId, key_handles: Vec<crate::KeyHandle>, status: Sender<crate::StatusUpdate>, callback: StateCallback<crate::Result<crate::RegisterResult>>, ) -> crate::Result<()>14 fn register(
15 &mut self,
16 flags: crate::RegisterFlags,
17 timeout: u64,
18 challenge: Vec<u8>,
19 application: crate::AppId,
20 key_handles: Vec<crate::KeyHandle>,
21 status: Sender<crate::StatusUpdate>,
22 callback: StateCallback<crate::Result<crate::RegisterResult>>,
23 ) -> crate::Result<()>;
24
25 /// The implementation of this method must return quickly and should
26 /// report its status via the status and callback methods
sign( &mut self, flags: crate::SignFlags, timeout: u64, challenge: Vec<u8>, app_ids: Vec<crate::AppId>, key_handles: Vec<crate::KeyHandle>, status: Sender<crate::StatusUpdate>, callback: StateCallback<crate::Result<crate::SignResult>>, ) -> crate::Result<()>27 fn sign(
28 &mut self,
29 flags: crate::SignFlags,
30 timeout: u64,
31 challenge: Vec<u8>,
32 app_ids: Vec<crate::AppId>,
33 key_handles: Vec<crate::KeyHandle>,
34 status: Sender<crate::StatusUpdate>,
35 callback: StateCallback<crate::Result<crate::SignResult>>,
36 ) -> crate::Result<()>;
37
cancel(&mut self) -> crate::Result<()>38 fn cancel(&mut self) -> crate::Result<()>;
39 }
40
41 pub struct AuthenticatorService {
42 transports: Vec<Arc<Mutex<Box<dyn AuthenticatorTransport + Send>>>>,
43 }
44
clone_and_configure_cancellation_callback<T>( mut callback: StateCallback<T>, transports_to_cancel: Vec<Arc<Mutex<Box<dyn AuthenticatorTransport + Send>>>>, ) -> StateCallback<T>45 fn clone_and_configure_cancellation_callback<T>(
46 mut callback: StateCallback<T>,
47 transports_to_cancel: Vec<Arc<Mutex<Box<dyn AuthenticatorTransport + Send>>>>,
48 ) -> StateCallback<T> {
49 callback.add_uncloneable_observer(Box::new(move || {
50 debug!(
51 "Callback observer is running, cancelling \
52 {} unchosen transports...",
53 transports_to_cancel.len()
54 );
55 for transport_mutex in &transports_to_cancel {
56 if let Err(e) = transport_mutex.lock().unwrap().cancel() {
57 error!("Cancellation failed: {:?}", e);
58 }
59 }
60 }));
61 callback
62 }
63
64 impl AuthenticatorService {
new() -> crate::Result<Self>65 pub fn new() -> crate::Result<Self> {
66 Ok(Self {
67 transports: Vec::new(),
68 })
69 }
70
71 /// Add any detected platform transports
add_detected_transports(&mut self)72 pub fn add_detected_transports(&mut self) {
73 self.add_u2f_usb_hid_platform_transports();
74 }
75
add_transport(&mut self, boxed_token: Box<dyn AuthenticatorTransport + Send>)76 fn add_transport(&mut self, boxed_token: Box<dyn AuthenticatorTransport + Send>) {
77 self.transports.push(Arc::new(Mutex::new(boxed_token)))
78 }
79
add_u2f_usb_hid_platform_transports(&mut self)80 pub fn add_u2f_usb_hid_platform_transports(&mut self) {
81 match crate::U2FManager::new() {
82 Ok(token) => self.add_transport(Box::new(token)),
83 Err(e) => error!("Could not add U2F HID transport: {}", e),
84 }
85 }
86
87 #[cfg(feature = "webdriver")]
add_webdriver_virtual_bus(&mut self)88 pub fn add_webdriver_virtual_bus(&mut self) {
89 match crate::virtualdevices::webdriver::VirtualManager::new() {
90 Ok(token) => {
91 println!("WebDriver ready, listening at {}", &token.url());
92 self.add_transport(Box::new(token));
93 }
94 Err(e) => error!("Could not add WebDriver virtual bus: {}", e),
95 }
96 }
97
register( &mut self, flags: crate::RegisterFlags, timeout: u64, challenge: Vec<u8>, application: crate::AppId, key_handles: Vec<crate::KeyHandle>, status: Sender<crate::StatusUpdate>, callback: StateCallback<crate::Result<crate::RegisterResult>>, ) -> crate::Result<()>98 pub fn register(
99 &mut self,
100 flags: crate::RegisterFlags,
101 timeout: u64,
102 challenge: Vec<u8>,
103 application: crate::AppId,
104 key_handles: Vec<crate::KeyHandle>,
105 status: Sender<crate::StatusUpdate>,
106 callback: StateCallback<crate::Result<crate::RegisterResult>>,
107 ) -> crate::Result<()> {
108 if challenge.len() != PARAMETER_SIZE || application.len() != PARAMETER_SIZE {
109 return Err(AuthenticatorError::InvalidRelyingPartyInput);
110 }
111
112 for key_handle in &key_handles {
113 if key_handle.credential.len() > 256 {
114 return Err(AuthenticatorError::InvalidRelyingPartyInput);
115 }
116 }
117
118 let iterable_transports = self.transports.clone();
119 if iterable_transports.is_empty() {
120 return Err(AuthenticatorError::NoConfiguredTransports);
121 }
122
123 debug!(
124 "register called with {} transports, iterable is {}",
125 self.transports.len(),
126 iterable_transports.len()
127 );
128
129 for (idx, transport_mutex) in iterable_transports.iter().enumerate() {
130 let mut transports_to_cancel = iterable_transports.clone();
131 transports_to_cancel.remove(idx);
132
133 debug!(
134 "register transports_to_cancel {}",
135 transports_to_cancel.len()
136 );
137
138 transport_mutex.lock().unwrap().register(
139 flags,
140 timeout,
141 challenge.clone(),
142 application.clone(),
143 key_handles.clone(),
144 status.clone(),
145 clone_and_configure_cancellation_callback(callback.clone(), transports_to_cancel),
146 )?;
147 }
148
149 Ok(())
150 }
151
sign( &mut self, flags: crate::SignFlags, timeout: u64, challenge: Vec<u8>, app_ids: Vec<crate::AppId>, key_handles: Vec<crate::KeyHandle>, status: Sender<crate::StatusUpdate>, callback: StateCallback<crate::Result<crate::SignResult>>, ) -> crate::Result<()>152 pub fn sign(
153 &mut self,
154 flags: crate::SignFlags,
155 timeout: u64,
156 challenge: Vec<u8>,
157 app_ids: Vec<crate::AppId>,
158 key_handles: Vec<crate::KeyHandle>,
159 status: Sender<crate::StatusUpdate>,
160 callback: StateCallback<crate::Result<crate::SignResult>>,
161 ) -> crate::Result<()> {
162 if challenge.len() != PARAMETER_SIZE {
163 return Err(AuthenticatorError::InvalidRelyingPartyInput);
164 }
165
166 if app_ids.is_empty() {
167 return Err(AuthenticatorError::InvalidRelyingPartyInput);
168 }
169
170 for app_id in &app_ids {
171 if app_id.len() != PARAMETER_SIZE {
172 return Err(AuthenticatorError::InvalidRelyingPartyInput);
173 }
174 }
175
176 for key_handle in &key_handles {
177 if key_handle.credential.len() > 256 {
178 return Err(AuthenticatorError::InvalidRelyingPartyInput);
179 }
180 }
181
182 let iterable_transports = self.transports.clone();
183 if iterable_transports.is_empty() {
184 return Err(AuthenticatorError::NoConfiguredTransports);
185 }
186
187 for (idx, transport_mutex) in iterable_transports.iter().enumerate() {
188 let mut transports_to_cancel = iterable_transports.clone();
189 transports_to_cancel.remove(idx);
190
191 transport_mutex.lock().unwrap().sign(
192 flags,
193 timeout,
194 challenge.clone(),
195 app_ids.clone(),
196 key_handles.clone(),
197 status.clone(),
198 clone_and_configure_cancellation_callback(callback.clone(), transports_to_cancel),
199 )?;
200 }
201
202 Ok(())
203 }
204
cancel(&mut self) -> crate::Result<()>205 pub fn cancel(&mut self) -> crate::Result<()> {
206 if self.transports.is_empty() {
207 return Err(AuthenticatorError::NoConfiguredTransports);
208 }
209
210 for transport_mutex in &mut self.transports {
211 transport_mutex.lock().unwrap().cancel()?;
212 }
213
214 Ok(())
215 }
216 }
217
218 ////////////////////////////////////////////////////////////////////////
219 // Tests
220 ////////////////////////////////////////////////////////////////////////
221
222 #[cfg(test)]
223 mod tests {
224 use super::{AuthenticatorService, AuthenticatorTransport};
225 use crate::consts::PARAMETER_SIZE;
226 use crate::statecallback::StateCallback;
227 use crate::{AuthenticatorTransports, KeyHandle, RegisterFlags, SignFlags, StatusUpdate};
228 use std::sync::atomic::{AtomicBool, Ordering};
229 use std::sync::mpsc::{channel, Sender};
230 use std::sync::Arc;
231 use std::{io, thread};
232
init()233 fn init() {
234 let _ = env_logger::builder().is_test(true).try_init();
235 }
236
237 pub struct TestTransportDriver {
238 consent: bool,
239 was_cancelled: Arc<AtomicBool>,
240 }
241
242 impl TestTransportDriver {
new(consent: bool) -> io::Result<Self>243 pub fn new(consent: bool) -> io::Result<Self> {
244 Ok(Self {
245 consent,
246 was_cancelled: Arc::new(AtomicBool::new(false)),
247 })
248 }
249 }
250
251 impl TestTransportDriver {
dev_info(&self) -> crate::u2ftypes::U2FDeviceInfo252 fn dev_info(&self) -> crate::u2ftypes::U2FDeviceInfo {
253 crate::u2ftypes::U2FDeviceInfo {
254 vendor_name: String::from("Mozilla").into_bytes(),
255 device_name: String::from("Test Transport Token").into_bytes(),
256 version_interface: 0,
257 version_major: 1,
258 version_minor: 2,
259 version_build: 3,
260 cap_flags: 0,
261 }
262 }
263 }
264
265 impl AuthenticatorTransport for TestTransportDriver {
register( &mut self, _flags: crate::RegisterFlags, _timeout: u64, _challenge: Vec<u8>, _application: crate::AppId, _key_handles: Vec<crate::KeyHandle>, _status: Sender<crate::StatusUpdate>, callback: StateCallback<crate::Result<crate::RegisterResult>>, ) -> crate::Result<()>266 fn register(
267 &mut self,
268 _flags: crate::RegisterFlags,
269 _timeout: u64,
270 _challenge: Vec<u8>,
271 _application: crate::AppId,
272 _key_handles: Vec<crate::KeyHandle>,
273 _status: Sender<crate::StatusUpdate>,
274 callback: StateCallback<crate::Result<crate::RegisterResult>>,
275 ) -> crate::Result<()> {
276 if self.consent {
277 let rv = Ok((vec![0u8; 16], self.dev_info()));
278 thread::spawn(move || callback.call(rv));
279 }
280 Ok(())
281 }
282
sign( &mut self, _flags: crate::SignFlags, _timeout: u64, _challenge: Vec<u8>, _app_ids: Vec<crate::AppId>, _key_handles: Vec<crate::KeyHandle>, _status: Sender<crate::StatusUpdate>, callback: StateCallback<crate::Result<crate::SignResult>>, ) -> crate::Result<()>283 fn sign(
284 &mut self,
285 _flags: crate::SignFlags,
286 _timeout: u64,
287 _challenge: Vec<u8>,
288 _app_ids: Vec<crate::AppId>,
289 _key_handles: Vec<crate::KeyHandle>,
290 _status: Sender<crate::StatusUpdate>,
291 callback: StateCallback<crate::Result<crate::SignResult>>,
292 ) -> crate::Result<()> {
293 if self.consent {
294 let rv = Ok((vec![0u8; 0], vec![0u8; 0], vec![0u8; 0], self.dev_info()));
295 thread::spawn(move || callback.call(rv));
296 }
297 Ok(())
298 }
299
cancel(&mut self) -> crate::Result<()>300 fn cancel(&mut self) -> crate::Result<()> {
301 self.was_cancelled
302 .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
303 .map_or(
304 Err(crate::errors::AuthenticatorError::U2FToken(
305 crate::errors::U2FTokenError::InvalidState,
306 )),
307 |_| Ok(()),
308 )
309 }
310 }
311
mk_key() -> KeyHandle312 fn mk_key() -> KeyHandle {
313 KeyHandle {
314 credential: vec![0],
315 transports: AuthenticatorTransports::USB,
316 }
317 }
318
mk_challenge() -> Vec<u8>319 fn mk_challenge() -> Vec<u8> {
320 vec![0x11; PARAMETER_SIZE]
321 }
322
mk_appid() -> Vec<u8>323 fn mk_appid() -> Vec<u8> {
324 vec![0x22; PARAMETER_SIZE]
325 }
326
327 #[test]
test_no_challenge()328 fn test_no_challenge() {
329 init();
330 let (status_tx, _) = channel::<StatusUpdate>();
331
332 let mut s = AuthenticatorService::new().unwrap();
333 s.add_transport(Box::new(TestTransportDriver::new(true).unwrap()));
334
335 assert_matches!(
336 s.register(
337 RegisterFlags::empty(),
338 1_000,
339 vec![],
340 mk_appid(),
341 vec![mk_key()],
342 status_tx.clone(),
343 StateCallback::new(Box::new(move |_rv| {})),
344 )
345 .unwrap_err(),
346 crate::errors::AuthenticatorError::InvalidRelyingPartyInput
347 );
348
349 assert_matches!(
350 s.sign(
351 SignFlags::empty(),
352 1_000,
353 vec![],
354 vec![mk_appid()],
355 vec![mk_key()],
356 status_tx,
357 StateCallback::new(Box::new(move |_rv| {})),
358 )
359 .unwrap_err(),
360 crate::errors::AuthenticatorError::InvalidRelyingPartyInput
361 );
362 }
363
364 #[test]
test_no_appids()365 fn test_no_appids() {
366 init();
367 let (status_tx, _) = channel::<StatusUpdate>();
368
369 let mut s = AuthenticatorService::new().unwrap();
370 s.add_transport(Box::new(TestTransportDriver::new(true).unwrap()));
371
372 assert_matches!(
373 s.register(
374 RegisterFlags::empty(),
375 1_000,
376 mk_challenge(),
377 vec![],
378 vec![mk_key()],
379 status_tx.clone(),
380 StateCallback::new(Box::new(move |_rv| {})),
381 )
382 .unwrap_err(),
383 crate::errors::AuthenticatorError::InvalidRelyingPartyInput
384 );
385
386 assert_matches!(
387 s.sign(
388 SignFlags::empty(),
389 1_000,
390 mk_challenge(),
391 vec![],
392 vec![mk_key()],
393 status_tx,
394 StateCallback::new(Box::new(move |_rv| {})),
395 )
396 .unwrap_err(),
397 crate::errors::AuthenticatorError::InvalidRelyingPartyInput
398 );
399 }
400
401 #[test]
test_no_keys()402 fn test_no_keys() {
403 init();
404 // No Keys is a resident-key use case. For U2F this would time out,
405 // but the actual reactions are up to the service implementation.
406 // This test yields OKs.
407 let (status_tx, _) = channel::<StatusUpdate>();
408
409 let mut s = AuthenticatorService::new().unwrap();
410 s.add_transport(Box::new(TestTransportDriver::new(true).unwrap()));
411
412 assert_matches!(
413 s.register(
414 RegisterFlags::empty(),
415 100,
416 mk_challenge(),
417 mk_appid(),
418 vec![],
419 status_tx.clone(),
420 StateCallback::new(Box::new(move |_rv| {})),
421 ),
422 Ok(())
423 );
424
425 assert_matches!(
426 s.sign(
427 SignFlags::empty(),
428 100,
429 mk_challenge(),
430 vec![mk_appid()],
431 vec![],
432 status_tx,
433 StateCallback::new(Box::new(move |_rv| {})),
434 ),
435 Ok(())
436 );
437 }
438
439 #[test]
test_large_keys()440 fn test_large_keys() {
441 init();
442 let (status_tx, _) = channel::<StatusUpdate>();
443
444 let large_key = KeyHandle {
445 credential: vec![0; 257],
446 transports: AuthenticatorTransports::USB,
447 };
448
449 let mut s = AuthenticatorService::new().unwrap();
450 s.add_transport(Box::new(TestTransportDriver::new(true).unwrap()));
451
452 assert_matches!(
453 s.register(
454 RegisterFlags::empty(),
455 1_000,
456 mk_challenge(),
457 mk_appid(),
458 vec![large_key.clone()],
459 status_tx.clone(),
460 StateCallback::new(Box::new(move |_rv| {})),
461 )
462 .unwrap_err(),
463 crate::errors::AuthenticatorError::InvalidRelyingPartyInput
464 );
465
466 assert_matches!(
467 s.sign(
468 SignFlags::empty(),
469 1_000,
470 mk_challenge(),
471 vec![mk_appid()],
472 vec![large_key],
473 status_tx,
474 StateCallback::new(Box::new(move |_rv| {})),
475 )
476 .unwrap_err(),
477 crate::errors::AuthenticatorError::InvalidRelyingPartyInput
478 );
479 }
480
481 #[test]
test_no_transports()482 fn test_no_transports() {
483 init();
484 let (status_tx, _) = channel::<StatusUpdate>();
485
486 let mut s = AuthenticatorService::new().unwrap();
487 assert_matches!(
488 s.register(
489 RegisterFlags::empty(),
490 1_000,
491 mk_challenge(),
492 mk_appid(),
493 vec![mk_key()],
494 status_tx.clone(),
495 StateCallback::new(Box::new(move |_rv| {})),
496 )
497 .unwrap_err(),
498 crate::errors::AuthenticatorError::NoConfiguredTransports
499 );
500
501 assert_matches!(
502 s.sign(
503 SignFlags::empty(),
504 1_000,
505 mk_challenge(),
506 vec![mk_appid()],
507 vec![mk_key()],
508 status_tx,
509 StateCallback::new(Box::new(move |_rv| {})),
510 )
511 .unwrap_err(),
512 crate::errors::AuthenticatorError::NoConfiguredTransports
513 );
514
515 assert_matches!(
516 s.cancel().unwrap_err(),
517 crate::errors::AuthenticatorError::NoConfiguredTransports
518 );
519 }
520
521 #[test]
test_cancellation_register()522 fn test_cancellation_register() {
523 init();
524 let (status_tx, _) = channel::<StatusUpdate>();
525
526 let mut s = AuthenticatorService::new().unwrap();
527 let ttd_one = TestTransportDriver::new(true).unwrap();
528 let ttd_two = TestTransportDriver::new(false).unwrap();
529 let ttd_three = TestTransportDriver::new(false).unwrap();
530
531 let was_cancelled_one = ttd_one.was_cancelled.clone();
532 let was_cancelled_two = ttd_two.was_cancelled.clone();
533 let was_cancelled_three = ttd_three.was_cancelled.clone();
534
535 s.add_transport(Box::new(ttd_one));
536 s.add_transport(Box::new(ttd_two));
537 s.add_transport(Box::new(ttd_three));
538
539 let callback = StateCallback::new(Box::new(move |_rv| {}));
540 assert!(s
541 .register(
542 RegisterFlags::empty(),
543 1_000,
544 mk_challenge(),
545 mk_appid(),
546 vec![],
547 status_tx,
548 callback.clone(),
549 )
550 .is_ok());
551 callback.wait();
552
553 assert_eq!(was_cancelled_one.load(Ordering::SeqCst), false);
554 assert_eq!(was_cancelled_two.load(Ordering::SeqCst), true);
555 assert_eq!(was_cancelled_three.load(Ordering::SeqCst), true);
556 }
557
558 #[test]
test_cancellation_sign()559 fn test_cancellation_sign() {
560 init();
561 let (status_tx, _) = channel::<StatusUpdate>();
562
563 let mut s = AuthenticatorService::new().unwrap();
564 let ttd_one = TestTransportDriver::new(true).unwrap();
565 let ttd_two = TestTransportDriver::new(false).unwrap();
566 let ttd_three = TestTransportDriver::new(false).unwrap();
567
568 let was_cancelled_one = ttd_one.was_cancelled.clone();
569 let was_cancelled_two = ttd_two.was_cancelled.clone();
570 let was_cancelled_three = ttd_three.was_cancelled.clone();
571
572 s.add_transport(Box::new(ttd_one));
573 s.add_transport(Box::new(ttd_two));
574 s.add_transport(Box::new(ttd_three));
575
576 let callback = StateCallback::new(Box::new(move |_rv| {}));
577 assert!(s
578 .sign(
579 SignFlags::empty(),
580 1_000,
581 mk_challenge(),
582 vec![mk_appid()],
583 vec![mk_key()],
584 status_tx,
585 callback.clone(),
586 )
587 .is_ok());
588 callback.wait();
589
590 assert_eq!(was_cancelled_one.load(Ordering::SeqCst), false);
591 assert_eq!(was_cancelled_two.load(Ordering::SeqCst), true);
592 assert_eq!(was_cancelled_three.load(Ordering::SeqCst), true);
593 }
594
595 #[test]
test_cancellation_race()596 fn test_cancellation_race() {
597 init();
598 let (status_tx, _) = channel::<StatusUpdate>();
599
600 let mut s = AuthenticatorService::new().unwrap();
601 // Let both of these race which one provides consent.
602 let ttd_one = TestTransportDriver::new(true).unwrap();
603 let ttd_two = TestTransportDriver::new(true).unwrap();
604
605 let was_cancelled_one = ttd_one.was_cancelled.clone();
606 let was_cancelled_two = ttd_two.was_cancelled.clone();
607
608 s.add_transport(Box::new(ttd_one));
609 s.add_transport(Box::new(ttd_two));
610
611 let callback = StateCallback::new(Box::new(move |_rv| {}));
612 assert!(s
613 .register(
614 RegisterFlags::empty(),
615 1_000,
616 mk_challenge(),
617 mk_appid(),
618 vec![],
619 status_tx,
620 callback.clone(),
621 )
622 .is_ok());
623 callback.wait();
624
625 let one = was_cancelled_one.load(Ordering::SeqCst);
626 let two = was_cancelled_two.load(Ordering::SeqCst);
627 assert_eq!(
628 one ^ two,
629 true,
630 "asserting that one={} xor two={} is true",
631 one,
632 two
633 );
634 }
635 }
636