#![no_std]
#![deny(missing_docs)]
extern crate no_std_compat as std;
use core::ops::Deref;
use std::convert::{TryFrom, TryInto};
use snafu::prelude::*;
#[cfg(test)]
mod tests;
#[derive(Debug, Clone)]
pub struct APDUCommand<B> {
pub cla: u8,
pub ins: u8,
pub p1: u8,
pub p2: u8,
pub data: B,
}
#[cfg(feature = "std")]
impl<B> APDUCommand<B>
where
B: Deref<Target = [u8]>,
{
pub fn serialize(&self) -> std::vec::Vec<u8> {
let mut v = std::vec![self.cla, self.ins, self.p1, self.p2, self.data.len() as u8];
v.extend(self.data.iter());
v
}
}
#[derive(Debug)]
pub struct APDUAnswer<B> {
data: B,
retcode: u16,
}
#[derive(Debug, Snafu, PartialEq, Eq)]
pub enum APDUAnswerError {
#[snafu(display("answer too short (< 2 bytes)"))]
TooShort,
}
impl<B> APDUAnswer<B>
where
B: std::ops::Deref<Target = [u8]>,
{
pub fn from_answer(answer: B) -> Result<Self, APDUAnswerError> {
ensure!(answer.len() >= 2, TooShortSnafu);
let retcode = arrayref::array_ref!(answer, answer.len() - 2, 2);
let retcode = u16::from_be_bytes(*retcode);
Ok(APDUAnswer {
data: answer,
retcode,
})
}
#[inline(always)]
pub fn apdu_data(&self) -> &[u8] {
&self.data[..self.data.len() - 2]
}
#[inline(always)]
pub fn data(&self) -> &[u8] {
self.apdu_data()
}
pub fn error_code(&self) -> Result<APDUErrorCode, u16> {
self.retcode.try_into().map_err(|_| self.retcode)
}
#[inline(always)]
pub fn retcode(&self) -> u16 {
self.retcode
}
}
#[derive(Copy, Clone, Debug, Snafu, PartialEq, Eq)]
#[repr(u16)]
pub enum APDUErrorCode {
NoError = 0x9000,
ExecutionError = 0x6400,
WrongLength = 0x6700,
EmptyBuffer = 0x6982,
OutputBufferTooSmall = 0x6983,
DataInvalid = 0x6984,
ConditionsNotSatisfied = 0x6985,
CommandNotAllowed = 0x6986,
BadKeyHandle = 0x6A80,
InvalidP1P2 = 0x6B00,
InsNotSupported = 0x6D00,
ClaNotSupported = 0x6E00,
Unknown = 0x6F00,
SignVerifyError = 0x6F01,
}
#[cfg(feature = "std")]
impl APDUErrorCode {
pub fn description(&self) -> std::string::String {
std::format!("{}", self)
}
}
impl From<APDUErrorCode> for u16 {
fn from(code: APDUErrorCode) -> Self {
code as u16
}
}
impl TryFrom<u16> for APDUErrorCode {
type Error = ();
fn try_from(value: u16) -> Result<Self, Self::Error> {
let this = match value {
0x9000 => Self::NoError,
0x6400 => Self::ExecutionError,
0x6700 => Self::WrongLength,
0x6982 => Self::EmptyBuffer,
0x6983 => Self::OutputBufferTooSmall,
0x6984 => Self::DataInvalid,
0x6985 => Self::ConditionsNotSatisfied,
0x6986 => Self::CommandNotAllowed,
0x6A80 => Self::BadKeyHandle,
0x6B00 => Self::InvalidP1P2,
0x6D00 => Self::InsNotSupported,
0x6E00 => Self::ClaNotSupported,
0x6F00 => Self::Unknown,
0x6F01 => Self::SignVerifyError,
_ => return Err(()),
};
Ok(this)
}
}