diff --git a/src/desfire/desfire.rs b/src/desfire/desfire.rs index 499615c..911c5c7 100644 --- a/src/desfire/desfire.rs +++ b/src/desfire/desfire.rs @@ -51,6 +51,41 @@ impl Desfire { response.check() } + pub fn get_application_ids_cmd(&self) -> Result { + Ok(APDUCommand { + case: IsoCase::Case2Short, + cla: 0x90, + ins: APDUInstructions::GetApplicationIds as u8, + ..Default::default() + }) + } + + /// Get all application ids on the defire token + pub fn get_application_ids(&self) -> Result> { + let cmd_get_application_ids = self.get_application_ids_cmd()?; + + let response = self + .card + .as_ref() + .unwrap() + .transmit(cmd_get_application_ids)?; + response.check()?; + + if let Some(body) = response.body { + Ok(body + // application ids are 3 byte long MSB first values + // TODO: use `slice::array_chunks` when its stable + .chunks_exact(3) + // pad with one byte extra byte to it it into an u32 + .map(|chunk| u32::from_le_bytes([chunk[0], chunk[1], chunk[2], 0x0])) + .collect()) + } else { + // body is empty, there are no applications on this card + // except the picc 0x000000 application + Ok(vec![]) + } + } + /// Authenticate to PICC, with ISO Authenticate for DES Key /// /// Arguments: @@ -1015,6 +1050,31 @@ mod tests { desfire.select_application(0xff000000).unwrap(); } + #[test] + fn get_application_ids() { + let mut mock = MockVirtualCard::new(); + mock.expect_transmit() + .withf(|x: &APDUCommand| { + (Vec::::try_from(x.clone()).unwrap()) == vec![0x90, 0x6a, 0x00, 0x00, 0x00] + }) + .return_once(move |_| { + Ok(APDUResponse { + body: Some(vec![0x01, 0x00, 0x00, 0x02, 0x00, 0x00]), + sw1: 0x91, + sw2: 0x00, + }) + }); + + let desfire = Desfire { + card: Some(Box::new(mock)), + cbc_iv: None, + session_key: None, + }; + + let ids = desfire.get_application_ids().unwrap(); + assert_eq!(ids, vec![1, 2]) + } + #[test] #[ignore] fn select_application_hardware() {