diff --git a/src/class.rs b/src/class.rs index bf7b7fa..5056049 100644 --- a/src/class.rs +++ b/src/class.rs @@ -6,12 +6,8 @@ use interchange::{Interchange, Requester}; use crate::{ constants::*, - types::{ - ClassRequest, - packet::RawPacket, - Status, - }, pipe::Pipe, + types::{packet::RawPacket, ClassRequest, Status}, }; use usb_device::class_prelude::*; @@ -55,7 +51,12 @@ where let pipe = Pipe::new(write, request_pipe, card_issuers_data); let interface_number = allocator.interface(); let string_index = allocator.string(); - Self { interface_number, string_index, read, /* interrupt, */ pipe } + Self { + interface_number, + string_index, + read, + /* interrupt, */ pipe, + } } /// Read response from application (if any) and start writing it to @@ -73,7 +74,7 @@ where } } - pub fn send_wait_extension (&mut self) -> Status { + pub fn send_wait_extension(&mut self) -> Status { if self.pipe.send_wait_extension() { // We should send another wait extension later Status::ReceivedData(1_000.milliseconds()) @@ -88,9 +89,7 @@ where Bus: 'static + UsbBus, I: 'static + Interchange, RESPONSE = Vec>, { - fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) - -> Result<()> - { + fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> { writer.interface_alt( self.interface_number, 0, @@ -99,10 +98,7 @@ where TransferMode::Bulk as u8, Some(self.string_index), )?; - writer.write( - FUNCTIONAL_INTERFACE, - &FUNCTIONAL_INTERFACE_DESCRIPTOR, - )?; + writer.write(FUNCTIONAL_INTERFACE, &FUNCTIONAL_INTERFACE_DESCRIPTOR)?; writer.endpoint(&self.pipe.write).unwrap(); writer.endpoint(&self.read).unwrap(); // writer.endpoint(&self.interrupt).unwrap(); @@ -110,8 +106,7 @@ where } fn get_string(&self, index: StringIndex, _lang_id: u16) -> Option<&str> { - (self.string_index == index) - .then_some(FUNCTIONAL_INTERFACE_STRING) + (self.string_index == index).then_some(FUNCTIONAL_INTERFACE_STRING) } #[inline(never)] @@ -122,13 +117,17 @@ where } fn endpoint_in_complete(&mut self, addr: EndpointAddress) { - if addr != self.pipe.write.address() { return; } + if addr != self.pipe.write.address() { + return; + } self.pipe.maybe_send_packet(); } fn endpoint_out(&mut self, addr: EndpointAddress) { - if addr != self.read.address() { return; } + if addr != self.read.address() { + return; + } // let maybe_packet = RawPacket::try_from( // |packet| self.read.read(packet)); @@ -148,12 +147,17 @@ where if let Ok(packet) = maybe_packet { self.pipe.handle_packet(packet); } - } fn control_in(&mut self, transfer: ControlIn) { use usb_device::control::*; - let Request { request_type, recipient, index, request, .. } = *transfer.request(); + let Request { + request_type, + recipient, + index, + request, + .. + } = *transfer.request(); if index != u8::from(self.interface_number) as u16 { return; } @@ -165,12 +169,12 @@ where // not strictly needed, as our bNumClockSupported = 0 ClassRequest::GetClockFrequencies => { transfer.accept_with(&CLOCK_FREQUENCY_KHZ).ok(); - }, + } // not strictly needed, as our bNumDataRatesSupported = 0 ClassRequest::GetDataRates => { transfer.accept_with_static(&DATA_RATE_BPS).ok(); - }, + } _ => panic!("unexpected direction for {:?}", &request), } } @@ -185,8 +189,14 @@ where fn control_out(&mut self, transfer: ControlOut) { use usb_device::control::*; - let Request { request_type, recipient, index, request, value, .. } - = *transfer.request(); + let Request { + request_type, + recipient, + index, + request, + value, + .. + } = *transfer.request(); if index as u8 != u8::from(self.interface_number) { return; } @@ -215,5 +225,4 @@ where } } } - } diff --git a/src/constants.rs b/src/constants.rs index aae9206..844aa1c 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -49,7 +49,8 @@ pub const PIN_SUPPORT: u8 = 0; // cf. Sec. 5.1 in: https://www.usb.org/sites/default/files/DWG_Smart-Card_CCID_Rev110.pdf pub const FUNCTIONAL_INTERFACE_DESCRIPTOR: [u8; 52] = [ // bcdCCID rev1.10 - 0x10, 0x01, + 0x10, + 0x01, // bMaxSlotIndex // NUM_SLOTS - 1, // "An USB-ICC is regarded as a single slot CCID." @@ -57,8 +58,10 @@ pub const FUNCTIONAL_INTERFACE_DESCRIPTOR: [u8; 52] = [ // bVoltageSupport (5.0V) 0x01, // dwProtocols: APDU level, T=1 only (0 = T=0, 3 = T0+T1) - 0x02, 0x00, 0x00, 0x00, - + 0x02, + 0x00, + 0x00, + 0x00, // dwDefaultClock (3.58 MHz) CLOCK_FREQUENCY_KHZ[0], CLOCK_FREQUENCY_KHZ[1], @@ -71,7 +74,6 @@ pub const FUNCTIONAL_INTERFACE_DESCRIPTOR: [u8; 52] = [ CLOCK_FREQUENCY_KHZ[3], // bNumClockSupported 0x00, - // dwDataRate (9600 bps) DATA_RATE_BPS[0], DATA_RATE_BPS[1], @@ -84,17 +86,21 @@ pub const FUNCTIONAL_INTERFACE_DESCRIPTOR: [u8; 52] = [ DATA_RATE_BPS[3], // bNumDataRatesSupported 0x00, - // dwMaxIFSD (254) MAX_IFSD[0], MAX_IFSD[1], MAX_IFSD[2], MAX_IFSD[3], // dwSyncProtocols: none - 0x00, 0x00, 0x00, 0x00, + 0x00, + 0x00, + 0x00, + 0x00, // dwMechanical: no special characteristics - 0x00, 0x00, 0x00, 0x00, - + 0x00, + 0x00, + 0x00, + 0x00, // dwFeatures, see following comments // Auto configuration based on ATR // Auto activation on insert @@ -106,21 +112,23 @@ pub const FUNCTIONAL_INTERFACE_DESCRIPTOR: [u8; 52] = [ // 0xFE, 0x00, 0x04, 0x00, // ICCD: lower word (=0840): only requests valid for USB-ICC // upper word: 0000 = char level, 0002 = short APDU, 0004 = short+exteded APDU - 0x40, 0x08, 0x04, 0x00, - + 0x40, + 0x08, + 0x04, + 0x00, // dwMaxCCIDMsgLen (3072) // gnuk: 271 MAX_MSG_LENGTH_LE[0], MAX_MSG_LENGTH_LE[1], MAX_MSG_LENGTH_LE[2], MAX_MSG_LENGTH_LE[3], - // bClassGetResponse ("echo"), as per ICCD spec 0xFF, // bClassEnvelope ("echo"), as per ICCD spec, gnuk: 0 0xFF, // wlcdLayout (none) - 0x00, 0x00, + 0x00, + 0x00, // bPinSupport // ICCD: "No PIN pad, not relevant, fixed for legacy reasons" PIN_SUPPORT, diff --git a/src/lib.rs b/src/lib.rs index 1fb0008..7a2bf2b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,8 @@ extern crate delog; generate_macros!(); -pub mod constants; pub mod class; +pub mod constants; pub mod pipe; pub mod types; diff --git a/src/pipe.rs b/src/pipe.rs index 19131ba..53ecd0a 100644 --- a/src/pipe.rs +++ b/src/pipe.rs @@ -5,16 +5,8 @@ use interchange::{Interchange, Requester}; use crate::{ constants::*, types::packet::{ - Chain, - Command as PacketCommand, - DataBlock, - Error as PacketError, - ExtPacket, - RawPacket, - XfrBlock, - - ChainedPacket as _, - PacketWithData as _, + Chain, ChainedPacket as _, Command as PacketCommand, DataBlock, Error as PacketError, + ExtPacket, PacketWithData as _, RawPacket, XfrBlock, }, }; @@ -73,7 +65,6 @@ where request_pipe: Requester, card_issuers_data: Option<&[u8]>, ) -> Self { - // assert!(MAX_MSG_LENGTH >= PACKET_SIZE); Self { @@ -136,7 +127,6 @@ where } } - impl Pipe where Bus: 'static + UsbBus, @@ -235,7 +225,6 @@ where } fn handle_transfer(&mut self, command: XfrBlock) { - // state: Idle, Receiving, Processing, Sending, // // conts: BeginsAndEnds, Begins, Ends, Continues, ExpectDataBlock, @@ -243,7 +232,6 @@ where // info!("handle xfrblock").ok(); // info!("{:X?}", &command); match self.state { - State::Idle => { // invariant: BUFFER_SIZE >= PACKET_SIZE match command.chain() { @@ -266,49 +254,48 @@ where self.state = State::Receiving; self.send_empty_datablock(Chain::ExpectingMore); } - _ => panic!("unexpectedly in idle state"), + _ => panic!("unexpectedly in idle state"), } } - State::Receiving => { - match command.chain() { - Chain::Continues => { - info!("continues"); - let message = self.interchange.request_mut().unwrap(); - assert!(command.data().len() + message.len() <= MAX_MSG_LENGTH); - message.extend_from_slice(command.data()).unwrap(); - self.send_empty_datablock(Chain::ExpectingMore); - } - Chain::Ends => { - info!("ends"); - let message = self.interchange.request_mut().unwrap(); - assert!(command.data().len() + message.len() <= MAX_MSG_LENGTH); - message.extend_from_slice(command.data()).unwrap(); - self.call_app(); - self.state = State::Processing; - } - _ => panic!("unexpectedly in receiving state"), + State::Receiving => match command.chain() { + Chain::Continues => { + info!("continues"); + let message = self.interchange.request_mut().unwrap(); + assert!(command.data().len() + message.len() <= MAX_MSG_LENGTH); + message.extend_from_slice(command.data()).unwrap(); + self.send_empty_datablock(Chain::ExpectingMore); } - } + Chain::Ends => { + info!("ends"); + let message = self.interchange.request_mut().unwrap(); + assert!(command.data().len() + message.len() <= MAX_MSG_LENGTH); + message.extend_from_slice(command.data()).unwrap(); + self.call_app(); + self.state = State::Processing; + } + _ => panic!("unexpectedly in receiving state"), + }, State::Processing => { // info!("handle xfrblock").ok(); // info!("{:X?}", &command).ok(); - panic!("ccid pipe unexpectedly received command while in processing state: {:?}", &command); + panic!( + "ccid pipe unexpectedly received command while in processing state: {:?}", + &command + ); } State::ReadyToSend => { panic!("unexpectedly in ready-to-send state") } - State::Sending => { - match command.chain() { - Chain::ExpectingMore => { - self.prime_outbox(); - } - _ => panic!("unexpectedly in receiving state"), + State::Sending => match command.chain() { + Chain::ExpectingMore => { + self.prime_outbox(); } - } + _ => panic!("unexpectedly in receiving state"), + }, } } @@ -346,7 +333,9 @@ where #[inline(never)] fn call_app(&mut self) { - self.interchange.send_request().expect("could not deposit command"); + self.interchange + .send_request() + .expect("could not deposit command"); self.started_processing = true; self.state = State::Processing; } @@ -358,7 +347,6 @@ where // self.interchange.state()).ok(); if interchange::State::Responded == self.interchange.state() { - // we should have an open XfrBlock allowance self.state = State::ReadyToSend; self.sent = 0; @@ -372,31 +360,44 @@ where return; } - if self.outbox.is_some() { panic!(); } + if self.outbox.is_some() { + panic!(); + } // if let Some(message) = self.interchange.response() { - let message: &mut Vec = unsafe { (*self.interchange.interchange.get()).rp_mut() }; + let message: &mut Vec = unsafe { (*self.interchange.interchange.get()).rp_mut() }; - let chunk_size = core::cmp::min(PACKET_SIZE - 10, message.len() - self.sent); - let chunk = &message[self.sent..][..chunk_size]; - self.sent += chunk_size; - let more = self.sent < message.len(); + let chunk_size = core::cmp::min(PACKET_SIZE - 10, message.len() - self.sent); + let chunk = &message[self.sent..][..chunk_size]; + self.sent += chunk_size; + let more = self.sent < message.len(); - let chain = match (self.state, more) { - (State::ReadyToSend, true) => { self.state = State::Sending; Chain::Begins } - (State::ReadyToSend, false) => { self.state = State::Idle; Chain::BeginsAndEnds } - (State::Sending, true) => Chain::Continues, - (State::Sending, false) => { self.state = State::Idle; Chain::Ends } - // logically impossible - _ => { return; } - }; + let chain = match (self.state, more) { + (State::ReadyToSend, true) => { + self.state = State::Sending; + Chain::Begins + } + (State::ReadyToSend, false) => { + self.state = State::Idle; + Chain::BeginsAndEnds + } + (State::Sending, true) => Chain::Continues, + (State::Sending, false) => { + self.state = State::Idle; + Chain::Ends + } + // logically impossible + _ => { + return; + } + }; - let primed_packet = DataBlock::new(self.seq, chain, chunk); - // info!("priming {:?}", &primed_packet).ok(); - self.outbox = Some(primed_packet.into()); + let primed_packet = DataBlock::new(self.seq, chain, chunk); + // info!("priming {:?}", &primed_packet).ok(); + self.outbox = Some(primed_packet.into()); - // fast-lane response attempt - self.maybe_send_packet(); + // fast-lane response attempt + self.maybe_send_packet(); // } } @@ -418,7 +419,7 @@ where packet.resize_default(10).ok(); packet[0] = 0x6c; packet[6] = self.seq; - packet[7] = 1<<6; + packet[7] = 1 << 6; packet[8] = error as u8; self.send_packet_assuming_possible(packet); } @@ -450,7 +451,6 @@ where self.seq, Chain::BeginsAndEnds, &atr, - // T=0, T=1, command chaining/extended Lc+Le/no logical channels, card issuer's data "Solo 2" // 3B 8C 80 01 80 73 C0 21 C0 56 53 6F 6C 6F 20 32 A4 // https://smartcard-atr.apdu.fr/parse?ATR=3B+8C+80+01+80+73+C0+21+C0+56+53+6F+6C+6F+20+32+A4 @@ -464,7 +464,6 @@ where self.send_packet_assuming_possible(packet.into()); } - fn send_packet_assuming_possible(&mut self, packet: RawPacket) { if self.outbox.is_some() { // Previous transaction will fail, but we'll be ready for new transactions. @@ -494,7 +493,6 @@ where } else { self.outbox = None; } - } Ok(_) => panic!("short write"), @@ -502,7 +500,7 @@ where // fine, can't write try later // this shouldn't happen probably info!("waiting to send"); - }, + } Err(_) => panic!("unexpected send error"), } @@ -522,5 +520,4 @@ where info!("ABORT expected for seq = {}", _seq); todo!(); } - } diff --git a/src/types.rs b/src/types.rs index d360bfe..cb745ee 100644 --- a/src/types.rs +++ b/src/types.rs @@ -29,4 +29,3 @@ impl core::convert::TryFrom for ClassRequest { }) } } - diff --git a/src/types/packet.rs b/src/types/packet.rs index 26611e6..465340f 100644 --- a/src/types/packet.rs +++ b/src/types/packet.rs @@ -2,7 +2,6 @@ use core::convert::TryInto; use crate::constants::*; - pub type RawPacket = heapless::Vec; pub type ExtPacket = heapless::Vec; @@ -28,7 +27,6 @@ pub enum Message { } pub trait Packet: core::ops::Deref { - #[inline] fn slot(&self) -> u8 { // we have only one slot @@ -37,17 +35,16 @@ pub trait Packet: core::ops::Deref { } #[inline] - fn seq(&self) -> u8 { self[6] } - + fn seq(&self) -> u8 { + self[6] + } } pub trait PacketWithData: Packet { - #[inline] 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 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); // hprintln!("delcared = {}, len = {}", declared_len, len).ok(); &self[10..][..len] @@ -55,7 +52,6 @@ pub trait PacketWithData: Packet { } pub trait ChainedPacket: Packet { - #[inline(always)] fn chain(&self) -> Chain { let level_parameter = u16::from_le_bytes(self[8..10].try_into().unwrap()); @@ -86,19 +82,18 @@ impl<'a> DataBlock<'a> { } impl core::fmt::Debug for DataBlock<'_> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let mut debug_struct = f.debug_struct("DataBlock"); - debug_struct - .field("seq", &self.seq) - ; + debug_struct.field("seq", &self.seq); - let l = core::cmp::min(self.data.len(), 16); - let escaped_bytes: heapless::Vec = - self.data.iter().take(l) - .flat_map(|byte| core::ascii::escape_default(*byte)) - .collect(); + let l = core::cmp::min(self.data.len(), 16); + let escaped_bytes: heapless::Vec = self + .data + .iter() + .take(l) + .flat_map(|byte| core::ascii::escape_default(*byte)) + .collect(); let data_as_str = &core::str::from_utf8(&escaped_bytes).unwrap(); debug_struct @@ -109,7 +104,6 @@ impl core::fmt::Debug for DataBlock<'_> { } } - // WELL. DataBlock does not deref to RawPacket // impl Deref for DataBlock<_> { // type Target: & @@ -144,7 +138,6 @@ impl From> for RawPacket { #[repr(u8)] #[derive(Copy, Clone, Debug)] pub enum CommandType { - // REQUESTS // supported @@ -158,7 +151,7 @@ pub enum CommandType { // unsupported ResetParameters = 0x6d, SetParameters = 0x61, - Escape = 0x6b,// for vendor commands + Escape = 0x6b, // for vendor commands IccClock = 0x7e, T0Apdu = 0x6a, Secure = 0x69, @@ -314,9 +307,10 @@ pub enum Chain { impl Chain { pub fn transfer_ongoing(&self) -> bool { - matches!(self, Chain::BeginsAndEnds | - Chain::Ends | - Chain::ExpectingMore) + matches!( + self, + Chain::BeginsAndEnds | Chain::Ends | Chain::ExpectingMore + ) } } @@ -326,36 +320,34 @@ pub enum Response { } impl core::fmt::Debug for Command { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let mut debug_struct = f.debug_struct("Command"); - // write!("Command({:?})", &self.command_type())); - // // "Command"); + // write!("Command({:?})", &self.command_type())); + // // "Command"); debug_struct .field("cmd", &self.command_type()) - .field("seq", &self.seq()) - ; + .field("seq", &self.seq()); if let Command::XfrBlock(block) = self { let l = core::cmp::min(self.len(), 8); - let escaped_bytes: heapless::Vec = - block.data().iter().take(l) - .flat_map(|byte| core::ascii::escape_default(*byte)) - .collect(); + let escaped_bytes: heapless::Vec = block + .data() + .iter() + .take(l) + .flat_map(|byte| core::ascii::escape_default(*byte)) + .collect(); let data_as_str = &core::str::from_utf8(&escaped_bytes).unwrap(); debug_struct .field("chain", &block.chain()) - .field("len", &block.data().len()) - ; + .field("len", &block.data().len()); if l < self.len() { debug_struct.field("data[..8]", &format_args!("b'{}'", data_as_str)) } else { debug_struct.field("data", &format_args!("b'{}'", data_as_str)) - } - ; + }; } // let mut debug_struct = match self.msg_type() { @@ -364,8 +356,6 @@ impl core::fmt::Debug for Command { // }; // let has_data = self.len() > 0; - debug_struct - .finish() + debug_struct.finish() } } - diff --git a/src/types/tlv.rs b/src/types/tlv.rs index e69de29..8b13789 100644 --- a/src/types/tlv.rs +++ b/src/types/tlv.rs @@ -0,0 +1 @@ +