1mod apdu;
4mod ctaphid;
5
6#[allow(unused_imports)]
7use crate::msp;
8use crate::{Authenticator, TrussedRequirements, UserPresence};
9
10use ctap_types::{ctap1, ctap2};
11use heapless::VecView;
12use iso7816::{command::CommandView, Status};
13
14impl<UP, T> iso7816::App for Authenticator<UP, T>
15where
16 UP: UserPresence,
17{
18 fn aid(&self) -> iso7816::Aid {
19 iso7816::Aid::new(&[0xA0, 0x00, 0x00, 0x06, 0x47, 0x2F, 0x00, 0x01])
20 }
21}
22
23#[inline(never)]
24fn handle_ctap1_from_hid<T, UP>(
26 authenticator: &mut Authenticator<UP, T>,
27 data: &[u8],
28 response: &mut VecView<u8>,
29) where
30 T: TrussedRequirements,
31 UP: UserPresence,
32{
33 debug!(
34 "handle CTAP1: remaining stack: {} bytes",
35 msp() - 0x2000_0000
36 );
37 {
38 let command = match CommandView::try_from(data) {
39 Ok(command) => command,
40 Err(_status) => {
41 let code: [u8; 2] = (Status::IncorrectDataParameter).into();
42 debug!("CTAP1 parse error: {:?} ({})", _status, hex_str!(&code));
43 response.extend_from_slice(&code).ok();
44 return;
45 }
46 };
47
48 match try_handle_ctap1(authenticator, command, response) {
50 Ok(()) => {
51 debug!("U2F response {} bytes", response.len());
52 response.extend_from_slice(&[0x90, 0x00]).ok();
55 }
56 Err(status) => {
57 let code: [u8; 2] = status.into();
58 debug!("CTAP1 error: {:?} ({})", status, hex_str!(&code));
59 response.extend_from_slice(&code).ok();
60 }
61 }
62 }
63 debug!("end handle CTAP1");
65}
66
67#[inline(never)]
68fn handle_ctap2<T, UP>(
70 authenticator: &mut Authenticator<UP, T>,
71 data: &[u8],
72 response: &mut VecView<u8>,
73) where
74 T: TrussedRequirements,
75 UP: UserPresence,
76{
77 debug!(
78 "handle CTAP2: remaining stack: {} bytes",
79 msp() - 0x2000_0000
80 );
81
82 debug!("1a SP: {:X}", msp());
83 if let Err(error) = try_handle_ctap2(authenticator, data, response) {
85 debug!("CTAP2 error: {:02X}", error);
86 response.push(error).ok();
87 }
88 debug!("end handle CTAP2");
90}
91
92#[inline(never)]
93fn try_handle_ctap1<T, UP>(
94 authenticator: &mut Authenticator<UP, T>,
95 command: CommandView<'_>,
96 response: &mut VecView<u8>,
97) -> Result<(), Status>
98where
99 T: TrussedRequirements,
100 UP: UserPresence,
101{
102 authenticator
104 .state
105 .persistent
106 .load_if_not_initialised(&mut authenticator.trussed);
107
108 let ctap_response = {
118 let ctap_request = ctap1::Request::try_from(command)?;
119 ctap1::Authenticator::call_ctap1(authenticator, &ctap_request)?
120 };
121 ctap_response.serialize(response).ok();
124 Ok(())
125}
126
127#[inline(never)]
128fn try_handle_ctap2<T, UP>(
129 authenticator: &mut Authenticator<UP, T>,
130 data: &[u8],
131 response: &mut VecView<u8>,
132) -> Result<(), u8>
133where
134 T: TrussedRequirements,
135 UP: UserPresence,
136{
137 authenticator
139 .state
140 .persistent
141 .load_if_not_initialised(&mut authenticator.trussed);
142
143 debug!(
144 "try_handle CTAP2: remaining stack: {} bytes",
145 msp() - 0x2000_0000
146 );
147
148 let ctap_response = try_get_ctap2_response(authenticator, data)?;
155 ctap_response.serialize(response);
156 Ok(())
157}
158
159#[inline(never)]
160fn try_get_ctap2_response<T, UP>(
161 authenticator: &mut Authenticator<UP, T>,
162 data: &[u8],
163) -> Result<ctap2::Response, u8>
164where
165 T: TrussedRequirements,
166 UP: UserPresence,
167{
168 authenticator
170 .state
171 .persistent
172 .load_if_not_initialised(&mut authenticator.trussed);
173
174 debug!(
175 "try_get CTAP2: remaining stack: {} bytes",
176 msp() - 0x2000_0000
177 );
178
179 let ctap_request = ctap2::Request::deserialize(data)
181 .inspect(|_request| {
182 info!("Received CTAP2 request {:?}", request_operation(_request));
183 trace!("CTAP2 request: {:?}", _request);
184 })
185 .map_err(|error| {
186 error!("Failed to deserialize CTAP2 request: {:?}", error);
187 trace!("The problematic input data was: {}", hex_str!(data));
188 error as u8
189 })?;
190 debug!("2a SP: {:X}", msp());
191 use ctap2::Authenticator;
192 authenticator
193 .call_ctap2(&ctap_request)
194 .inspect(|_response| {
195 info!("Sending CTAP2 response {:?}", response_operation(_response));
196 trace!("CTAP2 response: {:?}", _response);
197 })
198 .map_err(|error| {
199 info!("CTAP2 error: {:?}", error);
200 error as u8
201 })
202}
203
204#[allow(unused)]
205fn request_operation(request: &ctap2::Request) -> Option<ctap2::Operation> {
206 match request {
208 ctap2::Request::MakeCredential(_) => Some(ctap2::Operation::MakeCredential),
209 ctap2::Request::GetAssertion(_) => Some(ctap2::Operation::GetAssertion),
210 ctap2::Request::GetNextAssertion => Some(ctap2::Operation::GetNextAssertion),
211 ctap2::Request::GetInfo => Some(ctap2::Operation::GetInfo),
212 ctap2::Request::ClientPin(_) => Some(ctap2::Operation::ClientPin),
213 ctap2::Request::Reset => Some(ctap2::Operation::Reset),
214 ctap2::Request::CredentialManagement(_) => Some(ctap2::Operation::CredentialManagement),
215 ctap2::Request::Selection => Some(ctap2::Operation::Selection),
216 ctap2::Request::LargeBlobs(_) => Some(ctap2::Operation::LargeBlobs),
217 ctap2::Request::Vendor(operation) => Some(ctap2::Operation::Vendor(*operation)),
218 _ => None,
219 }
220}
221
222#[allow(unused)]
223fn response_operation(request: &ctap2::Response) -> Option<ctap2::Operation> {
224 match request {
225 ctap2::Response::MakeCredential(_) => Some(ctap2::Operation::MakeCredential),
226 ctap2::Response::GetAssertion(_) => Some(ctap2::Operation::GetAssertion),
227 ctap2::Response::GetNextAssertion(_) => Some(ctap2::Operation::GetNextAssertion),
228 ctap2::Response::GetInfo(_) => Some(ctap2::Operation::GetInfo),
229 ctap2::Response::ClientPin(_) => Some(ctap2::Operation::ClientPin),
230 ctap2::Response::Reset => Some(ctap2::Operation::Reset),
231 ctap2::Response::CredentialManagement(_) => Some(ctap2::Operation::CredentialManagement),
232 ctap2::Response::Selection => Some(ctap2::Operation::Selection),
233 ctap2::Response::LargeBlobs(_) => Some(ctap2::Operation::LargeBlobs),
234 ctap2::Response::Vendor => None,
235 _ => None,
236 }
237}