mirror of
https://github.com/trussed-dev/usbd-ccid.git
synced 2026-06-20 04:16:20 -07:00
Merge pull request #1 from trussed-dev/nitrokey-upstreaming
Upstream changes from the Nitrokey firmware repository
This commit is contained in:
+8
-4
@@ -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 {
|
||||
@@ -137,15 +137,19 @@ 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.len());
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -4,6 +4,8 @@ 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 CLASS_CCID: u8 = 0x0B;
|
||||
pub const SUBCLASS_NONE: u8 = 0x0;
|
||||
|
||||
@@ -39,7 +41,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;
|
||||
|
||||
+7
-2
@@ -1,7 +1,12 @@
|
||||
#![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 descriptor and USB CCID class implementation.
|
||||
//!
|
||||
//! This crate implements CCID communication to a USB host, and sends the resulting APDUs to an [Interchange](https://docs.rs/interchange)
|
||||
//!
|
||||
//! [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;
|
||||
|
||||
+17
-16
@@ -12,6 +12,9 @@ use crate::{
|
||||
|
||||
use usb_device::class_prelude::*;
|
||||
|
||||
// Const assertion
|
||||
const _: [(); 0 - !{ MAX_MSG_LENGTH >= PACKET_SIZE } as usize] = [];
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum State {
|
||||
Idle,
|
||||
@@ -65,8 +68,6 @@ where
|
||||
request_pipe: Requester<I>,
|
||||
card_issuers_data: Option<&[u8]>,
|
||||
) -> Self {
|
||||
// assert!(MAX_MSG_LENGTH >= PACKET_SIZE);
|
||||
|
||||
Self {
|
||||
write,
|
||||
seq: 0,
|
||||
@@ -144,18 +145,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 {
|
||||
if packet.len() < CCID_HEADER_LEN {
|
||||
panic!("unexpected short packet");
|
||||
}
|
||||
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 > PACKET_SIZE - CCID_HEADER_LEN {
|
||||
self.receiving_long = true;
|
||||
self.in_chain = 1;
|
||||
self.long_packet_missing = pl - 54;
|
||||
self.long_packet_missing = pl - PACKET_SIZE - CCID_HEADER_LEN;
|
||||
self.packet_len = pl;
|
||||
return;
|
||||
} else {
|
||||
@@ -303,7 +304,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;
|
||||
|
||||
@@ -322,7 +323,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
|
||||
@@ -342,7 +343,7 @@ where
|
||||
|
||||
#[inline(never)]
|
||||
pub fn poll_app(&mut self) {
|
||||
if let State::Processing = self.state {
|
||||
if State::Processing == self.state {
|
||||
// info!("processing, checking for response, interchange state {:?}",
|
||||
// self.interchange.state()).ok();
|
||||
|
||||
@@ -361,13 +362,14 @@ where
|
||||
}
|
||||
|
||||
if self.outbox.is_some() {
|
||||
panic!();
|
||||
panic!("Full outbox");
|
||||
}
|
||||
|
||||
// if let Some(message) = self.interchange.response() {
|
||||
let message: &mut Vec<u8, N> = unsafe { (*self.interchange.interchange.get()).rp_mut() };
|
||||
let Some(message) = self.interchange.response() else {
|
||||
panic!("No response while priming outbox");
|
||||
};
|
||||
|
||||
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();
|
||||
@@ -398,7 +400,6 @@ where
|
||||
|
||||
// fast-lane response attempt
|
||||
self.maybe_send_packet();
|
||||
// }
|
||||
}
|
||||
|
||||
fn send_empty_datablock(&mut self, chain: Chain) {
|
||||
@@ -408,7 +409,7 @@ 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);
|
||||
@@ -416,7 +417,7 @@ where
|
||||
|
||||
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;
|
||||
|
||||
@@ -2,7 +2,6 @@ use embedded_time::duration::Milliseconds;
|
||||
|
||||
// pub mod apdu;
|
||||
pub mod packet;
|
||||
pub mod tlv;
|
||||
|
||||
// pub type MessageBuffer = apdu_dispatch::interchanges::Data;
|
||||
|
||||
|
||||
+14
-10
@@ -1,4 +1,4 @@
|
||||
use core::convert::TryInto;
|
||||
use core::convert::{TryFrom, TryInto};
|
||||
|
||||
use crate::constants::*;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
}
|
||||
}
|
||||
@@ -117,9 +117,13 @@ impl From<DataBlock<'_>> for RawPacket {
|
||||
fn from(block: DataBlock<'_>) -> RawPacket {
|
||||
let mut packet = RawPacket::new();
|
||||
let len = block.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(&len.to_le_bytes());
|
||||
packet[1..][..4].copy_from_slice(
|
||||
&u32::try_from(len)
|
||||
.expect("Packets should not be more than 4GiB")
|
||||
.to_le_bytes(),
|
||||
);
|
||||
packet[5] = 0;
|
||||
packet[6] = block.seq;
|
||||
|
||||
@@ -129,7 +133,7 @@ impl From<DataBlock<'_>> for RawPacket {
|
||||
packet[8] = 0;
|
||||
// chain parameter
|
||||
packet[9] = block.chain as u8;
|
||||
packet[10..][..len].copy_from_slice(block.data);
|
||||
packet[CCID_HEADER_LEN..][..len].copy_from_slice(block.data);
|
||||
|
||||
packet
|
||||
}
|
||||
@@ -220,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 {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
Reference in New Issue
Block a user