You've already forked apdu-dispatch
mirror of
https://github.com/trussed-dev/apdu-dispatch.git
synced 2026-03-11 16:36:07 -07:00
1124 lines
47 KiB
Rust
1124 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,
|
|
_interface: dispatch::Interface,
|
|
_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,
|
|
_interface: dispatch::Interface,
|
|
_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,
|
|
_interface: dispatch::Interface,
|
|
_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);
|
|
}
|