Skip to main content

authenticator_ctap2_2021/ctap2/commands/
make_credentials.rs

1use super::{
2    Command, CommandError, PinAuthCommand, Request, RequestCtap1, RequestCtap2, Retryable,
3    StatusCode,
4};
5use crate::consts::{PARAMETER_SIZE, U2F_REGISTER, U2F_REQUEST_USER_PRESENCE};
6use crate::crypto::{serialize_key, COSEAlgorithm, COSEEC2Key, COSEKey, COSEKeyType, ECDSACurve};
7use crate::ctap2::attestation::{
8    AAGuid, AttestationObject, AttestationStatement, AttestedCredentialData, AuthenticatorData,
9    AuthenticatorDataFlags,
10};
11use crate::ctap2::client_data::CollectedClientData;
12use crate::ctap2::commands::client_pin::{Pin, PinAuth};
13use crate::ctap2::server::{
14    PublicKeyCredentialDescriptor, PublicKeyCredentialParameters, RelyingPartyWrapper, User,
15};
16use crate::transport::errors::{ApduErrorStatus, HIDError};
17use crate::u2ftypes::{U2FAPDUHeader, U2FDevice};
18use nom::{
19    bytes::complete::{tag, take},
20    error::VerboseError,
21    number::complete::be_u8,
22};
23#[cfg(test)]
24use serde::Deserialize;
25use serde::{
26    de::Error as DesError,
27    ser::{Error as SerError, SerializeMap},
28    Serialize, Serializer,
29};
30use serde_cbor::{self, de::from_slice, ser, Value};
31use std::fmt;
32use std::io;
33
34#[derive(Debug)]
35pub enum MakeCredentialsResult {
36    CTAP1(Vec<u8>),
37    CTAP2(AttestationObject, CollectedClientData),
38}
39
40#[derive(Copy, Clone, Debug, Serialize)]
41#[cfg_attr(test, derive(Deserialize))]
42pub struct MakeCredentialsOptions {
43    #[serde(rename = "rk", skip_serializing_if = "Option::is_none")]
44    pub resident_key: Option<bool>,
45    #[serde(rename = "uv", skip_serializing_if = "Option::is_none")]
46    pub user_verification: Option<bool>,
47    // TODO(MS): ctap2.1 supports user_presence, but ctap2.0 does not and tokens will error out
48    //           Commands need a version-flag to know what to de/serialize and what to ignore.
49}
50
51impl Default for MakeCredentialsOptions {
52    fn default() -> Self {
53        Self {
54            resident_key: None,
55            user_verification: None,
56        }
57    }
58}
59
60impl MakeCredentialsOptions {
61    pub(crate) fn has_some(&self) -> bool {
62        self.resident_key.is_some() || self.user_verification.is_some()
63    }
64}
65
66pub(crate) trait UserVerification {
67    fn ask_user_verification(&self) -> bool;
68}
69
70impl UserVerification for MakeCredentialsOptions {
71    fn ask_user_verification(&self) -> bool {
72        if let Some(e) = self.user_verification {
73            e
74        } else {
75            false
76        }
77    }
78}
79
80#[derive(Debug, Clone, Serialize, Default)]
81pub struct MakeCredentialsExtensions {
82    #[serde(rename = "pinMinLength", skip_serializing_if = "Option::is_none")]
83    pub pin_min_length: Option<bool>,
84    #[serde(rename = "hmac-secret", skip_serializing_if = "Option::is_none")]
85    pub hmac_secret: Option<bool>,
86}
87
88impl MakeCredentialsExtensions {
89    fn has_extensions(&self) -> bool {
90        self.pin_min_length.or(self.hmac_secret).is_some()
91    }
92}
93
94#[derive(Debug, Clone)]
95pub struct MakeCredentials {
96    pub(crate) client_data: CollectedClientData,
97    pub(crate) rp: RelyingPartyWrapper,
98    // Note(baloo): If none -> ctap1
99    pub(crate) user: Option<User>,
100    pub(crate) pub_cred_params: Vec<PublicKeyCredentialParameters>,
101    pub(crate) exclude_list: Vec<PublicKeyCredentialDescriptor>,
102
103    // https://www.w3.org/TR/webauthn/#client-extension-input
104    // The client extension input, which is a value that can be encoded in JSON,
105    // is passed from the WebAuthn Relying Party to the client in the get() or
106    // create() call, while the CBOR authenticator extension input is passed
107    // from the client to the authenticator for authenticator extensions during
108    // the processing of these calls.
109    pub(crate) extensions: MakeCredentialsExtensions,
110    pub(crate) options: MakeCredentialsOptions,
111    pub(crate) pin: Option<Pin>,
112    pub(crate) pin_auth: Option<PinAuth>,
113    // TODO(MS): pin_protocol
114}
115
116impl MakeCredentials {
117    pub fn new(
118        client_data: CollectedClientData,
119        rp: RelyingPartyWrapper,
120        user: Option<User>,
121        pub_cred_params: Vec<PublicKeyCredentialParameters>,
122        exclude_list: Vec<PublicKeyCredentialDescriptor>,
123        options: MakeCredentialsOptions,
124        extensions: MakeCredentialsExtensions,
125        pin: Option<Pin>,
126    ) -> Self {
127        Self {
128            client_data,
129            rp,
130            user,
131            pub_cred_params,
132            exclude_list,
133            extensions,
134            options,
135            pin,
136            pin_auth: None,
137        }
138    }
139}
140
141impl PinAuthCommand for MakeCredentials {
142    fn pin(&self) -> &Option<Pin> {
143        &self.pin
144    }
145
146    fn set_pin(&mut self, pin: Option<Pin>) {
147        self.pin = pin;
148    }
149
150    fn pin_auth(&self) -> &Option<PinAuth> {
151        &self.pin_auth
152    }
153
154    fn set_pin_auth(&mut self, pin_auth: Option<PinAuth>) {
155        self.pin_auth = pin_auth;
156    }
157
158    fn client_data(&self) -> &CollectedClientData {
159        &self.client_data
160    }
161
162    fn unset_uv_option(&mut self) {
163        self.options.user_verification = None;
164    }
165}
166
167impl Serialize for MakeCredentials {
168    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
169    where
170        S: Serializer,
171    {
172        debug!("Serialize MakeCredentials");
173        // Need to define how many elements are going to be in the map
174        // beforehand
175        let mut map_len = 4;
176        if !self.exclude_list.is_empty() {
177            map_len += 1;
178        }
179        if self.extensions.has_extensions() {
180            map_len += 1;
181        }
182        if self.options.has_some() {
183            map_len += 1;
184        }
185        if self.pin_auth.is_some() {
186            map_len += 2;
187        }
188
189        let mut map = serializer.serialize_map(Some(map_len))?;
190        let client_data_hash = self
191            .client_data
192            .hash()
193            .map_err(|e| S::Error::custom(format!("error while hashing client data: {}", e)))?;
194        map.serialize_entry(&1, &client_data_hash)?;
195        match self.rp {
196            RelyingPartyWrapper::Data(ref d) => {
197                map.serialize_entry(&2, &d)?;
198            }
199            _ => {
200                return Err(S::Error::custom(
201                    "Can't serialize a RelyingParty::Hash for CTAP2",
202                ));
203            }
204        }
205        map.serialize_entry(&3, &self.user)?;
206        map.serialize_entry(&4, &self.pub_cred_params)?;
207        if !self.exclude_list.is_empty() {
208            map.serialize_entry(&5, &self.exclude_list)?;
209        }
210        if self.extensions.has_extensions() {
211            map.serialize_entry(&6, &self.extensions)?;
212        }
213        if self.options.has_some() {
214            map.serialize_entry(&7, &self.options)?;
215        }
216        if let Some(pin_auth) = &self.pin_auth {
217            map.serialize_entry(&8, &pin_auth)?;
218            map.serialize_entry(&9, &1)?; // version
219        }
220        map.end()
221    }
222}
223
224impl Request<MakeCredentialsResult> for MakeCredentials {
225    fn is_ctap2_request(&self) -> bool {
226        self.user.is_some()
227    }
228}
229
230impl RequestCtap1 for MakeCredentials {
231    type Output = MakeCredentialsResult;
232
233    fn apdu_format<Dev>(&self, _dev: &mut Dev) -> Result<Vec<u8>, HIDError>
234    where
235        Dev: U2FDevice,
236    {
237        // TODO(MS): Mandatory sanity checks are missing:
238        // https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#u2f-authenticatorMakeCredential-interoperability
239        // If any of the below conditions is not true, platform errors out with CTAP2_ERR_UNSUPPORTED_OPTION.
240        //  * pubKeyCredParams must use the ES256 algorithm (-7).
241        //  * Options must not include "rk" set to true.
242        //  * Options must not include "uv" set to true.
243
244        let flags = if self.options.ask_user_verification() {
245            U2F_REQUEST_USER_PRESENCE
246        } else {
247            0
248        };
249
250        let mut register_data = Vec::with_capacity(2 * PARAMETER_SIZE);
251        if self.is_ctap2_request() {
252            register_data.extend_from_slice(
253                self.client_data
254                    .hash()
255                    .map_err(|e| HIDError::Command(CommandError::Json(e)))?
256                    .as_ref(),
257            );
258        } else {
259            let decoded =
260                base64::decode_config(&self.client_data.challenge.0, base64::URL_SAFE_NO_PAD)
261                    .map_err(|_| HIDError::DeviceError)?; // We encoded it, so this should never fail
262            register_data.extend_from_slice(&decoded);
263        }
264        register_data.extend_from_slice(self.rp.hash().as_ref());
265        let cmd = U2F_REGISTER;
266        let apdu = U2FAPDUHeader::serialize(cmd, flags, &register_data)?;
267
268        Ok(apdu)
269    }
270
271    fn handle_response_ctap1(
272        &self,
273        status: Result<(), ApduErrorStatus>,
274        input: &[u8],
275    ) -> Result<Self::Output, Retryable<HIDError>> {
276        if Err(ApduErrorStatus::ConditionsNotSatisfied) == status {
277            return Err(Retryable::Retry);
278        }
279        if let Err(err) = status {
280            return Err(Retryable::Error(HIDError::ApduStatus(err)));
281        }
282
283        if self.is_ctap2_request() {
284            let parse_register = |input| {
285                let (rest, _) = tag(&[0x05])(input)?;
286                let (rest, public_key) = take(65u8)(rest)?;
287                let (rest, key_handle_len) = be_u8(rest)?;
288                let (rest, key_handle) = take(key_handle_len)(rest)?;
289                Ok((rest, public_key, key_handle))
290            };
291            let (rest, public_key, key_handle) = parse_register(input)
292                .map_err(|e: nom::Err<VerboseError<_>>| {
293                    error!("error while parsing registration: {:?}", e);
294                    CommandError::Deserializing(DesError::custom("unable to parse registration"))
295                })
296                .map_err(HIDError::Command)
297                .map_err(Retryable::Error)?;
298            // TODO(MS): This is currently not parsed within the crate, but outside by a user-provided function
299            //           See examples/main.rs: u2f_get_key_handle_from_register_response()
300            //           We would need to add a DER parser as a dependency, which I don't want to do right now.
301            // let (signature, cert) = der_parser::parse_der(rest)
302            //     .map_err(|e| {
303            //         error!("error while parsing cert = {:?}", e);
304            //         let err = io::Error::new(io::ErrorKind::Other, "Failed to parse x509 certificate");
305            //         let err = error::Error::from(err);
306            //         let err = CommandError::Deserializing(err);
307            //         let err = HIDError::Command(err);
308            //         Retryable::Error(err)
309            //     })
310            //     .map(|(sig, cert)| (sig, &rest[..rest.len() - sig.len()]))?;
311            let (x, y) = serialize_key(ECDSACurve::SECP256R1, public_key)
312                .map_err(|e| HIDError::Command(CommandError::Crypto(e.into())))
313                .map_err(Retryable::Error)?;
314            let credential_public_key = COSEKey {
315                alg: COSEAlgorithm::ES256,
316                key: COSEKeyType::EC2(COSEEC2Key {
317                    curve: ECDSACurve::SECP256R1,
318                    x: x.to_vec(),
319                    y: y.to_vec(),
320                }),
321            };
322            let auth_data = AuthenticatorData {
323                rp_id_hash: self.rp.hash(),
324                // https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#u2f-authenticatorMakeCredential-interoperability
325                // "Let flags be a byte whose zeroth bit (bit 0, UP) is set, and whose sixth bit
326                // (bit 6, AT) is set, and all other bits are zero (bit zero is the least significant bit)"
327                flags: AuthenticatorDataFlags::USER_PRESENT | AuthenticatorDataFlags::ATTESTED,
328                counter: 0,
329                credential_data: Some(AttestedCredentialData {
330                    aaguid: AAGuid::default(),
331                    credential_id: Vec::from(key_handle),
332                    credential_public_key,
333                }),
334                extensions: Default::default(),
335            };
336
337            // TODO(MS)
338            // let att_statement_u2f = AttestationStatementFidoU2F::new(cert, signature);
339            let att_statement = AttestationStatement::Unparsed(rest.to_vec());
340            let attestation_object = AttestationObject {
341                auth_data,
342                att_statement,
343            };
344            let client_data = self.client_data.clone();
345
346            Ok(MakeCredentialsResult::CTAP2(
347                attestation_object,
348                client_data,
349            ))
350        } else {
351            Ok(MakeCredentialsResult::CTAP1(input.to_vec()))
352        }
353    }
354}
355
356impl RequestCtap2 for MakeCredentials {
357    type Output = MakeCredentialsResult;
358
359    fn command() -> Command {
360        Command::MakeCredentials
361    }
362
363    fn wire_format<Dev>(&self, _dev: &mut Dev) -> Result<Vec<u8>, HIDError>
364    where
365        Dev: U2FDevice + io::Read + io::Write + fmt::Debug,
366    {
367        Ok(ser::to_vec(&self).map_err(CommandError::Serializing)?)
368    }
369
370    fn handle_response_ctap2<Dev>(
371        &self,
372        _dev: &mut Dev,
373        input: &[u8],
374    ) -> Result<Self::Output, HIDError>
375    where
376        Dev: U2FDevice + io::Read + io::Write + fmt::Debug,
377    {
378        if input.is_empty() {
379            return Err(HIDError::Command(CommandError::InputTooSmall));
380        }
381
382        let status: StatusCode = input[0].into();
383        debug!("response status code: {:?}", status);
384        if input.len() > 1 {
385            if status.is_ok() {
386                let attestation = from_slice(&input[1..]).map_err(CommandError::Deserializing)?;
387                let client_data = self.client_data.clone();
388                Ok(MakeCredentialsResult::CTAP2(attestation, client_data))
389            } else {
390                let data: Value = from_slice(&input[1..]).map_err(CommandError::Deserializing)?;
391                Err(HIDError::Command(CommandError::StatusCode(
392                    status,
393                    Some(data),
394                )))
395            }
396        } else if status.is_ok() {
397            Err(HIDError::Command(CommandError::InputTooSmall))
398        } else {
399            Err(HIDError::Command(CommandError::StatusCode(status, None)))
400        }
401    }
402}
403
404#[cfg(test)]
405pub mod test {
406    use super::{MakeCredentials, MakeCredentialsOptions, MakeCredentialsResult};
407    use crate::crypto::{COSEAlgorithm, COSEEC2Key, COSEKey, COSEKeyType, ECDSACurve};
408    use crate::ctap2::attestation::{
409        AAGuid, AttestationCertificate, AttestationObject, AttestationStatement,
410        AttestationStatementPacked, AttestedCredentialData, AuthenticatorData,
411        AuthenticatorDataFlags, Signature,
412    };
413    use crate::ctap2::client_data::{Challenge, CollectedClientData, TokenBinding, WebauthnType};
414    use crate::ctap2::commands::{RequestCtap1, RequestCtap2};
415    use crate::ctap2::server::RpIdHash;
416    use crate::ctap2::server::{
417        PublicKeyCredentialParameters, RelyingParty, RelyingPartyWrapper, User,
418    };
419    use crate::transport::device_selector::Device;
420    use crate::transport::hid::HIDDevice;
421    use serde_bytes::ByteBuf;
422
423    #[test]
424    fn test_make_credentials_ctap2() {
425        let req = MakeCredentials::new(
426            CollectedClientData {
427                webauthn_type: WebauthnType::Create,
428                challenge: Challenge::from(vec![0x00, 0x01, 0x02, 0x03]),
429                origin: String::from("example.com"),
430                cross_origin: false,
431                token_binding: Some(TokenBinding::Present(String::from("AAECAw"))),
432            },
433            RelyingPartyWrapper::Data(RelyingParty {
434                id: String::from("example.com"),
435                name: Some(String::from("Acme")),
436                icon: None,
437            }),
438            Some(User {
439                id: base64::decode_config(
440                    "MIIBkzCCATigAwIBAjCCAZMwggE4oAMCAQIwggGTMII=",
441                    base64::URL_SAFE_NO_PAD,
442                )
443                .unwrap(),
444                icon: Some("https://pics.example.com/00/p/aBjjjpqPb.png".to_string()),
445                name: Some(String::from("johnpsmith@example.com")),
446                display_name: Some(String::from("John P. Smith")),
447            }),
448            vec![
449                PublicKeyCredentialParameters {
450                    alg: COSEAlgorithm::ES256,
451                },
452                PublicKeyCredentialParameters {
453                    alg: COSEAlgorithm::RS256,
454                },
455            ],
456            Vec::new(),
457            MakeCredentialsOptions {
458                resident_key: Some(true),
459                user_verification: None,
460            },
461            Default::default(),
462            None,
463        );
464
465        let mut device = Device::new("commands/make_credentials").unwrap(); // not really used (all functions ignore it)
466        let req_serialized = req
467            .wire_format(&mut device)
468            .expect("Failed to serialize MakeCredentials request");
469        assert_eq!(req_serialized, MAKE_CREDENTIALS_SAMPLE_REQUEST_CTAP2);
470        let (attestation_object, _collected_client_data) = match req
471            .handle_response_ctap2(&mut device, &MAKE_CREDENTIALS_SAMPLE_RESPONSE_CTAP2)
472            .expect("Failed to handle CTAP2 response")
473        {
474            MakeCredentialsResult::CTAP2(attestation_object, _collected_client_data) => {
475                (attestation_object, _collected_client_data)
476            }
477            _ => panic!("Got CTAP1 Result, but CTAP2 expected"),
478        };
479
480        let expected = AttestationObject {
481            auth_data: AuthenticatorData {
482                rp_id_hash: RpIdHash::from(&[
483                    0xc2, 0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4, 0x2d,
484                    0x84, 0x27, 0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6, 0xd0, 0x65,
485                    0xbe, 0x59, 0x7a, 0x87, 0x5, 0x1d,
486                ])
487                .unwrap(),
488                flags: AuthenticatorDataFlags::USER_PRESENT | AuthenticatorDataFlags::ATTESTED,
489                counter: 11,
490                credential_data: Some(AttestedCredentialData {
491                    aaguid: AAGuid::from(&[
492                        0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11,
493                        0x1f, 0x9e, 0xdc, 0x7d,
494                    ])
495                    .unwrap(),
496                    credential_id: vec![
497                        0x89, 0x59, 0xce, 0xad, 0x5b, 0x5c, 0x48, 0x16, 0x4e, 0x8a, 0xbc, 0xd6,
498                        0xd9, 0x43, 0x5c, 0x6f,
499                    ],
500                    credential_public_key: COSEKey {
501                        alg: COSEAlgorithm::ES256,
502                        key: COSEKeyType::EC2(COSEEC2Key {
503                            curve: ECDSACurve::SECP256R1,
504                            x: vec![
505                                0xA5, 0xFD, 0x5C, 0xE1, 0xB1, 0xC4, 0x58, 0xC5, 0x30, 0xA5, 0x4F,
506                                0xA6, 0x1B, 0x31, 0xBF, 0x6B, 0x04, 0xBE, 0x8B, 0x97, 0xAF, 0xDE,
507                                0x54, 0xDD, 0x8C, 0xBB, 0x69, 0x27, 0x5A, 0x8A, 0x1B, 0xE1,
508                            ],
509                            y: vec![
510                                0xFA, 0x3A, 0x32, 0x31, 0xDD, 0x9D, 0xEE, 0xD9, 0xD1, 0x89, 0x7B,
511                                0xE5, 0xA6, 0x22, 0x8C, 0x59, 0x50, 0x1E, 0x4B, 0xCD, 0x12, 0x97,
512                                0x5D, 0x3D, 0xFF, 0x73, 0x0F, 0x01, 0x27, 0x8E, 0xA6, 0x1C,
513                            ],
514                        }),
515                    },
516                }),
517                extensions: Default::default(),
518            },
519            att_statement: AttestationStatement::Packed(AttestationStatementPacked {
520                alg: COSEAlgorithm::ES256,
521                sig: Signature(ByteBuf::from([
522                    0x30, 0x45, 0x02, 0x20, 0x13, 0xf7, 0x3c, 0x5d, 0x9d, 0x53, 0x0e, 0x8c, 0xc1,
523                    0x5c, 0xc9, 0xbd, 0x96, 0xad, 0x58, 0x6d, 0x39, 0x36, 0x64, 0xe4, 0x62, 0xd5,
524                    0xf0, 0x56, 0x12, 0x35, 0xe6, 0x35, 0x0f, 0x2b, 0x72, 0x89, 0x02, 0x21, 0x00,
525                    0x90, 0x35, 0x7f, 0xf9, 0x10, 0xcc, 0xb5, 0x6a, 0xc5, 0xb5, 0x96, 0x51, 0x19,
526                    0x48, 0x58, 0x1c, 0x8f, 0xdd, 0xb4, 0xa2, 0xb7, 0x99, 0x59, 0x94, 0x80, 0x78,
527                    0xb0, 0x9f, 0x4b, 0xdc, 0x62, 0x29,
528                ])),
529                attestation_cert: vec![AttestationCertificate(vec![
530                    0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02,
531                    0x02, 0x09, 0x00, 0x85, 0x9b, 0x72, 0x6c, 0xb2, 0x4b, 0x4c, 0x29, 0x30, 0x0a,
532                    0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x47, 0x31,
533                    0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
534                    0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x59, 0x75, 0x62,
535                    0x69, 0x63, 0x6f, 0x20, 0x54, 0x65, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06,
536                    0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
537                    0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74,
538                    0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x32,
539                    0x30, 0x34, 0x31, 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x32, 0x36,
540                    0x31, 0x32, 0x30, 0x32, 0x31, 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a, 0x30, 0x47,
541                    0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
542                    0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x59, 0x75,
543                    0x62, 0x69, 0x63, 0x6f, 0x20, 0x54, 0x65, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20,
544                    0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e,
545                    0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73,
546                    0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a,
547                    0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
548                    0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xad, 0x11, 0xeb, 0x0e, 0x88, 0x52,
549                    0xe5, 0x3a, 0xd5, 0xdf, 0xed, 0x86, 0xb4, 0x1e, 0x61, 0x34, 0xa1, 0x8e, 0xc4,
550                    0xe1, 0xaf, 0x8f, 0x22, 0x1a, 0x3c, 0x7d, 0x6e, 0x63, 0x6c, 0x80, 0xea, 0x13,
551                    0xc3, 0xd5, 0x04, 0xff, 0x2e, 0x76, 0x21, 0x1b, 0xb4, 0x45, 0x25, 0xb1, 0x96,
552                    0xc4, 0x4c, 0xb4, 0x84, 0x99, 0x79, 0xcf, 0x6f, 0x89, 0x6e, 0xcd, 0x2b, 0xb8,
553                    0x60, 0xde, 0x1b, 0xf4, 0x37, 0x6b, 0xa3, 0x0d, 0x30, 0x0b, 0x30, 0x09, 0x06,
554                    0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0a, 0x06, 0x08, 0x2a,
555                    0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, 0x30, 0x46, 0x02,
556                    0x21, 0x00, 0xe9, 0xa3, 0x9f, 0x1b, 0x03, 0x19, 0x75, 0x25, 0xf7, 0x37, 0x3e,
557                    0x10, 0xce, 0x77, 0xe7, 0x80, 0x21, 0x73, 0x1b, 0x94, 0xd0, 0xc0, 0x3f, 0x3f,
558                    0xda, 0x1f, 0xd2, 0x2d, 0xb3, 0xd0, 0x30, 0xe7, 0x02, 0x21, 0x00, 0xc4, 0xfa,
559                    0xec, 0x34, 0x45, 0xa8, 0x20, 0xcf, 0x43, 0x12, 0x9c, 0xdb, 0x00, 0xaa, 0xbe,
560                    0xfd, 0x9a, 0xe2, 0xd8, 0x74, 0xf9, 0xc5, 0xd3, 0x43, 0xcb, 0x2f, 0x11, 0x3d,
561                    0xa2, 0x37, 0x23, 0xf3,
562                ])],
563            }),
564        };
565
566        assert_eq!(attestation_object, expected);
567    }
568
569    #[test]
570    fn test_make_credentials_ctap1() {
571        let req = MakeCredentials::new(
572            CollectedClientData {
573                webauthn_type: WebauthnType::Create,
574                challenge: Challenge::new(vec![0x00, 0x01, 0x02, 0x03]),
575                origin: String::from("example.com"),
576                cross_origin: false,
577                token_binding: Some(TokenBinding::Present(String::from("AAECAw"))),
578            },
579            RelyingPartyWrapper::Data(RelyingParty {
580                id: String::from("example.com"),
581                name: Some(String::from("Acme")),
582                icon: None,
583            }),
584            Some(User {
585                id: base64::decode_config(
586                    "MIIBkzCCATigAwIBAjCCAZMwggE4oAMCAQIwggGTMII=",
587                    base64::URL_SAFE_NO_PAD,
588                )
589                .unwrap(),
590                icon: Some("https://pics.example.com/00/p/aBjjjpqPb.png".to_string()),
591                name: Some(String::from("johnpsmith@example.com")),
592                display_name: Some(String::from("John P. Smith")),
593            }),
594            vec![
595                PublicKeyCredentialParameters {
596                    alg: COSEAlgorithm::ES256,
597                },
598                PublicKeyCredentialParameters {
599                    alg: COSEAlgorithm::RS256,
600                },
601            ],
602            Vec::new(),
603            MakeCredentialsOptions {
604                resident_key: Some(true),
605                user_verification: None,
606            },
607            Default::default(),
608            None,
609        );
610
611        let mut device = Device::new("commands/make_credentials").unwrap(); // not really used (all functions ignore it)
612        let req_serialized = req
613            .apdu_format(&mut device)
614            .expect("Failed to serialize MakeCredentials request");
615        assert_eq!(
616            req_serialized, MAKE_CREDENTIALS_SAMPLE_REQUEST_CTAP1,
617            "\nGot:      {:X?}\nExpected: {:X?}",
618            req_serialized, MAKE_CREDENTIALS_SAMPLE_REQUEST_CTAP1
619        );
620        let (attestation_object, _collected_client_data) = match req
621            .handle_response_ctap1(Ok(()), &MAKE_CREDENTIALS_SAMPLE_RESPONSE_CTAP1)
622            .expect("Failed to handle CTAP1 response")
623        {
624            MakeCredentialsResult::CTAP2(attestation_object, _collected_client_data) => {
625                (attestation_object, _collected_client_data)
626            }
627            _ => panic!("Got CTAP1 Result, but CTAP2 expected"),
628        };
629
630        let expected = AttestationObject {
631            auth_data: AuthenticatorData {
632                rp_id_hash: RpIdHash::from(&[
633                    0xA3, 0x79, 0xA6, 0xF6, 0xEE, 0xAF, 0xB9, 0xA5, 0x5E, 0x37, 0x8C, 0x11, 0x80,
634                    0x34, 0xE2, 0x75, 0x1E, 0x68, 0x2F, 0xAB, 0x9F, 0x2D, 0x30, 0xAB, 0x13, 0xD2,
635                    0x12, 0x55, 0x86, 0xCE, 0x19, 0x47,
636                ])
637                .unwrap(),
638                flags: AuthenticatorDataFlags::USER_PRESENT | AuthenticatorDataFlags::ATTESTED,
639                counter: 0,
640                credential_data: Some(AttestedCredentialData {
641                    aaguid: AAGuid::default(),
642                    credential_id: vec![
643                        0x3E, 0xBD, 0x89, 0xBF, 0x77, 0xEC, 0x50, 0x97, 0x55, 0xEE, 0x9C, 0x26,
644                        0x35, 0xEF, 0xAA, 0xAC, 0x7B, 0x2B, 0x9C, 0x5C, 0xEF, 0x17, 0x36, 0xC3,
645                        0x71, 0x7D, 0xA4, 0x85, 0x34, 0xC8, 0xC6, 0xB6, 0x54, 0xD7, 0xFF, 0x94,
646                        0x5F, 0x50, 0xB5, 0xCC, 0x4E, 0x78, 0x05, 0x5B, 0xDD, 0x39, 0x6B, 0x64,
647                        0xF7, 0x8D, 0xA2, 0xC5, 0xF9, 0x62, 0x00, 0xCC, 0xD4, 0x15, 0xCD, 0x08,
648                        0xFE, 0x42, 0x00, 0x38,
649                    ],
650                    credential_public_key: COSEKey {
651                        alg: COSEAlgorithm::ES256,
652                        key: COSEKeyType::EC2(COSEEC2Key {
653                            curve: ECDSACurve::SECP256R1,
654                            x: vec![
655                                0xE8, 0x76, 0x25, 0x89, 0x6E, 0xE4, 0xE4, 0x6D, 0xC0, 0x32, 0x76,
656                                0x6E, 0x80, 0x87, 0x96, 0x2F, 0x36, 0xDF, 0x9D, 0xFE, 0x8B, 0x56,
657                                0x7F, 0x37, 0x63, 0x01, 0x5B, 0x19, 0x90, 0xA6, 0x0E, 0x14,
658                            ],
659                            y: vec![
660                                0x27, 0xDE, 0x61, 0x2D, 0x66, 0x41, 0x8B, 0xDA, 0x19, 0x50, 0x58,
661                                0x1E, 0xBC, 0x5C, 0x8C, 0x1D, 0xAD, 0x71, 0x0C, 0xB1, 0x4C, 0x22,
662                                0xF8, 0xC9, 0x70, 0x45, 0xF4, 0x61, 0x2F, 0xB2, 0x0C, 0x91,
663                            ],
664                        }),
665                    },
666                }),
667                extensions: Default::default(),
668            },
669            att_statement: AttestationStatement::Unparsed(vec![
670                0x30, 0x82, 0x02, 0x4A, 0x30, 0x82, 0x01, 0x32, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02,
671                0x04, 0x04, 0x6C, 0x88, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7,
672                0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x30, 0x2E, 0x31, 0x2C, 0x30, 0x2A, 0x06, 0x03,
673                0x55, 0x04, 0x03, 0x13, 0x23, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6F, 0x20, 0x55, 0x32,
674                0x46, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41, 0x20, 0x53, 0x65, 0x72, 0x69,
675                0x61, 0x6C, 0x20, 0x34, 0x35, 0x37, 0x32, 0x30, 0x30, 0x36, 0x33, 0x31, 0x30, 0x20,
676                0x17, 0x0D, 0x31, 0x34, 0x30, 0x38, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
677                0x5A, 0x18, 0x0F, 0x32, 0x30, 0x35, 0x30, 0x30, 0x39, 0x30, 0x34, 0x30, 0x30, 0x30,
678                0x30, 0x30, 0x30, 0x5A, 0x30, 0x2C, 0x31, 0x2A, 0x30, 0x28, 0x06, 0x03, 0x55, 0x04,
679                0x03, 0x0C, 0x21, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6F, 0x20, 0x55, 0x32, 0x46, 0x20,
680                0x45, 0x45, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6C, 0x20, 0x32, 0x34, 0x39, 0x31,
681                0x38, 0x32, 0x33, 0x32, 0x34, 0x37, 0x37, 0x30, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
682                0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
683                0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x3C, 0xCA, 0xB9, 0x2C, 0xCB, 0x97, 0x28,
684                0x7E, 0xE8, 0xE6, 0x39, 0x43, 0x7E, 0x21, 0xFC, 0xD6, 0xB6, 0xF1, 0x65, 0xB2, 0xD5,
685                0xA3, 0xF3, 0xDB, 0x13, 0x1D, 0x31, 0xC1, 0x6B, 0x74, 0x2B, 0xB4, 0x76, 0xD8, 0xD1,
686                0xE9, 0x90, 0x80, 0xEB, 0x54, 0x6C, 0x9B, 0xBD, 0xF5, 0x56, 0xE6, 0x21, 0x0F, 0xD4,
687                0x27, 0x85, 0x89, 0x9E, 0x78, 0xCC, 0x58, 0x9E, 0xBE, 0x31, 0x0F, 0x6C, 0xDB, 0x9F,
688                0xF4, 0xA3, 0x3B, 0x30, 0x39, 0x30, 0x22, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01,
689                0x82, 0xC4, 0x0A, 0x02, 0x04, 0x15, 0x31, 0x2E, 0x33, 0x2E, 0x36, 0x2E, 0x31, 0x2E,
690                0x34, 0x2E, 0x31, 0x2E, 0x34, 0x31, 0x34, 0x38, 0x32, 0x2E, 0x31, 0x2E, 0x32, 0x30,
691                0x13, 0x06, 0x0B, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xE5, 0x1C, 0x02, 0x01, 0x01,
692                0x04, 0x04, 0x03, 0x02, 0x04, 0x30, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
693                0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x9F, 0x9B,
694                0x05, 0x22, 0x48, 0xBC, 0x4C, 0xF4, 0x2C, 0xC5, 0x99, 0x1F, 0xCA, 0xAB, 0xAC, 0x9B,
695                0x65, 0x1B, 0xBE, 0x5B, 0xDC, 0xDC, 0x8E, 0xF0, 0xAD, 0x2C, 0x1C, 0x1F, 0xFB, 0x36,
696                0xD1, 0x87, 0x15, 0xD4, 0x2E, 0x78, 0xB2, 0x49, 0x22, 0x4F, 0x92, 0xC7, 0xE6, 0xE7,
697                0xA0, 0x5C, 0x49, 0xF0, 0xE7, 0xE4, 0xC8, 0x81, 0xBF, 0x2E, 0x94, 0xF4, 0x5E, 0x4A,
698                0x21, 0x83, 0x3D, 0x74, 0x56, 0x85, 0x1D, 0x0F, 0x6C, 0x14, 0x5A, 0x29, 0x54, 0x0C,
699                0x87, 0x4F, 0x30, 0x92, 0xC9, 0x34, 0xB4, 0x3D, 0x22, 0x2B, 0x89, 0x62, 0xC0, 0xF4,
700                0x10, 0xCE, 0xF1, 0xDB, 0x75, 0x89, 0x2A, 0xF1, 0x16, 0xB4, 0x4A, 0x96, 0xF5, 0xD3,
701                0x5A, 0xDE, 0xA3, 0x82, 0x2F, 0xC7, 0x14, 0x6F, 0x60, 0x04, 0x38, 0x5B, 0xCB, 0x69,
702                0xB6, 0x5C, 0x99, 0xE7, 0xEB, 0x69, 0x19, 0x78, 0x67, 0x03, 0xC0, 0xD8, 0xCD, 0x41,
703                0xE8, 0xF7, 0x5C, 0xCA, 0x44, 0xAA, 0x8A, 0xB7, 0x25, 0xAD, 0x8E, 0x79, 0x9F, 0xF3,
704                0xA8, 0x69, 0x6A, 0x6F, 0x1B, 0x26, 0x56, 0xE6, 0x31, 0xB1, 0xE4, 0x01, 0x83, 0xC0,
705                0x8F, 0xDA, 0x53, 0xFA, 0x4A, 0x8F, 0x85, 0xA0, 0x56, 0x93, 0x94, 0x4A, 0xE1, 0x79,
706                0xA1, 0x33, 0x9D, 0x00, 0x2D, 0x15, 0xCA, 0xBD, 0x81, 0x00, 0x90, 0xEC, 0x72, 0x2E,
707                0xF5, 0xDE, 0xF9, 0x96, 0x5A, 0x37, 0x1D, 0x41, 0x5D, 0x62, 0x4B, 0x68, 0xA2, 0x70,
708                0x7C, 0xAD, 0x97, 0xBC, 0xDD, 0x17, 0x85, 0xAF, 0x97, 0xE2, 0x58, 0xF3, 0x3D, 0xF5,
709                0x6A, 0x03, 0x1A, 0xA0, 0x35, 0x6D, 0x8E, 0x8D, 0x5E, 0xBC, 0xAD, 0xC7, 0x4E, 0x07,
710                0x16, 0x36, 0xC6, 0xB1, 0x10, 0xAC, 0xE5, 0xCC, 0x9B, 0x90, 0xDF, 0xEA, 0xCA, 0xE6,
711                0x40, 0xFF, 0x1B, 0xB0, 0xF1, 0xFE, 0x5D, 0xB4, 0xEF, 0xF7, 0xA9, 0x5F, 0x06, 0x07,
712                0x33, 0xF5, // ...
713                0x30, 0x45, 0x02, 0x20, 0x32, 0x47, 0x79, 0xC6, 0x8F, 0x33, 0x80, 0x28, 0x8A, 0x11,
714                0x97, 0xB6, 0x09, 0x5F, 0x7A, 0x6E, 0xB9, 0xB1, 0xB1, 0xC1, 0x27, 0xF6, 0x6A, 0xE1,
715                0x2A, 0x99, 0xFE, 0x85, 0x32, 0xEC, 0x23, 0xB9, 0x02, 0x21, 0x00, 0xE3, 0x95, 0x16,
716                0xAC, 0x4D, 0x61, 0xEE, 0x64, 0x04, 0x4D, 0x50, 0xB4, 0x15, 0xA6, 0xA4, 0xD4, 0xD8,
717                0x4B, 0xA6, 0xD8, 0x95, 0xCB, 0x5A, 0xB7, 0xA1, 0xAA, 0x7D, 0x08, 0x1D, 0xE3, 0x41,
718                0xFA, // ...
719                      // TODO(MS): Once handle_response_ctap1() can parse signature and certs, uncomment below
720                      // sig: Signature(ByteBuf::from([
721                      // 0x30, 0x45, 0x02, 0x20, 0x13, 0xf7, 0x3c, 0x5d, 0x9d, 0x53, 0x0e, 0x8c, 0xc1, 0x5c,
722                      // 0xc9, 0xbd, 0x96, 0xad, 0x58, 0x6d, 0x39, 0x36, 0x64, 0xe4, 0x62, 0xd5, 0xf0, 0x56,
723                      // 0x12, 0x35, 0xe6, 0x35, 0x0f, 0x2b, 0x72, 0x89, 0x02, 0x21, 0x00, 0x90, 0x35, 0x7f,
724                      // 0xf9, 0x10, 0xcc, 0xb5, 0x6a, 0xc5, 0xb5, 0x96, 0x51, 0x19, 0x48, 0x58, 0x1c, 0x8f,
725                      // 0xdd, 0xb4, 0xa2, 0xb7, 0x99, 0x59, 0x94, 0x80, 0x78, 0xb0, 0x9f, 0x4b, 0xdc, 0x62,
726                      // 0x29,
727                      // ])),
728                      // attestation_cert: vec![AttestationCertificate(vec![
729                      // 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
730                      // 0x09, 0x00, 0x85, 0x9b, 0x72, 0x6c, 0xb2, 0x4b, 0x4c, 0x29, 0x30, 0x0a, 0x06, 0x08,
731                      // 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09,
732                      // 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06,
733                      // 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x54,
734                      // 0x65, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19,
735                      // 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x20,
736                      // 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x1e, 0x17,
737                      // 0x0d, 0x31, 0x36, 0x31, 0x32, 0x30, 0x34, 0x31, 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a,
738                      // 0x17, 0x0d, 0x32, 0x36, 0x31, 0x32, 0x30, 0x32, 0x31, 0x31, 0x35, 0x35, 0x30, 0x30,
739                      // 0x5a, 0x30, 0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
740                      // 0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x59,
741                      // 0x75, 0x62, 0x69, 0x63, 0x6f, 0x20, 0x54, 0x65, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20,
742                      // 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
743                      // 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61,
744                      // 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce,
745                      // 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
746                      // 0x42, 0x00, 0x04, 0xad, 0x11, 0xeb, 0x0e, 0x88, 0x52, 0xe5, 0x3a, 0xd5, 0xdf, 0xed,
747                      // 0x86, 0xb4, 0x1e, 0x61, 0x34, 0xa1, 0x8e, 0xc4, 0xe1, 0xaf, 0x8f, 0x22, 0x1a, 0x3c,
748                      // 0x7d, 0x6e, 0x63, 0x6c, 0x80, 0xea, 0x13, 0xc3, 0xd5, 0x04, 0xff, 0x2e, 0x76, 0x21,
749                      // 0x1b, 0xb4, 0x45, 0x25, 0xb1, 0x96, 0xc4, 0x4c, 0xb4, 0x84, 0x99, 0x79, 0xcf, 0x6f,
750                      // 0x89, 0x6e, 0xcd, 0x2b, 0xb8, 0x60, 0xde, 0x1b, 0xf4, 0x37, 0x6b, 0xa3, 0x0d, 0x30,
751                      // 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0a,
752                      // 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, 0x30,
753                      // 0x46, 0x02, 0x21, 0x00, 0xe9, 0xa3, 0x9f, 0x1b, 0x03, 0x19, 0x75, 0x25, 0xf7, 0x37,
754                      // 0x3e, 0x10, 0xce, 0x77, 0xe7, 0x80, 0x21, 0x73, 0x1b, 0x94, 0xd0, 0xc0, 0x3f, 0x3f,
755                      // 0xda, 0x1f, 0xd2, 0x2d, 0xb3, 0xd0, 0x30, 0xe7, 0x02, 0x21, 0x00, 0xc4, 0xfa, 0xec,
756                      // 0x34, 0x45, 0xa8, 0x20, 0xcf, 0x43, 0x12, 0x9c, 0xdb, 0x00, 0xaa, 0xbe, 0xfd, 0x9a,
757                      // 0xe2, 0xd8, 0x74, 0xf9, 0xc5, 0xd3, 0x43, 0xcb, 0x2f, 0x11, 0x3d, 0xa2, 0x37, 0x23,
758                      // 0xf3,
759                      // ])],
760            ]),
761            // }),
762        };
763
764        assert_eq!(attestation_object, expected);
765    }
766
767    #[rustfmt::skip]
768    pub const MAKE_CREDENTIALS_SAMPLE_RESPONSE_CTAP2: [u8; 660] = [
769        0x00, // status = success
770        0xa3, // map(3)
771          0x01, // unsigned(1)
772          0x66, // text(6)
773            0x70, 0x61, 0x63, 0x6b, 0x65, 0x64, // "packed"
774          0x02, // unsigned(2)
775          0x58, 0x94, // bytes(148)
776            // authData
777            0xc2, 0x89, 0xc5, 0xca, 0x9b, 0x04, 0x60, 0xf9, 0x34, 0x6a, 0xb4, 0xe4, 0x2d, 0x84, 0x27, // rp_id_hash
778            0x43, 0x40, 0x4d, 0x31, 0xf4, 0x84, 0x68, 0x25, 0xa6, 0xd0, 0x65, 0xbe, 0x59, 0x7a, 0x87, // rp_id_hash
779            0x05, 0x1d, // rp_id_hash
780            0x41, // authData Flags
781            0x00, 0x00, 0x00, 0x0b, // authData counter
782            0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, // AAGUID
783            0x00, 0x10, // credential id length
784            0x89, 0x59, 0xce, 0xad, 0x5b, 0x5c, 0x48, 0x16, 0x4e, 0x8a, 0xbc, 0xd6, 0xd9, 0x43, 0x5c, 0x6f, // credential id
785            // credential public key
786            0xa5, 0x01, 0x02, 0x03, 0x26, 0x20, 0x01, 0x21, 0x58, 0x20, 0xa5, 0xfd, 0x5c, 0xe1, 0xb1, 0xc4,
787             0x58, 0xc5, 0x30, 0xa5, 0x4f, 0xa6, 0x1b, 0x31, 0xbf, 0x6b, 0x04, 0xbe, 0x8b, 0x97, 0xaf, 0xde,
788             0x54, 0xdd, 0x8c, 0xbb, 0x69, 0x27, 0x5a, 0x8a, 0x1b, 0xe1, 0x22, 0x58, 0x20, 0xfa, 0x3a, 0x32,
789             0x31, 0xdd, 0x9d, 0xee, 0xd9, 0xd1, 0x89, 0x7b, 0xe5, 0xa6, 0x22, 0x8c, 0x59, 0x50, 0x1e, 0x4b,
790             0xcd, 0x12, 0x97, 0x5d, 0x3d, 0xff, 0x73, 0x0f, 0x01, 0x27, 0x8e, 0xa6, 0x1c,
791          0x03, // unsigned(3)
792          0xa3, // map(3)
793            0x63, // text(3)
794              0x61, 0x6c, 0x67, // "alg"
795            0x26, // -7 (ES256)
796            0x63, // text(3)
797              0x73, 0x69, 0x67, // "sig"
798            0x58, 0x47, // bytes(71)
799              0x30, 0x45, 0x02, 0x20, 0x13, 0xf7, 0x3c, 0x5d, 0x9d, 0x53, 0x0e, 0x8c, 0xc1, 0x5c, 0xc9, // signature
800              0xbd, 0x96, 0xad, 0x58, 0x6d, 0x39, 0x36, 0x64, 0xe4, 0x62, 0xd5, 0xf0, 0x56, 0x12, 0x35, // ..
801              0xe6, 0x35, 0x0f, 0x2b, 0x72, 0x89, 0x02, 0x21, 0x00, 0x90, 0x35, 0x7f, 0xf9, 0x10, 0xcc, // ..
802              0xb5, 0x6a, 0xc5, 0xb5, 0x96, 0x51, 0x19, 0x48, 0x58, 0x1c, 0x8f, 0xdd, 0xb4, 0xa2, 0xb7, // ..
803              0x99, 0x59, 0x94, 0x80, 0x78, 0xb0, 0x9f, 0x4b, 0xdc, 0x62, 0x29, // ..
804            0x63, // text(3)
805              0x78, 0x35, 0x63, // "x5c"
806            0x81, // array(1)
807              0x59, 0x01, 0x97, // bytes(407)
808                0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, //certificate...
809                0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0x9b, 0x72, 0x6c, 0xb2, 0x4b,
810                0x4c, 0x29, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30,
811                0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
812                0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x59, 0x75, 0x62, 0x69, 0x63,
813                0x6f, 0x20, 0x54, 0x65, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b,
814                0x0c, 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72,
815                0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x1e, 0x17,
816                0x0d, 0x31, 0x36, 0x31, 0x32, 0x30, 0x34, 0x31, 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a, 0x17,
817                0x0d, 0x32, 0x36, 0x31, 0x32, 0x30, 0x32, 0x31, 0x31, 0x35, 0x35, 0x30, 0x30, 0x5a, 0x30,
818                0x47, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
819                0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x59, 0x75, 0x62, 0x69, 0x63,
820                0x6f, 0x20, 0x54, 0x65, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0b,
821                0x0c, 0x19, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72,
822                0x20, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x30, 0x59, 0x30,
823                0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
824                0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xad, 0x11, 0xeb, 0x0e, 0x88, 0x52,
825                0xe5, 0x3a, 0xd5, 0xdf, 0xed, 0x86, 0xb4, 0x1e, 0x61, 0x34, 0xa1, 0x8e, 0xc4, 0xe1, 0xaf,
826                0x8f, 0x22, 0x1a, 0x3c, 0x7d, 0x6e, 0x63, 0x6c, 0x80, 0xea, 0x13, 0xc3, 0xd5, 0x04, 0xff,
827                0x2e, 0x76, 0x21, 0x1b, 0xb4, 0x45, 0x25, 0xb1, 0x96, 0xc4, 0x4c, 0xb4, 0x84, 0x99, 0x79,
828                0xcf, 0x6f, 0x89, 0x6e, 0xcd, 0x2b, 0xb8, 0x60, 0xde, 0x1b, 0xf4, 0x37, 0x6b, 0xa3, 0x0d,
829                0x30, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0a,
830                0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, 0x00, 0x30, 0x46,
831                0x02, 0x21, 0x00, 0xe9, 0xa3, 0x9f, 0x1b, 0x03, 0x19, 0x75, 0x25, 0xf7, 0x37, 0x3e, 0x10,
832                0xce, 0x77, 0xe7, 0x80, 0x21, 0x73, 0x1b, 0x94, 0xd0, 0xc0, 0x3f, 0x3f, 0xda, 0x1f, 0xd2,
833                0x2d, 0xb3, 0xd0, 0x30, 0xe7, 0x02, 0x21, 0x00, 0xc4, 0xfa, 0xec, 0x34, 0x45, 0xa8, 0x20,
834                0xcf, 0x43, 0x12, 0x9c, 0xdb, 0x00, 0xaa, 0xbe, 0xfd, 0x9a, 0xe2, 0xd8, 0x74, 0xf9, 0xc5,
835                0xd3, 0x43, 0xcb, 0x2f, 0x11, 0x3d, 0xa2, 0x37, 0x23, 0xf3,
836    ];
837
838    #[rustfmt::skip]
839    pub const MAKE_CREDENTIALS_SAMPLE_REQUEST_CTAP2: [u8; 260] = [
840        // NOTE: This has been taken from CTAP2.0 spec, but the clientDataHash has been replaced
841        //       to be able to operate with known values for CollectedClientData (spec doesn't say
842        //       what values led to the provided example hash (see client_data.rs))
843        0xa5, // map(5)
844          0x01, // unsigned(1) - clientDataHash
845          0x58, 0x20, // bytes(32)
846            0x75, 0x35, 0x35, 0x7d, 0x49, 0x6e, 0x33, 0xc8, 0x18, 0x7f, 0xea, 0x8d, 0x11, // hash
847            0x32, 0x64, 0xaa, 0xa4, 0x52, 0x3e, 0x13, 0x40, 0x14, 0x9f, 0xbe, 0x00, 0x3f, // hash
848            0x10, 0x87, 0x54, 0xc3, 0x2d, 0x80, // hash
849          0x02, // unsigned(2) - rp
850            0xa2, // map(2) Replace line below with this one, once RelyingParty supports "name"
851              0x62, // text(2)
852                0x69, 0x64, // "id"
853              0x6b, // text(11)
854                0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, // "example.com"
855              0x64, // text(4)
856                0x6e, 0x61, 0x6d, 0x65, // "name"
857              0x64, // text(4)
858                0x41, 0x63, 0x6d, 0x65, // "Acme"
859          0x03, // unsigned(3) - user
860          0xa4, // map(4)
861            0x62, // text(2)
862              0x69, 0x64, // "id"
863            0x58, 0x20, // bytes(32)
864              0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, // userid
865              0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, // ...
866              0x30, 0x82, 0x01, 0x93, 0x30, 0x82, // ...
867            0x64, // text(4)
868              0x69, 0x63, 0x6f, 0x6e, // "icon"
869            0x78, 0x2b, // text(43)
870              0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, // "https://pics.example.com/00/p/aBjjjpqPb.png"
871              0x2f, 0x70, 0x69, 0x63, 0x73, 0x2e, 0x65, 0x78, // ..
872              0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x30, 0x2f, 0x70, // ..
873              0x2f, 0x61, 0x42, 0x6a, 0x6a, 0x6a, 0x70, 0x71, 0x50, 0x62, 0x2e, 0x70, 0x6e, 0x67, // ..
874            0x64, // text(4)
875              0x6e, 0x61, 0x6d, 0x65, // "name"
876            0x76, // text(22)
877              0x6a, 0x6f, 0x68, 0x6e, 0x70, 0x73, 0x6d, 0x69, 0x74, // "johnpsmith@example.com"
878              0x68, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, // ...
879            0x6b, // text(11)
880              0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, // "displayName"
881            0x6d, // text(13)
882              0x4a, 0x6f, 0x68, 0x6e, 0x20, 0x50, 0x2e, 0x20, 0x53, 0x6d, 0x69, 0x74, 0x68, // "John P. Smith"
883          0x04, // unsigned(4) - pubKeyCredParams
884          0x82, // array(2)
885            0xa2, // map(2)
886              0x63, // text(3)
887                0x61, 0x6c, 0x67, // "alg"
888              0x26, // -7 (ES256)
889              0x64, // text(4)
890                0x74, 0x79, 0x70, 0x65, // "type"
891              0x6a, // text(10)
892                0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x2D, 0x6B, 0x65, 0x79, // "public-key"
893              0xa2, // map(2)
894              0x63, // text(3)
895                0x61, 0x6c, 0x67, // "alg"
896              0x39, 0x01, 0x00, // -257 (RS256)
897              0x64, // text(4)
898                0x74, 0x79, 0x70, 0x65, // "type"
899              0x6a, // text(10)
900                0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x2D, 0x6B, 0x65, 0x79, // "public-key"
901          // TODO(MS): Options seem to be parsed differently than in the example here.
902           0x07, // unsigned(7) - options
903           0xa1, // map(1)
904             0x62, // text(2)
905               0x72, 0x6b, // "rk"
906             0xf5, // primitive(21)
907    ];
908
909    pub const MAKE_CREDENTIALS_SAMPLE_REQUEST_CTAP1: [u8; 73] = [
910        // CBOR Header
911        0x0, // leading zero
912        0x1, // CMD U2F_Register
913        0x0, // Flags
914        0x0, 0x0, // zero bits
915        0x0, 0x40, // size
916        // NOTE: This has been taken from CTAP2.0 spec, but the clientDataHash has been replaced
917        //       to be able to operate with known values for CollectedClientData (spec doesn't say
918        //       what values led to the provided example hash)
919        // clientDataHash:
920        0x75, 0x35, 0x35, 0x7d, 0x49, 0x6e, 0x33, 0xc8, 0x18, 0x7f, 0xea, 0x8d, 0x11, // hash
921        0x32, 0x64, 0xaa, 0xa4, 0x52, 0x3e, 0x13, 0x40, 0x14, 0x9f, 0xbe, 0x00, 0x3f, // hash
922        0x10, 0x87, 0x54, 0xc3, 0x2d, 0x80, // hash
923        // rpIdHash:
924        0xA3, 0x79, 0xA6, 0xF6, 0xEE, 0xAF, 0xB9, 0xA5, 0x5E, 0x37, 0x8C, 0x11, 0x80, 0x34, 0xE2,
925        0x75, 0x1E, 0x68, 0x2F, 0xAB, 0x9F, 0x2D, 0x30, 0xAB, 0x13, 0xD2, 0x12, 0x55, 0x86, 0xCE,
926        0x19, 0x47, 0x0, 0x0, // 2 trailing zeros from protocol
927    ];
928
929    pub const MAKE_CREDENTIALS_SAMPLE_RESPONSE_CTAP1: [u8; 792] = [
930        0x05, // Reserved Byte (1 Byte)
931        // User Public Key (65 Bytes)
932        0x04, 0xE8, 0x76, 0x25, 0x89, 0x6E, 0xE4, 0xE4, 0x6D, 0xC0, 0x32, 0x76, 0x6E, 0x80, 0x87,
933        0x96, 0x2F, 0x36, 0xDF, 0x9D, 0xFE, 0x8B, 0x56, 0x7F, 0x37, 0x63, 0x01, 0x5B, 0x19, 0x90,
934        0xA6, 0x0E, 0x14, 0x27, 0xDE, 0x61, 0x2D, 0x66, 0x41, 0x8B, 0xDA, 0x19, 0x50, 0x58, 0x1E,
935        0xBC, 0x5C, 0x8C, 0x1D, 0xAD, 0x71, 0x0C, 0xB1, 0x4C, 0x22, 0xF8, 0xC9, 0x70, 0x45, 0xF4,
936        0x61, 0x2F, 0xB2, 0x0C, 0x91, // ...
937        0x40, // Key Handle Length (1 Byte)
938        // Key Handle (Key Handle Length Bytes)
939        0x3E, 0xBD, 0x89, 0xBF, 0x77, 0xEC, 0x50, 0x97, 0x55, 0xEE, 0x9C, 0x26, 0x35, 0xEF, 0xAA,
940        0xAC, 0x7B, 0x2B, 0x9C, 0x5C, 0xEF, 0x17, 0x36, 0xC3, 0x71, 0x7D, 0xA4, 0x85, 0x34, 0xC8,
941        0xC6, 0xB6, 0x54, 0xD7, 0xFF, 0x94, 0x5F, 0x50, 0xB5, 0xCC, 0x4E, 0x78, 0x05, 0x5B, 0xDD,
942        0x39, 0x6B, 0x64, 0xF7, 0x8D, 0xA2, 0xC5, 0xF9, 0x62, 0x00, 0xCC, 0xD4, 0x15, 0xCD, 0x08,
943        0xFE, 0x42, 0x00, 0x38, // ...
944        // X.509 Cert (Variable length Cert)
945        0x30, 0x82, 0x02, 0x4A, 0x30, 0x82, 0x01, 0x32, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x04,
946        0x04, 0x6C, 0x88, 0x22, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01,
947        0x01, 0x0B, 0x05, 0x00, 0x30, 0x2E, 0x31, 0x2C, 0x30, 0x2A, 0x06, 0x03, 0x55, 0x04, 0x03,
948        0x13, 0x23, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6F, 0x20, 0x55, 0x32, 0x46, 0x20, 0x52, 0x6F,
949        0x6F, 0x74, 0x20, 0x43, 0x41, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6C, 0x20, 0x34, 0x35,
950        0x37, 0x32, 0x30, 0x30, 0x36, 0x33, 0x31, 0x30, 0x20, 0x17, 0x0D, 0x31, 0x34, 0x30, 0x38,
951        0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x18, 0x0F, 0x32, 0x30, 0x35, 0x30,
952        0x30, 0x39, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x30, 0x2C, 0x31, 0x2A,
953        0x30, 0x28, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x21, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6F,
954        0x20, 0x55, 0x32, 0x46, 0x20, 0x45, 0x45, 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6C, 0x20,
955        0x32, 0x34, 0x39, 0x31, 0x38, 0x32, 0x33, 0x32, 0x34, 0x37, 0x37, 0x30, 0x30, 0x59, 0x30,
956        0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, 0x86, 0x48,
957        0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x3C, 0xCA, 0xB9, 0x2C, 0xCB, 0x97,
958        0x28, 0x7E, 0xE8, 0xE6, 0x39, 0x43, 0x7E, 0x21, 0xFC, 0xD6, 0xB6, 0xF1, 0x65, 0xB2, 0xD5,
959        0xA3, 0xF3, 0xDB, 0x13, 0x1D, 0x31, 0xC1, 0x6B, 0x74, 0x2B, 0xB4, 0x76, 0xD8, 0xD1, 0xE9,
960        0x90, 0x80, 0xEB, 0x54, 0x6C, 0x9B, 0xBD, 0xF5, 0x56, 0xE6, 0x21, 0x0F, 0xD4, 0x27, 0x85,
961        0x89, 0x9E, 0x78, 0xCC, 0x58, 0x9E, 0xBE, 0x31, 0x0F, 0x6C, 0xDB, 0x9F, 0xF4, 0xA3, 0x3B,
962        0x30, 0x39, 0x30, 0x22, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0xC4, 0x0A, 0x02,
963        0x04, 0x15, 0x31, 0x2E, 0x33, 0x2E, 0x36, 0x2E, 0x31, 0x2E, 0x34, 0x2E, 0x31, 0x2E, 0x34,
964        0x31, 0x34, 0x38, 0x32, 0x2E, 0x31, 0x2E, 0x32, 0x30, 0x13, 0x06, 0x0B, 0x2B, 0x06, 0x01,
965        0x04, 0x01, 0x82, 0xE5, 0x1C, 0x02, 0x01, 0x01, 0x04, 0x04, 0x03, 0x02, 0x04, 0x30, 0x30,
966        0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03,
967        0x82, 0x01, 0x01, 0x00, 0x9F, 0x9B, 0x05, 0x22, 0x48, 0xBC, 0x4C, 0xF4, 0x2C, 0xC5, 0x99,
968        0x1F, 0xCA, 0xAB, 0xAC, 0x9B, 0x65, 0x1B, 0xBE, 0x5B, 0xDC, 0xDC, 0x8E, 0xF0, 0xAD, 0x2C,
969        0x1C, 0x1F, 0xFB, 0x36, 0xD1, 0x87, 0x15, 0xD4, 0x2E, 0x78, 0xB2, 0x49, 0x22, 0x4F, 0x92,
970        0xC7, 0xE6, 0xE7, 0xA0, 0x5C, 0x49, 0xF0, 0xE7, 0xE4, 0xC8, 0x81, 0xBF, 0x2E, 0x94, 0xF4,
971        0x5E, 0x4A, 0x21, 0x83, 0x3D, 0x74, 0x56, 0x85, 0x1D, 0x0F, 0x6C, 0x14, 0x5A, 0x29, 0x54,
972        0x0C, 0x87, 0x4F, 0x30, 0x92, 0xC9, 0x34, 0xB4, 0x3D, 0x22, 0x2B, 0x89, 0x62, 0xC0, 0xF4,
973        0x10, 0xCE, 0xF1, 0xDB, 0x75, 0x89, 0x2A, 0xF1, 0x16, 0xB4, 0x4A, 0x96, 0xF5, 0xD3, 0x5A,
974        0xDE, 0xA3, 0x82, 0x2F, 0xC7, 0x14, 0x6F, 0x60, 0x04, 0x38, 0x5B, 0xCB, 0x69, 0xB6, 0x5C,
975        0x99, 0xE7, 0xEB, 0x69, 0x19, 0x78, 0x67, 0x03, 0xC0, 0xD8, 0xCD, 0x41, 0xE8, 0xF7, 0x5C,
976        0xCA, 0x44, 0xAA, 0x8A, 0xB7, 0x25, 0xAD, 0x8E, 0x79, 0x9F, 0xF3, 0xA8, 0x69, 0x6A, 0x6F,
977        0x1B, 0x26, 0x56, 0xE6, 0x31, 0xB1, 0xE4, 0x01, 0x83, 0xC0, 0x8F, 0xDA, 0x53, 0xFA, 0x4A,
978        0x8F, 0x85, 0xA0, 0x56, 0x93, 0x94, 0x4A, 0xE1, 0x79, 0xA1, 0x33, 0x9D, 0x00, 0x2D, 0x15,
979        0xCA, 0xBD, 0x81, 0x00, 0x90, 0xEC, 0x72, 0x2E, 0xF5, 0xDE, 0xF9, 0x96, 0x5A, 0x37, 0x1D,
980        0x41, 0x5D, 0x62, 0x4B, 0x68, 0xA2, 0x70, 0x7C, 0xAD, 0x97, 0xBC, 0xDD, 0x17, 0x85, 0xAF,
981        0x97, 0xE2, 0x58, 0xF3, 0x3D, 0xF5, 0x6A, 0x03, 0x1A, 0xA0, 0x35, 0x6D, 0x8E, 0x8D, 0x5E,
982        0xBC, 0xAD, 0xC7, 0x4E, 0x07, 0x16, 0x36, 0xC6, 0xB1, 0x10, 0xAC, 0xE5, 0xCC, 0x9B, 0x90,
983        0xDF, 0xEA, 0xCA, 0xE6, 0x40, 0xFF, 0x1B, 0xB0, 0xF1, 0xFE, 0x5D, 0xB4, 0xEF, 0xF7, 0xA9,
984        0x5F, 0x06, 0x07, 0x33, 0xF5, // ...
985        // Signature (variable Length)
986        0x30, 0x45, 0x02, 0x20, 0x32, 0x47, 0x79, 0xC6, 0x8F, 0x33, 0x80, 0x28, 0x8A, 0x11, 0x97,
987        0xB6, 0x09, 0x5F, 0x7A, 0x6E, 0xB9, 0xB1, 0xB1, 0xC1, 0x27, 0xF6, 0x6A, 0xE1, 0x2A, 0x99,
988        0xFE, 0x85, 0x32, 0xEC, 0x23, 0xB9, 0x02, 0x21, 0x00, 0xE3, 0x95, 0x16, 0xAC, 0x4D, 0x61,
989        0xEE, 0x64, 0x04, 0x4D, 0x50, 0xB4, 0x15, 0xA6, 0xA4, 0xD4, 0xD8, 0x4B, 0xA6, 0xD8, 0x95,
990        0xCB, 0x5A, 0xB7, 0xA1, 0xAA, 0x7D, 0x08, 0x1D, 0xE3, 0x41, 0xFA, // ...
991    ];
992}