1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
use std::borrow;
use std::error;
use std::fmt;
use std::os::raw;
use std::result;
/// An error returned by the nitrokey crate.
#[derive(Debug)]
pub enum Error {
/// An error reported by the Nitrokey device in the response packet.
CommandError(CommandError),
/// Placeholder for testing.
CommunicationError(CommunicationError),
/// An error that occured during random number generation.
RandError(rand_core::Error),
/// An unknown error returned by libnitrokey.
Unknown(i64),
}
impl From<raw::c_int> for Error {
fn from(code: raw::c_int) -> Self {
if let Some(err) = CommandError::try_from(code) {
Error::CommandError(err)
} else {
Error::Unknown(code.into())
}
}
}
impl From<CommandError> for Error {
fn from(err: CommandError) -> Self {
Error::CommandError(err)
}
}
impl From<rand_core::Error> for Error {
fn from(error: rand_core::Error) -> Self {
Error::RandError(error)
}
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
Error::CommandError(ref err) => Some(err),
Error::CommunicationError(_) => None,
Error::RandError(ref err) => Some(err),
Error::Unknown(_) => None,
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Error::CommandError(ref err) => write!(f, "Command error: {}", err),
Error::CommunicationError(_) => write!(f, "Placeholder"),
Error::RandError(ref err) => write!(f, "RNG error: {}", err),
Error::Unknown(ref err) => write!(f, "Unknown error: {}", err),
}
}
}
/// A result returned by the nitrokey crate.
pub type Result<T> = result::Result<T, Error>;
/// An error reported by the Nitrokey device in the response packet.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum CommandError {
/// A packet with a wrong checksum has been sent or received.
WrongCrc,
/// A command tried to access an OTP slot that does not exist.
WrongSlot,
/// A command tried to generate an OTP on a slot that is not configured.
SlotNotProgrammed,
/// The provided password is wrong.
WrongPassword,
/// You are not authorized for this command or provided a wrong temporary
/// password.
NotAuthorized,
/// An error occurred when getting or setting the time.
Timestamp,
/// You did not provide a name for the OTP slot.
NoName,
/// This command is not supported by this device.
NotSupported,
/// This command is unknown.
UnknownCommand,
/// AES decryption failed.
AesDecryptionFailed,
/// An unspecified error occurred.
Undefined,
/// You passed a string containing a null byte.
InvalidString,
/// A supplied string exceeded a length limit.
StringTooLong,
/// You passed an invalid slot.
InvalidSlot,
/// The supplied string was not in hexadecimal format.
InvalidHexString,
/// The target buffer was smaller than the source.
TargetBufferTooSmall,
}
/// Placeholder for testing.
#[derive(Debug)]
pub enum CommunicationError {
/// Placeholder for testing.
NotConnected,
}
impl CommandError {
fn try_from(value: raw::c_int) -> Option<Self> {
match value {
1 => Some(CommandError::WrongCrc),
2 => Some(CommandError::WrongSlot),
3 => Some(CommandError::SlotNotProgrammed),
4 => Some(CommandError::WrongPassword),
5 => Some(CommandError::NotAuthorized),
6 => Some(CommandError::Timestamp),
7 => Some(CommandError::NoName),
8 => Some(CommandError::NotSupported),
9 => Some(CommandError::UnknownCommand),
10 => Some(CommandError::AesDecryptionFailed),
200 => Some(CommandError::StringTooLong),
201 => Some(CommandError::InvalidSlot),
202 => Some(CommandError::InvalidHexString),
203 => Some(CommandError::TargetBufferTooSmall),
_ => None,
}
}
fn as_str(&self) -> borrow::Cow<'static, str> {
match *self {
CommandError::WrongCrc => {
"A packet with a wrong checksum has been sent or received".into()
}
CommandError::WrongSlot => "The given OTP slot does not exist".into(),
CommandError::SlotNotProgrammed => "The given OTP slot is not programmed".into(),
CommandError::WrongPassword => "The given password is wrong".into(),
CommandError::NotAuthorized => {
"You are not authorized for this command or provided a wrong temporary \
password"
.into()
}
CommandError::Timestamp => "An error occurred when getting or setting the time".into(),
CommandError::NoName => "You did not provide a name for the OTP slot".into(),
CommandError::NotSupported => "This command is not supported by this device".into(),
CommandError::UnknownCommand => "This command is unknown".into(),
CommandError::AesDecryptionFailed => "AES decryption failed".into(),
CommandError::Undefined => "An unspecified error occurred".into(),
CommandError::InvalidString => "You passed a string containing a null byte".into(),
CommandError::StringTooLong => "The supplied string is too long".into(),
CommandError::InvalidSlot => "The given slot is invalid".into(),
CommandError::InvalidHexString => {
"The supplied string is not in hexadecimal format".into()
}
CommandError::TargetBufferTooSmall => "The target buffer is too small".into(),
}
}
}
impl error::Error for CommandError {}
impl fmt::Display for CommandError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
|