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