Skip to content

Commit

Permalink
Merge pull request #149 from Nitrokey/usbip-ccid
Browse files Browse the repository at this point in the history
Add ccid apps to the usbip runner
  • Loading branch information
sosthene-nitrokey authored Jan 25, 2023
2 parents a891a19 + 5a2722c commit c494cc4
Show file tree
Hide file tree
Showing 11 changed files with 215 additions and 222 deletions.
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

0 comments on commit c494cc4

Please sign in to comment.