webauthn_authenticator_rs/
error.rs

1use std::sync::PoisonError;
2
3pub type Result<T> = std::result::Result<T, WebauthnCError>;
4
5#[derive(Debug, PartialEq, Eq)]
6pub enum WebauthnCError {
7    Json,
8    Cbor,
9    Unknown,
10    Security,
11    NotSupported,
12    PlatformAuthenticator,
13    Internal,
14    ParseNOMFailure,
15    OpenSSL(String),
16    ApduConstruction,
17    ApduTransmission,
18    InvalidAlgorithm,
19    InvalidAssertion,
20    InvalidRegistration,
21    MessageTooLarge,
22    MessageTooShort,
23    /// Message was an unexpected length
24    InvalidMessageLength,
25    Cancelled,
26    Ctap(CtapError),
27    /// The PIN was too short.
28    PinTooShort,
29    /// The PIN was too long.
30    PinTooLong,
31    /// The PIN contained a null byte (`\0`).
32    PinContainsNull,
33    NoSelectedToken,
34    /// The authenticator did not provide a required field. This may indicate a bug in this library, or the
35    /// authenticator.
36    MissingRequiredField,
37    /// The provided `friendly_name` was too long.
38    FriendlyNameTooLong,
39    #[cfg(feature = "usb")]
40    HidError(fido_hid_rs::HidError),
41    #[cfg(feature = "nfc")]
42    PcscError(pcsc::Error),
43    /// No HID devices were detected **at all**. This may indicate a permissions
44    /// issue.
45    NoHidDevices,
46    /// See [PoisonError]; generally indicates that a method holding a prior lock on the mutex failed.
47    PoisonedMutex,
48    /// The checksum of the value was incorrect.
49    Checksum,
50    /// The card reported as a PC/SC storage card, rather than a smart card.
51    StorageCard,
52    IoError(String),
53    InvalidCableUrl,
54    #[cfg(feature = "cable")]
55    Base10(crate::cable::DecodeError),
56    BluetoothError(String),
57    NoBluetoothAdapter,
58    /// Attempt to communicate with an authenticator for which the connection
59    /// has been closed.
60    Closed,
61    WebsocketError(String),
62    /// The value of the nonce for this object has exceeded the limit.
63    NonceOverflow,
64    PermissionDenied,
65    /// User verification was required, but is not available for this
66    /// authenticator. You may need to set a PIN, or use a different
67    /// authenticator.
68    UserVerificationRequired,
69    /// The library is in an unexpected state. This could indicate that
70    /// something has not been initialised correctly, or that the authenticator
71    /// is sending unexpected messages.
72    UnexpectedState,
73    #[cfg(feature = "usb")]
74    U2F(crate::transport::types::U2FError),
75}
76
77#[cfg(feature = "nfc")]
78impl From<pcsc::Error> for WebauthnCError {
79    fn from(e: pcsc::Error) -> Self {
80        Self::PcscError(e)
81    }
82}
83
84#[cfg(feature = "usb")]
85impl From<fido_hid_rs::HidError> for WebauthnCError {
86    fn from(e: fido_hid_rs::HidError) -> Self {
87        Self::HidError(e)
88    }
89}
90
91impl<T> From<PoisonError<T>> for WebauthnCError {
92    fn from(_: PoisonError<T>) -> Self {
93        Self::PoisonedMutex
94    }
95}
96
97#[cfg(feature = "ctap2")]
98impl From<crate::transport::iso7816::Error> for WebauthnCError {
99    fn from(v: crate::transport::iso7816::Error) -> Self {
100        use crate::transport::iso7816::Error::*;
101        match v {
102            ResponseTooShort => WebauthnCError::MessageTooShort,
103            DataTooLong => WebauthnCError::MessageTooLarge,
104            _ => WebauthnCError::Internal,
105        }
106    }
107}
108
109#[cfg(feature = "crypto")]
110impl From<openssl::error::ErrorStack> for WebauthnCError {
111    fn from(v: openssl::error::ErrorStack) -> Self {
112        Self::OpenSSL(v.to_string())
113    }
114}
115
116impl From<std::io::Error> for WebauthnCError {
117    fn from(v: std::io::Error) -> Self {
118        Self::IoError(v.to_string())
119    }
120}
121
122#[cfg(feature = "cable")]
123impl From<crate::cable::DecodeError> for WebauthnCError {
124    fn from(v: crate::cable::DecodeError) -> Self {
125        Self::Base10(v)
126    }
127}
128
129#[cfg(feature = "cable")]
130impl From<tokio_tungstenite::tungstenite::error::Error> for WebauthnCError {
131    fn from(v: tokio_tungstenite::tungstenite::error::Error) -> Self {
132        Self::WebsocketError(v.to_string())
133    }
134}
135
136#[cfg(any(feature = "bluetooth", feature = "cable"))]
137impl From<btleplug::Error> for WebauthnCError {
138    fn from(v: btleplug::Error) -> Self {
139        use btleplug::Error::*;
140        match v {
141            PermissionDenied => WebauthnCError::PermissionDenied,
142            _ => Self::BluetoothError(v.to_string()),
143        }
144    }
145}
146
147#[cfg(feature = "usb")]
148impl From<crate::transport::types::U2FError> for WebauthnCError {
149    fn from(value: crate::transport::types::U2FError) -> Self {
150        Self::U2F(value)
151    }
152}
153
154/// <https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html#error-responses>
155#[derive(Debug, PartialEq, Eq)]
156pub enum CtapError {
157    /// Indicates successful response.
158    Ok,
159    /// The command is not a valid CTAP command.
160    Ctap1InvalidCommand,
161    /// The command included an invalid parameter.
162    Ctap1InvalidParameter,
163    /// Invalid message or item length.
164    Ctap1InvalidLength,
165    /// Invalid message sequencing.
166    Ctap1InvalidSeq,
167    /// Message timed out.
168    Ctap1Timeout,
169    /// Channel busy. Client SHOULD retry the request after a short delay.
170    /// Note that the client MAY abort the transaction if the command is no longer relevant.
171    Ctap1ChannelBusy,
172    /// Command not allowed on this cid.
173    Ctap1LockRequired,
174    /// Command not allowed on this cid.
175    Ctap1InvalidChannel,
176    Ctap2CborUnexpectedType,
177    Ctap2InvalidCBOR,
178    Ctap2MissingParameter,
179    Ctap2LimitExceeded,
180    Ctap2FingerprintDatabaseFull,
181    Ctap2LargeBlobStorageFull,
182    Ctap2CredentialExcluded,
183    Ctap2Processing,
184    Ctap2InvalidCredential,
185    Ctap2UserActionPending,
186    Ctap2OperationPending,
187    Ctap2NoOperations,
188    Ctap2UnsupportedAlgorithm,
189    Ctap2OperationDenied,
190    Ctap2KeyStoreFull,
191    Ctap2UnsupportedOption,
192    Ctap2InvalidOption,
193    Ctap2KeepAliveCancel,
194    Ctap2NoCredentials,
195    Ctap2UserActionTimeout,
196    Ctap2NotAllowed,
197    Ctap2PinInvalid,
198    Ctap2PinBlocked,
199    Ctap2PinAuthInvalid,
200    Ctap2PinAuthBlocked,
201    Ctap2PinNotSet,
202    Ctap2PUATRequired,
203    Ctap2PinPolicyViolation,
204    Ctap2RequestTooLarge,
205    Ctap2ActionTimeout,
206    Ctap2UserPresenceRequired,
207    Ctap2UserVerificationBlocked,
208    Ctap2IntegrityFailure,
209    Ctap2InvalidSubcommand,
210    Ctap2UserVerificationInvalid,
211    Ctap2UnauthorizedPermission,
212    Ctap1Unspecified,
213    Ctap2LastError,
214    /// The error code was unknown
215    Unknown(u8),
216}
217
218impl CtapError {
219    pub fn is_ok(&self) -> bool {
220        *self == CtapError::Ok
221    }
222}
223
224impl From<u8> for CtapError {
225    fn from(e: u8) -> Self {
226        use CtapError::*;
227        match e {
228            0x00 => Ok,
229            0x01 => Ctap1InvalidCommand,
230            0x02 => Ctap1InvalidParameter,
231            0x03 => Ctap1InvalidLength,
232            0x04 => Ctap1InvalidSeq,
233            0x05 => Ctap1Timeout,
234            0x06 => Ctap1ChannelBusy,
235            0x0a => Ctap1LockRequired,
236            0x0b => Ctap1InvalidChannel,
237            0x11 => Ctap2CborUnexpectedType,
238            0x12 => Ctap2InvalidCBOR,
239            0x14 => Ctap2MissingParameter,
240            0x15 => Ctap2LimitExceeded,
241            0x17 => Ctap2FingerprintDatabaseFull,
242            0x18 => Ctap2LargeBlobStorageFull,
243            0x19 => Ctap2CredentialExcluded,
244            0x21 => Ctap2Processing,
245            0x22 => Ctap2InvalidCredential,
246            0x23 => Ctap2UserActionPending,
247            0x24 => Ctap2OperationPending,
248            0x25 => Ctap2NoOperations,
249            0x26 => Ctap2UnsupportedAlgorithm,
250            0x27 => Ctap2OperationDenied,
251            0x28 => Ctap2KeyStoreFull,
252            0x2b => Ctap2UnsupportedOption,
253            0x2c => Ctap2InvalidOption,
254            0x2d => Ctap2KeepAliveCancel,
255            0x2e => Ctap2NoCredentials,
256            0x2f => Ctap2UserActionTimeout,
257            0x30 => Ctap2NotAllowed,
258            0x31 => Ctap2PinInvalid,
259            0x32 => Ctap2PinBlocked,
260            0x33 => Ctap2PinAuthInvalid,
261            0x34 => Ctap2PinAuthBlocked,
262            0x35 => Ctap2PinNotSet,
263            0x36 => Ctap2PUATRequired,
264            0x37 => Ctap2PinPolicyViolation,
265            0x39 => Ctap2RequestTooLarge,
266            0x3a => Ctap2ActionTimeout,
267            0x3b => Ctap2UserPresenceRequired,
268            0x3c => Ctap2UserVerificationBlocked,
269            0x3d => Ctap2IntegrityFailure,
270            0x3e => Ctap2InvalidSubcommand,
271            0x3f => Ctap2UserVerificationInvalid,
272            0x40 => Ctap2UnauthorizedPermission,
273            0x7f => Ctap1Unspecified,
274            0xdf => Ctap2LastError,
275            e => Unknown(e),
276        }
277    }
278}
279
280impl From<CtapError> for u8 {
281    fn from(e: CtapError) -> Self {
282        use CtapError::*;
283        match e {
284            Ok => 0x00,
285            Ctap1InvalidCommand => 0x01,
286            Ctap1InvalidParameter => 0x02,
287            Ctap1InvalidLength => 0x03,
288            Ctap1InvalidSeq => 0x04,
289            Ctap1Timeout => 0x05,
290            Ctap1ChannelBusy => 0x06,
291            Ctap1LockRequired => 0x0a,
292            Ctap1InvalidChannel => 0x0b,
293            Ctap2CborUnexpectedType => 0x11,
294            Ctap2InvalidCBOR => 0x12,
295            Ctap2MissingParameter => 0x14,
296            Ctap2LimitExceeded => 0x15,
297            Ctap2FingerprintDatabaseFull => 0x17,
298            Ctap2LargeBlobStorageFull => 0x18,
299            Ctap2CredentialExcluded => 0x19,
300            Ctap2Processing => 0x21,
301            Ctap2InvalidCredential => 0x22,
302            Ctap2UserActionPending => 0x23,
303            Ctap2OperationPending => 0x24,
304            Ctap2NoOperations => 0x25,
305            Ctap2UnsupportedAlgorithm => 0x26,
306            Ctap2OperationDenied => 0x27,
307            Ctap2KeyStoreFull => 0x28,
308            Ctap2UnsupportedOption => 0x2b,
309            Ctap2InvalidOption => 0x2c,
310            Ctap2KeepAliveCancel => 0x2d,
311            Ctap2NoCredentials => 0x2e,
312            Ctap2UserActionTimeout => 0x2f,
313            Ctap2NotAllowed => 0x30,
314            Ctap2PinInvalid => 0x31,
315            Ctap2PinBlocked => 0x32,
316            Ctap2PinAuthInvalid => 0x33,
317            Ctap2PinAuthBlocked => 0x34,
318            Ctap2PinNotSet => 0x35,
319            Ctap2PUATRequired => 0x36,
320            Ctap2PinPolicyViolation => 0x37,
321            Ctap2RequestTooLarge => 0x39,
322            Ctap2ActionTimeout => 0x3a,
323            Ctap2UserPresenceRequired => 0x3b,
324            Ctap2UserVerificationBlocked => 0x3c,
325            Ctap2IntegrityFailure => 0x3d,
326            Ctap2InvalidSubcommand => 0x3e,
327            Ctap2UserVerificationInvalid => 0x3f,
328            Ctap2UnauthorizedPermission => 0x40,
329            Ctap1Unspecified => 0x7f,
330            Ctap2LastError => 0xdf,
331            Unknown(e) => e,
332        }
333    }
334}
335
336impl From<CtapError> for WebauthnCError {
337    fn from(e: CtapError) -> Self {
338        Self::Ctap(e)
339    }
340}