Still WIP: move PIV to its own "app"

This commit is contained in:
Nicolas Stalder
2020-05-11 03:43:23 +02:00
parent 7647dc5b5c
commit 71ede067f7
5 changed files with 110 additions and 19 deletions
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 })
}