use apdu_app::Interface;
use ctap_types::{serde::error::Error as SerdeError, Error};
use heapless::VecView;
use iso7816::{command::CommandView, Status};
use crate::{Authenticator, TrussedRequirements, UserPresence};
pub enum CtapMappingError {
InvalidCommand(u8),
ParsingError(SerdeError),
}
impl From<CtapMappingError> for Error {
fn from(mapping_error: CtapMappingError) -> Error {
match mapping_error {
CtapMappingError::InvalidCommand(_cmd) => Error::InvalidCommand,
CtapMappingError::ParsingError(cbor_error) => match cbor_error {
SerdeError::SerdeMissingField => Error::MissingParameter,
_ => Error::InvalidCbor,
},
}
}
}
impl<UP, T> apdu_app::App for Authenticator<UP, T>
where
UP: UserPresence,
T: TrussedRequirements,
{
fn select(
&mut self,
interface: Interface,
_: CommandView<'_>,
reply: &mut VecView<u8>,
) -> apdu_app::Result {
if interface != Interface::Contactless {
return Err(Status::ConditionsOfUseNotSatisfied);
}
reply.extend_from_slice(b"U2F_V2").unwrap();
Ok(())
}
fn deselect(&mut self) {}
fn call(
&mut self,
interface: Interface,
apdu: CommandView<'_>,
response: &mut VecView<u8>,
) -> apdu_app::Result {
if interface != Interface::Contactless {
return Err(Status::ConditionsOfUseNotSatisfied);
}
let instruction: u8 = apdu.instruction().into();
match instruction {
0x00..=0x02 => super::try_handle_ctap1(self, apdu, response)?,
_ => {
match ctaphid_app::Command::try_from(instruction) {
Ok(ctaphid_app::Command::Cbor) => {
super::handle_ctap2(self, apdu.data(), response)
}
Ok(ctaphid_app::Command::Msg) => super::try_handle_ctap1(self, apdu, response)?,
Ok(ctaphid_app::Command::Deselect) => apdu_app::App::deselect(self),
_ => {
info!("Unsupported ins for fido app {:02x}", instruction);
return Err(iso7816::Status::InstructionNotSupportedOrInvalid);
}
}
}
};
Ok(())
}
}