Files
apdu-dispatch/tests/dispatch.rs
2023-02-14 10:45:07 +01:00

1109 lines
47 KiB
Rust

use apdu_dispatch::app::{App, Result as AppResult};
use apdu_dispatch::dispatch;
use apdu_dispatch::Command;
use apdu_dispatch::{interchanges, response};
use hex_literal::hex;
use interchange::Channel;
use iso7816::Status;
#[macro_use]
extern crate serial_test;
#[macro_use]
extern crate delog;
generate_macros!();
#[derive(Debug)]
pub struct StdoutFlusher {}
impl delog::Flusher for StdoutFlusher {
fn flush(&self, logs: &str) {
print!("{logs}");
}
}
delog!(Delogger, 25 * 1024, 25 * 1024, StdoutFlusher);
static STDOUT_FLUSHER: StdoutFlusher = StdoutFlusher {};
#[allow(dead_code)]
enum TestInstruction {
Echo = 0x10,
Add = 0x11,
GetData = 0x12,
}
fn dump_hex(data: &[u8]) {
for b in data {
print!("{b:02X} ");
}
println!();
}
pub struct TestApp1 {}
impl iso7816::App for TestApp1 {
fn aid(&self) -> iso7816::Aid {
iso7816::Aid::new(&hex!("0A01000001"))
}
}
// This app echos to Ins code 0x10
impl App<{ apdu_dispatch::command::SIZE }, { apdu_dispatch::response::SIZE }> for TestApp1 {
fn select(&mut self, _apdu: &Command, _reply: &mut response::Data) -> AppResult {
Ok(())
}
fn deselect(&mut self) {}
fn call(
&mut self,
_: dispatch::Interface,
apdu: &Command,
reply: &mut response::Data,
) -> AppResult {
println!("TestApp1::call");
match apdu.instruction().into() {
0x10 => {
// Just echo 5x 0's for the request apdu header
reply.push(0).unwrap();
reply.push(0).unwrap();
reply.push(0).unwrap();
reply.push(0).unwrap();
reply.push(0).unwrap();
reply.extend_from_slice(apdu.data()).unwrap();
Ok(())
}
// For measuring the stack burden of dispatch
0x15 => {
let buf = heapless::Vec::new();
let addr = (&buf as *const response::Data) as u32;
reply.extend_from_slice(&addr.to_be_bytes()).unwrap();
Ok(())
}
// Testing a response larger than the interchange's size
0x21 => {
reply
.extend_from_slice(&[10; interchanges::SIZE + 1])
.unwrap();
Ok(())
}
0x22 => {
reply
.extend_from_slice(&[10; interchanges::SIZE - 2])
.unwrap();
Ok(())
}
0x23 => {
reply
.extend_from_slice(&[10; interchanges::SIZE - 1])
.unwrap();
Ok(())
}
0x24 => {
reply.extend_from_slice(&[10; interchanges::SIZE]).unwrap();
Ok(())
}
_ => Err(Status::InstructionNotSupportedOrInvalid),
}
}
}
pub struct TestApp2 {}
impl iso7816::App for TestApp2 {
fn aid(&self) -> iso7816::Aid {
iso7816::Aid::new(&hex!("0A01000002"))
}
}
// This app echos to Ins code 0x20
impl App<{ apdu_dispatch::command::SIZE }, { apdu_dispatch::response::SIZE }> for TestApp2 {
fn select(&mut self, _apdu: &Command, _reply: &mut response::Data) -> AppResult {
Ok(())
}
fn deselect(&mut self) {}
fn call(
&mut self,
_: dispatch::Interface,
apdu: &Command,
reply: &mut response::Data,
) -> AppResult {
println!("TestApp2::call");
match apdu.instruction().into() {
0x20 => {
reply.push(0).unwrap();
reply.push(0).unwrap();
reply.push(0).unwrap();
reply.push(0).unwrap();
reply.push(0).unwrap();
reply.extend_from_slice(apdu.data()).unwrap();
Ok(())
}
0x30 => {
// Return 2KB bytes of byte-truncated fibonacci
reply.extend_from_slice(&[0, 1, 1]).unwrap();
for i in 3..2048 {
let next = ((reply[i - 1] as u32 + reply[i - 2] as u32) & 0xff) as u8;
reply.push(next).unwrap();
}
Ok(())
}
_ => Err(Status::InstructionNotSupportedOrInvalid),
}
}
}
pub struct PanicApp {}
impl iso7816::App for PanicApp {
fn aid(&self) -> iso7816::Aid {
iso7816::Aid::new(&hex!("0A01000003"))
}
}
// This app echos to Ins code 0x20
impl App<{ apdu_dispatch::command::SIZE }, { apdu_dispatch::response::SIZE }> for PanicApp {
fn select(&mut self, _apdu: &Command, _reply: &mut response::Data) -> AppResult {
panic!("Dont call the panic app");
}
fn deselect(&mut self) {
panic!("Dont call the panic app");
}
fn call(
&mut self,
_: dispatch::Interface,
_apdu: &Command,
_reply: &mut response::Data,
) -> AppResult {
panic!("Dont call the panic app");
}
}
fn run_apdus(apdu_response_pairs: &[&[u8]]) {
assert!(!apdu_response_pairs.is_empty());
assert!((apdu_response_pairs.len() & 1) == 0);
Delogger::init_default(delog::LevelFilter::Info, &STDOUT_FLUSHER).ok();
let contact = Channel::new();
let (mut contact_requester, contact_responder) = contact
.split()
.expect("could not setup ccid ApduInterchange");
let contactless = Channel::new();
let (_contactless_requester, contactless_responder) = contactless
.split()
.expect("could not setup iso14443 ApduInterchange");
let mut apdu_dispatch =
apdu_dispatch::dispatch::ApduDispatch::new(contact_responder, contactless_responder);
Delogger::flush();
let mut app0 = PanicApp {};
let mut app1 = TestApp1 {};
let mut app2 = PanicApp {};
let mut app3 = TestApp2 {};
let mut app4 = PanicApp {};
// for i in 0..apdu_response_pairs.len() {
// print!("- ");
// dump_hex(apdu_response_pairs[i]);
// }
for i in (0..apdu_response_pairs.len()).step_by(2) {
let raw_req = apdu_response_pairs[i];
let raw_expected_res = apdu_response_pairs[i + 1];
// let command = Command::try_from(raw_req).unwrap();
// let expected_response = Response::Data::from_slice(&raw_res);
print!("<< ");
dump_hex(raw_req);
contact_requester
.request(interchanges::Data::from_slice(raw_req).unwrap())
.expect("could not deposit command");
apdu_dispatch.poll(&mut [&mut app0, &mut app1, &mut app2, &mut app3, &mut app4]);
Delogger::flush();
let response = contact_requester.take_response().unwrap();
print!(">> ");
dump_hex(&response);
if raw_expected_res != response.as_slice() {
print!("expected: ");
dump_hex(raw_expected_res);
print!("got: ");
dump_hex(&response);
panic!("Expected responses do not match");
}
}
}
#[test]
#[serial]
fn malformed_apdus() {
run_apdus(&[
// Too short
&hex!("00"),
&hex!("6F00"),
// Too short
&hex!("0000"),
&hex!("6F00"),
// Too short
&hex!("000000"),
&hex!("6F00"),
// Wrong length
&hex!("0000000010010101"),
&hex!("6F00"),
// Extra data
&hex!("000000000501010101010101010101010101"),
&hex!("6F00"),
// Invalid CLA
&hex!("FF000000"),
&hex!("6F00"),
// Invalid extended length
&hex!("00000000ff00050101010101"),
&hex!("6F00"),
// sanity check with Valid APDU with extended length
&hex!("000000000000050101010101"),
&hex!("6A82"),
])
}
#[test]
#[serial]
fn select_1() {
run_apdus(&[
// Select
&hex!("00A40400 05 0A01000001"),
// Ok
&hex!("9000"),
])
}
#[test]
#[serial]
fn select_2() {
run_apdus(&[
// Select
&hex!("00A40400 05 0A01000002"),
// Ok
&hex!("9000"),
])
}
#[test]
#[serial]
fn select_not_found() {
run_apdus(&[
// Select
&hex!("00A40400 05 0A01000100"),
// Not found
&hex!("6A82"),
])
}
#[test]
#[serial]
fn select_bad_aid() {
// Select with an incorrect AID shouldn't crash the application
run_apdus(&[
// Select 1
&hex!("00A40400"),
&hex!("6A80"),
])
}
#[test]
#[serial]
fn echo_1() {
run_apdus(&[
// Select
&hex!("00A40400 05 0A01000001"),
// Ok
&hex!("9000"),
// Echo
&hex!("00100000 05 0102030405 00"),
// Echo + Ok
&hex!("0000000000 01020304059000"),
])
}
#[test]
#[serial]
fn echo_with_cla_bits_set() {
run_apdus(&[
// Select
&hex!("00A40400 05 0A01000001"),
// Ok
&hex!("9000"),
// Echo
&hex!("80100000 05 0102030405 00"),
// Echo + Ok
&hex!("0000000000 0102030405 9000"),
])
}
#[test]
#[serial]
fn echo_wrong_instruction() {
run_apdus(&[
// Select
&hex!("00A40400 05 0A01000001"),
// Ok
&hex!("9000"),
// Echo
&hex!("00200000 05 0102030405 00"),
// Wrong Ins
&hex!("6d00"),
])
}
#[test]
#[serial]
fn echo_2() {
run_apdus(&[
// Select
&hex!("00A40400 05 0A01000002"),
// Ok
&hex!("9000"),
// Echo
&hex!("00200000 05 0102030405 00"),
// Echo + Ok
&hex!("0000000000 0102030405 9000"),
])
}
#[test]
#[serial]
fn echo_wrong_instruction_2() {
run_apdus(&[
// Select
&hex!("00A40400 05 0A01000002"),
// Ok
&hex!("9000"),
// Echo
&hex!("00100000 05 0102030405 00"),
// Wrong Ins
&hex!("6d00"),
])
}
#[test]
#[serial]
fn unsolicited_instruction() {
run_apdus(&[
// Echo
&hex!("00100000 05 0102030405"),
// Not found
&hex!("6a82"),
])
}
#[test]
#[serial]
fn deselect() {
run_apdus(&[
// Select 1
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
// Echo 1
&hex!("00100000 05 0102030405 00"),
&hex!("0000000000 0102030405 9000"),
// Select 2
&hex!("00A40400 05 0A01000002"),
&hex!("9000"),
// Echo 1
&hex!("00100000 05 0102030405 00"),
&hex!("6d00"),
])
}
#[test]
#[serial]
fn extended_length_echo() {
run_apdus(
&[
// Select 1
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
// To be echo'd
&hex!("00100000 000123
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 9 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 10 */ 01 01 01
0000
"),
// echo Success
&hex!("0000000000
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 9 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 10 */ 01 01 01
9000
")
]
)
}
#[test]
#[serial]
fn chained_apdu_1() {
run_apdus(
&[
// Select 1
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
// Set chaining bit
&hex!("10200000FF
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
"),
&hex!("9000"),
// Set chaining bit
&hex!("10200000FF
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
"),
&hex!("9000"),
// Send last command
&hex!("0010000020
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
00
"),
// Expect 0xff + 0xff + 0x20 + 5 == 547 bytes back
// Echo chunk + remaining
&hex!("
/* 1 8 16 24 32 */
/* 1 */ 00 00 00 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
6100
"),
// Get Response
&hex!("00C00000 00"),
// Echo chunk + remaining
&hex!("
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
6123
"),
// Get Response
&hex!("00C00000 00"),
// Echo chunk + success
&hex!("
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01
9000
"),
// Get Response
&hex!("00C00000 00"),
// Error
&hex!("6F00"),
]
)
}
#[test]
#[serial]
fn chained_response() {
run_apdus(
&[
// Select 1
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
// Set chaining bit
&hex!("10200000FF
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
"),
&hex!("9000"),
// Set chaining bit
&hex!("10200000FF
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
"),
&hex!("9000"),
// Send last command
&hex!("0010000040
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
23 // Ask for less than 256
"),
// Echo chunk + remaining
&hex!("
/* 1 8 16 24 32 */
/* 1 */ 00 00 00 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01
6100
"),
// Get Response
&hex!("00C00000 00"),
// Echo chunk + remaining
&hex!("
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
6100
"),
// Get Response
&hex!("00C00000 00"),
// Echo chunk + success
&hex!("
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
6120
"),
// Get Response
&hex!("00C00000 00"),
&hex!("
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
9000
"),
// Get Response
&hex!("00C00000 00"),
// Error
&hex!("6F00"),
]
)
}
#[test]
#[serial]
fn multiple_chained_apdu_1() {
run_apdus(
&[
// Select 1
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
// Set chaining bit
&hex!(" 10200000ff
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
"),
&hex!("9000"),
// Send last command
&hex!(" 0010000020
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
00
"),
// Expect 0xff + 0xff + 0x20 + 5 == 292 bytes back
// Data + remaining bytes
&hex!("
/* 1 8 16 24 32 */
/* 1 */ 00 00 00 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
6124
"),
// Get Response
&hex!("00C00000 00"),
// Echo chunk + success
&hex!("
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01
9000
"),
// Check short commands still work
// Echo 1
&hex!("00100000 05 0102030405 00"),
&hex!("0000000000 01020304059000"),
// Echo 2
&hex!("00200000 05 0102030405 00"),
&hex!("6d00"),
// Check chaining command still works
// Set chaining bit
&hex!("10200000FF
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
"),
&hex!("9000"),
// Send last command
&hex!("0010000020
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
00
"),
// Expect 0xff + 0xff + 0x20 + 5 == 292 bytes back
// Data + remaining bytes
&hex!("
/* 1 8 16 24 32 */
/* 1 */ 00 00 00 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
6124
"),
// Get Response
&hex!("00C00000 00"),
// Echo chunk + success
&hex!("
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01
9000
"),
]
)
}
#[test]
#[serial]
fn test_chained_fibonacci_response() {
let mut expected = response::Data::new();
expected.extend_from_slice(&[0, 1, 1]).unwrap();
for i in 3..2048 {
let next = ((expected[i - 1] as u32 + expected[i - 2] as u32) & 0xff) as u8;
expected.push(next).unwrap();
}
// expected_reply.extend_from_slice(&[0x90, 0x00]).unwrap();
fn apdu_res_chunk(data: &response::Data, start: &mut usize, size: usize) -> response::Data {
let mut chunk = response::Data::new();
let end = *start + size;
chunk.extend_from_slice(&data[*start..end]).unwrap();
if data[*start..].len() > 256 {
chunk.push(0x61).unwrap();
if data[end..].len() > 255 {
chunk.push(0).unwrap();
} else {
chunk.push(data[end..].len() as u8).unwrap();
}
} else {
chunk.push(0x90).unwrap();
chunk.push(0x00).unwrap();
}
*start += size;
chunk
}
let mut start = 0;
let mut start2 = 0;
run_apdus(
&[
// Select 2
&hex!("00A40400 05 0A01000002"),
&hex!("9000"),
// Set chaining bit, command to get long fibonacci back
&hex!("10300000FF
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
"),
&hex!("9000"),
// Send last command
&hex!("0030000020
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
00
"),
apdu_res_chunk(&expected, &mut start, 256).as_slice(),
&hex!("00C00000 00"),
apdu_res_chunk(&expected, &mut start, 256).as_slice(),
&hex!("00C00000 00"),
apdu_res_chunk(&expected, &mut start, 256).as_slice(),
&hex!("00C00000 00"),
apdu_res_chunk(&expected, &mut start, 256).as_slice(),
&hex!("00C00000 00"),
apdu_res_chunk(&expected, &mut start, 256).as_slice(),
&hex!("00C00000 00"),
apdu_res_chunk(&expected, &mut start, 256).as_slice(),
&hex!("00C00000 00"),
apdu_res_chunk(&expected, &mut start, 256).as_slice(),
&hex!("00C00000 00"),
apdu_res_chunk(&expected, &mut start, 256).as_slice(),
// chaining bit, command to get long fibonacci back
&hex!("10300000 05 0102030405"),
&hex!("9000 "),
&hex!("00300000 05 0102030405 00"),
apdu_res_chunk(&expected, &mut start2, 256).as_slice(),
&hex!("00C00000 00"),
apdu_res_chunk(&expected, &mut start2, 256).as_slice(),
&hex!("00C00000 00"),
apdu_res_chunk(&expected, &mut start2, 256).as_slice(),
&hex!("00C00000 00"),
apdu_res_chunk(&expected, &mut start2, 256).as_slice(),
&hex!("00C00000 00"),
apdu_res_chunk(&expected, &mut start2, 256).as_slice(),
&hex!("00C00000 00"),
apdu_res_chunk(&expected, &mut start2, 256).as_slice(),
&hex!("00C00000 00"),
apdu_res_chunk(&expected, &mut start2, 256).as_slice(),
&hex!("00C00000 00"),
apdu_res_chunk(&expected, &mut start2, 256).as_slice(),
]
)
}
#[test]
#[serial]
fn multiple_chained_apdu_interruption() {
run_apdus(
&[
// Select 1
&hex!("00A40400050A01000001"),
&hex!("9000"),
// Set chaining bit
&hex!("10200000FF
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
"),
&hex!("9000"),
// Send last command
&hex!("0010000020
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
00
"),
// Expect 0xff + 0xff + 0x20 + 5 == 292 bytes back
// Data + remaining bytes
&hex!("
/* 1 8 16 24 32 */
/* 1 */ 00 00 00 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
6124
"),
// Just ignore those 36 bytes and do something different
// Echo 1
&hex!("00100000 05 0102030405 00"),
&hex!("0000000000 0102030405 9000"),
// GetResponse no longer works
&hex!("00C00000"),
&hex!("6F00 "),
// Check that new chaining transaction works
&hex!("10200000FF
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
"),
&hex!("9000"),
// Send last command
&hex!("0010000020
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
00
"),
// Expect 0xff + 0xff + 0x20 + 5 == 292 bytes back
// Data + remaining bytes
&hex!("
/* 1 8 16 24 32 */
/* 1 */ 00 00 00 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
6124
"),
]
)
}
#[test]
#[serial]
fn chaining_with_unknown_class_range() {
run_apdus(
&[
// Select 1
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
// Set chaining bit + upper range bit
&hex!("90200000FF
/* 1 8 16 24 32 */
/* 1 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 2 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 3 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 4 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 5 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 6 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 7 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
/* 8 */ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
"),
&hex!("9000"),
]
)
}
#[test]
#[serial]
fn send_select_preceded_with_zero_chained_data() {
// Sending a select after chaining 0 bytes should result in successful select operation
run_apdus(&[
// Chaining zero data
&hex!("9060000000"),
&hex!("9000"),
// Select 1
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
])
}
#[test]
#[serial]
fn response_larger_than_interchange() {
// Sending a select after chaining 0 bytes should result in successful select operation
let mut response1 = vec![0x0A; interchanges::SIZE - 2];
response1.extend_from_slice(&hex!("6103"));
let mut response2 = vec![0x0A; interchanges::SIZE - 2];
response2.extend_from_slice(&hex!("9000"));
let mut response3 = vec![0x0A; interchanges::SIZE - 2];
response3.extend_from_slice(&hex!("6101"));
let mut response4 = vec![0x0A; interchanges::SIZE - 2];
response4.extend_from_slice(&hex!("6102"));
run_apdus(&[
// Select 1
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
&hex!("00210000 00ffff"),
&response1,
// Get Response
&hex!("00C00000 00"),
&hex!("0A0A0A 9000"),
&hex!("00220000 00ffff"),
&response2,
&hex!("00230000 00ffff"),
&response3,
// Get Response
&hex!("00C00000 00"),
&hex!("0A 9000"),
&hex!("00240000 00ffff"),
&response4,
// Get Response
&hex!("00C00000 00"),
&hex!("0A0A 9000"),
])
}
#[test]
#[serial]
fn check_stack_burden() {
let contact = Channel::new();
let (mut contact_requester, contact_responder) = contact
.split()
.expect("could not setup ccid ApduInterchange");
let contactless = Channel::new();
let (_contactless_requester, contactless_responder) = contactless
.split()
.expect("could not setup iso14443 ApduInterchange");
let mut apdu_dispatch =
apdu_dispatch::dispatch::ApduDispatch::new(contact_responder, contactless_responder);
let mut app1 = TestApp1 {};
contact_requester
.request(interchanges::Data::from_slice(&hex!("00A40400050A01000001")).unwrap())
.expect("could not deposit command");
apdu_dispatch.poll(&mut [&mut app1]);
let response = contact_requester.take_response().unwrap();
print!(">> ");
dump_hex(&response);
contact_requester
.request(interchanges::Data::from_slice(&hex!("0015000000")).unwrap())
.expect("could not deposit command");
apdu_dispatch.poll(&mut [&mut app1]);
let response = contact_requester.take_response().unwrap();
print!(">> ");
dump_hex(&response);
let payload: [u8; 4] = [response[0], response[1], response[2], response[3]];
let min_stack = u32::from_be_bytes(payload);
let max_stack = (&response as *const interchanges::Data) as u32;
// Last checked:
// Burden: 43744 bytes with Large apdu for Command & Response, not returning Data.
println!("Burden: {} bytes", max_stack - min_stack);
// Uncomment to see stack burden printed out
// assert!(false);
}