1#![no_std]
19#![deny(missing_docs)]
20
21extern crate no_std_compat as std;
22use core::ops::Deref;
23use std::convert::{TryFrom, TryInto};
24
25use snafu::prelude::*;
26
27#[cfg(test)]
28mod tests;
29
30#[derive(Debug, Clone)]
31pub struct APDUCommand<B> {
33 pub cla: u8,
37 pub ins: u8,
39 pub p1: u8,
41 pub p2: u8,
43 pub data: B,
45}
46
47#[cfg(feature = "std")]
48impl<B> APDUCommand<B>
49where
50 B: Deref<Target = [u8]>,
51{
52 pub fn serialize(&self) -> std::vec::Vec<u8> {
54 let mut v = std::vec![self.cla, self.ins, self.p1, self.p2, self.data.len() as u8];
55 v.extend(self.data.iter());
56 v
57 }
58}
59
60#[derive(Debug)]
61pub struct APDUAnswer<B> {
63 data: B,
64 retcode: u16,
65}
66
67#[derive(Debug, Snafu, PartialEq, Eq)]
68pub enum APDUAnswerError {
70 #[snafu(display("answer too short (< 2 bytes)"))]
71 TooShort,
73}
74
75impl<B> APDUAnswer<B>
76where
77 B: Deref<Target = [u8]>,
78{
79 pub fn from_answer(answer: B) -> Result<Self, APDUAnswerError> {
81 ensure!(answer.len() >= 2, TooShortSnafu);
82 let retcode = arrayref::array_ref!(answer, answer.len() - 2, 2);
83 let retcode = u16::from_be_bytes(*retcode);
84
85 Ok(APDUAnswer { data: answer, retcode })
86 }
87
88 #[inline(always)]
90 pub fn apdu_data(&self) -> &[u8] {
91 &self.data[.. self.data.len() - 2]
92 }
93
94 #[inline(always)]
96 pub fn data(&self) -> &[u8] {
97 self.apdu_data()
98 }
99
100 pub fn error_code(&self) -> Result<APDUErrorCode, u16> {
103 self.retcode
104 .try_into()
105 .map_err(|_| self.retcode)
106 }
107
108 #[inline(always)]
110 pub fn retcode(&self) -> u16 {
111 self.retcode
112 }
113}
114
115#[derive(Copy, Clone, Debug, Snafu, PartialEq, Eq)]
116#[repr(u16)]
117pub enum APDUErrorCode {
119 NoError = 0x9000,
121 ExecutionError = 0x6400,
123 WrongLength = 0x6700,
125 EmptyBuffer = 0x6982,
127 OutputBufferTooSmall = 0x6983,
129 DataInvalid = 0x6984,
131 ConditionsNotSatisfied = 0x6985,
133 CommandNotAllowed = 0x6986,
135 BadKeyHandle = 0x6A80,
137 InvalidP1P2 = 0x6B00,
139 InsNotSupported = 0x6D00,
141 ClaNotSupported = 0x6E00,
143 Unknown = 0x6F00,
145 SignVerifyError = 0x6F01,
147}
148
149#[cfg(feature = "std")]
150impl APDUErrorCode {
151 pub fn description(&self) -> std::string::String {
153 std::format!("{}", self)
154 }
155}
156
157impl From<APDUErrorCode> for u16 {
158 fn from(code: APDUErrorCode) -> Self {
159 code as u16
160 }
161}
162
163impl TryFrom<u16> for APDUErrorCode {
164 type Error = ();
165
166 fn try_from(value: u16) -> Result<Self, Self::Error> {
167 let this = match value {
168 0x9000 => Self::NoError,
169 0x6400 => Self::ExecutionError,
170 0x6700 => Self::WrongLength,
171 0x6982 => Self::EmptyBuffer,
172 0x6983 => Self::OutputBufferTooSmall,
173 0x6984 => Self::DataInvalid,
174 0x6985 => Self::ConditionsNotSatisfied,
175 0x6986 => Self::CommandNotAllowed,
176 0x6A80 => Self::BadKeyHandle,
177 0x6B00 => Self::InvalidP1P2,
178 0x6D00 => Self::InsNotSupported,
179 0x6E00 => Self::ClaNotSupported,
180 0x6F00 => Self::Unknown,
181 0x6F01 => Self::SignVerifyError,
182 _ => return Err(()),
183 };
184
185 Ok(this)
186 }
187}