1use crate::consts::PARAMETER_SIZE;
6use crate::ctap2::commands::client_pin::Pin;
7pub use crate::ctap2::commands::get_assertion::{
8 GetAssertionExtensions, GetAssertionOptions, HmacSecretExtension,
9};
10pub use crate::ctap2::commands::make_credentials::{
11 MakeCredentialsExtensions, MakeCredentialsOptions,
12};
13use crate::ctap2::server::{
14 PublicKeyCredentialDescriptor, PublicKeyCredentialParameters, RelyingParty, User,
15};
16use crate::errors::*;
17use crate::manager::Manager;
18use crate::statecallback::StateCallback;
19use std::sync::{mpsc::Sender, Arc, Mutex};
20
21#[derive(Debug, Clone, PartialEq, Eq)]
23pub enum CtapVersion {
24 CTAP1,
25 CTAP2,
26}
27
28#[derive(Debug, Clone)]
29pub struct RegisterArgsCtap1 {
30 pub flags: crate::RegisterFlags,
31 pub challenge: Vec<u8>,
32 pub application: crate::AppId,
33 pub key_handles: Vec<crate::KeyHandle>,
34}
35
36#[derive(Debug, Clone)]
37pub struct RegisterArgsCtap2 {
38 pub challenge: Vec<u8>,
39 pub relying_party: RelyingParty,
40 pub origin: String,
41 pub user: User,
42 pub pub_cred_params: Vec<PublicKeyCredentialParameters>,
43 pub exclude_list: Vec<PublicKeyCredentialDescriptor>,
44 pub options: MakeCredentialsOptions,
45 pub extensions: MakeCredentialsExtensions,
46 pub pin: Option<Pin>,
47}
48
49#[derive(Debug)]
50pub enum RegisterArgs {
51 CTAP1(RegisterArgsCtap1),
52 CTAP2(RegisterArgsCtap2),
53}
54
55impl From<RegisterArgsCtap1> for RegisterArgs {
56 fn from(args: RegisterArgsCtap1) -> Self {
57 RegisterArgs::CTAP1(args)
58 }
59}
60
61impl From<RegisterArgsCtap2> for RegisterArgs {
62 fn from(args: RegisterArgsCtap2) -> Self {
63 RegisterArgs::CTAP2(args)
64 }
65}
66
67#[derive(Debug, Clone)]
68pub struct SignArgsCtap1 {
69 pub flags: crate::SignFlags,
70 pub challenge: Vec<u8>,
71 pub app_ids: Vec<crate::AppId>,
72 pub key_handles: Vec<crate::KeyHandle>,
73}
74
75#[derive(Debug, Clone)]
76pub struct SignArgsCtap2 {
77 pub challenge: Vec<u8>,
78 pub origin: String,
79 pub relying_party_id: String,
80 pub allow_list: Vec<PublicKeyCredentialDescriptor>,
81 pub options: GetAssertionOptions,
82 pub extensions: GetAssertionExtensions,
83 pub pin: Option<Pin>,
84 }
86
87#[derive(Debug)]
88pub enum SignArgs {
89 CTAP1(SignArgsCtap1),
90 CTAP2(SignArgsCtap2),
91}
92
93impl From<SignArgsCtap1> for SignArgs {
94 fn from(args: SignArgsCtap1) -> Self {
95 SignArgs::CTAP1(args)
96 }
97}
98
99impl From<SignArgsCtap2> for SignArgs {
100 fn from(args: SignArgsCtap2) -> Self {
101 SignArgs::CTAP2(args)
102 }
103}
104
105#[derive(Debug, Clone, Default)]
106pub struct AssertionExtensions {
107 pub hmac_secret: Option<HmacSecretExtension>,
108}
109
110pub trait AuthenticatorTransport {
111 fn register(
114 &mut self,
115 timeout: u64,
116 ctap_args: RegisterArgs,
117 status: Sender<crate::StatusUpdate>,
118 callback: StateCallback<crate::Result<crate::RegisterResult>>,
119 ) -> crate::Result<()>;
120
121 fn sign(
124 &mut self,
125 timeout: u64,
126 ctap_args: SignArgs,
127 status: Sender<crate::StatusUpdate>,
128 callback: StateCallback<crate::Result<crate::SignResult>>,
129 ) -> crate::Result<()>;
130
131 fn cancel(&mut self) -> crate::Result<()>;
132
133 fn reset(
134 &mut self,
135 timeout: u64,
136 status: Sender<crate::StatusUpdate>,
137 callback: StateCallback<crate::Result<crate::ResetResult>>,
138 ) -> crate::Result<()>;
139
140 fn set_pin(
141 &mut self,
142 timeout: u64,
143 new_pin: Pin,
144 status: Sender<crate::StatusUpdate>,
145 callback: StateCallback<crate::Result<crate::ResetResult>>,
146 ) -> crate::Result<()>;
147
148 fn info(
149 &mut self,
150 timeout: u64,
151 status: Sender<crate::StatusUpdate>,
152 callback: StateCallback<crate::Result<crate::InfoResult>>,
153 ) -> crate::Result<()>;
154}
155
156pub struct AuthenticatorService {
157 transports: Vec<Arc<Mutex<Box<dyn AuthenticatorTransport + Send>>>>,
158 ctap_version: CtapVersion,
159}
160
161fn clone_and_configure_cancellation_callback<T>(
162 mut callback: StateCallback<T>,
163 transports_to_cancel: Vec<Arc<Mutex<Box<dyn AuthenticatorTransport + Send>>>>,
164) -> StateCallback<T> {
165 callback.add_uncloneable_observer(Box::new(move || {
166 debug!(
167 "Callback observer is running, cancelling \
168 {} unchosen transports...",
169 transports_to_cancel.len()
170 );
171 for transport_mutex in &transports_to_cancel {
172 if let Err(e) = transport_mutex.lock().unwrap().cancel() {
173 error!("Cancellation failed: {:?}", e);
174 }
175 }
176 }));
177 callback
178}
179
180impl AuthenticatorService {
181 pub fn new(ctap_version: CtapVersion) -> crate::Result<Self> {
182 Ok(Self {
183 transports: Vec::new(),
184 ctap_version,
185 })
186 }
187
188 pub fn add_detected_transports(&mut self) {
190 self.add_u2f_usb_hid_platform_transports();
191 }
192
193 fn add_transport(&mut self, boxed_token: Box<dyn AuthenticatorTransport + Send>) {
194 self.transports.push(Arc::new(Mutex::new(boxed_token)))
195 }
196
197 pub fn add_u2f_usb_hid_platform_transports(&mut self) {
198 if self.ctap_version == CtapVersion::CTAP1 {
199 match crate::U2FManager::new() {
200 Ok(token) => self.add_transport(Box::new(token)),
201 Err(e) => error!("Could not add U2F HID transport: {}", e),
202 }
203 } else {
204 match Manager::new() {
205 Ok(token) => self.add_transport(Box::new(token)),
206 Err(e) => error!("Could not add CTAP2 HID transport: {}", e),
207 }
208 }
209 }
210
211 #[cfg(feature = "webdriver")]
212 pub fn add_webdriver_virtual_bus(&mut self) {
213 match crate::virtualdevices::webdriver::VirtualManager::new() {
214 Ok(token) => {
215 println!("WebDriver ready, listening at {}", &token.url());
216 self.add_transport(Box::new(token));
217 }
218 Err(e) => error!("Could not add WebDriver virtual bus: {}", e),
219 }
220 }
221
222 pub fn register(
223 &mut self,
224 timeout: u64,
225 ctap_args: RegisterArgs,
226 status: Sender<crate::StatusUpdate>,
227 callback: StateCallback<crate::Result<crate::RegisterResult>>,
228 ) -> crate::Result<()> {
229 match ctap_args {
230 RegisterArgs::CTAP1(a) => self.register_ctap1(timeout, a, status, callback),
231 RegisterArgs::CTAP2(a) => self.register_ctap2(timeout, a, status, callback),
232 }
233 }
234
235 fn register_ctap1(
236 &mut self,
237 timeout: u64,
238 args: RegisterArgsCtap1,
239 status: Sender<crate::StatusUpdate>,
240 callback: StateCallback<crate::Result<crate::RegisterResult>>,
241 ) -> crate::Result<()> {
242 if args.challenge.len() != PARAMETER_SIZE || args.application.len() != PARAMETER_SIZE {
243 return Err(AuthenticatorError::InvalidRelyingPartyInput);
244 }
245
246 for key_handle in &args.key_handles {
247 if key_handle.credential.len() > 256 {
248 return Err(AuthenticatorError::InvalidRelyingPartyInput);
249 }
250 }
251
252 let iterable_transports = self.transports.clone();
253 if iterable_transports.is_empty() {
254 return Err(AuthenticatorError::NoConfiguredTransports);
255 }
256
257 debug!(
258 "register called with {} transports, iterable is {}",
259 self.transports.len(),
260 iterable_transports.len()
261 );
262
263 for (idx, transport_mutex) in iterable_transports.iter().enumerate() {
264 let mut transports_to_cancel = iterable_transports.clone();
265 transports_to_cancel.remove(idx);
266
267 debug!(
268 "register transports_to_cancel {}",
269 transports_to_cancel.len()
270 );
271
272 transport_mutex.lock().unwrap().register(
273 timeout,
274 RegisterArgs::CTAP1(args.clone()),
275 status.clone(),
276 clone_and_configure_cancellation_callback(callback.clone(), transports_to_cancel),
277 )?;
278 }
279
280 Ok(())
281 }
282
283 fn register_ctap2(
284 &mut self,
285 timeout: u64,
286 args: RegisterArgsCtap2,
287 status: Sender<crate::StatusUpdate>,
288 callback: StateCallback<crate::Result<crate::RegisterResult>>,
289 ) -> crate::Result<()> {
290 if args.exclude_list.iter().any(|x| x.id.len() > 256) {
291 return Err(AuthenticatorError::InvalidRelyingPartyInput);
292 }
293
294 let iterable_transports = self.transports.clone();
295 if iterable_transports.is_empty() {
296 return Err(AuthenticatorError::NoConfiguredTransports);
297 }
298
299 debug!(
300 "register called with {} transports, iterable is {}",
301 self.transports.len(),
302 iterable_transports.len()
303 );
304
305 for (idx, transport_mutex) in iterable_transports.iter().enumerate() {
306 let mut transports_to_cancel = iterable_transports.clone();
307 transports_to_cancel.remove(idx);
308
309 debug!(
310 "register transports_to_cancel {}",
311 transports_to_cancel.len()
312 );
313
314 transport_mutex.lock().unwrap().register(
315 timeout,
316 RegisterArgs::CTAP2(args.clone()),
317 status.clone(),
318 clone_and_configure_cancellation_callback(callback.clone(), transports_to_cancel),
319 )?;
320 }
321
322 Ok(())
323 }
324
325 pub fn sign(
326 &mut self,
327 timeout: u64,
328 ctap_args: SignArgs,
329 status: Sender<crate::StatusUpdate>,
330 callback: StateCallback<crate::Result<crate::SignResult>>,
331 ) -> crate::Result<()> {
332 match ctap_args {
333 SignArgs::CTAP1(a) => self.sign_ctap1(timeout, a, status, callback),
334 SignArgs::CTAP2(a) => self.sign_ctap2(timeout, a, status, callback),
335 }
336 }
337
338 pub fn sign_ctap1(
339 &mut self,
340 timeout: u64,
341 args: SignArgsCtap1,
342 status: Sender<crate::StatusUpdate>,
343 callback: StateCallback<crate::Result<crate::SignResult>>,
344 ) -> crate::Result<()> {
345 if args.challenge.len() != PARAMETER_SIZE {
346 return Err(AuthenticatorError::InvalidRelyingPartyInput);
347 }
348
349 if args.app_ids.is_empty() {
350 return Err(AuthenticatorError::InvalidRelyingPartyInput);
351 }
352
353 for app_id in &args.app_ids {
354 if app_id.len() != PARAMETER_SIZE {
355 return Err(AuthenticatorError::InvalidRelyingPartyInput);
356 }
357 }
358
359 for key_handle in &args.key_handles {
360 if key_handle.credential.len() > 256 {
361 return Err(AuthenticatorError::InvalidRelyingPartyInput);
362 }
363 }
364
365 let iterable_transports = self.transports.clone();
366 if iterable_transports.is_empty() {
367 return Err(AuthenticatorError::NoConfiguredTransports);
368 }
369
370 for (idx, transport_mutex) in iterable_transports.iter().enumerate() {
371 let mut transports_to_cancel = iterable_transports.clone();
372 transports_to_cancel.remove(idx);
373
374 transport_mutex.lock().unwrap().sign(
375 timeout,
376 SignArgs::CTAP1(args.clone()),
377 status.clone(),
378 clone_and_configure_cancellation_callback(callback.clone(), transports_to_cancel),
379 )?;
380 }
381
382 Ok(())
383 }
384
385 pub fn sign_ctap2(
386 &mut self,
387 timeout: u64,
388 args: SignArgsCtap2,
389 status: Sender<crate::StatusUpdate>,
390 callback: StateCallback<crate::Result<crate::SignResult>>,
391 ) -> crate::Result<()> {
392 let iterable_transports = self.transports.clone();
393 if iterable_transports.is_empty() {
394 return Err(AuthenticatorError::NoConfiguredTransports);
395 }
396
397 for (idx, transport_mutex) in iterable_transports.iter().enumerate() {
398 let mut transports_to_cancel = iterable_transports.clone();
399 transports_to_cancel.remove(idx);
400
401 transport_mutex.lock().unwrap().sign(
402 timeout,
403 SignArgs::CTAP2(args.clone()),
404 status.clone(),
405 clone_and_configure_cancellation_callback(callback.clone(), transports_to_cancel),
406 )?;
407 }
408
409 Ok(())
410 }
411
412 pub fn cancel(&mut self) -> crate::Result<()> {
413 if self.transports.is_empty() {
414 return Err(AuthenticatorError::NoConfiguredTransports);
415 }
416
417 for transport_mutex in &mut self.transports {
418 transport_mutex.lock().unwrap().cancel()?;
419 }
420
421 Ok(())
422 }
423
424 pub fn reset(
425 &mut self,
426 timeout: u64,
427 status: Sender<crate::StatusUpdate>,
428 callback: StateCallback<crate::Result<crate::ResetResult>>,
429 ) -> crate::Result<()> {
430 let iterable_transports = self.transports.clone();
431 if iterable_transports.is_empty() {
432 return Err(AuthenticatorError::NoConfiguredTransports);
433 }
434
435 debug!(
436 "reset called with {} transports, iterable is {}",
437 self.transports.len(),
438 iterable_transports.len()
439 );
440
441 for (idx, transport_mutex) in iterable_transports.iter().enumerate() {
442 let mut transports_to_cancel = iterable_transports.clone();
443 transports_to_cancel.remove(idx);
444
445 debug!("reset transports_to_cancel {}", transports_to_cancel.len());
446
447 transport_mutex.lock().unwrap().reset(
448 timeout,
449 status.clone(),
450 clone_and_configure_cancellation_callback(callback.clone(), transports_to_cancel),
451 )?;
452 }
453
454 Ok(())
455 }
456
457 pub fn set_pin(
458 &mut self,
459 timeout: u64,
460 new_pin: Pin,
461 status: Sender<crate::StatusUpdate>,
462 callback: StateCallback<crate::Result<crate::ResetResult>>,
463 ) -> crate::Result<()> {
464 let iterable_transports = self.transports.clone();
465 if iterable_transports.is_empty() {
466 return Err(AuthenticatorError::NoConfiguredTransports);
467 }
468
469 debug!(
470 "reset called with {} transports, iterable is {}",
471 self.transports.len(),
472 iterable_transports.len()
473 );
474
475 for (idx, transport_mutex) in iterable_transports.iter().enumerate() {
476 let mut transports_to_cancel = iterable_transports.clone();
477 transports_to_cancel.remove(idx);
478
479 debug!("reset transports_to_cancel {}", transports_to_cancel.len());
480
481 transport_mutex.lock().unwrap().set_pin(
482 timeout,
483 new_pin.clone(),
484 status.clone(),
485 clone_and_configure_cancellation_callback(callback.clone(), transports_to_cancel),
486 )?;
487 }
488
489 Ok(())
490 }
491
492 pub fn info(
493 &mut self,
494 timeout: u64,
495 status: Sender<crate::StatusUpdate>,
496 callback: StateCallback<crate::Result<crate::InfoResult>>,
497 ) -> crate::Result<()> {
498 let iterable_transports = self.transports.clone();
499 if iterable_transports.is_empty() {
500 return Err(AuthenticatorError::NoConfiguredTransports);
501 }
502
503 debug!(
504 "info called with {} transports, iterable is {}",
505 self.transports.len(),
506 iterable_transports.len()
507 );
508
509 for (idx, transport_mutex) in iterable_transports.iter().enumerate() {
510 let mut transports_to_cancel = iterable_transports.clone();
511 transports_to_cancel.remove(idx);
512
513 debug!("info transports_to_cancel {}", transports_to_cancel.len());
514
515 transport_mutex.lock().unwrap().info(
516 timeout,
517 status.clone(),
518 clone_and_configure_cancellation_callback(callback.clone(), transports_to_cancel),
519 )?;
520 }
521
522 Ok(())
523 }
524}
525
526#[cfg(test)]
531mod tests {
532 use super::{
533 AuthenticatorService, AuthenticatorTransport, CtapVersion, Pin, RegisterArgs,
534 RegisterArgsCtap1, SignArgs, SignArgsCtap1,
535 };
536 use crate::consts::Capability;
537 use crate::consts::PARAMETER_SIZE;
538 use crate::statecallback::StateCallback;
539 use crate::{AuthenticatorTransports, KeyHandle, RegisterFlags, SignFlags, StatusUpdate};
540 use crate::{RegisterResult, SignResult};
541 use std::sync::atomic::{AtomicBool, Ordering};
542 use std::sync::mpsc::{channel, Sender};
543 use std::sync::Arc;
544 use std::{io, thread};
545
546 fn init() {
547 let _ = env_logger::builder().is_test(true).try_init();
548 }
549
550 pub struct TestTransportDriver {
551 consent: bool,
552 was_cancelled: Arc<AtomicBool>,
553 }
554
555 impl TestTransportDriver {
556 pub fn new(consent: bool) -> io::Result<Self> {
557 Ok(Self {
558 consent,
559 was_cancelled: Arc::new(AtomicBool::new(false)),
560 })
561 }
562 }
563
564 impl TestTransportDriver {
565 fn dev_info(&self) -> crate::u2ftypes::U2FDeviceInfo {
566 crate::u2ftypes::U2FDeviceInfo {
567 vendor_name: String::from("Mozilla").into_bytes(),
568 device_name: String::from("Test Transport Token").into_bytes(),
569 version_interface: 0,
570 version_major: 1,
571 version_minor: 2,
572 version_build: 3,
573 cap_flags: Capability::empty(),
574 }
575 }
576 }
577
578 impl AuthenticatorTransport for TestTransportDriver {
579 fn register(
580 &mut self,
581 _timeout: u64,
582 _args: RegisterArgs,
583 _status: Sender<crate::StatusUpdate>,
584 callback: StateCallback<crate::Result<crate::RegisterResult>>,
585 ) -> crate::Result<()> {
586 if self.consent {
587 let rv = Ok(RegisterResult::CTAP1(vec![0u8; 16], self.dev_info()));
588 thread::spawn(move || callback.call(rv));
589 }
590 Ok(())
591 }
592
593 fn sign(
594 &mut self,
595 _timeout: u64,
596 _ctap_args: SignArgs,
597 _status: Sender<crate::StatusUpdate>,
598 callback: StateCallback<crate::Result<crate::SignResult>>,
599 ) -> crate::Result<()> {
600 if self.consent {
601 let rv = Ok(SignResult::CTAP1(
602 vec![0u8; 0],
603 vec![0u8; 0],
604 vec![0u8; 0],
605 self.dev_info(),
606 ));
607 thread::spawn(move || callback.call(rv));
608 }
609 Ok(())
610 }
611
612 fn cancel(&mut self) -> crate::Result<()> {
613 self.was_cancelled
614 .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
615 .map_or(
616 Err(crate::errors::AuthenticatorError::U2FToken(
617 crate::errors::U2FTokenError::InvalidState,
618 )),
619 |_| Ok(()),
620 )
621 }
622
623 fn reset(
624 &mut self,
625 _timeout: u64,
626 _status: Sender<crate::StatusUpdate>,
627 _callback: StateCallback<crate::Result<crate::ResetResult>>,
628 ) -> crate::Result<()> {
629 unimplemented!();
630 }
631
632 fn set_pin(
633 &mut self,
634 _timeout: u64,
635 _new_pin: Pin,
636 _status: Sender<crate::StatusUpdate>,
637 _callback: StateCallback<crate::Result<crate::ResetResult>>,
638 ) -> crate::Result<()> {
639 unimplemented!();
640 }
641
642 fn info(
643 &mut self,
644 _timeout: u64,
645 _status: Sender<crate::StatusUpdate>,
646 _callback: StateCallback<crate::Result<crate::InfoResult>>,
647 ) -> crate::Result<()> {
648 unimplemented!();
649 }
650 }
651
652 fn mk_key() -> KeyHandle {
653 KeyHandle {
654 credential: vec![0],
655 transports: AuthenticatorTransports::USB,
656 }
657 }
658
659 fn mk_challenge() -> Vec<u8> {
660 vec![0x11; PARAMETER_SIZE]
661 }
662
663 fn mk_appid() -> Vec<u8> {
664 vec![0x22; PARAMETER_SIZE]
665 }
666
667 #[test]
668 fn test_no_challenge() {
669 init();
670 let (status_tx, _) = channel::<StatusUpdate>();
671
672 let mut s = AuthenticatorService::new(CtapVersion::CTAP1).unwrap();
673 s.add_transport(Box::new(TestTransportDriver::new(true).unwrap()));
674
675 assert_matches!(
676 s.register(
677 1_000,
678 RegisterArgsCtap1 {
679 challenge: vec![],
680 flags: RegisterFlags::empty(),
681 application: mk_appid(),
682 key_handles: vec![mk_key()],
683 }
684 .into(),
685 status_tx.clone(),
686 StateCallback::new(Box::new(move |_rv| {})),
687 )
688 .unwrap_err(),
689 crate::errors::AuthenticatorError::InvalidRelyingPartyInput
690 );
691
692 assert_matches!(
693 s.sign(
694 1_000,
695 SignArgsCtap1 {
696 flags: SignFlags::empty(),
697 challenge: vec![],
698 app_ids: vec![mk_appid()],
699 key_handles: vec![mk_key()]
700 }
701 .into(),
702 status_tx,
703 StateCallback::new(Box::new(move |_rv| {})),
704 )
705 .unwrap_err(),
706 crate::errors::AuthenticatorError::InvalidRelyingPartyInput
707 );
708 }
709
710 #[test]
711 fn test_no_appids() {
712 init();
713 let (status_tx, _) = channel::<StatusUpdate>();
714
715 let mut s = AuthenticatorService::new(CtapVersion::CTAP1).unwrap();
716 s.add_transport(Box::new(TestTransportDriver::new(true).unwrap()));
717
718 assert_matches!(
719 s.register(
720 1_000,
721 RegisterArgsCtap1 {
722 challenge: mk_challenge(),
723 flags: RegisterFlags::empty(),
724 application: vec![],
725 key_handles: vec![mk_key()],
726 }
727 .into(),
728 status_tx.clone(),
729 StateCallback::new(Box::new(move |_rv| {})),
730 )
731 .unwrap_err(),
732 crate::errors::AuthenticatorError::InvalidRelyingPartyInput
733 );
734
735 assert_matches!(
736 s.sign(
737 1_000,
738 SignArgsCtap1 {
739 flags: SignFlags::empty(),
740 challenge: mk_challenge(),
741 app_ids: vec![],
742 key_handles: vec![mk_key()]
743 }
744 .into(),
745 status_tx,
746 StateCallback::new(Box::new(move |_rv| {})),
747 )
748 .unwrap_err(),
749 crate::errors::AuthenticatorError::InvalidRelyingPartyInput
750 );
751 }
752
753 #[test]
754 fn test_no_keys() {
755 init();
756 let (status_tx, _) = channel::<StatusUpdate>();
760
761 let mut s = AuthenticatorService::new(CtapVersion::CTAP1).unwrap();
762 s.add_transport(Box::new(TestTransportDriver::new(true).unwrap()));
763
764 assert_matches!(
765 s.register(
766 100,
767 RegisterArgsCtap1 {
768 challenge: mk_challenge(),
769 flags: RegisterFlags::empty(),
770 application: mk_appid(),
771 key_handles: vec![],
772 }
773 .into(),
774 status_tx.clone(),
775 StateCallback::new(Box::new(move |_rv| {})),
776 ),
777 Ok(())
778 );
779
780 assert_matches!(
781 s.sign(
782 100,
783 SignArgsCtap1 {
784 flags: SignFlags::empty(),
785 challenge: mk_challenge(),
786 app_ids: vec![mk_appid()],
787 key_handles: vec![]
788 }
789 .into(),
790 status_tx,
791 StateCallback::new(Box::new(move |_rv| {})),
792 ),
793 Ok(())
794 );
795 }
796
797 #[test]
798 fn test_large_keys() {
799 init();
800 let (status_tx, _) = channel::<StatusUpdate>();
801
802 let large_key = KeyHandle {
803 credential: vec![0; 257],
804 transports: AuthenticatorTransports::USB,
805 };
806
807 let mut s = AuthenticatorService::new(CtapVersion::CTAP1).unwrap();
808 s.add_transport(Box::new(TestTransportDriver::new(true).unwrap()));
809
810 assert_matches!(
811 s.register(
812 1_000,
813 RegisterArgsCtap1 {
814 challenge: mk_challenge(),
815 flags: RegisterFlags::empty(),
816 application: mk_appid(),
817 key_handles: vec![large_key.clone()],
818 }
819 .into(),
820 status_tx.clone(),
821 StateCallback::new(Box::new(move |_rv| {})),
822 )
823 .unwrap_err(),
824 crate::errors::AuthenticatorError::InvalidRelyingPartyInput
825 );
826
827 assert_matches!(
828 s.sign(
829 1_000,
830 SignArgsCtap1 {
831 flags: SignFlags::empty(),
832 challenge: mk_challenge(),
833 app_ids: vec![mk_appid()],
834 key_handles: vec![large_key]
835 }
836 .into(),
837 status_tx,
838 StateCallback::new(Box::new(move |_rv| {})),
839 )
840 .unwrap_err(),
841 crate::errors::AuthenticatorError::InvalidRelyingPartyInput
842 );
843 }
844
845 #[test]
846 fn test_no_transports() {
847 init();
848 let (status_tx, _) = channel::<StatusUpdate>();
849
850 let mut s = AuthenticatorService::new(CtapVersion::CTAP1).unwrap();
851 assert_matches!(
852 s.register(
853 1_000,
854 RegisterArgsCtap1 {
855 challenge: mk_challenge(),
856 flags: RegisterFlags::empty(),
857 application: mk_appid(),
858 key_handles: vec![mk_key()],
859 }
860 .into(),
861 status_tx.clone(),
862 StateCallback::new(Box::new(move |_rv| {})),
863 )
864 .unwrap_err(),
865 crate::errors::AuthenticatorError::NoConfiguredTransports
866 );
867
868 assert_matches!(
869 s.sign(
870 1_000,
871 SignArgsCtap1 {
872 flags: SignFlags::empty(),
873 challenge: mk_challenge(),
874 app_ids: vec![mk_appid()],
875 key_handles: vec![mk_key()]
876 }
877 .into(),
878 status_tx,
879 StateCallback::new(Box::new(move |_rv| {})),
880 )
881 .unwrap_err(),
882 crate::errors::AuthenticatorError::NoConfiguredTransports
883 );
884
885 assert_matches!(
886 s.cancel().unwrap_err(),
887 crate::errors::AuthenticatorError::NoConfiguredTransports
888 );
889 }
890
891 #[test]
892 fn test_cancellation_register() {
893 init();
894 let (status_tx, _) = channel::<StatusUpdate>();
895
896 let mut s = AuthenticatorService::new(CtapVersion::CTAP1).unwrap();
897 let ttd_one = TestTransportDriver::new(true).unwrap();
898 let ttd_two = TestTransportDriver::new(false).unwrap();
899 let ttd_three = TestTransportDriver::new(false).unwrap();
900
901 let was_cancelled_one = ttd_one.was_cancelled.clone();
902 let was_cancelled_two = ttd_two.was_cancelled.clone();
903 let was_cancelled_three = ttd_three.was_cancelled.clone();
904
905 s.add_transport(Box::new(ttd_one));
906 s.add_transport(Box::new(ttd_two));
907 s.add_transport(Box::new(ttd_three));
908
909 let callback = StateCallback::new(Box::new(move |_rv| {}));
910 assert!(s
911 .register(
912 1_000,
913 RegisterArgsCtap1 {
914 challenge: mk_challenge(),
915 flags: RegisterFlags::empty(),
916 application: mk_appid(),
917 key_handles: vec![],
918 }
919 .into(),
920 status_tx,
921 callback.clone(),
922 )
923 .is_ok());
924 callback.wait();
925
926 assert_eq!(was_cancelled_one.load(Ordering::SeqCst), false);
927 assert_eq!(was_cancelled_two.load(Ordering::SeqCst), true);
928 assert_eq!(was_cancelled_three.load(Ordering::SeqCst), true);
929 }
930
931 #[test]
932 fn test_cancellation_sign() {
933 init();
934 let (status_tx, _) = channel::<StatusUpdate>();
935
936 let mut s = AuthenticatorService::new(CtapVersion::CTAP1).unwrap();
937 let ttd_one = TestTransportDriver::new(true).unwrap();
938 let ttd_two = TestTransportDriver::new(false).unwrap();
939 let ttd_three = TestTransportDriver::new(false).unwrap();
940
941 let was_cancelled_one = ttd_one.was_cancelled.clone();
942 let was_cancelled_two = ttd_two.was_cancelled.clone();
943 let was_cancelled_three = ttd_three.was_cancelled.clone();
944
945 s.add_transport(Box::new(ttd_one));
946 s.add_transport(Box::new(ttd_two));
947 s.add_transport(Box::new(ttd_three));
948
949 let callback = StateCallback::new(Box::new(move |_rv| {}));
950 assert!(s
951 .sign(
952 1_000,
953 SignArgsCtap1 {
954 flags: SignFlags::empty(),
955 challenge: mk_challenge(),
956 app_ids: vec![mk_appid()],
957 key_handles: vec![mk_key()]
958 }
959 .into(),
960 status_tx,
961 callback.clone(),
962 )
963 .is_ok());
964 callback.wait();
965
966 assert_eq!(was_cancelled_one.load(Ordering::SeqCst), false);
967 assert_eq!(was_cancelled_two.load(Ordering::SeqCst), true);
968 assert_eq!(was_cancelled_three.load(Ordering::SeqCst), true);
969 }
970
971 #[test]
972 fn test_cancellation_race() {
973 init();
974 let (status_tx, _) = channel::<StatusUpdate>();
975
976 let mut s = AuthenticatorService::new(CtapVersion::CTAP1).unwrap();
977 let ttd_one = TestTransportDriver::new(true).unwrap();
979 let ttd_two = TestTransportDriver::new(true).unwrap();
980
981 let was_cancelled_one = ttd_one.was_cancelled.clone();
982 let was_cancelled_two = ttd_two.was_cancelled.clone();
983
984 s.add_transport(Box::new(ttd_one));
985 s.add_transport(Box::new(ttd_two));
986
987 let callback = StateCallback::new(Box::new(move |_rv| {}));
988 assert!(s
989 .register(
990 1_000,
991 RegisterArgsCtap1 {
992 challenge: mk_challenge(),
993 flags: RegisterFlags::empty(),
994 application: mk_appid(),
995 key_handles: vec![],
996 }
997 .into(),
998 status_tx,
999 callback.clone(),
1000 )
1001 .is_ok());
1002 callback.wait();
1003
1004 let one = was_cancelled_one.load(Ordering::SeqCst);
1005 let two = was_cancelled_two.load(Ordering::SeqCst);
1006 assert_eq!(
1007 one ^ two,
1008 true,
1009 "asserting that one={} xor two={} is true",
1010 one,
1011 two
1012 );
1013 }
1014}