1use std::fmt;
4
5#[derive(Debug, Clone, PartialEq)]
7pub enum Error {
8 Success,
10 DoesAlreadyExist,
12 DoesNotExist,
14 KeyStoreFull,
16 OutOfMemory,
18 Timeout,
20 Other,
22 InitializationFailed,
24 InvalidCallbackResult,
26 CborCommandFailed(i32),
28 InvalidClientDataHash,
30 CtapError(u8),
32 IoError(String),
34}
35
36impl fmt::Display for Error {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 match self {
39 Error::Success => write!(f, "Success"),
40 Error::DoesAlreadyExist => write!(f, "Value already exists"),
41 Error::DoesNotExist => write!(f, "Value does not exist"),
42 Error::KeyStoreFull => write!(f, "Key store is full"),
43 Error::OutOfMemory => write!(f, "Out of memory"),
44 Error::Timeout => write!(f, "Operation timed out"),
45 Error::Other => write!(f, "Unspecified error"),
46 Error::InitializationFailed => write!(f, "Initialization failed"),
47 Error::InvalidCallbackResult => write!(f, "Invalid callback result"),
48 Error::CborCommandFailed(code) => {
49 write!(f, "CBOR command failed with code {}", code)
50 }
51 Error::InvalidClientDataHash => {
52 write!(f, "Invalid client data hash (must be 32 bytes)")
53 }
54 Error::CtapError(code) => write!(f, "CTAP error: 0x{:02X}", code),
55 Error::IoError(msg) => write!(f, "IO error: {}", msg),
56 }
57 }
58}
59
60impl std::error::Error for Error {}
61
62impl From<i32> for Error {
63 fn from(value: i32) -> Self {
64 match value {
65 0 => Error::Success,
66 -1 => Error::DoesAlreadyExist,
67 -2 => Error::DoesNotExist,
68 -3 => Error::KeyStoreFull,
69 -4 => Error::OutOfMemory,
70 -5 => Error::Timeout,
71 -6 => Error::Other,
72 _ => Error::CborCommandFailed(value),
73 }
74 }
75}
76
77impl From<soft_fido2_ctap::StatusCode> for Error {
78 fn from(status: soft_fido2_ctap::StatusCode) -> Self {
79 use soft_fido2_ctap::StatusCode;
80
81 match status {
82 StatusCode::Success => Error::Success,
83 StatusCode::InvalidCommand => Error::CtapError(0x01),
84 StatusCode::InvalidParameter => Error::CtapError(0x02),
85 StatusCode::InvalidLength => Error::CtapError(0x03),
86 StatusCode::InvalidSeq => Error::CtapError(0x04),
87 StatusCode::Timeout => Error::Timeout,
88 StatusCode::ChannelBusy => Error::CtapError(0x06),
89 StatusCode::LockRequired => Error::CtapError(0x0A),
90 StatusCode::InvalidChannel => Error::CtapError(0x0B),
91 StatusCode::CborUnexpectedType => Error::CtapError(0x11),
92 StatusCode::InvalidCbor => Error::CtapError(0x12),
93 StatusCode::MissingParameter => Error::CtapError(0x14),
94 StatusCode::LimitExceeded => Error::CtapError(0x15),
95 StatusCode::UnsupportedExtension => Error::CtapError(0x16),
96 StatusCode::CredentialExcluded => Error::CtapError(0x19),
97 StatusCode::Processing => Error::CtapError(0x21),
98 StatusCode::InvalidCredential => Error::CtapError(0x22),
99 StatusCode::UserActionPending => Error::CtapError(0x23),
100 StatusCode::OperationPending => Error::CtapError(0x24),
101 StatusCode::NoOperations => Error::CtapError(0x25),
102 StatusCode::UnsupportedAlgorithm => Error::CtapError(0x26),
103 StatusCode::OperationDenied => Error::CtapError(0x27),
104 StatusCode::KeyStoreFull => Error::KeyStoreFull,
105 StatusCode::NotBusy => Error::CtapError(0x29),
106 StatusCode::NoOperationPending => Error::CtapError(0x2A),
107 StatusCode::UnsupportedOption => Error::CtapError(0x2B),
108 StatusCode::InvalidOption => Error::CtapError(0x2C),
109 StatusCode::KeepaliveCancel => Error::CtapError(0x2D),
110 StatusCode::NoCredentials => Error::DoesNotExist,
111 StatusCode::UserActionTimeout => Error::Timeout,
112 StatusCode::NotAllowed => Error::CtapError(0x30),
113 StatusCode::PinInvalid => Error::CtapError(0x31),
114 StatusCode::PinBlocked => Error::CtapError(0x32),
115 StatusCode::PinAuthInvalid => Error::CtapError(0x33),
116 StatusCode::PinAuthBlocked => Error::CtapError(0x34),
117 StatusCode::PinNotSet => Error::CtapError(0x35),
118 StatusCode::PinRequired => Error::CtapError(0x36),
119 StatusCode::PinPolicyViolation => Error::CtapError(0x37),
120 StatusCode::PinTokenExpired => Error::CtapError(0x38),
121 StatusCode::RequestTooLarge => Error::CtapError(0x39),
122 StatusCode::ActionTimeout => Error::Timeout,
123 StatusCode::UpRequired => Error::CtapError(0x3A),
124 StatusCode::UvBlocked => Error::CtapError(0x3C),
125 StatusCode::IntegrityFailure => Error::CtapError(0x3D),
126 StatusCode::InvalidSubcommand => Error::CtapError(0x3E),
127 StatusCode::UvInvalid => Error::CtapError(0x3F),
128 StatusCode::UnauthorizedPermission => Error::CtapError(0x40),
129 StatusCode::Other => Error::Other,
130 }
131 }
132}
133
134impl From<Error> for soft_fido2_ctap::StatusCode {
135 fn from(error: Error) -> Self {
136 use soft_fido2_ctap::StatusCode;
137
138 match error {
139 Error::Success => StatusCode::Success,
140 Error::DoesNotExist => StatusCode::NoCredentials,
141 Error::KeyStoreFull => StatusCode::KeyStoreFull,
142 Error::Timeout => StatusCode::Timeout,
143 Error::Other => StatusCode::Other,
144 Error::CtapError(code) => {
145 match code {
147 0x01 => StatusCode::InvalidCommand,
148 0x02 => StatusCode::InvalidParameter,
149 0x03 => StatusCode::InvalidLength,
150 0x04 => StatusCode::InvalidSeq,
151 0x06 => StatusCode::ChannelBusy,
152 0x0A => StatusCode::LockRequired,
153 0x0B => StatusCode::InvalidChannel,
154 0x11 => StatusCode::CborUnexpectedType,
155 0x12 => StatusCode::InvalidCbor,
156 0x14 => StatusCode::MissingParameter,
157 0x15 => StatusCode::LimitExceeded,
158 0x31 => StatusCode::PinInvalid,
159 0x33 => StatusCode::PinAuthInvalid,
160 0x35 => StatusCode::PinNotSet,
161 0x36 => StatusCode::PinRequired,
162 _ => StatusCode::Other,
163 }
164 }
165 _ => StatusCode::Other,
166 }
167 }
168}
169
170impl From<std::io::Error> for Error {
172 fn from(error: std::io::Error) -> Self {
173 Error::IoError(error.to_string())
174 }
175}
176
177pub type Result<T> = std::result::Result<T, Error>;