1use super::{Command, CommandError, RequestCtap2, StatusCode};
2use crate::ctap2::attestation::AAGuid;
3use crate::ctap2::server::PublicKeyCredentialParameters;
4use crate::transport::errors::HIDError;
5use crate::u2ftypes::U2FDevice;
6use serde::{
7 de::{Error as SError, MapAccess, Visitor},
8 Deserialize, Deserializer,
9};
10use serde_cbor::{de::from_slice, Value};
11use std::collections::BTreeMap;
12use std::fmt;
13
14#[derive(Debug)]
15pub struct GetInfo {}
16
17impl Default for GetInfo {
18 fn default() -> GetInfo {
19 GetInfo {}
20 }
21}
22
23impl RequestCtap2 for GetInfo {
24 type Output = AuthenticatorInfo;
25
26 fn command() -> Command {
27 Command::GetInfo
28 }
29
30 fn wire_format<Dev>(&self, _dev: &mut Dev) -> Result<Vec<u8>, HIDError>
31 where
32 Dev: U2FDevice,
33 {
34 Ok(Vec::new())
35 }
36
37 fn handle_response_ctap2<Dev>(
38 &self,
39 _dev: &mut Dev,
40 input: &[u8],
41 ) -> Result<Self::Output, HIDError>
42 where
43 Dev: U2FDevice,
44 {
45 if input.is_empty() {
46 return Err(CommandError::InputTooSmall.into());
47 }
48
49 let status: StatusCode = input[0].into();
50
51 if input.len() > 1 {
52 if status.is_ok() {
53 trace!("parsing authenticator info data: {:#04X?}", &input[1..]);
54 let authenticator_info =
55 from_slice(&input[1..]).map_err(CommandError::Deserializing)?;
56 Ok(authenticator_info)
57 } else {
58 let data: Value = from_slice(&input[1..]).map_err(CommandError::Deserializing)?;
59 Err(CommandError::StatusCode(status, Some(data)).into())
60 }
61 } else {
62 Err(CommandError::InputTooSmall.into())
63 }
64 }
65}
66
67fn true_val() -> bool {
68 true
69}
70
71#[derive(Debug, Deserialize, Clone, Eq, PartialEq)]
72pub(crate) struct AuthenticatorOptions {
73 #[serde(rename = "plat", default)]
76 pub(crate) platform_device: bool,
77 #[serde(rename = "rk", default)]
81 pub(crate) resident_key: bool,
82
83 #[serde(rename = "clientPin")]
92 pub(crate) client_pin: Option<bool>,
93
94 #[serde(rename = "up", default = "true_val")]
96 pub(crate) user_presence: bool,
97
98 #[serde(rename = "uv")]
116 pub(crate) user_verification: Option<bool>,
117}
118
119impl Default for AuthenticatorOptions {
120 fn default() -> Self {
121 AuthenticatorOptions {
122 platform_device: false,
123 resident_key: false,
124 client_pin: None,
125 user_presence: true,
126 user_verification: None,
127 }
128 }
129}
130
131#[derive(Clone, Debug, Default, Eq, PartialEq)]
132pub struct AuthenticatorInfo {
133 pub(crate) versions: Vec<String>,
134 pub(crate) extensions: Vec<String>,
135 pub(crate) aaguid: AAGuid,
136 pub(crate) options: AuthenticatorOptions,
137 pub(crate) max_msg_size: Option<usize>,
138 pub(crate) pin_protocols: Vec<u32>,
139 pub(crate) max_credential_count_in_list: Option<usize>,
141 pub(crate) max_credential_id_length: Option<usize>,
142 pub(crate) transports: Option<Vec<String>>,
143 pub(crate) algorithms: Option<Vec<PublicKeyCredentialParameters>>,
144 pub(crate) max_ser_large_blob_array: Option<u32>,
145 pub(crate) force_pin_change: Option<bool>,
146 pub(crate) min_pin_length: Option<u32>,
147 pub(crate) firmware_version: Option<u32>,
148 pub(crate) max_cred_blob_length: Option<u32>,
149 pub(crate) max_rpids_for_set_min_pin_length: Option<u32>,
150 pub(crate) preferred_platform_uv_attempts: Option<u32>,
151 pub(crate) uvmodality: Option<u32>,
152 pub(crate) certifications: Option<BTreeMap<String, u32>>,
153 pub(crate) remaining_discoverable_credentials: Option<u32>,
154 pub(crate) vendor_prototype_config_commands: Option<Vec<u32>>,
155}
156
157impl AuthenticatorInfo {
158 pub fn supports_hmac_secret(&self) -> bool {
159 self.extensions.contains(&"hmac-secret".to_string())
160 }
161}
162
163impl fmt::Display for AuthenticatorInfo {
164 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165 writeln!(f, "Authenticator Info")?;
166 writeln!(f, "AAGuid: {}", self.aaguid)?;
167
168 write!(f, "Supported Versions: ")?;
169 for i in &self.versions {
170 write!(f, "{}, ", i)?;
171 }
172 writeln!(f, "")?;
173
174 write!(f, "Extensions: ")?;
175 for i in &self.extensions {
176 write!(f, "{}, ", i)?;
177 }
178 writeln!(f, "")?;
179
180 write!(f, "Transports: ")?;
189 if let Some(transports) = self.transports.as_ref() {
190 for i in transports {
191 write!(f, "{}, ", i)?;
192 }
193 } else {
194 write!(f, "Unknown")?;
195 }
196 writeln!(f, "")?;
197
198 write!(f, "Algorithms : ")?;
199 if let Some(pk_param) = self.algorithms.as_ref() {
200 for pk in pk_param {
201 write!(f, "{:?}, ", pk.alg)?;
202 }
203 } else {
204 write!(f, "Unknown")?;
205 }
206 writeln!(f, "")?;
207
208 writeln!(f, "PIN Change Required: {}", self.force_pin_change.unwrap_or(false))?;
209 if let Some(fv) = self.firmware_version {
210 writeln!(f, "Firmware Version: {}", fv)?;
211 } else {
212 writeln!(f, "Firmware Version: Unknown")?;
213 }
214 writeln!(f, "Maximum RP PIN Reqs: {}", self.max_rpids_for_set_min_pin_length.unwrap_or(0))?;
215
216 writeln!(f, "UserVerification Modality: 0x{:08X}", self.uvmodality.unwrap_or(0))?;
217
218 write!(f, "Certifications :")?;
219 if let Some(certs) = self.certifications.as_ref() {
220 for cert in certs {
221 write!(f, "{}:{} ", cert.0, cert.1)?;
222 }
223 } else {
224 write!(f, "None")?;
225 }
226 writeln!(f, "")?;
227
228 if let Some(rem_rk) = self.remaining_discoverable_credentials {
229 writeln!(f, "Remaining Discoverable Credentials: {}", rem_rk)?;
230 } else {
231 writeln!(f, "Remaining Discoverable Credentials: Unknown")?;
232 }
233
234 Ok(())
235 }
236}
237
238impl<'de> Deserialize<'de> for AuthenticatorInfo {
239 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
240 where
241 D: Deserializer<'de>,
242 {
243 struct AuthenticatorInfoVisitor;
244
245 impl<'de> Visitor<'de> for AuthenticatorInfoVisitor {
246 type Value = AuthenticatorInfo;
247
248 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
249 formatter.write_str("a byte array")
250 }
251
252 fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
253 where
254 M: MapAccess<'de>,
255 {
256 let mut versions = Vec::new();
257 let mut extensions = Vec::new();
258 let mut aaguid = None;
259 let mut options = AuthenticatorOptions::default();
260 let mut max_msg_size = None;
261 let mut pin_protocols = Vec::new();
262 let mut max_credential_count_in_list = None;
263 let mut max_credential_id_length = None;
264 let mut transports = None;
265 let mut algorithms = None;
266 let mut max_ser_large_blob_array = None;
267 let mut force_pin_change = None;
268 let mut min_pin_length = None;
269 let mut firmware_version = None;
270 let mut max_cred_blob_length = None;
271 let mut max_rpids_for_set_min_pin_length = None;
272 let mut preferred_platform_uv_attempts = None;
273 let mut uvmodality = None;
274 let mut certifications = None;
275 let mut remaining_discoverable_credentials = None;
276 let mut vendor_prototype_config_commands = None;
277
278 while let Some(key) = map.next_key()? {
279 match key {
280 0x01 => {
281 trace!("key 0x01");
282 if !versions.is_empty() {
283 return Err(serde::de::Error::duplicate_field("versions"));
284 }
285 versions = map.next_value()?;
286 }
287 0x02 => {
288 trace!("key 0x02");
289 if !extensions.is_empty() {
290 return Err(serde::de::Error::duplicate_field("extensions"));
291 }
292 extensions = map.next_value()?;
293 }
294 0x03 => {
295 trace!("key 0x03");
296 if aaguid.is_some() {
297 return Err(serde::de::Error::duplicate_field("aaguid"));
298 }
299 aaguid = Some(map.next_value()?);
300 }
301 0x04 => {
302 trace!("key 0x04");
303 options = map.next_value()?;
304 }
305 0x05 => {
306 trace!("key 0x05");
307 max_msg_size = Some(map.next_value()?);
308 }
309 0x06 => {
310 trace!("key 0x06");
311 pin_protocols = map.next_value()?;
312 }
313 0x07 => {
314 trace!("key 0x07");
315 if max_credential_count_in_list.is_some() {
316 return Err(serde::de::Error::duplicate_field(
317 "max_credential_count_in_list",
318 ));
319 }
320 max_credential_count_in_list = Some(map.next_value()?);
321 }
322 0x08 => {
323 trace!("key 0x08");
324 if max_credential_id_length.is_some() {
325 return Err(serde::de::Error::duplicate_field(
326 "max_credential_id_length",
327 ));
328 }
329 max_credential_id_length = Some(map.next_value()?);
330 }
331 0x09 => {
332 trace!("key 0x09");
333 if transports.is_some() {
334 return Err(serde::de::Error::duplicate_field("transports"));
335 }
336 transports = Some(map.next_value()?);
337 }
338 0x0a => {
339 trace!("key 0x0a");
340 if algorithms.is_some() {
341 return Err(serde::de::Error::duplicate_field("algorithms"));
342 }
343 algorithms = Some(map.next_value()?);
344 }
345 0x0b => {
346 trace!("key 0x0b");
347 if max_ser_large_blob_array.is_some() {
348 return Err(serde::de::Error::duplicate_field(
349 "max_ser_large_blob_array",
350 ));
351 }
352 max_ser_large_blob_array = Some(map.next_value()?);
353 }
354 0x0c => {
355 trace!("key 0x0c");
356 if force_pin_change.is_some() {
357 return Err(serde::de::Error::duplicate_field("force_pin_change"));
358 }
359 force_pin_change = Some(map.next_value()?);
360 }
361 0x0d => {
362 trace!("key 0x0d");
363 if min_pin_length.is_some() {
364 return Err(serde::de::Error::duplicate_field("min_pin_length"));
365 }
366 min_pin_length = Some(map.next_value()?);
367 }
368 0x0e => {
369 trace!("key 0x0e");
370 if firmware_version.is_some() {
371 return Err(serde::de::Error::duplicate_field("firmware_version"));
372 }
373 firmware_version = Some(map.next_value()?);
374 }
375 0x0f => {
376 trace!("key 0x0f");
377 if max_cred_blob_length.is_some() {
378 return Err(serde::de::Error::duplicate_field(
379 "max_cred_blob_length",
380 ));
381 }
382 max_cred_blob_length = Some(map.next_value()?);
383 }
384 0x10 => {
385 trace!("key 0x10");
386 if max_rpids_for_set_min_pin_length.is_some() {
387 return Err(serde::de::Error::duplicate_field(
388 "max_rpids_for_set_min_pin_length",
389 ));
390 }
391 max_rpids_for_set_min_pin_length = Some(map.next_value()?);
392 }
393 0x11 => {
394 trace!("key 0x11");
395 if preferred_platform_uv_attempts.is_some() {
396 return Err(serde::de::Error::duplicate_field(
397 "preferred_platform_uv_attempts",
398 ));
399 }
400 preferred_platform_uv_attempts = Some(map.next_value()?);
401 }
402 0x12 => {
403 trace!("key 0x12");
404 if uvmodality.is_some() {
405 return Err(serde::de::Error::duplicate_field("uvmodality"));
406 }
407 uvmodality = Some(map.next_value()?);
408 }
409 0x13 => {
410 trace!("key 0x13");
411 if certifications.is_some() {
412 return Err(serde::de::Error::duplicate_field("certifications"));
413 }
414 certifications = Some(map.next_value()?);
415 }
416 0x14 => {
417 trace!("key 0x14");
418 if remaining_discoverable_credentials.is_some() {
419 return Err(serde::de::Error::duplicate_field(
420 "remaining_discoverable_credentials",
421 ));
422 }
423 remaining_discoverable_credentials = Some(map.next_value()?);
424 }
425 0x15 => {
426 trace!("key 0x15");
427 if vendor_prototype_config_commands.is_some() {
428 return Err(serde::de::Error::duplicate_field(
429 "vendor_prototype_config_commands",
430 ));
431 }
432 vendor_prototype_config_commands = Some(map.next_value()?);
433 }
434 k => {
435 warn!("GetInfo: unsupported key: 0x{:x}", k);
437 continue;
438 }
439 }
440 }
441
442 if versions.is_empty() {
443 return Err(M::Error::custom(
444 "expected at least one version, got none".to_string(),
445 ));
446 }
447
448 if let Some(aaguid) = aaguid {
449 Ok(AuthenticatorInfo {
450 versions,
451 extensions,
452 aaguid,
453 options,
454 max_msg_size,
455 pin_protocols,
456 max_credential_count_in_list,
457 max_credential_id_length,
458 transports,
459 algorithms,
460 max_ser_large_blob_array,
461 force_pin_change,
462 min_pin_length,
463 firmware_version,
464 max_cred_blob_length,
465 max_rpids_for_set_min_pin_length,
466 preferred_platform_uv_attempts,
467 uvmodality,
468 certifications,
469 remaining_discoverable_credentials,
470 vendor_prototype_config_commands,
471 })
472 } else {
473 Err(M::Error::custom("No AAGuid specified".to_string()))
474 }
475 }
476 }
477
478 deserializer.deserialize_bytes(AuthenticatorInfoVisitor)
479 }
480}
481
482#[cfg(test)]
483pub mod tests {
484 use super::*;
485 use crate::consts::{Capability, HIDCmd, CID_BROADCAST};
486 use crate::transport::device_selector::Device;
487 use crate::transport::platform::device::IN_HID_RPT_SIZE;
488 use crate::transport::{hid::HIDDevice, FidoDevice, Nonce};
489 use crate::u2ftypes::U2FDevice;
490 use rand::{thread_rng, RngCore};
491 use serde_cbor::de::from_slice;
492
493 pub const AAGUID_RAW: [u8; 16] = [
495 0xF8, 0xA0, 0x11, 0xF3, 0x8C, 0x0A, 0x4D, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1F, 0x9E, 0xDC,
496 0x7D,
497 ];
498
499 pub const AUTHENTICATOR_INFO_PAYLOAD: [u8; 89] = [
500 0xa6, 0x01, 0x82, 0x66, 0x55, 0x32, 0x46, 0x5f, 0x56, 0x32, 0x68, 0x46, 0x49, 0x44, 0x4f,
501 0x5f, 0x32, 0x5f, 0x30, 0x02, 0x82, 0x63, 0x75, 0x76, 0x6d, 0x6b, 0x68, 0x6d, 0x61, 0x63,
502 0x2d, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x03, 0x50, 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a,
503 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, 0x04, 0xa4, 0x62, 0x72, 0x6b,
504 0xf5, 0x62, 0x75, 0x70, 0xf5, 0x64, 0x70, 0x6c, 0x61, 0x74, 0xf4, 0x69, 0x63, 0x6c, 0x69,
505 0x65, 0x6e, 0x74, 0x50, 0x69, 0x6e, 0xf4, 0x05, 0x19, 0x04, 0xb0, 0x06, 0x81, 0x01,
506 ];
507
508 #[test]
509 fn parse_authenticator_info() {
510 let authenticator_info: AuthenticatorInfo =
511 from_slice(&AUTHENTICATOR_INFO_PAYLOAD).unwrap();
512
513 let expected = AuthenticatorInfo {
514 versions: vec!["U2F_V2".to_string(), "FIDO_2_0".to_string()],
515 extensions: vec!["uvm".to_string(), "hmac-secret".to_string()],
516 aaguid: AAGuid(AAGUID_RAW),
517 options: AuthenticatorOptions {
518 platform_device: false,
519 resident_key: true,
520 client_pin: Some(false),
521 user_presence: true,
522 user_verification: None,
523 },
524 max_msg_size: Some(1200),
525 pin_protocols: vec![1],
526 max_credential_count_in_list: None,
527 max_credential_id_length: None,
528 transports: None,
529 algorithms: None,
530 max_ser_large_blob_array: None,
531 force_pin_change: None,
532 min_pin_length: None,
533 firmware_version: None,
534 max_cred_blob_length: None,
535 max_rpids_for_set_min_pin_length: None,
536 preferred_platform_uv_attempts: None,
537 uvmodality: None,
538 certifications: None,
539 remaining_discoverable_credentials: None,
540 vendor_prototype_config_commands: None,
541 };
542
543 assert_eq!(authenticator_info, expected);
544 }
545
546 pub const AUTHENTICATOR_INFO_PAYLOAD_YK_BIO_5C: [u8; 409] = [
547 0xB3, 0x01, 0x84, 0x66, 0x55, 0x32, 0x46, 0x5F, 0x56, 0x32, 0x68, 0x46, 0x49, 0x44, 0x4F,
548 0x5F, 0x32, 0x5F, 0x30, 0x6C, 0x46, 0x49, 0x44, 0x4F, 0x5F, 0x32, 0x5F, 0x31, 0x5F, 0x50,
549 0x52, 0x45, 0x68, 0x46, 0x49, 0x44, 0x4F, 0x5F, 0x32, 0x5F, 0x31, 0x02, 0x85, 0x6B, 0x63,
550 0x72, 0x65, 0x64, 0x50, 0x72, 0x6F, 0x74, 0x65, 0x63, 0x74, 0x6B, 0x68, 0x6D, 0x61, 0x63,
551 0x2D, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x6C, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x42, 0x6C,
552 0x6F, 0x62, 0x4B, 0x65, 0x79, 0x68, 0x63, 0x72, 0x65, 0x64, 0x42, 0x6C, 0x6F, 0x62, 0x6C,
553 0x6D, 0x69, 0x6E, 0x50, 0x69, 0x6E, 0x4C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0x03, 0x50, 0xD8,
554 0x52, 0x2D, 0x9F, 0x57, 0x5B, 0x48, 0x66, 0x88, 0xA9, 0xBA, 0x99, 0xFA, 0x02, 0xF3, 0x5B,
555 0x04, 0xB0, 0x62, 0x72, 0x6B, 0xF5, 0x62, 0x75, 0x70, 0xF5, 0x62, 0x75, 0x76, 0xF5, 0x64,
556 0x70, 0x6C, 0x61, 0x74, 0xF4, 0x67, 0x75, 0x76, 0x54, 0x6F, 0x6B, 0x65, 0x6E, 0xF5, 0x68,
557 0x61, 0x6C, 0x77, 0x61, 0x79, 0x73, 0x55, 0x76, 0xF5, 0x68, 0x63, 0x72, 0x65, 0x64, 0x4D,
558 0x67, 0x6D, 0x74, 0xF5, 0x69, 0x61, 0x75, 0x74, 0x68, 0x6E, 0x72, 0x43, 0x66, 0x67, 0xF5,
559 0x69, 0x62, 0x69, 0x6F, 0x45, 0x6E, 0x72, 0x6F, 0x6C, 0x6C, 0xF5, 0x69, 0x63, 0x6C, 0x69,
560 0x65, 0x6E, 0x74, 0x50, 0x69, 0x6E, 0xF5, 0x6A, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x42, 0x6C,
561 0x6F, 0x62, 0x73, 0xF5, 0x6E, 0x70, 0x69, 0x6E, 0x55, 0x76, 0x41, 0x75, 0x74, 0x68, 0x54,
562 0x6F, 0x6B, 0x65, 0x6E, 0xF5, 0x6F, 0x73, 0x65, 0x74, 0x4D, 0x69, 0x6E, 0x50, 0x49, 0x4E,
563 0x4C, 0x65, 0x6E, 0x67, 0x74, 0x68, 0xF5, 0x70, 0x6D, 0x61, 0x6B, 0x65, 0x43, 0x72, 0x65,
564 0x64, 0x55, 0x76, 0x4E, 0x6F, 0x74, 0x52, 0x71, 0x64, 0xF4, 0x75, 0x63, 0x72, 0x65, 0x64,
565 0x65, 0x6E, 0x74, 0x69, 0x61, 0x6C, 0x4D, 0x67, 0x6D, 0x74, 0x50, 0x72, 0x65, 0x76, 0x69,
566 0x65, 0x77, 0xF5, 0x78, 0x1B, 0x75, 0x73, 0x65, 0x72, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69,
567 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x4D, 0x67, 0x6D, 0x74, 0x50, 0x72, 0x65, 0x76, 0x69,
568 0x65, 0x77, 0xF5, 0x05, 0x19, 0x04, 0xB0, 0x06, 0x82, 0x02, 0x01, 0x07, 0x08, 0x08, 0x18,
569 0x80, 0x09, 0x81, 0x63, 0x75, 0x73, 0x62, 0x0A, 0x82, 0xA2, 0x63, 0x61, 0x6C, 0x67, 0x26,
570 0x64, 0x74, 0x79, 0x70, 0x65, 0x6A, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x2D, 0x6B, 0x65,
571 0x79, 0xA2, 0x63, 0x61, 0x6C, 0x67, 0x27, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6A, 0x70, 0x75,
572 0x62, 0x6C, 0x69, 0x63, 0x2D, 0x6B, 0x65, 0x79, 0x0B, 0x19, 0x04, 0x00, 0x0C, 0xF4, 0x0D,
573 0x04, 0x0E, 0x1A, 0x00, 0x05, 0x05, 0x06, 0x0F, 0x18, 0x20, 0x10, 0x01, 0x11, 0x03, 0x12,
574 0x02, 0x14, 0x18, 0x18,
575 ];
576
577 #[test]
578 fn parse_authenticator_info_yk_bio_5c() {
579 let _ = env_logger::builder().is_test(true).try_init();
580 error!("Logs are alive!");
581
582 let authenticator_info: AuthenticatorInfo =
583 from_slice(&AUTHENTICATOR_INFO_PAYLOAD_YK_BIO_5C).unwrap();
584
585 debug!("{:?}", authenticator_info);
586 }
587
588 #[test]
589 fn test_get_info_ctap2_only() {
590 let mut device = Device::new("commands/get_info").unwrap();
591 let nonce = [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01];
592
593 let mut cid = [0u8; 4];
595 thread_rng().fill_bytes(&mut cid);
596
597 let mut msg = CID_BROADCAST.to_vec();
599 msg.extend(vec![HIDCmd::Init.into(), 0x00, 0x08]); msg.extend_from_slice(&nonce);
601 device.add_write(&msg, 0);
602
603 let mut msg = CID_BROADCAST.to_vec();
605 msg.extend(vec![
606 0x06, 0x00, 0x11,
608 ]); msg.extend_from_slice(&nonce);
610 msg.extend_from_slice(&cid); msg.extend(vec![0x02, 0x04, 0x01, 0x08, 0x01 | 0x04 | 0x08]); device.add_read(&msg, 0);
615
616 let mut msg = cid.to_vec();
618 msg.extend(vec![HIDCmd::Cbor.into(), 0x00, 0x1]); msg.extend(vec![0x04]); device.add_write(&msg, 0);
621
622 let mut msg = cid.to_vec();
624 msg.extend(vec![HIDCmd::Cbor.into(), 0x00, 0x5A]); msg.extend(vec![0]); msg.extend(&AUTHENTICATOR_INFO_PAYLOAD[0..(IN_HID_RPT_SIZE - 8)]);
627 device.add_read(&msg, 0);
628 let mut msg = cid.to_vec();
630 msg.extend(vec![0x00]); msg.extend(&AUTHENTICATOR_INFO_PAYLOAD[(IN_HID_RPT_SIZE - 8)..]);
632 device.add_read(&msg, 0);
633 device
634 .init(Nonce::Use(nonce))
635 .expect("Failed to init device");
636
637 assert_eq!(device.get_cid(), &cid);
638
639 let dev_info = device.get_device_info();
640 assert_eq!(
641 dev_info.cap_flags,
642 Capability::WINK | Capability::CBOR | Capability::NMSG
643 );
644
645 let result = device
646 .get_authenticator_info()
647 .expect("Didn't get any authenticator_info");
648 let expected = AuthenticatorInfo {
649 versions: vec!["U2F_V2".to_string(), "FIDO_2_0".to_string()],
650 extensions: vec!["uvm".to_string(), "hmac-secret".to_string()],
651 aaguid: AAGuid(AAGUID_RAW),
652 options: AuthenticatorOptions {
653 platform_device: false,
654 resident_key: true,
655 client_pin: Some(false),
656 user_presence: true,
657 user_verification: None,
658 },
659 max_msg_size: Some(1200),
660 pin_protocols: vec![1],
661 max_credential_count_in_list: None,
662 max_credential_id_length: None,
663 transports: None,
664 algorithms: None,
665 max_ser_large_blob_array: None,
666 force_pin_change: None,
667 min_pin_length: None,
668 firmware_version: None,
669 max_cred_blob_length: None,
670 max_rpids_for_set_min_pin_length: None,
671 preferred_platform_uv_attempts: None,
672 uvmodality: None,
673 certifications: None,
674 remaining_discoverable_credentials: None,
675 vendor_prototype_config_commands: None,
676 };
677
678 assert_eq!(result, &expected);
679 }
680}