use core::error::Error;
use thiserror::Error;
use crate::Transport;
use crate::commands::{
SecureChannel, authenticate_ev2_first_aes, authenticate_ev2_first_lrp,
authenticate_ev2_non_first_aes, authenticate_ev2_non_first_lrp, change_file_settings,
change_key, change_master_key, get_card_uid, get_file_counters, get_file_settings,
get_file_settings_mac, get_key_version, get_tt_status, get_version, get_version_mac,
iso_read_binary, iso_select_ef_by_fid, iso_update_binary, read_data_full, read_data_mac,
read_data_plain, read_sig, read_sig_mac, select_ndef_application, set_configuration,
write_data_full, write_data_mac, write_data_plain,
};
use crate::crypto::originality::{self, OriginalityError};
use crate::crypto::suite::{AesSuite, LrpSuite, SessionSuite};
use crate::types::{
CommMode, Configuration, File, FileSettingsError, FileSettingsView, KeyNumber,
NonMasterKeyNumber, ResponseStatus, TagTamperStatusReadout, Uid, Version,
};
mod authenticated;
mod unauthenticated;
pub use authenticated::Authenticated;
pub use unauthenticated::Unauthenticated;
#[cfg(test)]
mod tests;
#[derive(Error, Debug)]
pub enum SessionError<E: Error + core::fmt::Debug> {
#[error(transparent)]
Transport(#[from] E),
#[error("error response: {0:?}")]
ErrorResponse(ResponseStatus),
#[error("unexpected response length: got {got}, expected {expected}")]
UnexpectedLength { got: usize, expected: usize },
#[error("invalid command parameter {parameter}: {reason} (got {value})")]
InvalidCommandParameter {
parameter: &'static str,
value: usize,
reason: &'static str,
},
#[error("APDU body too large: got {got}, maximum {max}")]
ApduBodyTooLarge { got: usize, max: usize },
#[error(transparent)]
FileSettings(FileSettingsError),
#[error("originality verification failed: {0:?}")]
OriginalityVerificationFailed(OriginalityError),
#[error("authentication mismatch")]
AuthenticationMismatch,
#[error("response MAC mismatch")]
ResponseMacMismatch,
}
pub struct Session<S> {
state: S,
ndef_selected: bool,
ef_selected: Option<u16>,
}
impl<S> Session<S> {
pub async fn get_selected_uid<T: Transport>(
&self,
transport: &mut T,
) -> Result<Uid, SessionError<T::Error>> {
let data = transport.get_uid().await?;
let data = data.as_ref();
match data.len() {
7 => {
let mut uid = [0u8; 7];
uid.copy_from_slice(data);
Ok(Uid::Fixed(uid))
}
4 => {
let mut uid = [0u8; 4];
uid.copy_from_slice(data);
Ok(Uid::Random(uid))
}
got => Err(SessionError::UnexpectedLength { got, expected: 7 }),
}
}
}