use super::{
Authenticated, AuthenticationState, Card, CardIoDefault, Unauthenticated, command,
command_encrypted_request,
};
use crate::{ApplicationId, Error, Instruction, Key, KeyCount, KeySettings, StatusCode, io};
impl<'card, IoBackendT, AuthenticationStateT> Card<'card, IoBackendT, AuthenticationStateT>
where
AuthenticationStateT: AuthenticationState,
IoBackendT: io::Backend,
Self: CardIoDefault<IoBackendT>,
{
pub async fn list_applications<'a>(
&mut self,
out: &'a mut [u8],
) -> Result<&'a [ApplicationId], Error<IoBackendT::Error>> {
let (status_code, response) = self
.default_exchange(out, &[Instruction::GetApplicationIdList as u8])
.await?;
if status_code != StatusCode::Ack {
return Err(Error::BadStatusCode(status_code));
}
let (application_ids, &[]) = response.as_chunks::<3>() else {
return Err(Error::BadSize);
};
Ok(application_ids)
}
pub async fn get_current_application(&self) -> ApplicationId {
self.application_id
}
}
impl<'card, IoBackendT> Card<'card, IoBackendT, Authenticated>
where
IoBackendT: io::Backend,
{
pub async fn select_application<'a>(
self,
out: &'a mut [u8],
application_id: ApplicationId,
) -> Result<Card<'card, IoBackendT, Unauthenticated>, Error<IoBackendT::Error>> {
let card = self.to_unauthenticated();
card.select_application(out, application_id).await
}
pub async fn create_application(
&mut self,
out: &mut [u8],
application_id: ApplicationId,
key_settings: KeySettings,
key_number: KeyCount,
) -> Result<(), Error<IoBackendT::Error>> {
let (status_code, response) = command!(self, out, {
instruction: Instruction = Instruction::CreateApplication,
application_id: ApplicationId = application_id,
key_settings: u8 = key_settings.as_u8()?,
key_number: u8 = key_number.as_u8()?
}, 6, []);
if !response.is_empty() {
return Err(Error::BadSize);
};
if status_code != StatusCode::Ack {
return Err(Error::BadStatusCode(status_code));
}
Ok(())
}
pub async fn delete_application(
&mut self,
out: &mut [u8],
application_id: ApplicationId,
) -> Result<(), Error<IoBackendT::Error>> {
let (status_code, response) = command!(self, out, {
instruction: Instruction = Instruction::DeleteApplication,
application_id: ApplicationId = application_id
}, 4, []);
if !response.is_empty() {
return Err(Error::BadSize);
};
if status_code != StatusCode::Ack {
return Err(Error::BadStatusCode(status_code));
}
Ok(())
}
pub async fn change_default_application_key(
&mut self,
out: &mut [u8],
key: Key,
key_version: u8,
) -> Result<(), Error<IoBackendT::Error>> {
let mut default_key = [0; 24];
match key {
Key::Aes(key) => default_key[..16].copy_from_slice(&key),
Key::Des(key) => default_key[..8].copy_from_slice(&key),
}
let (status_code, response) = command_encrypted_request!(self, out, {
instruction: Instruction = Instruction::SetConfiguration,
configuration_key: u8 = 0x01
}, 2, [&default_key, &[key_version]]);
if !response.is_empty() {
return Err(Error::BadSize);
};
if status_code != StatusCode::Ack {
return Err(Error::BadStatusCode(status_code));
}
Ok(())
}
}
impl<'card, IoBackendT> Card<'card, IoBackendT, Unauthenticated>
where
IoBackendT: io::Backend,
{
pub async fn select_application(
mut self,
out: &mut [u8],
application_id: ApplicationId,
) -> Result<Self, Error<IoBackendT::Error>> {
let (status_code, response) = command!((&mut self), out, {
instruction: Instruction = Instruction::SelectApplication,
application_id: ApplicationId = application_id
}, 4, []);
if !response.is_empty() {
return Err(Error::BadSize);
};
if status_code != StatusCode::Ack {
return Err(Error::BadStatusCode(status_code));
}
self.application_id = application_id;
Ok(self)
}
}