ctaphid_types/
error.rs

1// Copyright (C) 2021 Robin Krahl <robin.krahl@ireas.org>
2// SPDX-License-Identifier: Apache-2.0 or MIT
3
4use core::fmt;
5#[cfg(feature = "std")]
6use std::error;
7
8use crate::{channel::Channel, packet::PacketType};
9
10/// Error code returned by the device for a failed CTAPHID transaction.
11///
12/// See [ยง 11.2.9.1.6 of the CTAP specification][spec].
13///
14/// [spec]: https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#usb-hid-error
15#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
16pub enum DeviceError {
17    /// The command in the request is invalid.
18    InvalidCommand,
19    /// The parameter(s) in the request is invalid.
20    InvalidParameter,
21    /// The length field (BCNT) is invalid for the request.
22    InvalidLength,
23    /// The sequence does not match expected value.
24    InvalidSequence,
25    /// The message has timed out.
26    MessageTimeout,
27    /// The device is busy for the requesting channel.
28    ChannelBusy,
29    /// Command requires channel lock.
30    LockRequired,
31    /// CID is not valid.
32    InvalidChannel,
33    /// Unspecified error.
34    Other,
35    /// Unknown error code.
36    Unknown(u8),
37}
38
39impl From<u8> for DeviceError {
40    fn from(error: u8) -> Self {
41        match error {
42            0x01 => Self::InvalidCommand,
43            0x02 => Self::InvalidParameter,
44            0x03 => Self::InvalidLength,
45            0x04 => Self::InvalidSequence,
46            0x05 => Self::MessageTimeout,
47            0x06 => Self::ChannelBusy,
48            0x0a => Self::LockRequired,
49            0x0b => Self::InvalidChannel,
50            0x7f => Self::Other,
51            error => Self::Unknown(error),
52        }
53    }
54}
55
56#[cfg(feature = "std")]
57impl error::Error for DeviceError {}
58
59impl fmt::Display for DeviceError {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        match self {
62            Self::InvalidCommand => "the command in the request is invalid".fmt(f),
63            Self::InvalidParameter => "the parameter(s) in the request is invalid".fmt(f),
64            Self::InvalidLength => "the length field is invalid for the request".fmt(f),
65            Self::InvalidSequence => "the sequence does not match expected value".fmt(f),
66            Self::MessageTimeout => "the message has timed out".fmt(f),
67            Self::ChannelBusy => "the device is busy for the requesting channel".fmt(f),
68            Self::LockRequired => "command requires channel lock".fmt(f),
69            Self::InvalidChannel => "CID is not valid".fmt(f),
70            Self::Other => "unspecified error".fmt(f),
71            Self::Unknown(value) => write!(f, "unknown error code 0x{:x}", value),
72        }
73    }
74}
75
76/// An error that occured while assembling a CTAPHID message from packets.
77#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
78pub enum DefragmentationError {
79    /// The packet has an invalid channel.
80    InvalidChannel {
81        /// The expected channel.
82        expected: Channel,
83        /// The actual channel.
84        actual: Channel,
85    },
86    /// The packet has an invalid type.
87    InvalidPacketType {
88        /// The expected packet type.
89        expected: PacketType,
90        /// The actual packet type.
91        actual: PacketType,
92    },
93    /// The packet has an invalid sequence.
94    InvalidSequence {
95        /// The epxected sequence.
96        expected: u8,
97        /// The actual sequence.
98        actual: u8,
99    },
100}
101
102#[cfg(feature = "std")]
103impl error::Error for DefragmentationError {}
104
105impl fmt::Display for DefragmentationError {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        match self {
108            Self::InvalidChannel { expected, actual } => {
109                write!(
110                    f,
111                    "expected a message with channel {} but got {}",
112                    expected, actual
113                )
114            }
115            Self::InvalidPacketType { expected, actual } => {
116                write!(
117                    f,
118                    "expected a packet with type {:?} but got {:?}",
119                    expected, actual
120                )
121            }
122            Self::InvalidSequence { expected, actual } => {
123                write!(
124                    f,
125                    "expected a message with sequence {} but got {}",
126                    expected, actual
127                )
128            }
129        }
130    }
131}
132
133/// An error that occured while fragmenting a CTAPHID message into packets.
134#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
135pub enum FragmentationError {
136    /// The message data is too long to be expressed in CTAPHID packets.
137    DataTooLong,
138    /// The packet size is too small to fit CTAPHID packet.
139    PacketSizeTooSmall,
140}
141
142#[cfg(feature = "std")]
143impl error::Error for FragmentationError {}
144
145impl fmt::Display for FragmentationError {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        match self {
148            Self::DataTooLong => "the message data is too long to be expressed in CTAPHID packets",
149            Self::PacketSizeTooSmall => "the packet size is too small to fit a CTAPHID packet",
150        }
151        .fmt(f)
152    }
153}
154
155/// An error that occured while parsing a CTAPHID packet.
156#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
157pub enum ParseError {
158    /// Not enough data for a CTAPHID packet.
159    NotEnoughData,
160    /// The packet has an invalid type.
161    InvalidPacketType {
162        /// The expected packet type.
163        expected: PacketType,
164        /// The actual packet type.
165        actual: PacketType,
166    },
167    /// Failed to create a buffer for storing the CTAPHID packet.
168    BufferCreationFailed,
169}
170
171#[cfg(feature = "std")]
172impl error::Error for ParseError {}
173
174impl fmt::Display for ParseError {
175    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176        match self {
177            Self::NotEnoughData => "there is not enough data for a CTAPHID packet".fmt(f),
178            Self::InvalidPacketType { expected, actual } => {
179                write!(
180                    f,
181                    "expected a {:?} packet but received a {:?} packet",
182                    expected, actual
183                )
184            }
185            Self::BufferCreationFailed => "failed to create a buffer for the CTAPHID packet".fmt(f),
186        }
187    }
188}
189
190/// An error that occured while serializing a CTAPHID packet.
191#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
192pub enum SerializationError {
193    /// The provided buffer is too small for the CTAPHID packet.
194    BufferTooSmall,
195}
196
197#[cfg(feature = "std")]
198impl error::Error for SerializationError {}
199
200impl fmt::Display for SerializationError {
201    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202        match self {
203            Self::BufferTooSmall => "the buffer for serializing a CTAPHID packet is too small",
204        }
205        .fmt(f)
206    }
207}