Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ccid apps to the usbip runner #149

Merged
merged 16 commits into from
Jan 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
289 changes: 132 additions & 157 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion components/apps/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ edition = "2021"
apdu-dispatch = "0.1"
ctaphid-dispatch = "0.1"
trussed = "0.1"
trussed-usbip = { git = "https://github.com/trussed-dev/pc-usbip-runner", features = ["ctaphid"], optional = true }
trussed-usbip = { git = "https://github.com/trussed-dev/pc-usbip-runner", default-features = false, features = ["ctaphid", "ccid"], optional = true }
usbd-ctaphid = { path = "../usbd-ctaphid", optional = true }

# apps
Expand Down
7 changes: 7 additions & 0 deletions components/apps/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,13 @@ impl<R: Runner> trussed_usbip::Apps<Client<R>, (&R, NonPortable<R>)> for Apps<R>
fn with_ctaphid_apps<T>(&mut self, f: impl FnOnce(&mut [&mut dyn CtaphidApp]) -> T) -> T {
self.ctaphid_dispatch(f)
}

fn with_ccid_apps<T>(
&mut self,
f: impl FnOnce(&mut [&mut dyn apdu_dispatch::App<ApduCommandSize, ApduResponseSize>]) -> T,
) -> T {
self.apdu_dispatch(f)
}
}

trait App<R: Runner>: Sized {
Expand Down
2 changes: 1 addition & 1 deletion components/usbd-ccid/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name = "usbd-ccid"
version = "0.0.0-unreleased"
authors = ["Nicolas Stalder <[email protected]>"]
edition = "2018"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand Down
47 changes: 28 additions & 19 deletions components/usbd-ccid/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ where
}

