1use iso7816::command::{CommandView, FromSliceError};
5use server::{AsScalar, FromScalar};
6
7use crate::error::FidoError;
8use crate::SecurityKeyView;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
11#[rkyv(derive(Debug))]
12pub enum Transport {
13 Usb,
14 Nfc,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum U2fApduParseError {
19 WrongLength,
20 ClassNotSupported,
21}
22
23impl U2fApduParseError {
24 pub fn to_u2f_response(self) -> Vec<u8> {
25 match self {
26 Self::WrongLength => vec![0x67, 0x00],
27 Self::ClassNotSupported => vec![0x6e, 0x00],
28 }
29 }
30}
31
32impl From<FromSliceError> for U2fApduParseError {
33 fn from(error: FromSliceError) -> Self {
34 match error {
35 FromSliceError::InvalidClass => Self::ClassNotSupported,
36 FromSliceError::TooShort
37 | FromSliceError::TooLong
38 | FromSliceError::InvalidFirstBodyByteForExtended
39 | FromSliceError::InvalidSliceLength => Self::WrongLength,
40 }
41 }
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
45pub struct U2fApduCommand {
46 pub class: u8,
47 pub instruction: u8,
48 pub p1: u8,
49 pub p2: u8,
50 pub data: Vec<u8>,
51 pub expected: u32,
52 pub extended: bool,
53}
54
55impl U2fApduCommand {
56 pub fn parse(apdu: &[u8]) -> Result<Self, U2fApduParseError> {
57 let command = CommandView::try_from(apdu)?;
58 Ok(Self::from_command_view(command))
59 }
60
61 pub fn from_command_view(command: CommandView<'_>) -> Self {
62 Self {
63 class: command.class().into_inner(),
64 instruction: command.instruction().into(),
65 p1: command.p1,
66 p2: command.p2,
67 data: command.data().to_vec(),
68 expected: command.expected() as u32,
69 extended: command.extended,
70 }
71 }
72
73 pub fn data(&self) -> &[u8] { &self.data }
74}
75
76#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
80pub struct KeysChangedEvent {
81 pub keys: Vec<SecurityKeyView>,
82}
83
84#[derive(server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
89#[event(KeysChangedEvent)]
90pub struct SubscribeKeyChanges;
91
92#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
102pub struct PresenceKeepAliveEvent {
103 pub fingerprint: [u8; 32],
104}
105
106#[derive(server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
108#[event(PresenceKeepAliveEvent)]
109pub struct SubscribePresenceKeepAlive;
110
111#[derive(Debug, Clone, Copy, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
115pub enum OperationType {
116 Registration,
117 Authentication,
118}
119
120#[derive(Debug, Clone, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
125pub struct OperationOutcomeEvent {
126 pub security_key_index: usize,
127 pub operation: OperationType,
128 pub success: bool,
129}
130
131#[derive(server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
133#[event(OperationOutcomeEvent)]
134pub struct SubscribeOperationOutcomes;
135
136#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
142#[response(Result<usize, FidoError>)]
143pub struct CreateSecurityKey {
144 pub label: String,
145 pub color: u8,
146 pub icon: String,
147}
148
149#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
152#[response(Result<(), FidoError>)]
153pub struct EditSecurityKey {
154 pub index: usize,
155 pub label: String,
156 pub color: u8,
157 pub icon: String,
158 pub date: u64,
159}
160
161#[derive(Debug, server::Message)]
165#[response(Result<(), FidoError>)]
166pub struct SetArchived {
167 pub index: usize,
168 pub archived: bool,
169}
170
171impl AsScalar<2> for SetArchived {
172 fn as_scalar(&self) -> [u32; 2] { [self.index as u32, self.archived as u32] }
173}
174impl FromScalar<2> for SetArchived {
175 fn from_scalar([a, b]: [u32; 2]) -> Self { Self { index: a as usize, archived: b != 0 } }
176}
177
178#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
183#[response(Vec<SecurityKeyView>)]
184pub struct ListSecurityKeys;
185
186#[derive(Debug, server::Message)]
189#[response(Option<usize>)]
190pub struct GetSelectedSecurityKey;
191
192#[derive(Debug, server::Message)]
194pub struct SelectSecurityKey(pub Option<usize>);
195
196#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
199#[response(Vec<u8>)]
200pub struct U2fProcessApdu {
201 pub command: U2fApduCommand,
202 pub transport: Transport,
203}
204
205#[derive(Debug, Clone, server::Message, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
206#[response(Vec<u8>)]
207pub struct CtapProcessCbor {
208 pub cmd: u8,
209 pub raw: Vec<u8>,
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 #[test]
217 fn u2f_apdu_command_rejects_short_buffers() {
218 for len in 0..4 {
219 let data = vec![0; len];
220 assert_eq!(U2fApduCommand::parse(&data), Err(U2fApduParseError::WrongLength));
221 }
222 }
223
224 #[test]
225 fn u2f_apdu_command_parses_short_apdu() {
226 let command = U2fApduCommand::parse(&[0x00, 0x01, 0x02, 0x00, 0x02, 0xaa, 0xbb, 0x00]).unwrap();
227
228 assert_eq!(command.class, 0x00);
229 assert_eq!(command.instruction, 0x01);
230 assert_eq!(command.p1, 0x02);
231 assert_eq!(command.p2, 0x00);
232 assert_eq!(command.data(), &[0xaa, 0xbb]);
233 assert_eq!(command.expected, 256);
234 assert!(!command.extended);
235 }
236
237 #[test]
238 fn u2f_apdu_command_parses_extended_apdu() {
239 let command =
240 U2fApduCommand::parse(&[0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x02, 0xaa, 0xbb, 0x00, 0x00])
241 .unwrap();
242
243 assert_eq!(command.data(), &[0xaa, 0xbb]);
244 assert_eq!(command.expected, 65_536);
245 assert!(command.extended);
246 }
247}
248
249#[cfg(feature = "test-app")]
252#[derive(Debug, server::Message)]
253#[response(Result<(), FidoError>)]
254pub struct ResetState;