use std::fmt;
#[derive(Clone)]
pub struct APDU {
pub cla: u8,
pub ins: u8,
pub p1: u8,
pub p2: u8,
pub data: Vec<u8>,
pub iapdus: Vec<Vec<u8>>,
}
impl fmt::Debug for APDU {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut start = String::from("[");
for iapdu in &self.iapdus {
let mut resp = String::from("[");
for value in iapdu {
let hex = format!("0x{:X?}, ", value);
resp.push_str(&hex[..]);
}
resp.push_str("]");
start.push_str(&resp[..]);
}
start.push_str("]");
f.debug_struct("APDU")
.field("CLA", &self.cla)
.field("INS", &self.ins)
.field("P1", &self.p1)
.field("P2", &self.p2)
.field("ipapdus", &start)
.finish()
}
}
impl APDU {
pub fn new(cla: u8, ins: u8, p1: u8, p2: u8, inputdata: Option<Vec<u8>>) -> Self {
let mut index = 1;
let mut oindex = 0;
let mut _cindex = 0;
let data = match inputdata {
Some(data) => data,
None => vec![],
};
let length = data.len();
let mut iapdus = Vec::new();
while data.len() > index * 254 {
_cindex = index * 254;
let mut res = vec![0x10, ins, p1, p2, 254];
res.extend(data[oindex.._cindex].iter().copied());
iapdus.push(res);
index += 1;
oindex = _cindex;
}
let mut res = vec![cla, ins, p1, p2, (data.len() - oindex) as u8];
res.extend(data[oindex..length].iter().copied());
iapdus.push(res);
APDU {
cla,
ins,
p1,
p2,
data,
iapdus,
}
}
pub fn create_big_apdu(cla: u8, ins: u8, p1: u8, p2: u8, data: Vec<u8>) -> Self {
let len = data.len() as u16;
let mut iapdus = Vec::new();
let mut res = vec![cla, ins, p1, p2];
if len > 0xFF {
let length = len.to_be_bytes();
res.push(0x00);
res.push(length[0]);
res.push(length[1]);
} else {
let len = len as u8;
res.push(len);
}
res.extend(data.iter());
iapdus.push(res);
APDU {
cla,
ins,
p1,
p2,
data,
iapdus,
}
}
}
impl<'a> IntoIterator for &'a APDU {
type Item = Vec<u8>;
type IntoIter = APDUIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
APDUIterator {
apdu: self,
index: 0,
}
}
}
pub struct APDUIterator<'a> {
apdu: &'a APDU,
index: usize,
}
impl<'a> Iterator for APDUIterator<'a> {
type Item = Vec<u8>;
fn next(&mut self) -> Option<Vec<u8>> {
if self.index < self.apdu.iapdus.len() {
let res = self.apdu.iapdus[self.index].clone();
self.index += 1;
Some(res)
} else {
None
}
}
}
pub fn create_apdu_select_openpgp() -> APDU {
APDU::new(
0x00,
0xA4,
0x04,
0x00,
Some(vec![0xD2, 0x76, 0x00, 0x01, 0x24, 0x01]),
)
}
pub fn create_apdu_get_url() -> APDU {
APDU::new(0x00, 0xCA, 0x5F, 0x50, None)
}
pub fn create_apdu_verify_pw1_for_others(pin: Vec<u8>) -> APDU {
APDU::new(0x00, 0x20, 0x00, 0x82, Some(pin))
}
pub fn create_apdu_verify_pw1_for_sign(pin: Vec<u8>) -> APDU {
APDU::new(0x00, 0x20, 0x00, 0x81, Some(pin))
}
pub fn create_apdu_verify_pw3(pin: Vec<u8>) -> APDU {
APDU::new(0x00, 0x20, 0x00, 0x83, Some(pin))
}
pub fn create_apdu_change_pw1(pin: Vec<u8>) -> APDU {
APDU::new(0x00, 0x2C, 0x02, 0x81, Some(pin))
}
pub fn create_apdu_change_pw3(pin: Vec<u8>, newpin: Vec<u8>) -> APDU {
let mut fullpin = pin.clone();
fullpin.extend(newpin.iter());
APDU::new(0x00, 0x24, 0x00, 0x83, Some(fullpin))
}
pub fn create_apdu_personal_information() -> APDU {
APDU::new(0x00, 0xCA, 0x00, 0x65, None)
}
pub fn create_apdu_get_aid() -> APDU {
APDU::new(0x00, 0xCA, 0x00, 0x4F, None)
}
pub fn create_apdu_get_application_data() -> APDU {
APDU::new(0x00, 0xCA, 0x00, 0x6E, None)
}
pub fn create_apdu_get_security_template() -> APDU {
APDU::new(0x00, 0xCA, 0x00, 0x7A, None)
}
pub fn create_apdu_for_decryption(data: Vec<u8>) -> APDU {
APDU::new(0x00, 0x2A, 0x80, 0x86, Some(data))
}
pub fn create_apdu_for_reading(length: u8) -> APDU {
let cla = 0x00;
let ins = 0xC0;
let p1 = 0x00;
let p2 = 0x00;
let mut iapdus = Vec::new();
let res = vec![0x00, 0xC0, 0x00, 0x00, length];
iapdus.push(res);
let data: Vec<u8> = Vec::new();
APDU {
cla,
ins,
p1,
p2,
data,
iapdus,
}
}
pub fn create_apdu_management_selection() -> APDU {
APDU::new(
0x00,
0xA4,
0x04,
0x00,
Some(vec![0xA0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17]),
)
}
pub fn create_apdu_management_read_config() -> APDU {
APDU::new(0x00, 0x1D, 0x00, 0x00, None)
}
pub fn create_usb_otp_enable() -> APDU {
APDU::new(
0x00,
0x1C,
0x00,
0x00,
Some(vec![
0x0A, 0x0C, 0x00, 0x03, 0x02, 0x02, 0x3B, 0x0E, 0x02, 0x02, 0x3B,
]),
)
}
pub fn create_usb_otp_disable() -> APDU {
APDU::new(
0x00,
0x1C,
0x00,
0x00,
Some(vec![
0x0A, 0x0C, 0x00, 0x03, 0x02, 0x02, 0x3A, 0x0E, 0x02, 0x02, 0x3B,
]),
)
}
pub fn create_apdu_for_algo_attributes(data: Vec<u8>) -> APDU {
APDU::create_big_apdu(0x00, 0xDA, 0x00, 0xC2, data)
}