Skip to main content

authenticator_ctap2_2021/
authenticatorservice.rs

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
5use 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// TODO(MS): Once U2FManager gets completely removed, this can be removed as well
22#[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    // Todo: Extensions
85}
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    /// The implementation of this method must return quickly and should
112    /// report its status via the status and callback methods
113    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    /// The implementation of this method must return quickly and should
122    /// report its status via the status and callback methods
123    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    /// Add any detected platform transports
189    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////////////////////////////////////////////////////////////////////////
527// Tests
528////////////////////////////////////////////////////////////////////////
529
530#[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        // No Keys is a resident-key use case. For U2F this would time out,
757        // but the actual reactions are up to the service implementation.
758        // This test yields OKs.
759        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 both of these race which one provides consent.
978        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}