mirror of
https://github.com/trussed-dev/usbd-ccid.git
synced 2026-06-20 04:16:20 -07:00
Still WIP: move PIV to its own "app"
This commit is contained in:
@@ -12,6 +12,7 @@ cortex-m-semihosting = { version = "0.3.5", optional = true}
|
||||
heapless = "0.5.5"
|
||||
heapless-bytes = { git = "https://github.com/ycrypto/heapless-bytes", branch = "main" }
|
||||
# heapless-bytes = { path = "../../../heapless-bytes" }
|
||||
interchange = { path = "../interchange" }
|
||||
usb-device = { version = "0.2.3", features = ["control-buffer-256"] }
|
||||
|
||||
[features]
|
||||
|
||||
+16
-3
@@ -1,11 +1,15 @@
|
||||
use core::convert::TryFrom;
|
||||
|
||||
use cortex_m_semihosting::hprintln;
|
||||
use interchange::RequestPipe;
|
||||
|
||||
use crate::{
|
||||
constants::*,
|
||||
types::{
|
||||
apdu,
|
||||
apdu::{
|
||||
self,
|
||||
ApduInterchange,
|
||||
},
|
||||
ClassRequest,
|
||||
packet::{
|
||||
self,
|
||||
@@ -33,7 +37,10 @@ impl<Bus> Ccid<Bus>
|
||||
where
|
||||
Bus: 'static + UsbBus,
|
||||
{
|
||||
pub fn new(allocator: &'static UsbBusAllocator<Bus>) -> Self {
|
||||
pub fn new(
|
||||
allocator: &'static UsbBusAllocator<Bus>,
|
||||
request_pipe: RequestPipe<ApduInterchange>,
|
||||
) -> Self {
|
||||
let read = allocator.bulk(PACKET_SIZE as _);
|
||||
let write = allocator.bulk(PACKET_SIZE as _);
|
||||
// TODO: Add interrupt endpoint, so PC/SC does not
|
||||
@@ -42,10 +49,15 @@ where
|
||||
// PROBLEM: We don't have enough endpoints on the peripheral :/
|
||||
// (USBHS should have one more)
|
||||
// let interrupt = allocator.interrupt(8 as _, 32);
|
||||
let pipe = Pipe::new(write);
|
||||
let pipe = Pipe::new(write, request_pipe);
|
||||
let interface_number = allocator.interface();
|
||||
Self { interface_number, read, /* interrupt, */ pipe }
|
||||
}
|
||||
|
||||
// needs better name, maybe call directly
|
||||
pub fn sneaky_poll(&mut self) {
|
||||
self.poll();
|
||||
}
|
||||
}
|
||||
|
||||
impl<Bus> UsbClass<Bus> for Ccid<Bus>
|
||||
@@ -72,6 +84,7 @@ where
|
||||
}
|
||||
|
||||
fn poll(&mut self) {
|
||||
// hprintln!("poll of ccid").ok();
|
||||
self.pipe.poll_app();
|
||||
self.pipe.maybe_send_packet();
|
||||
}
|
||||
|
||||
+37
-8
@@ -1,11 +1,15 @@
|
||||
use core::convert::TryFrom;
|
||||
|
||||
use cortex_m_semihosting::hprintln;
|
||||
use interchange::RequestPipe;
|
||||
|
||||
use crate::{
|
||||
constants::*,
|
||||
types::{
|
||||
apdu,
|
||||
apdu::{
|
||||
self,
|
||||
ApduInterchange,
|
||||
},
|
||||
MessageBuffer,
|
||||
packet::{
|
||||
self,
|
||||
@@ -41,7 +45,9 @@ where
|
||||
// pub(crate) rpc: TransportEndpoint<'rpc>,
|
||||
seq: u8,
|
||||
state: State,
|
||||
// TODO: remove, use interchange
|
||||
message: MessageBuffer,
|
||||
interchange: RequestPipe<ApduInterchange>,
|
||||
sent: usize,
|
||||
outbox: Option<RawPacket>,
|
||||
}
|
||||
@@ -50,7 +56,10 @@ impl<Bus> Pipe<Bus>
|
||||
where
|
||||
Bus: 'static + UsbBus,
|
||||
{
|
||||
pub(crate) fn new(write: EndpointIn<'static, Bus>) -> Self {
|
||||
pub(crate) fn new(
|
||||
write: EndpointIn<'static, Bus>,
|
||||
request_pipe: RequestPipe<ApduInterchange>,
|
||||
) -> Self {
|
||||
|
||||
assert!(MAX_MSG_LENGTH >= PACKET_SIZE);
|
||||
|
||||
@@ -61,6 +70,7 @@ where
|
||||
sent: 0,
|
||||
outbox: None,
|
||||
message: MessageBuffer::new(),
|
||||
interchange: request_pipe,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +158,6 @@ where
|
||||
assert!(command.data().len() + self.message.len() <= MAX_MSG_LENGTH);
|
||||
self.message.extend_from_slice(command.data()).unwrap();
|
||||
self.call_app();
|
||||
self.state = State::Processing;
|
||||
}
|
||||
_ => panic!("{:?} unexpected in receiving state"),
|
||||
}
|
||||
@@ -174,18 +183,38 @@ where
|
||||
}
|
||||
|
||||
fn call_app(&mut self) {
|
||||
hprintln!("called piv app").ok();
|
||||
self.interchange.try_request(
|
||||
apdu::Command::try_from(&self.message).unwrap()
|
||||
).expect("could not deposit command");
|
||||
hprintln!("set ccid state to processing").ok();
|
||||
self.state = State::Processing;
|
||||
// todo!("have message of length {} to dispatch", self.message.len());
|
||||
}
|
||||
|
||||
pub fn poll_app(&mut self) {
|
||||
// static mut i: usize = 0;
|
||||
// unsafe {
|
||||
// if i < 100 {
|
||||
// i += 1;
|
||||
// } else {
|
||||
// hprintln!(".").ok();
|
||||
// }
|
||||
// }
|
||||
if let State::Processing = self.state {
|
||||
hprintln!("processing, checking for response, interchange state {:?}",
|
||||
self.interchange.state_byte).ok();
|
||||
|
||||
crate::piv::fake_piv(&mut self.message);
|
||||
if let Some(response) = self.interchange.take_response() {
|
||||
self.message = response.into_message();
|
||||
|
||||
// we should have an open XfrBlock allowance
|
||||
self.state = State::ReadyToSend;
|
||||
self.sent = 0;
|
||||
self.prime_outbox();
|
||||
// crate::piv::fake_piv(&mut self.message);
|
||||
|
||||
// we should have an open XfrBlock allowance
|
||||
self.state = State::ReadyToSend;
|
||||
self.sent = 0;
|
||||
self.prime_outbox();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -44,7 +44,7 @@ pub const PIV_AID: [u8; 11]
|
||||
pub const YUBICO_OTP_PIX: &[u8; 3] = &[0x20, 0x01, 0x01];
|
||||
pub const YUBICO_OTP_AID: &[u8; 8] = &[0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01, 0x01];
|
||||
// they use it to "deauthenticate user PIN and mgmt key": https://git.io/JfWgN
|
||||
pub const YUBICO_MGMT_PIX: [u8; 3] = &[0x47, 0x11, 0x17];
|
||||
pub const YUBICO_MGMT_PIX: &[u8; 3] = &[0x47, 0x11, 0x17];
|
||||
pub const YUBICO_MGMT_AID: &[u8; 8] = &[0xa0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01, 0x01];
|
||||
|
||||
// https://git.io/JfW28
|
||||
@@ -146,7 +146,7 @@ pub const GET_DATA: (u8, u8, u8, u8) = (
|
||||
// == == == == == == == == == == ==
|
||||
|
||||
pub fn fake_piv(command: &mut MessageBuffer) {
|
||||
let apdu = match apdu::Apdu::try_from(command.as_mut()) {
|
||||
let apdu = match apdu::Apdu::try_from(command.as_ref()) {
|
||||
Ok(apdu) => apdu,
|
||||
Err(_) => {
|
||||
invalid_apdu(command);
|
||||
@@ -170,11 +170,11 @@ pub fn fake_piv(command: &mut MessageBuffer) {
|
||||
//
|
||||
// 05808693 APDU: 00 A4 04 00 05 A0 00 00 03 08
|
||||
hprintln!("got SELECT").ok();
|
||||
let is_nist_rid = apdu.data() == &NIST_RID;
|
||||
let is_nist_rid = apdu.data() == &NIST_RID[..];
|
||||
let is_piv = apdu.data() == &PIV_AID;
|
||||
let is_trunc_piv = apdu.data() == &PIV_TRUNCATED_AID;
|
||||
let is_pivish = is_piv || is_trunc_piv || is_nist_rid;
|
||||
let is_yubico = apdu.data() == YUBICO_AID;
|
||||
let is_yubico = apdu.data() == YUBICO_OTP_AID;
|
||||
|
||||
if is_pivish {
|
||||
hprintln!("for PIV").ok();
|
||||
@@ -381,7 +381,7 @@ fn select(command: &mut MessageBuffer) {
|
||||
// Coexistent tag allocation authority
|
||||
der.nested(0x79, |der| {
|
||||
// Application identifier
|
||||
der.raw_tlv(0x4f, &NIST_RID)
|
||||
der.raw_tlv(0x4f, &NIST_RID[..])
|
||||
// })?;
|
||||
})
|
||||
|
||||
|
||||
+51
-3
@@ -1,10 +1,58 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Command {
|
||||
pub cla: u8,
|
||||
pub ins: u8,
|
||||
pub p1: u8,
|
||||
pub p2: u8,
|
||||
pub lc: usize,
|
||||
pub le: usize,
|
||||
pub data: MessageBuffer,
|
||||
}
|
||||
|
||||
impl core::convert::TryFrom<&MessageBuffer> for Command {
|
||||
type Error = ();
|
||||
fn try_from(message: &MessageBuffer) -> core::result::Result<Self, Self::Error> {
|
||||
let apdu = Apdu::try_from(message.as_ref())?;
|
||||
Ok(Self {
|
||||
cla: apdu.cla(),
|
||||
ins: apdu.ins(),
|
||||
p1: apdu.p1(),
|
||||
p2: apdu.p2(),
|
||||
lc: apdu.lc(),
|
||||
le: apdu.le(),
|
||||
data: MessageBuffer::try_from_slice(apdu.data()).unwrap(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct Response {
|
||||
pub sw1: u8,
|
||||
pub sw2: u8,
|
||||
pub data: MessageBuffer,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
pub fn into_message(self) -> MessageBuffer {
|
||||
let mut message = MessageBuffer::new();
|
||||
message.extend_from_slice(&self.data).unwrap();
|
||||
message.push(self.sw1).unwrap();
|
||||
message.push(self.sw2).unwrap();
|
||||
message
|
||||
}
|
||||
}
|
||||
|
||||
interchange::interchange! {
|
||||
ApduInterchange: (Command, Response)
|
||||
}
|
||||
|
||||
pub struct Apdu<'a> {
|
||||
lc: usize,
|
||||
le: usize,
|
||||
offset: usize,
|
||||
apdu: &'a mut [u8]
|
||||
apdu: &'a [u8]
|
||||
}
|
||||
|
||||
impl<'a> core::ops::Deref for Apdu<'a> {
|
||||
@@ -16,9 +64,9 @@ impl<'a> core::ops::Deref for Apdu<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> core::convert::TryFrom<&'a mut [u8]> for Apdu<'a> {
|
||||
impl<'a> core::convert::TryFrom<&'a [u8]> for Apdu<'a> {
|
||||
type Error = ();
|
||||
fn try_from(apdu: &'a mut [u8]) -> core::result::Result<Self, Self::Error> {
|
||||
fn try_from(apdu: &'a [u8]) -> core::result::Result<Self, Self::Error> {
|
||||
let (lc, le, offset) = calculate_lengths(apdu)?;
|
||||
Ok(Self { lc, le, offset, apdu })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user