Skip to main content

authenticator_ctap2_2021/ctap2/commands/
get_info.rs

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    /// Indicates that the device is attached to the client and therefore can’t
74    /// be removed and used on another client.
75    #[serde(rename = "plat", default)]
76    pub(crate) platform_device: bool,
77    /// Indicates that the device is capable of storing keys on the device
78    /// itself and therefore can satisfy the authenticatorGetAssertion request
79    /// with allowList parameter not specified or empty.
80    #[serde(rename = "rk", default)]
81    pub(crate) resident_key: bool,
82
83    /// Client PIN:
84    ///  If present and set to true, it indicates that the device is capable of
85    ///   accepting a PIN from the client and PIN has been set.
86    ///  If present and set to false, it indicates that the device is capable of
87    ///   accepting a PIN from the client and PIN has not been set yet.
88    ///  If absent, it indicates that the device is not capable of accepting a
89    ///   PIN from the client.
90    /// Client PIN is one of the ways to do user verification.
91    #[serde(rename = "clientPin")]
92    pub(crate) client_pin: Option<bool>,
93
94    /// Indicates that the device is capable of testing user presence.
95    #[serde(rename = "up", default = "true_val")]
96    pub(crate) user_presence: bool,
97
98    /// Indicates that the device is capable of verifying the user within
99    /// itself. For example, devices with UI, biometrics fall into this
100    /// category.
101    ///  If present and set to true, it indicates that the device is capable of
102    ///   user verification within itself and has been configured.
103    ///  If present and set to false, it indicates that the device is capable of
104    ///   user verification within itself and has not been yet configured. For
105    ///   example, a biometric device that has not yet been configured will
106    ///   return this parameter set to false.
107    ///  If absent, it indicates that the device is not capable of user
108    ///   verification within itself.
109    /// A device that can only do Client PIN will not return the "uv" parameter.
110    /// If a device is capable of verifying the user within itself as well as
111    /// able to do Client PIN, it will return both "uv" and the Client PIN
112    /// option.
113    // TODO(MS): My Token (key-ID FIDO2) does return Some(false) here, even though
114    //           it has no built-in verification method. Not to be trusted...
115    #[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    // CTAP 2.1
140    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        // options
181
182        // pin_protocols
183
184        // max_msg_size
185
186        // max_credential_id_length
187
188        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                            // DANGER: If we hit this it tottaly trashes parsing :(
436                            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    // Raw data take from https://github.com/Yubico/python-fido2/blob/master/test/test_ctap2.py
494    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        // channel id
594        let mut cid = [0u8; 4];
595        thread_rng().fill_bytes(&mut cid);
596
597        // init packet
598        let mut msg = CID_BROADCAST.to_vec();
599        msg.extend(vec![HIDCmd::Init.into(), 0x00, 0x08]); // cmd + bcnt
600        msg.extend_from_slice(&nonce);
601        device.add_write(&msg, 0);
602
603        // init_resp packet
604        let mut msg = CID_BROADCAST.to_vec();
605        msg.extend(vec![
606            0x06, /*HIDCmd::Init without TYPE_INIT*/
607            0x00, 0x11,
608        ]); // cmd + bcnt
609        msg.extend_from_slice(&nonce);
610        msg.extend_from_slice(&cid); // new channel id
611
612        // We are setting NMSG, to signal that the device does not support CTAP1
613        msg.extend(vec![0x02, 0x04, 0x01, 0x08, 0x01 | 0x04 | 0x08]); // versions + flags (wink+cbor+nmsg)
614        device.add_read(&msg, 0);
615
616        // ctap2 request
617        let mut msg = cid.to_vec();
618        msg.extend(vec![HIDCmd::Cbor.into(), 0x00, 0x1]); // cmd + bcnt
619        msg.extend(vec![0x04]); // authenticatorGetInfo
620        device.add_write(&msg, 0);
621
622        // ctap2 response
623        let mut msg = cid.to_vec();
624        msg.extend(vec![HIDCmd::Cbor.into(), 0x00, 0x5A]); // cmd + bcnt
625        msg.extend(vec![0]); // Status code: Success
626        msg.extend(&AUTHENTICATOR_INFO_PAYLOAD[0..(IN_HID_RPT_SIZE - 8)]);
627        device.add_read(&msg, 0);
628        // Continuation package
629        let mut msg = cid.to_vec();
630        msg.extend(vec![0x00]); // SEQ
631        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}