pub fn did_start_processing(&mut self) -> Status {
if self.pipe.did_started_processing() {
if self.pipe.did_start_processing() {
// We should send a wait extension later
Status::ReceivedData(1_000.milliseconds())
} else {
Expand All @@ -90,19 +90,26 @@ where
I: 'static + Interchange<REQUEST = Vec<u8, N>, RESPONSE = Vec<u8, N>>,
{
fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
writer.interface_alt(
self.interface_number,
0,
CLASS_CCID,
SUBCLASS_NONE,
TransferMode::Bulk as u8,
Some(self.string_index),
)?;
writer.write(FUNCTIONAL_INTERFACE, &FUNCTIONAL_INTERFACE_DESCRIPTOR)?;
writer.endpoint(&self.pipe.write).unwrap();
writer.endpoint(&self.read).unwrap();
// writer.endpoint(&self.interrupt).unwrap();
Ok(())
// Wrapp in closure to be able to use `?` and inspect the error
(|| {
writer.interface_alt(
self.interface_number,
0,
CLASS_CCID,
SUBCLASS_NONE,
TransferMode::Bulk as u8,
Some(self.string_index),
)?;
writer.write(FUNCTIONAL_INTERFACE, &FUNCTIONAL_INTERFACE_DESCRIPTOR)?;
writer.endpoint(&self.pipe.write)?;
writer.endpoint(&self.read)?;
// writer.endpoint(&self.interrupt).unwrap();
Ok(())
})()
.map_err(|err| {
warn!("Failed to write descriptors: {err:?}");
err
})
}

fn get_string(&self, index: StringIndex, _lang_id: u16) -> Option<&str> {
Expand Down Expand Up @@ -137,15 +144,17 @@ where
packet.resize_default(packet.capacity()).unwrap();
let result = self.read.read(&mut packet);
result.map(|count| {
packet.resize_default(count).unwrap();
assert!(count <= packet.capacity());
packet.truncate(count);
packet
})
};

// should we return an error message
// if the raw packet is invalid?
if let Ok(packet) = maybe_packet {
self.pipe.handle_packet(packet);
match maybe_packet {
Ok(packet) => self.pipe.handle_packet(packet),
Err(_err) => {
error!("Failed to read packet: {_err:?}");
}
}
}

Expand Down
6 changes: 5 additions & 1 deletion components/usbd-ccid/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ pub const PACKET_SIZE: usize = 512;
#[cfg(not(feature = "highspeed-usb"))]
pub const PACKET_SIZE: usize = 64;

pub const CCID_HEADER_LEN: usize = 10;

pub const MAX_CCID_DATA_LEN: usize = PACKET_SIZE - CCID_HEADER_LEN;

pub const CLASS_CCID: u8 = 0x0B;
pub const SUBCLASS_NONE: u8 = 0x0;

Expand Down Expand Up @@ -39,7 +43,7 @@ pub const MAX_IFSD: [u8; 4] = [0xfe, 0x00, 0x00, 0x00];
// "The value shall be between 261 + 10 and 65544 + 10
// dwMaxCCIDMsgLen 3072
pub const MAX_MSG_LENGTH: usize = 3072;
pub const MAX_MSG_LENGTH_LE: [u8; 4] = [0x00, 0x0C, 0x00, 0x00];
pub const MAX_MSG_LENGTH_LE: [u8; 4] = (MAX_MSG_LENGTH as u32).to_le_bytes();

pub const NUM_SLOTS: u8 = 1;
pub const MAX_BUSY_SLOTS: u8 = 1;
Expand Down
5 changes: 3 additions & 2 deletions components/usbd-ccid/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#![no_std]

//! https://www.usb.org/sites/default/files/DWG_Smart-Card_CCID_Rev110.pdf
//! https://www.usb.org/sites/default/files/DWG_Smart-Card_USB-ICC_ICCD_rev10.pdf
//! [CCID Specification for Integrated Circuit(s) Cards Interface Devices](https://www.usb.org/sites/default/files/DWG_Smart-Card_CCID_Rev110.pdf)
//!
//! [CCID SpecificationUSB Integrated Circuit(s) Card Devices](https://www.usb.org/sites/default/files/DWG_Smart-Card_USB-ICC_ICCD_rev10.pdf)

#[macro_use]
extern crate delog;
Expand Down
55 changes: 26 additions & 29 deletions components/usbd-ccid/src/pipe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,18 +159,18 @@ where
// when certificates are transmitted, because PIV somehow uses short APDUs
// only (can we fix this), so 255B is the maximum)
if !self.receiving_long {
if packet.len() < 10 {
panic!("unexpected short packet");
if packet.len() < CCID_HEADER_LEN {
panic!("unexpected short packet. Len: {}", packet.len());
}
self.ext_packet.clear();
// TODO check
self.ext_packet.extend_from_slice(&packet).unwrap();

let pl = packet.packet_len();
if pl > 54 {
let pl = packet.data_len();
if pl > MAX_CCID_DATA_LEN {
self.receiving_long = true;
self.in_chain = 1;
self.long_packet_missing = pl - 54;
self.long_packet_missing = pl - MAX_CCID_DATA_LEN;
self.packet_len = pl;
return;
} else {
Expand All @@ -180,7 +180,12 @@ where
// TODO check
self.ext_packet.extend_from_slice(&packet).ok();
self.in_chain += 1;
assert!(packet.len() <= self.long_packet_missing);
assert!(
packet.len() <= self.long_packet_missing,
"Got packet of length {}, expected max {}",
packet.len(),
self.long_packet_missing
);
self.long_packet_missing -= packet.len();
if self.long_packet_missing > 0 {
return;
Expand Down Expand Up @@ -280,7 +285,7 @@ where
self.state = State::Receiving;
self.send_empty_datablock(Chain::ExpectingMore);
}
_ => panic!("unexpectedly in idle state"),
chain => panic!("unexpectedly in idle state. Got chain: {chain:?}",),
}
}

Expand All @@ -300,7 +305,7 @@ where
self.call_app();
self.state = State::Processing;
}
_ => panic!("unexpectedly in receiving state"),
chain => panic!("unexpectedly in receiving state. Got chain: {chain:?}",),
},

State::Processing => {
Expand All @@ -320,7 +325,7 @@ where
Chain::ExpectingMore => {
self.prime_outbox();
}
_ => panic!("unexpectedly in receiving state"),
chain => panic!("unexpectedly in sending state. Got chain: {chain:?}"),
},
}
}
Expand All @@ -329,7 +334,7 @@ where
if self.state == State::Processing {
// Need to send a wait extension request.
let mut packet = RawPacket::new();
packet.resize_default(10).ok();
packet.resize_default(CCID_HEADER_LEN).ok();
packet[0] = 0x80;
packet[6] = self.seq;

Expand All @@ -348,7 +353,7 @@ where
}

/// Turns false on read. Intended for checking to see if a wait extension request needs to be started.
pub fn did_started_processing(&mut self) -> bool {
pub fn did_start_processing(&mut self) -> bool {
if self.started_processing {
self.started_processing = false;
true
Expand All @@ -368,12 +373,14 @@ where

#[inline(never)]
pub fn poll_app(&mut self) {
if let State::Processing = self.state {
info!("Poll_app");
if State::Processing == self.state {
// info!("processing, checking for response, interchange state {:?}",
// self.interchange.state()).ok();

info!("State: processing");
if interchange::State::Responded == self.interchange.state() {
// we should have an open XfrBlock allowance
info!("Has response");
self.state = State::ReadyToSend;
self.sent = 0;
self.prime_outbox();
Expand All @@ -387,13 +394,12 @@ where
}

if self.outbox.is_some() {
panic!();
panic!("Outbox is already primed");
}

// if let Some(message) = self.interchange.response() {
let message: &mut Vec<u8, N> = unsafe { (*self.interchange.interchange.get()).rp_mut() };
let message = self.interchange.response().unwrap();

let chunk_size = core::cmp::min(PACKET_SIZE - 10, message.len() - self.sent);
let chunk_size = core::cmp::min(PACKET_SIZE - CCID_HEADER_LEN, message.len() - self.sent);
let chunk = &message[self.sent..][..chunk_size];
self.sent += chunk_size;
let more = self.sent < message.len();
Expand Down Expand Up @@ -424,7 +430,6 @@ where

// fast-lane response attempt
self.maybe_send_packet();
// }
}

fn send_empty_datablock(&mut self, chain: Chain) {
Expand All @@ -434,15 +439,15 @@ where

fn send_slot_status_ok(&mut self) {
let mut packet = RawPacket::new();
packet.resize_default(10).ok();
packet.resize_default(CCID_HEADER_LEN).ok();
packet[0] = 0x81;
packet[6] = self.seq;
self.send_packet_assuming_possible(packet);
}

fn send_slot_status_error(&mut self, error: Error) {
let mut packet = RawPacket::new();
packet.resize_default(10).ok();
packet.resize_default(CCID_HEADER_LEN).ok();
packet[0] = 0x6c;
packet[6] = self.seq;
packet[7] = 1 << 6;
Expand Down Expand Up @@ -528,19 +533,11 @@ where
info!("waiting to send");
}

Err(_) => panic!("unexpected send error"),
Err(err) => panic!("unexpected send error {err:?}"),
}
}
}

// pub fn read_address(&self) -> EndpointAddress {
// self.read.address()
// }

// pub fn write_address(&self) -> EndpointAddress {
// self.write.address()
// }

// Called if we receive an ABORT request on the control pipe.
pub fn expect_abort(&mut self, slot: u8, seq: u8) {
debug_assert!(slot == 0);
Expand Down
20 changes: 10 additions & 10 deletions components/usbd-ccid/src/types/packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ pub type RawPacket = heapless::Vec<u8, PACKET_SIZE>;
pub type ExtPacket = heapless::Vec<u8, MAX_MSG_LENGTH>;

pub trait RawPacketExt {
fn packet_len(&self) -> usize;
fn data_len(&self) -> usize;
}

impl RawPacketExt for RawPacket {
fn packet_len(&self) -> usize {
fn data_len(&self) -> usize {
u32::from_le_bytes(self[1..5].try_into().unwrap()) as usize
}
}
Expand Down Expand Up @@ -45,9 +45,9 @@ pub trait PacketWithData: Packet {
fn data(&self) -> &[u8] {
// let len = u32::from_le_bytes(self[1..5].try_into().unwrap()) as usize;
let declared_len = u32::from_le_bytes(self[1..5].try_into().unwrap()) as usize;
let len = core::cmp::min(MAX_MSG_LENGTH - 10, declared_len);
let len = core::cmp::min(MAX_MSG_LENGTH - CCID_HEADER_LEN, declared_len);
// hprintln!("delcared = {}, len = {}", declared_len, len).ok();
&self[10..][..len]
&self[CCID_HEADER_LEN..][..len]
}
}

Expand All @@ -61,7 +61,7 @@ pub trait ChainedPacket: Packet {
2 => Chain::Ends,
3 => Chain::Continues,
0x10 => Chain::ExpectingMore,
_ => panic!("invalid power select parameter"),
_ => panic!("invalid power select parameter {level_parameter:x}"),
}
}
}
Expand All @@ -76,7 +76,7 @@ pub struct DataBlock<'a> {

impl<'a> DataBlock<'a> {
pub fn new(seq: u8, chain: Chain, data: &'a [u8]) -> Self {
assert!(data.len() + 10 <= PACKET_SIZE);
assert!(data.len() + CCID_HEADER_LEN <= PACKET_SIZE);
Self { seq, chain, data }
}
}
Expand Down Expand Up @@ -117,7 +117,7 @@ impl From<DataBlock<'_>> for RawPacket {
fn from(v: DataBlock<'_>) -> RawPacket {
let mut packet = RawPacket::new();
let len = v.data.len();
packet.resize_default(10 + len).ok();
packet.resize_default(CCID_HEADER_LEN + len).ok();
packet[0] = 0x80;
packet[1..][..4].copy_from_slice(
&u32::try_from(len)
Expand All @@ -133,7 +133,7 @@ impl From<DataBlock<'_>> for RawPacket {
packet[8] = 0;
// chain parameter
packet[9] = v.chain as u8;
packet[10..][..len].copy_from_slice(v.data);
packet[CCID_HEADER_LEN..][..len].copy_from_slice(v.data);

packet
}
Expand Down Expand Up @@ -224,7 +224,7 @@ macro_rules! command_message {
fn try_from(packet: ExtPacket)
-> core::result::Result<Self, Self::Error>
{
if packet.len() < 10 {
if packet.len() < CCID_HEADER_LEN {
return Err(Error::ShortPacket);
}
if packet[5] != 0 {
Expand Down Expand Up @@ -294,7 +294,7 @@ impl PowerOn {
1 => PowerSelection::V5,
2 => PowerSelection::V3_3,
3 => PowerSelection::V1_8,
_ => panic!("invalid power select parameter"),
_ => panic!("invalid power select parameter {:x}", &self[7]),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion runners/embedded/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ license = "MIT"
apps = { path = "../../components/apps" }
cfg-if = "*"
delog = "0.1"
cortex-m = "0.7"
cortex-m = { version = "0.7", features = ["critical-section-single-core"]}
cortex-m-rtic = "1.0"
embedded-storage = "0.3"
embedded-hal = "0.2.3"
Expand Down
2 changes: 1 addition & 1 deletion runners/usbip/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ log = { version = "0.4.14", default-features = false }
rand_core = { version = "0.6.4", features = ["getrandom"] }
pretty_env_logger = "0.4.0"
trussed = { version = "0.1", features = ["clients-3"] }
trussed-usbip = { git = "https://github.com/trussed-dev/pc-usbip-runner", features = ["ctaphid"] }
trussed-usbip = { git = "https://github.com/trussed-dev/pc-usbip-runner", default-features = false, features = ["ctaphid", "ccid"] }

[features]
alpha = ["apps/alpha"]
Expand Down