use apdu_dispatch::app::{App, CommandView, Result as AppResult};
use apdu_dispatch::dispatch;
use apdu_dispatch::{interchanges, response};
use heapless::VecView;
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"))
}
}
impl App for TestApp1 {
fn select(
&mut self,
_interface: dispatch::Interface,
_apdu: CommandView<'_>,
_reply: &mut VecView<u8>,
) -> AppResult {
Ok(())
}
fn deselect(&mut self) {}
fn call(
&mut self,
_: dispatch::Interface,
apdu: CommandView<'_>,
reply: &mut VecView<u8>,
) -> AppResult {
println!("TestApp1::call");
match apdu.instruction().into() {
0x10 => {
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(())
}
0x15 => {
let buf = heapless::Vec::<u8, { response::SIZE }>::new();
let addr = (&buf as *const VecView<u8>).addr() as u32;
reply.extend_from_slice(&addr.to_be_bytes()).unwrap();
Ok(())
}
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"))
}
}
impl App for TestApp2 {
fn select(
&mut self,
_interface: dispatch::Interface,
_apdu: CommandView<'_>,
_reply: &mut VecView<u8>,
) -> AppResult {
Ok(())
}
fn deselect(&mut self) {}
fn call(
&mut self,
_: dispatch::Interface,
apdu: CommandView<'_>,
reply: &mut VecView<u8>,
) -> 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 => {
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"))
}
}
impl App for PanicApp {
fn select(
&mut self,
_interface: dispatch::Interface,
_apdu: CommandView<'_>,
_reply: &mut VecView<u8>,
) -> AppResult {
panic!("Dont call the panic app");
}
fn deselect(&mut self) {
panic!("Dont call the panic app");
}
fn call(
&mut self,
_: dispatch::Interface,
_apdu: CommandView<'_>,
_reply: &mut VecView<u8>,
) -> 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()).step_by(2) {
let raw_req = apdu_response_pairs[i];
let raw_expected_res = apdu_response_pairs[i + 1];
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(&[
&hex!("00"),
&hex!("6F00"),
&hex!("0000"),
&hex!("6F00"),
&hex!("000000"),
&hex!("6F00"),
&hex!("0000000010010101"),
&hex!("6F00"),
&hex!("000000000501010101010101010101010101"),
&hex!("6F00"),
&hex!("FF000000"),
&hex!("6F00"),
&hex!("00000000ff00050101010101"),
&hex!("6F00"),
&hex!("000000000000050101010101"),
&hex!("6A82"),
])
}
#[test]
#[serial]
fn select_1() {
run_apdus(&[
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
])
}
#[test]
#[serial]
fn select_2() {
run_apdus(&[
&hex!("00A40400 05 0A01000002"),
&hex!("9000"),
])
}
#[test]
#[serial]
fn select_not_found() {
run_apdus(&[
&hex!("00A40400 05 0A01000100"),
&hex!("6A82"),
])
}
#[test]
#[serial]
fn select_not_found_still_selected() {
run_apdus(&[
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
&hex!("00A40400 05 0A01000100"),
&hex!("6A82"),
&hex!("80100000 05 0102030405 00"),
&hex!("0000000000 0102030405 9000"),
])
}
#[test]
#[serial]
fn select_bad_aid() {
run_apdus(&[
&hex!("00A40400"),
&hex!("6A80"),
])
}
#[test]
#[serial]
fn echo_1() {
run_apdus(&[
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
&hex!("00100000 05 0102030405 00"),
&hex!("0000000000 01020304059000"),
])
}
#[test]
#[serial]
fn echo_with_cla_bits_set() {
run_apdus(&[
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
&hex!("80100000 05 0102030405 00"),
&hex!("0000000000 0102030405 9000"),
])
}
#[test]
#[serial]
fn echo_wrong_instruction() {
run_apdus(&[
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
&hex!("00200000 05 0102030405 00"),
&hex!("6d00"),
])
}
#[test]
#[serial]
fn echo_2() {
run_apdus(&[
&hex!("00A40400 05 0A01000002"),
&hex!("9000"),
&hex!("00200000 05 0102030405 00"),
&hex!("0000000000 0102030405 9000"),
])
}
#[test]
#[serial]
fn echo_wrong_instruction_2() {
run_apdus(&[
&hex!("00A40400 05 0A01000002"),
&hex!("9000"),
&hex!("00100000 05 0102030405 00"),
&hex!("6d00"),
])
}
#[test]
#[serial]
fn unsolicited_instruction() {
run_apdus(&[
&hex!("00100000 05 0102030405"),
&hex!("6a82"),
])
}
#[test]
#[serial]
fn deselect() {
run_apdus(&[
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
&hex!("00100000 05 0102030405 00"),
&hex!("0000000000 0102030405 9000"),
&hex!("00A40400 05 0A01000002"),
&hex!("9000"),
&hex!("00100000 05 0102030405 00"),
&hex!("6d00"),
])
}
#[test]
#[serial]
fn extended_length_echo() {
run_apdus(
&[
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
&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
"),
&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(
&[
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
&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"),
&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"),
&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
"),
&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
"),
&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
/* 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
"),
&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
/* 2 */ 01 01 01
9000
"),
&hex!("00C00000 00"),
&hex!("6F00"),
]
)
}
#[test]
#[serial]
fn chained_response() {
run_apdus(
&[
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
&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"),
&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"),
&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
"),
&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
"),
&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
/* 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
"),
&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
/* 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
"),
&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
"),
&hex!("00C00000 00"),
&hex!("6F00"),
]
)
}
#[test]
#[serial]
fn multiple_chained_apdu_1() {
run_apdus(
&[
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
&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"),
&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
"),
&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
"),
&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
/* 2 */ 01 01 01 01
9000
"),
&hex!("00100000 05 0102030405 00"),
&hex!("0000000000 01020304059000"),
&hex!("00200000 05 0102030405 00"),
&hex!("6d00"),
&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"),
&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
"),
&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
"),
&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
/* 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();
}
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(
&[
&hex!("00A40400 05 0A01000002"),
&hex!("9000"),
&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"),
&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(),
&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(
&[
&hex!("00A40400050A01000001"),
&hex!("9000"),
&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"),
&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
"),
&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
"),
&hex!("00100000 05 0102030405 00"),
&hex!("0000000000 0102030405 9000"),
&hex!("00C00000"),
&hex!("6F00 "),
&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"),
&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
"),
&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(
&[
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
&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() {
run_apdus(&[
&hex!("9060000000"),
&hex!("9000"),
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
])
}
#[test]
#[serial]
fn response_larger_than_interchange() {
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(&[
&hex!("00A40400 05 0A01000001"),
&hex!("9000"),
&hex!("00210000 00ffff"),
&response1,
&hex!("00C00000 00"),
&hex!("0A0A0A 9000"),
&hex!("00220000 00ffff"),
&response2,
&hex!("00230000 00ffff"),
&response3,
&hex!("00C00000 00"),
&hex!("0A 9000"),
&hex!("00240000 00ffff"),
&response4,
&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;
println!("Burden: {} bytes", max_stack - min_stack);
}