openpgp_card/ocard/apdu/
command.rs1use secrecy::ExposeSecret as _;
8use secrecy::SecretVec;
9
10use crate::Error;
11
12#[derive(Clone, Copy)]
13pub enum Expect {
14 Empty,
15 Some,
16 Short(u8),
17}
18
19#[derive(Debug)]
20pub(crate) struct Command {
21 cla: u8,
23
24 ins: u8,
26
27 p1: u8,
29 p2: u8,
30
31 data: Data,
33}
34
35impl Command {
36 pub fn new(cla: u8, ins: u8, p1: u8, p2: u8, data: impl Into<Data>) -> Result<Self, Error> {
41 let data = data.into();
44
45 if data.len() > u16::MAX as usize {
46 Err(Error::InternalError(
47 "Command data too large, must be <64 kbyte".to_string(),
48 ))
49 } else {
50 Ok(Command {
51 cla,
52 ins,
53 p1,
54 p2,
55 data,
56 })
57 }
58 }
59
60 pub(crate) fn ins(&self) -> u8 {
61 self.ins
62 }
63
64 pub(crate) fn p1(&self) -> u8 {
65 self.p1
66 }
67
68 pub(crate) fn p2(&self) -> u8 {
69 self.p2
70 }
71
72 pub(crate) fn data(&self) -> &Data {
73 &self.data
74 }
75
76 pub(crate) fn serialize(
80 &self,
81 ext_len: bool,
82 expect_response: Expect,
83 ) -> Result<Vec<u8>, Error> {
84 debug_assert!(self.data.len() <= u16::MAX as usize);
90
91 let nc = self.data.len() as u16;
92
93 let mut buf = vec![self.cla, self.ins, self.p1, self.p2];
94 buf.extend(Self::make_lc(nc, ext_len)?);
95
96 match &self.data {
97 Data::Plain(data) => buf.extend(data),
98 Data::Sensitive(sensitive) => buf.extend(sensitive.expose_secret()),
99 }
100
101 buf.extend(Self::make_le(nc, ext_len, expect_response));
102
103 Ok(buf)
104 }
105
106 fn make_lc(len: u16, ext_len: bool) -> Result<Vec<u8>, crate::Error> {
108 if !ext_len && len > 0xff {
109 return Err(crate::Error::InternalError(format!(
110 "Command len = {len:x?}, but extended length is unsupported by backend"
111 )));
112 }
113
114 if len == 0 {
115 Ok(vec![])
116 } else if !ext_len {
117 Ok(vec![len as u8])
118 } else {
119 Ok(vec![0, (len >> 8) as u8, (len & 255) as u8])
120 }
121 }
122
123 fn make_le(nc: u16, ext_len: bool, expect_response: Expect) -> Vec<u8> {
126 match (ext_len, expect_response) {
127 (_, Expect::Empty) => {
128 vec![]
131 }
132 (false, Expect::Some) => {
133 vec![0]
135 }
136 (false, Expect::Short(size)) => {
137 vec![size]
139 }
140 (true, Expect::Some) => {
141 if nc == 0 {
142 vec![0, 0, 0]
145 } else {
146 vec![0, 0]
149 }
150 }
151 _ => {
152 unreachable!("This should not happen")
153 }
154 }
155 }
156}
157
158pub(crate) enum Data {
159 Plain(Vec<u8>),
160 Sensitive(SecretVec<u8>),
161}
162
163impl std::fmt::Debug for Data {
164 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165 match self {
166 Data::Plain(vec) => write!(f, "{vec:02x?}"),
167 Data::Sensitive(_) => write!(f, "REDACTED"),
168 }
169 }
170}
171
172impl Data {
173 #[must_use]
174 fn len(&self) -> usize {
175 match self {
176 Data::Plain(vec) => vec.len(),
177 Data::Sensitive(secret_vec) => secret_vec.expose_secret().len(),
178 }
179 }
180
181 #[must_use]
182 pub fn is_empty(&self) -> bool {
183 self.len() == 0
184 }
185}
186
187impl From<Vec<u8>> for Data {
188 fn from(value: Vec<u8>) -> Self {
189 Data::Plain(value)
190 }
191}
192
193impl From<SecretVec<u8>> for Data {
194 fn from(value: SecretVec<u8>) -> Self {
195 Data::Sensitive(value)
196 }
197}