webauthn_authenticator_rs/transport/
mod.rs

1//! Low-level transport abstraction layer for communication with FIDO tokens.
2//!
3//! See [crate::ctap2] for a higher-level abstraction over this API.
4mod any;
5pub mod iso7816;
6#[cfg(any(all(doc, not(doctest)), feature = "vendor-solokey"))]
7pub(crate) mod solokey;
8#[cfg(any(doc, feature = "bluetooth", feature = "usb"))]
9pub(crate) mod types;
10#[cfg(any(all(doc, not(doctest)), feature = "vendor-yubikey"))]
11pub(crate) mod yubikey;
12
13pub use crate::transport::any::{AnyToken, AnyTransport};
14
15use async_trait::async_trait;
16use futures::stream::BoxStream;
17use std::fmt;
18use webauthn_rs_proto::AuthenticatorTransport;
19
20use crate::{ctap2::*, error::WebauthnCError, ui::UiCallback};
21
22#[cfg(any(doc, feature = "bluetooth", feature = "usb"))]
23pub(crate) const TYPE_INIT: u8 = 0x80;
24
25#[derive(Debug)]
26pub enum TokenEvent<T: Token> {
27    Added(T),
28    Removed(T::Id),
29    EnumerationComplete,
30}
31
32/// Represents a transport layer protocol for [Token].
33///
34/// If you don't care which transport your application uses, use [AnyTransport]
35/// to automatically use all available transports on the platform.
36#[async_trait]
37pub trait Transport<'b>: Sized + fmt::Debug + Send {
38    /// The type of [Token] returned by this [Transport].
39    type Token: Token + 'b;
40
41    /// Watches for token connection and disconnection on this [Transport].
42    ///
43    /// Initially, this send synthetic [`TokenEvent::Added`] for all
44    /// currently-connected tokens, followed by
45    /// [`TokenEvent::EnumerationComplete`].
46    async fn watch(&self) -> Result<BoxStream<TokenEvent<Self::Token>>, WebauthnCError>;
47
48    /// Gets all currently-connected devices associated with this [Transport].
49    ///
50    /// This method does not work for Bluetooth devices. Use
51    /// [`watch()`][] instead.
52    ///
53    /// [`watch()`]: Transport::watch
54    async fn tokens(&self) -> Result<Vec<Self::Token>, WebauthnCError>;
55}
56
57/// Represents a connection to a single FIDO token over a [Transport].
58///
59/// This is a low level interface to FIDO tokens, passing raw messages.
60/// [crate::ctap2] provides a higher level abstraction.
61#[async_trait]
62pub trait Token: Sized + fmt::Debug + Sync + Send {
63    type Id: Sized + fmt::Debug + Sync + Send;
64
65    fn has_button(&self) -> bool {
66        true
67    }
68
69    /// Gets the transport layer used for communication with this token.
70    fn get_transport(&self) -> AuthenticatorTransport;
71
72    /// Transmit a CBOR message to a token, and deserialises the response.
73    async fn transmit<'a, C, R, U>(&mut self, cmd: C, ui: &U) -> Result<R, WebauthnCError>
74    where
75        C: CBORCommand<Response = R>,
76        R: CBORResponse,
77        U: UiCallback,
78    {
79        let cbor = cmd.cbor().map_err(|_| WebauthnCError::Cbor)?;
80        trace!(">>> {}", hex::encode(&cbor));
81
82        let resp = self.transmit_raw(&cbor, ui).await?;
83
84        trace!("<<< {}", hex::encode(&resp));
85        R::try_from(resp.as_slice()).map_err(|_| {
86            //error!("error: {:?}", e);
87            WebauthnCError::Cbor
88        })
89    }
90
91    /// Transmits a command on the underlying transport.
92    ///
93    /// `cbor` is a CBOR-encoded command.
94    ///
95    /// Interfaces need to check for and return any transport-layer-specific
96    /// error code [WebauthnCError::Ctap], but don't need to worry about
97    /// deserialising CBOR.
98    async fn transmit_raw<U>(&mut self, cbor: &[u8], ui: &U) -> Result<Vec<u8>, WebauthnCError>
99    where
100        U: UiCallback;
101
102    /// Cancels a pending request.
103    async fn cancel(&mut self) -> Result<(), WebauthnCError>;
104
105    /// Initializes the [Token]
106    async fn init(&mut self) -> Result<(), WebauthnCError>;
107
108    /// Closes the [Token]
109    async fn close(&mut self) -> Result<(), WebauthnCError>;
110}