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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
// Copyright (C) 2021 Robin Krahl <robin.krahl@ireas.org>
// SPDX-License-Identifier: Apache-2.0 or MIT
/// A CTAPHID command.
///
/// See [§ 11.2.9 of the CTAP specification][spec].
///
/// [spec]: https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#usb-commands
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub enum Command {
/// The message command.
Message,
/// The CBOR command.
Cbor,
/// The init command.
Init,
/// The ping command.
Ping,
/// The cancel command.
Cancel,
/// The error command.
Error,
/// The keep alive command.
KeepAlive,
/// The wink command.
Wink,
/// The lock command.
Lock,
/// A vendor command.
Vendor(VendorCommand),
/// An unknown command.
Unknown(u8),
}
impl From<Command> for u8 {
fn from(command: Command) -> Self {
match command {
Command::Message => 0x03,
Command::Cbor => 0x10,
Command::Init => 0x06,
Command::Ping => 0x01,
Command::Cancel => 0x11,
Command::Error => 0x3f,
Command::KeepAlive => 0x3b,
Command::Wink => 0x08,
Command::Lock => 0x04,
Command::Vendor(command) => command.into(),
Command::Unknown(command) => command,
}
}
}
impl From<u8> for Command {
fn from(value: u8) -> Self {
match value {
0x01 => Self::Ping,
0x03 => Self::Message,
0x04 => Self::Lock,
0x06 => Self::Init,
0x08 => Self::Wink,
0x10 => Self::Cbor,
0x11 => Self::Cancel,
0x3b => Self::KeepAlive,
0x3f => Self::Error,
_ => VendorCommand::new(value).map_or(Command::Unknown(value), Command::Vendor),
}
}
}
/// A CTAPHID vendor command.
///
/// See [§ 11.2.9.3 of the CTAP specification][spec].
///
/// [spec]: https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#usb-vendor-specific-commands
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct VendorCommand(u8);
impl VendorCommand {
const FIRST: u8 = 0x40;
const LAST: u8 = 0x7f;
/// The range for valid vendor command IDs.
pub const RANGE: core::ops::RangeInclusive<u8> = (Self::FIRST..=Self::LAST);
/// The vendor-specific command with the ID 0x40.
pub const H40: VendorCommand = VendorCommand(0x40);
/// The vendor-specific command with the ID 0x41.
pub const H41: VendorCommand = VendorCommand(0x41);
/// The vendor-specific command with the ID 0x42.
pub const H42: VendorCommand = VendorCommand(0x42);
/// The vendor-specific command with the ID 0x43.
pub const H43: VendorCommand = VendorCommand(0x43);
/// The vendor-specific command with the ID 0x44.
pub const H44: VendorCommand = VendorCommand(0x44);
/// The vendor-specific command with the ID 0x45.
pub const H45: VendorCommand = VendorCommand(0x45);
/// The vendor-specific command with the ID 0x46.
pub const H46: VendorCommand = VendorCommand(0x46);
/// The vendor-specific command with the ID 0x47.
pub const H47: VendorCommand = VendorCommand(0x47);
/// The vendor-specific command with the ID 0x48.
pub const H48: VendorCommand = VendorCommand(0x48);
/// The vendor-specific command with the ID 0x49.
pub const H49: VendorCommand = VendorCommand(0x49);
/// The vendor-specific command with the ID 0x4a.
pub const H4A: VendorCommand = VendorCommand(0x4a);
/// The vendor-specific command with the ID 0x4b.
pub const H4B: VendorCommand = VendorCommand(0x4b);
/// The vendor-specific command with the ID 0x4c.
pub const H4C: VendorCommand = VendorCommand(0x4c);
/// The vendor-specific command with the ID 0x4d.
pub const H4D: VendorCommand = VendorCommand(0x4d);
/// The vendor-specific command with the ID 0x4e.
pub const H4E: VendorCommand = VendorCommand(0x4e);
/// The vendor-specific command with the ID 0x4f.
pub const H4F: VendorCommand = VendorCommand(0x4f);
/// The vendor-specific command with the ID 0x50.
pub const H50: VendorCommand = VendorCommand(0x50);
/// The vendor-specific command with the ID 0x51.
pub const H51: VendorCommand = VendorCommand(0x51);
/// The vendor-specific command with the ID 0x52.
pub const H52: VendorCommand = VendorCommand(0x52);
/// The vendor-specific command with the ID 0x53.
pub const H53: VendorCommand = VendorCommand(0x53);
/// The vendor-specific command with the ID 0x54.
pub const H54: VendorCommand = VendorCommand(0x54);
/// The vendor-specific command with the ID 0x55.
pub const H55: VendorCommand = VendorCommand(0x55);
/// The vendor-specific command with the ID 0x56.
pub const H56: VendorCommand = VendorCommand(0x56);
/// The vendor-specific command with the ID 0x57.
pub const H57: VendorCommand = VendorCommand(0x57);
/// The vendor-specific command with the ID 0x58.
pub const H58: VendorCommand = VendorCommand(0x58);
/// The vendor-specific command with the ID 0x59.
pub const H59: VendorCommand = VendorCommand(0x59);
/// The vendor-specific command with the ID 0x5a.
pub const H5A: VendorCommand = VendorCommand(0x5a);
/// The vendor-specific command with the ID 0x5b.
pub const H5B: VendorCommand = VendorCommand(0x5b);
/// The vendor-specific command with the ID 0x5c.
pub const H5C: VendorCommand = VendorCommand(0x5c);
/// The vendor-specific command with the ID 0x5d.
pub const H5D: VendorCommand = VendorCommand(0x5d);
/// The vendor-specific command with the ID 0x5e.
pub const H5E: VendorCommand = VendorCommand(0x5e);
/// The vendor-specific command with the ID 0x5f.
pub const H5F: VendorCommand = VendorCommand(0x5f);
/// The vendor-specific command with the ID 0x60.
pub const H60: VendorCommand = VendorCommand(0x60);
/// The vendor-specific command with the ID 0x61.
pub const H61: VendorCommand = VendorCommand(0x61);
/// The vendor-specific command with the ID 0x62.
pub const H62: VendorCommand = VendorCommand(0x62);
/// The vendor-specific command with the ID 0x63.
pub const H63: VendorCommand = VendorCommand(0x63);
/// The vendor-specific command with the ID 0x64.
pub const H64: VendorCommand = VendorCommand(0x64);
/// The vendor-specific command with the ID 0x65.
pub const H65: VendorCommand = VendorCommand(0x65);
/// The vendor-specific command with the ID 0x66.
pub const H66: VendorCommand = VendorCommand(0x66);
/// The vendor-specific command with the ID 0x67.
pub const H67: VendorCommand = VendorCommand(0x67);
/// The vendor-specific command with the ID 0x68.
pub const H68: VendorCommand = VendorCommand(0x68);
/// The vendor-specific command with the ID 0x69.
pub const H69: VendorCommand = VendorCommand(0x69);
/// The vendor-specific command with the ID 0x6a.
pub const H6A: VendorCommand = VendorCommand(0x6a);
/// The vendor-specific command with the ID 0x6b.
pub const H6B: VendorCommand = VendorCommand(0x6b);
/// The vendor-specific command with the ID 0x6c.
pub const H6C: VendorCommand = VendorCommand(0x6c);
/// The vendor-specific command with the ID 0x6d.
pub const H6D: VendorCommand = VendorCommand(0x6d);
/// The vendor-specific command with the ID 0x6e.
pub const H6E: VendorCommand = VendorCommand(0x6e);
/// The vendor-specific command with the ID 0x6f.
pub const H6F: VendorCommand = VendorCommand(0x6f);
/// The vendor-specific command with the ID 0x70.
pub const H70: VendorCommand = VendorCommand(0x70);
/// The vendor-specific command with the ID 0x71.
pub const H71: VendorCommand = VendorCommand(0x71);
/// The vendor-specific command with the ID 0x72.
pub const H72: VendorCommand = VendorCommand(0x72);
/// The vendor-specific command with the ID 0x73.
pub const H73: VendorCommand = VendorCommand(0x73);
/// The vendor-specific command with the ID 0x74.
pub const H74: VendorCommand = VendorCommand(0x74);
/// The vendor-specific command with the ID 0x75.
pub const H75: VendorCommand = VendorCommand(0x75);
/// The vendor-specific command with the ID 0x76.
pub const H76: VendorCommand = VendorCommand(0x76);
/// The vendor-specific command with the ID 0x77.
pub const H77: VendorCommand = VendorCommand(0x77);
/// The vendor-specific command with the ID 0x78.
pub const H78: VendorCommand = VendorCommand(0x78);
/// The vendor-specific command with the ID 0x79.
pub const H79: VendorCommand = VendorCommand(0x79);
/// The vendor-specific command with the ID 0x7a.
pub const H7A: VendorCommand = VendorCommand(0x7a);
/// The vendor-specific command with the ID 0x7b.
pub const H7B: VendorCommand = VendorCommand(0x7b);
/// The vendor-specific command with the ID 0x7c.
pub const H7C: VendorCommand = VendorCommand(0x7c);
/// The vendor-specific command with the ID 0x7d.
pub const H7D: VendorCommand = VendorCommand(0x7d);
/// The vendor-specific command with the ID 0x7e.
pub const H7E: VendorCommand = VendorCommand(0x7e);
/// The vendor-specific command with the ID 0x7f.
pub const H7F: VendorCommand = VendorCommand(0x7f);
/// Creates a new `VendorCommand` from the given command ID if it is within [`Self::RANGE`][].
pub fn new(id: u8) -> Option<Self> {
if Self::RANGE.contains(&id) {
Some(Self(id))
} else {
None
}
}
}
impl From<VendorCommand> for u8 {
fn from(command: VendorCommand) -> u8 {
command.0
}
}
#[cfg(test)]
mod test {
use super::{Command, VendorCommand};
impl quickcheck::Arbitrary for Command {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
u8::arbitrary(g).into()
}
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
Box::new(u8::from(*self).shrink().map(From::from))
}
}
impl quickcheck::Arbitrary for VendorCommand {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
let n = VendorCommand::RANGE.end() - VendorCommand::RANGE.start() + 1;
let command = u8::arbitrary(g) % n + VendorCommand::RANGE.start();
VendorCommand::new(command).unwrap()
}
}
}