openpgp_card/ocard/data/
extended_cap.rs1use std::convert::TryFrom;
7
8use crate::ocard::data::ExtendedCapabilities;
9use crate::Error;
10
11impl ExtendedCapabilities {
12 pub fn secure_messaging(&self) -> bool {
16 self.secure_messaging
17 }
18
19 pub fn get_challenge(&self) -> bool {
23 self.get_challenge
24 }
25
26 pub fn max_len_challenge(&self) -> u16 {
31 self.max_len_challenge
32 }
33
34 pub fn key_import(&self) -> bool {
36 self.key_import
37 }
38
39 pub fn pw_status_change(&self) -> bool {
42 self.pw_status_change
43 }
44
45 pub fn private_use_dos(&self) -> bool {
47 self.private_use_dos
48 }
49
50 pub fn algo_attrs_changeable(&self) -> bool {
53 self.algo_attrs_changeable
54 }
55
56 pub fn aes(&self) -> bool {
58 self.aes
59 }
60
61 pub fn kdf_do(&self) -> bool {
63 self.kdf_do
64 }
65
66 pub fn max_len_cardholder_cert(&self) -> u16 {
68 self.max_len_cardholder_cert
69 }
70
71 pub fn max_len_special_do(&self) -> Option<u16> {
76 self.max_len_special_do
77 }
78
79 pub fn pin_block_2_format_support(&self) -> Option<bool> {
83 self.pin_block_2_format_support
84 }
85
86 pub fn mse_command_support(&self) -> Option<bool> {
91 self.mse_command_support
92 }
93
94 pub(crate) fn max_cmd_len(&self) -> Option<u16> {
99 self.max_cmd_len
100 }
101
102 pub(crate) fn max_resp_len(&self) -> Option<u16> {
107 self.max_resp_len
108 }
109}
110
111impl TryFrom<(&[u8], u16)> for ExtendedCapabilities {
112 type Error = Error;
113
114 fn try_from((input, version): (&[u8], u16)) -> Result<Self, Self::Error> {
115 let version = ((version >> 8) as u8, (version & 0xff) as u8);
118
119 if version.0 != 2 && version.0 != 3 {
123 return Err(Error::UnsupportedFeature(format!(
124 "Card version {:?} is unsupported",
125 version
126 )));
127 }
128
129 if input.len() != 10 {
131 return Err(Error::InternalError(format!(
132 "Unexpected ExtendedCapabilities length {}",
133 input.len()
134 )));
135 }
136
137 let b = input[0];
138
139 let secure_messaging = b & 0x80 != 0;
140 let get_challenge = b & 0x40 != 0;
141 let key_import = b & 0x20 != 0;
142 let pw_status_change = b & 0x10 != 0;
143 let private_use_dos = b & 0x08 != 0;
144 let algo_attrs_changeable = b & 0x04 != 0;
145 let aes = b & 0x02 != 0;
146 let kdf_do = b & 0x01 != 0;
147
148 let sm_algo = input[1];
149
150 let max_len_challenge = input[2] as u16 * 256 + input[3] as u16;
151 let max_len_cardholder_cert = input[4] as u16 * 256 + input[5] as u16;
152
153 let mut max_cmd_len = None;
154 let mut max_resp_len = None;
155
156 let mut max_len_special_do = None;
157 let mut pin_block_2_format_support = None;
158 let mut mse_command_support = None;
159
160 if version.0 == 2 {
161 max_cmd_len = Some(input[6] as u16 * 256 + input[7] as u16);
163 max_resp_len = Some(input[8] as u16 * 256 + input[9] as u16);
164 } else {
165 max_len_special_do = Some(input[6] as u16 * 256 + input[7] as u16);
167
168 let i8 = input[8];
169 let i9 = input[9];
170
171 if i8 > 1 {
172 return Err(Error::ParseError(format!(
173 "Illegal value '{i8}' for pin_block_2_format_support"
174 )));
175 }
176
177 pin_block_2_format_support = Some(i8 != 0);
178
179 if i9 > 1 {
180 return Err(Error::ParseError(format!(
181 "Illegal value '{i9}' for mse_command_support"
182 )));
183 }
184 mse_command_support = Some(i9 != 0);
185 }
186
187 Ok(Self {
188 secure_messaging,
189 get_challenge,
190 key_import,
191 pw_status_change,
192 private_use_dos,
193 algo_attrs_changeable,
194 aes,
195 kdf_do,
196
197 sm_algo,
198 max_len_challenge,
199 max_len_cardholder_cert,
200
201 max_cmd_len, max_resp_len, max_len_special_do, pin_block_2_format_support, mse_command_support, })
208 }
209}
210
211#[cfg(test)]
212mod test {
213 use std::convert::TryFrom;
214
215 use hex_literal::hex;
216
217 use crate::ocard::data::extended_cap::ExtendedCapabilities;
218
219 #[test]
220 fn test_yk5() {
221 let data = hex!("7d 00 0b fe 08 00 00 ff 00 00");
223
224 let ec = ExtendedCapabilities::try_from((&data[..], 0x0304)).unwrap();
225
226 assert_eq!(
227 ec,
228 ExtendedCapabilities {
229 secure_messaging: false,
230 get_challenge: true,
231 key_import: true,
232 pw_status_change: true,
233 private_use_dos: true,
234 algo_attrs_changeable: true,
235 aes: false,
236 kdf_do: true,
237 sm_algo: 0x0,
238 max_len_challenge: 0xbfe,
239 max_len_cardholder_cert: 0x800,
240 max_cmd_len: None,
241 max_resp_len: None,
242 max_len_special_do: Some(0xff),
243 pin_block_2_format_support: Some(false),
244 mse_command_support: Some(false),
245 }
246 );
247 }
248
249 #[test]
250 fn test_floss21() {
251 let data = hex!("7c 00 08 00 08 00 08 00 08 00");
253
254 let ec = ExtendedCapabilities::try_from((&data[..], 0x0201)).unwrap();
255
256 assert_eq!(
257 ec,
258 ExtendedCapabilities {
259 secure_messaging: false,
260 get_challenge: true,
261 key_import: true,
262 pw_status_change: true,
263 private_use_dos: true,
264 algo_attrs_changeable: true,
265 aes: false,
266 kdf_do: false,
267 sm_algo: 0,
268 max_len_challenge: 2048,
269 max_len_cardholder_cert: 2048,
270 max_cmd_len: Some(2048),
271 max_resp_len: Some(2048),
272 max_len_special_do: None,
273 pin_block_2_format_support: None,
274 mse_command_support: None,
275 }
276 );
277 }
278}