webauthn_rs_core/
internals.rs

1//! Internal structures for parsing webauthn registrations and challenges. This *may* change
2//! at anytime and should not be relied on in your library.
3
4use crate::error::WebauthnError;
5use crate::proto::*;
6use serde::Deserialize;
7
8use base64urlsafedata::{Base64UrlSafeData, HumanBinaryData};
9
10use std::borrow::Borrow;
11use std::ops::Deref;
12
13use nom::bytes::complete::{tag, take};
14use nom::combinator::cond;
15use nom::combinator::{map_opt, verify};
16use nom::error::ParseError;
17use nom::number::complete::{be_u16, be_u32, be_u64};
18
19/// Representation of a UserId
20pub type UserId = Vec<u8>;
21
22/// A challenge issued by the server. This contains a set of random bytes.
23#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
24pub struct Challenge(Vec<u8>);
25
26impl Challenge {
27    /// Creates a new Challenge from a vector of bytes.
28    pub(crate) fn new(challenge: Vec<u8>) -> Self {
29        Challenge(challenge)
30    }
31}
32
33impl From<Challenge> for HumanBinaryData {
34    fn from(chal: Challenge) -> Self {
35        HumanBinaryData::from(chal.0)
36    }
37}
38
39impl From<Challenge> for Base64UrlSafeData {
40    fn from(chal: Challenge) -> Self {
41        Base64UrlSafeData::from(chal.0)
42    }
43}
44
45impl From<HumanBinaryData> for Challenge {
46    fn from(d: HumanBinaryData) -> Self {
47        Challenge(d.into())
48    }
49}
50
51impl<'a> From<&'a HumanBinaryData> for &'a ChallengeRef {
52    fn from(d: &'a HumanBinaryData) -> Self {
53        ChallengeRef::new(d.as_slice())
54    }
55}
56
57impl ToOwned for ChallengeRef {
58    type Owned = Challenge;
59
60    fn to_owned(&self) -> Self::Owned {
61        Challenge(self.0.to_vec())
62    }
63}
64
65impl AsRef<[u8]> for ChallengeRef {
66    fn as_ref(&self) -> &[u8] {
67        &self.0
68    }
69}
70
71impl Deref for ChallengeRef {
72    type Target = [u8];
73
74    fn deref(&self) -> &Self::Target {
75        self.as_ref()
76    }
77}
78
79impl Borrow<ChallengeRef> for Challenge {
80    fn borrow(&self) -> &ChallengeRef {
81        ChallengeRef::new(&self.0)
82    }
83}
84
85impl AsRef<ChallengeRef> for Challenge {
86    fn as_ref(&self) -> &ChallengeRef {
87        ChallengeRef::new(&self.0)
88    }
89}
90
91impl Deref for Challenge {
92    type Target = ChallengeRef;
93
94    fn deref(&self) -> &Self::Target {
95        self.as_ref()
96    }
97}
98
99/// A reference to the [Challenge] issued by the server.
100/// This contains a set of random bytes.
101///
102/// [ChallengeRef] is the `?Sized` type that corresponds to [Challenge]
103/// in the same way that [`&[u8]`] corresponds to [`Vec<u8>`].
104#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
105#[repr(transparent)]
106pub struct ChallengeRef([u8]);
107
108impl ChallengeRef {
109    /// Creates a new ChallengeRef from a slice
110    pub fn new(challenge: &[u8]) -> &ChallengeRef {
111        // SAFETY
112        // Because of #[repr(transparent)], [u8] is guaranteed to have the same representation as ChallengeRef.
113        // This allows safe casting between *const pointers of these types.
114        unsafe { &*(challenge as *const [u8] as *const ChallengeRef) }
115    }
116}
117
118impl PartialEq<Credential> for Credential {
119    fn eq(&self, c: &Credential) -> bool {
120        self.cred_id == c.cred_id
121    }
122}
123#[allow(clippy::too_many_arguments)]
124impl Credential {
125    pub(crate) fn new(
126        acd: &AttestedCredentialData,
127        auth_data: &AuthenticatorData<Registration>,
128        ck: COSEKey,
129        registration_policy: UserVerificationPolicy,
130        attestation: ParsedAttestation,
131        req_extn: &RequestRegistrationExtensions,
132        client_extn: &RegistrationExtensionsClientOutputs,
133        attestation_format: AttestationFormat,
134        transports: &Option<Vec<AuthenticatorTransport>>,
135    ) -> Self {
136        let cred_protect = match (
137            auth_data.extensions.cred_protect.as_ref(),
138            req_extn.cred_protect.is_some(),
139        ) {
140            (Some(credprotect), false) => ExtnState::Unsolicited(credprotect.0),
141            (Some(credprotect), true) => ExtnState::Set(credprotect.0),
142            (None, true) => ExtnState::Ignored,
143            (None, false) => ExtnState::NotRequested,
144        };
145
146        let hmac_create_secret = match (
147            auth_data.extensions.hmac_secret.as_ref(),
148            req_extn.hmac_create_secret.is_some(),
149        ) {
150            (Some(hmac_create_secret), false) => ExtnState::Unsolicited(*hmac_create_secret),
151            (Some(hmac_create_secret), true) => ExtnState::Set(*hmac_create_secret),
152            (None, true) => ExtnState::Ignored,
153            (None, false) => ExtnState::NotRequested,
154        };
155
156        let appid = ExtnState::NotRequested;
157        /*
158        let appid = match (
159            client_extn.appid,
160            req_extn.appid.is_some()
161        ) {
162            (Some(b), _) => ExtnState::Unsigned(b),
163            (None, true) => ExtnState::Ignored,
164            (None, false) => ExtnState::NotRequested,
165        };
166        */
167
168        let cred_props = match (
169            client_extn.cred_props.as_ref(),
170            req_extn.cred_props.is_some(),
171        ) {
172            (Some(b), _) => ExtnState::Unsigned(b.clone()),
173            (None, true) => ExtnState::Ignored,
174            (None, false) => ExtnState::NotRequested,
175        };
176
177        let extensions = RegisteredExtensions {
178            cred_protect,
179            hmac_create_secret,
180            appid,
181            cred_props,
182        };
183
184        trace!(?extensions);
185        let counter = auth_data.counter;
186        let user_verified = auth_data.user_verified;
187        let backup_eligible = auth_data.backup_eligible;
188        let backup_state = auth_data.backup_state;
189
190        let transports = if attestation_format == AttestationFormat::Packed
191            || attestation_format == AttestationFormat::Tpm
192        {
193            transports.clone()
194        } else {
195            None
196        };
197
198        Credential {
199            cred_id: acd.credential_id.clone(),
200            cred: ck,
201            counter,
202            transports,
203            user_verified,
204            backup_eligible,
205            backup_state,
206            registration_policy,
207            extensions,
208            attestation,
209            attestation_format,
210        }
211    }
212}
213
214pub(crate) fn process_authentication_extensions(
215    auth_extn: &AuthenticationSignedExtensions,
216) -> AuthenticationExtensions {
217    trace!(?auth_extn);
218    AuthenticationExtensions {}
219}
220
221/*
222WebauthnError::COSEKeyInvalidAlgorithm
223
224impl From<&COSEAlgorithm> for i64 {
225    fn from(c: &COSEAlgorithm) -> Self {
226        match c {
227            COSEAlgorithm::ES256 => -7,
228            COSEAlgorithm::ES384 => -35,
229            COSEAlgorithm::ES512 => -6,
230            COSEAlgorithm::RS256 => -257,
231            COSEAlgorithm::RS384 => -258,
232            COSEAlgorithm::RS512 => -259,
233            COSEAlgorithm::PS256 => -37,
234            COSEAlgorithm::PS384 => -38,
235            COSEAlgorithm::PS512 => -39,
236            COSEAlgorithm::EDDSA => -8,
237            COSEAlgorithm::INSECURE_RS1 => -65535,
238        }
239    }
240}
241*/
242
243impl TryFrom<i128> for ECDSACurve {
244    type Error = WebauthnError;
245    fn try_from(u: i128) -> Result<Self, Self::Error> {
246        match u {
247            1 => Ok(ECDSACurve::SECP256R1),
248            2 => Ok(ECDSACurve::SECP384R1),
249            3 => Ok(ECDSACurve::SECP521R1),
250            _ => Err(WebauthnError::COSEKeyECDSAInvalidCurve),
251        }
252    }
253}
254
255impl TryFrom<i128> for EDDSACurve {
256    type Error = WebauthnError;
257    fn try_from(u: i128) -> Result<Self, Self::Error> {
258        match u {
259            6 => Ok(EDDSACurve::ED25519),
260            7 => Ok(EDDSACurve::ED448),
261            _ => Err(WebauthnError::COSEKeyEDDSAInvalidCurve),
262        }
263    }
264}
265
266fn cbor_parser(i: &[u8]) -> nom::IResult<&[u8], serde_cbor_2::Value> {
267    let mut deserializer = serde_cbor_2::Deserializer::from_slice(i);
268    let v = serde::de::Deserialize::deserialize(&mut deserializer).map_err(|e| {
269        error!(?e, "cbor_parser");
270        nom::Err::Failure(nom::error::Error::from_error_kind(
271            i,
272            nom::error::ErrorKind::Fail,
273        ))
274    })?;
275
276    let len = deserializer.byte_offset();
277
278    Ok((&i[len..], v))
279}
280
281fn extensions_parser<T: Ceremony>(i: &[u8]) -> nom::IResult<&[u8], T::SignedExtensions> {
282    let (i, v) = cbor_parser(i)?;
283    trace!(?v, "OK!");
284
285    let v: T::SignedExtensions = serde_cbor_2::value::from_value(v).map_err(|e| {
286        error!(?e, "extensions_parser");
287        nom::Err::Failure(nom::error::Error::from_error_kind(
288            i,
289            nom::error::ErrorKind::Fail,
290        ))
291    })?;
292    Ok((i, v))
293}
294
295fn aaguid_parser(i: &[u8]) -> nom::IResult<&[u8], Aaguid> {
296    let (i, aaguid) = take(16usize)(i)?;
297    Ok((i, aaguid.try_into().expect("took 16 bytes exactly")))
298}
299
300fn acd_parser(i: &[u8]) -> nom::IResult<&[u8], AttestedCredentialData> {
301    let (i, aaguid) = aaguid_parser(i)?;
302    let (i, cred_id_len) = be_u16(i)?;
303
304    if usize::from(cred_id_len) > i.len() {
305        warn!(
306            "cred_id_len ({:?}) is larger than remaining number of bytes to parse ({:?}).",
307            cred_id_len,
308            i.len()
309        );
310    }
311
312    let (i, cred_id) = take(cred_id_len as usize)(i)?;
313    let (i, cred_pk) = cbor_parser(i)?;
314
315    Ok((
316        i,
317        AttestedCredentialData {
318            aaguid,
319            credential_id: HumanBinaryData::from(cred_id.to_vec()),
320            credential_pk: cred_pk,
321        },
322    ))
323}
324#[allow(clippy::type_complexity)]
325fn authenticator_data_flags(i: &[u8]) -> nom::IResult<&[u8], (bool, bool, bool, bool, bool, bool)> {
326    // Using nom for bit fields is shit, do it by hand.
327    let (i, ctrl) = nom::number::complete::u8(i)?;
328    let exten_pres = (ctrl & 0b1000_0000) != 0;
329    let acd_pres = (ctrl & 0b0100_0000) != 0;
330    let res_1 = (ctrl & 0b0010_0000) != 0;
331    let bak_st = (ctrl & 0b0001_0000) != 0;
332    let bak_el = (ctrl & 0b0000_1000) != 0;
333    let u_ver = (ctrl & 0b0000_0100) != 0;
334    let res_4 = (ctrl & 0b0000_0010) != 0;
335    let u_pres = (ctrl & 0b0000_0001) != 0;
336
337    if res_1 || res_4 {
338        warn!(
339            "Usage of unknown authenticator data flags detected! {:b}",
340            ctrl
341        );
342    }
343
344    Ok((i, (exten_pres, acd_pres, u_ver, u_pres, bak_el, bak_st)))
345}
346
347fn authenticator_data_parser<T: Ceremony>(i: &[u8]) -> nom::IResult<&[u8], AuthenticatorData<T>> {
348    let (i, rp_id_hash) = take(32usize)(i)?;
349    let (i, data_flags) = authenticator_data_flags(i)?;
350    let (i, counter) = be_u32(i)?;
351    let (i, acd) = cond(data_flags.1, acd_parser)(i)?;
352    let (i, extensions) = cond(data_flags.0, extensions_parser::<T>)(i)?;
353    trace!(?extensions);
354    let extensions = extensions.unwrap_or_default();
355
356    Ok((
357        i,
358        AuthenticatorData {
359            rp_id_hash: rp_id_hash.try_into().expect("took 32 bytes from input"),
360            counter,
361            user_verified: data_flags.2,
362            user_present: data_flags.3,
363            backup_eligible: data_flags.4,
364            backup_state: data_flags.5,
365            acd,
366            extensions,
367        },
368    ))
369}
370
371/// Data returned by this authenticator during registration.
372#[derive(Debug, Clone)]
373pub struct AuthenticatorData<T: Ceremony> {
374    /// Hash of the relying party id.
375    pub(crate) rp_id_hash: [u8; 32],
376    /// The counter of this credentials activations.
377    pub counter: u32,
378    /// Flag if the user was present.
379    pub user_present: bool,
380    /// Flag is the user verified to the device. Implies presence.
381    pub user_verified: bool,
382    /// Flag defining if the authenticator *could* be backed up OR transferred
383    /// between multiple devices.
384    pub backup_eligible: bool,
385    /// Flag defining if the authenticator *knows* it is currently backed up or
386    /// present on multiple devices.
387    pub backup_state: bool,
388    /// The optional attestation.
389    pub acd: Option<AttestedCredentialData>,
390    /// Extensions supplied by the device.
391    pub extensions: T::SignedExtensions,
392}
393
394impl<T: Ceremony> TryFrom<&[u8]> for AuthenticatorData<T> {
395    type Error = WebauthnError;
396    fn try_from(auth_data_bytes: &[u8]) -> Result<Self, Self::Error> {
397        authenticator_data_parser(auth_data_bytes)
398            .map_err(|e| {
399                error!(?e, "try_from authenticator_data_parser");
400                WebauthnError::ParseNOMFailure
401            })
402            .map(|(_, ad)| ad)
403    }
404}
405
406#[derive(Debug, Deserialize)]
407#[serde(rename_all = "camelCase")]
408pub(crate) struct AttestationObjectInner<'a> {
409    pub(crate) fmt: &'a str,
410    pub(crate) att_stmt: serde_cbor_2::Value,
411    pub(crate) auth_data: &'a [u8],
412    pub(crate) ep_att: Option<bool>,
413    pub(crate) large_blob_key: Option<&'a [u8]>,
414}
415
416/// Attestation Object
417#[derive(Debug)]
418pub struct AttestationObject<T: Ceremony> {
419    /// format.
420    pub(crate) fmt: String,
421    /// <https://w3c.github.io/webauthn/#generating-an-attestation-object>
422    pub(crate) att_stmt: serde_cbor_2::Value,
423    /// auth_data.
424    pub(crate) auth_data: AuthenticatorData<T>,
425    /// auth_data_bytes.
426    pub(crate) auth_data_bytes: Vec<u8>,
427    /// ep_att
428    pub(crate) _ep_att: Option<bool>,
429    /// large_blob_key
430    pub(crate) _large_blob_key: Option<Vec<u8>>,
431}
432
433impl<T: Ceremony> TryFrom<&[u8]> for AttestationObject<T> {
434    type Error = WebauthnError;
435
436    fn try_from(data: &[u8]) -> Result<AttestationObject<T>, WebauthnError> {
437        let v: serde_cbor_2::Value =
438            serde_cbor_2::from_slice(data).map_err(WebauthnError::ParseCBORFailure)?;
439        trace!(?v, "AttestationObjectInner");
440
441        let aoi: AttestationObjectInner =
442            serde_cbor_2::from_slice(data).map_err(WebauthnError::ParseCBORFailure)?;
443        let auth_data_bytes: &[u8] = aoi.auth_data;
444        let auth_data = AuthenticatorData::try_from(auth_data_bytes)?;
445
446        // Yay! Now we can assemble a reasonably sane structure.
447        Ok(AttestationObject {
448            fmt: aoi.fmt.to_owned(),
449            att_stmt: aoi.att_stmt,
450            auth_data,
451            auth_data_bytes: auth_data_bytes.to_owned(),
452            _ep_att: aoi.ep_att,
453            _large_blob_key: aoi.large_blob_key.map(|v| v.to_owned()),
454        })
455    }
456}
457
458impl TryFrom<u8> for CredProtectResponse {
459    type Error = <CredentialProtectionPolicy as TryFrom<u8>>::Error;
460
461    fn try_from(v: u8) -> Result<Self, Self::Error> {
462        CredentialProtectionPolicy::try_from(v).map(CredProtectResponse)
463    }
464}
465
466impl From<CredProtectResponse> for u8 {
467    fn from(policy: CredProtectResponse) -> Self {
468        policy.0 as u8
469    }
470}
471
472pub(crate) struct AuthenticatorAttestationResponse<T: Ceremony> {
473    pub(crate) attestation_object: AttestationObject<T>,
474    pub(crate) client_data_json: CollectedClientData,
475    pub(crate) client_data_json_bytes: Vec<u8>,
476    pub(crate) transports: Option<Vec<AuthenticatorTransport>>,
477}
478
479impl<T: Ceremony> TryFrom<&AuthenticatorAttestationResponseRaw>
480    for AuthenticatorAttestationResponse<T>
481{
482    type Error = WebauthnError;
483    fn try_from(aarr: &AuthenticatorAttestationResponseRaw) -> Result<Self, Self::Error> {
484        let ccdj = serde_json::from_slice(aarr.client_data_json.as_ref())
485            .map_err(WebauthnError::ParseJSONFailure)?;
486
487        let ao = AttestationObject::try_from(aarr.attestation_object.as_ref())?;
488
489        Ok(AuthenticatorAttestationResponse {
490            attestation_object: ao,
491            client_data_json: ccdj,
492            client_data_json_bytes: aarr.client_data_json.clone().into(),
493            transports: aarr.transports.clone(),
494        })
495    }
496}
497
498#[derive(Debug)]
499pub(crate) struct AuthenticatorAssertionResponse<T: Ceremony> {
500    pub(crate) authenticator_data: AuthenticatorData<T>,
501    pub(crate) authenticator_data_bytes: Vec<u8>,
502    pub(crate) client_data: CollectedClientData,
503    pub(crate) client_data_bytes: Vec<u8>,
504    pub(crate) signature: Vec<u8>,
505    pub(crate) _user_handle: Option<Vec<u8>>,
506}
507
508impl<T: Ceremony> TryFrom<&AuthenticatorAssertionResponseRaw>
509    for AuthenticatorAssertionResponse<T>
510{
511    type Error = WebauthnError;
512    fn try_from(aarr: &AuthenticatorAssertionResponseRaw) -> Result<Self, Self::Error> {
513        Ok(AuthenticatorAssertionResponse {
514            authenticator_data: AuthenticatorData::try_from(aarr.authenticator_data.as_ref())?,
515            authenticator_data_bytes: aarr.authenticator_data.clone().into(),
516            client_data: serde_json::from_slice(aarr.client_data_json.as_ref())
517                .map_err(WebauthnError::ParseJSONFailure)?,
518            client_data_bytes: aarr.client_data_json.clone().into(),
519            signature: aarr.signature.clone().into(),
520            _user_handle: aarr.user_handle.clone().map(|uh| uh.into()),
521        })
522    }
523}
524
525// ===== tpm shit show begins =====
526
527/// A magic constant that defines that a Tpm attestation comes from a TPM
528pub const TPM_GENERATED_VALUE: u32 = 0xff544347;
529
530#[derive(Debug, PartialEq, Eq)]
531#[repr(u16)]
532/// Tpm statement types.
533pub enum TpmSt {
534    /// Unused
535    RspCommand = 0x00c4,
536    /// Unused
537    Null = 0x8000,
538    /// Unused
539    NoSessions = 0x8001,
540    /// Unused
541    Sessions = 0x8002,
542    /// Unused
543    ReservedA = 0x8003,
544    /// Unused
545    ReservedB = 0x8004,
546    /// Unused
547    AttestNV = 0x8014,
548    /// Unused
549    AttestCommandAudit = 0x8015,
550    /// Unused
551    AttestSessionAudit = 0x8016,
552    /// Denote that this attestation contains a certify statement.
553    AttestCertify = 0x8017,
554    /// Unused
555    AttestQuote = 0x8018,
556    /// Unused
557    AttestTime = 0x8019,
558    /// Unused
559    AttestCreation = 0x801a,
560    /// Unused
561    ReservedC = 0x801b,
562    /// Unused
563    Creation = 0x8021,
564    /// Unused
565    Verified = 0x8022,
566    /// Unused
567    AuthSecret = 0x8023,
568    /// Unused
569    Hashcheck = 0x8024,
570    /// Unused
571    AuthSigned = 0x8025,
572    /// Unused
573    FUManifest = 0x8029,
574}
575
576impl TpmSt {
577    fn new(v: u16) -> Option<Self> {
578        match v {
579            0x00c4 => Some(TpmSt::RspCommand),
580            0x8000 => Some(TpmSt::Null),
581            0x8001 => Some(TpmSt::NoSessions),
582            0x8002 => Some(TpmSt::Sessions),
583            0x8003 => Some(TpmSt::ReservedA),
584            0x8004 => Some(TpmSt::ReservedB),
585            0x8014 => Some(TpmSt::AttestNV),
586            0x8015 => Some(TpmSt::AttestCommandAudit),
587            0x8016 => Some(TpmSt::AttestSessionAudit),
588            0x8017 => Some(TpmSt::AttestCertify),
589            0x8018 => Some(TpmSt::AttestQuote),
590            0x8019 => Some(TpmSt::AttestTime),
591            0x801a => Some(TpmSt::AttestCreation),
592            0x801b => Some(TpmSt::ReservedC),
593            0x8021 => Some(TpmSt::Creation),
594            0x8022 => Some(TpmSt::Verified),
595            0x8023 => Some(TpmSt::AuthSecret),
596            0x8024 => Some(TpmSt::Hashcheck),
597            0x8025 => Some(TpmSt::AuthSigned),
598            0x8029 => Some(TpmSt::FUManifest),
599            _ => None,
600        }
601    }
602}
603
604#[derive(Debug)]
605/// Information about the TPM's clock. May be obfuscated.
606pub struct TpmsClockInfo {
607    _clock: u64,
608    _reset_count: u32,
609    _restart_count: u32,
610    _safe: bool, // u8
611}
612
613fn tpmsclockinfo_parser(i: &[u8]) -> nom::IResult<&[u8], TpmsClockInfo> {
614    let (i, clock) = be_u64(i)?;
615    let (i, reset_count) = be_u32(i)?;
616    let (i, restart_count) = be_u32(i)?;
617    let (i, safe) = nom::combinator::map(nom::number::complete::u8, |v| v != 0)(i)?;
618
619    Ok((
620        i,
621        TpmsClockInfo {
622            _clock: clock,
623            _reset_count: reset_count,
624            _restart_count: restart_count,
625            _safe: safe,
626        },
627    ))
628}
629
630#[derive(Debug)]
631/// Tpm name enumeration.
632pub enum Tpm2bName {
633    /// No name present
634    None,
635    /// A handle reference
636    Handle(u32),
637    /// A digest of a name
638    Digest(Vec<u8>),
639}
640
641#[derive(Debug)]
642/// Tpm attestation union, switched by TpmSt.
643pub enum TpmuAttest {
644    /// The TpmuAttest contains a certify structure.
645    AttestCertify(Tpm2bName, Tpm2bName),
646    // AttestNV
647    // AttestCommandAudit
648    // AttestSessionAudit
649    // AttestQuote
650    // AttestTime
651    // AttestCreation
652    #[allow(dead_code)]
653    /// An invalid union
654    Invalid,
655}
656
657#[derive(Debug)]
658/// Tpm attestation structure.
659pub struct TpmsAttest {
660    /// Magic. Should be set to TPM_GENERATED_VALUE
661    pub magic: u32,
662    /// The type of attestation for typeattested.
663    pub type_: TpmSt,
664    /// Ignored in webauthn.
665    pub qualified_signer: Tpm2bName,
666    /// Ignored in webauthn.
667    pub extra_data: Option<Vec<u8>>,
668    /// Tpm Clock Information
669    pub clock_info: TpmsClockInfo,
670    /// The TPM firmware version. May be obfuscated.
671    pub firmware_version: u64,
672    /// The attestation.
673    pub typeattested: TpmuAttest,
674}
675
676fn tpm2b_name(i: &[u8]) -> nom::IResult<&[u8], Tpm2bName> {
677    let (i, case) = be_u16(i)?;
678    let (i, r) = match case {
679        0 => (i, Tpm2bName::None),
680        4 => {
681            let (i, h) = be_u32(i)?;
682            (i, Tpm2bName::Handle(h))
683        }
684        size => {
685            let (i, d) = take(size as usize)(i)?;
686            (i, Tpm2bName::Digest(d.to_vec()))
687        }
688    };
689
690    Ok((i, r))
691}
692
693fn tpm2b_data(i: &[u8]) -> nom::IResult<&[u8], Option<Vec<u8>>> {
694    let (i, size) = be_u16(i)?;
695    match size {
696        0 => Ok((i, None)),
697        size => {
698            let (i, d) = take(size as usize)(i)?;
699            Ok((i, Some(d.to_vec())))
700        }
701    }
702}
703
704fn tpmuattestcertify(i: &[u8]) -> nom::IResult<&[u8], TpmuAttest> {
705    let (i, name) = tpm2b_name(i)?;
706    let (i, qualified_name) = tpm2b_name(i)?;
707
708    Ok((i, TpmuAttest::AttestCertify(name, qualified_name)))
709}
710
711fn tpmsattest_parser(i: &[u8]) -> nom::IResult<&[u8], TpmsAttest> {
712    let (i, magic) = verify(be_u32, |x| *x == TPM_GENERATED_VALUE)(i)?;
713    let (i, type_) = map_opt(be_u16, TpmSt::new)(i)?;
714    let (i, qualified_signer) = tpm2b_name(i)?;
715    let (i, extra_data) = tpm2b_data(i)?;
716    let (i, clock_info) = tpmsclockinfo_parser(i)?;
717    let (i, firmware_version) = be_u64(i)?;
718    let (i, typeattested) = tpmuattestcertify(i)?;
719
720    Ok((
721        i,
722        TpmsAttest {
723            magic,
724            type_,
725            qualified_signer,
726            extra_data,
727            clock_info,
728            firmware_version,
729            typeattested,
730        },
731    ))
732}
733
734impl TryFrom<&[u8]> for TpmsAttest {
735    type Error = WebauthnError;
736
737    fn try_from(data: &[u8]) -> Result<TpmsAttest, WebauthnError> {
738        tpmsattest_parser(data)
739            .map_err(|e| {
740                error!(?e, "try_from tpmsattest_parser");
741                WebauthnError::ParseNOMFailure
742            })
743            .map(|(_, v)| v)
744    }
745}
746
747#[derive(Debug, Clone, Copy)]
748#[repr(u16)]
749/// The tpm cryptographic algorithm that may be in use.
750pub enum TpmAlgId {
751    /// Error occured
752    Error = 0x0000,
753    /// RSA
754    Rsa = 0x0001,
755    /// Insecure Sha1
756    Sha1 = 0x0004,
757    /// Hmac
758    Hmac = 0x0005,
759    /// Aes
760    Aes = 0x0006,
761    // Mgf1 = 0x0007,
762    // KeyedHash = 0x0008,
763    // Xor = 0x000A,
764    /// Sha256
765    Sha256 = 0x000B,
766    /// Sha384
767    Sha384 = 0x000C,
768    /// Sha512
769    Sha512 = 0x000D,
770    /// Null (no algorithm)
771    Null = 0x0010,
772    // Sm3_256 = 0x0012,
773    // Sm4 = 0x0013,
774    /// Rsa SSA
775    RsaSSA = 0x0014,
776    // RsAes = 0x0015,
777    /// Rsa PSS
778    RsaPSS = 0x0016,
779    // Oaep = 0x0017,
780    /// Ecdsa
781    Ecdsa = 0x0018,
782    // Ecdh = 0x0019,
783    /// Ecdaa
784    Ecdaa = 0x001A,
785    // Sm2 = 0x001B,
786    // EcSchnorr = 0x001C,
787    // EcMqv = 0x001D,
788    // Kdf1Sp80056A = 0x0020,
789    // Kdf2 = 0x0021,
790    // Kdf1Sp800108 = 0x0022,
791    /// Ecc
792    Ecc = 0x0023,
793    // Symcipher = 0x0025,
794    // Camellia = 0x0026,
795    // Ctr = 0x0040,
796    // Ofb = 0x0041,
797    // Cbc = 0x0042,
798    // Cfb = 0x0043,
799    // Ecb = 0x0044,
800}
801
802impl TpmAlgId {
803    fn new(v: u16) -> Option<Self> {
804        trace!("TpmAlgId::new ( {:x?} )", v);
805        match v {
806            0x0000 => Some(TpmAlgId::Error),
807            0x0001 => Some(TpmAlgId::Rsa),
808            0x0004 => Some(TpmAlgId::Sha1),
809            0x0005 => Some(TpmAlgId::Hmac),
810            0x0006 => Some(TpmAlgId::Aes),
811            0x000B => Some(TpmAlgId::Sha256),
812            0x000C => Some(TpmAlgId::Sha384),
813            0x000D => Some(TpmAlgId::Sha512),
814            0x0010 => Some(TpmAlgId::Null),
815            0x0014 => Some(TpmAlgId::RsaSSA),
816            0x0016 => Some(TpmAlgId::RsaPSS),
817            0x0018 => Some(TpmAlgId::Ecdsa),
818            0x001A => Some(TpmAlgId::Ecdaa),
819            0x0023 => Some(TpmAlgId::Ecc),
820            _ => None,
821        }
822    }
823}
824
825// Later, this probably would be rewritten interms of the chosen
826// symetric algo, but for now it's always Null
827#[derive(Debug)]
828/// Symmetric crypto definition. Unused in webauthn
829pub struct TpmtSymDefObject {
830    _algorithm: TpmAlgId,
831    // keybits: Option<()>,
832    // mode: Option<()>,
833    // details
834}
835
836fn parse_tpmtsymdefobject(input: &[u8]) -> nom::IResult<&[u8], Option<TpmtSymDefObject>> {
837    let (data, algorithm) = map_opt(be_u16, TpmAlgId::new)(input)?;
838    match algorithm {
839        TpmAlgId::Null => Ok((data, None)),
840        _ => Err(nom::Err::Failure(nom::error::Error::from_error_kind(
841            input,
842            nom::error::ErrorKind::Fail,
843        ))),
844    }
845}
846
847#[derive(Debug)]
848/// Symmetric crypto definition. Unused in webauthn
849pub struct TpmtEccScheme {
850    _algorithm: TpmAlgId,
851}
852
853fn parse_tpmteccscheme(input: &[u8]) -> nom::IResult<&[u8], Option<TpmtEccScheme>> {
854    let (data, algorithm) = map_opt(be_u16, TpmAlgId::new)(input)?;
855    match algorithm {
856        TpmAlgId::Null => Ok((data, None)),
857        _ => Err(nom::Err::Failure(nom::error::Error::from_error_kind(
858            input,
859            nom::error::ErrorKind::Fail,
860        ))),
861    }
862}
863
864// 11.2.5.5 TPMI_ECC_CURVE
865// 6.4 TPM_ECC_CURVE
866#[derive(Debug, Clone, Copy)]
867#[repr(u16)]
868pub(crate) enum TpmiEccCurve {
869    None = 0x0000,
870    NistP192 = 0x0001,
871    NistP224 = 0x0002,
872    NistP256 = 0x0003,
873    NistP384 = 0x0004,
874    NistP521 = 0x0005,
875    BnP256 = 0x0010,
876    BnP638 = 0x0011,
877    Sm2P256 = 0x0020,
878}
879
880impl TpmiEccCurve {
881    fn new(v: u16) -> Option<Self> {
882        trace!("TpmiEccCurve::new ( {:x?} )", v);
883        match v {
884            0x0000 => Some(TpmiEccCurve::None),
885            0x0001 => Some(TpmiEccCurve::NistP192),
886            0x0002 => Some(TpmiEccCurve::NistP224),
887            0x0003 => Some(TpmiEccCurve::NistP256),
888            0x0004 => Some(TpmiEccCurve::NistP384),
889            0x0005 => Some(TpmiEccCurve::NistP521),
890            0x0010 => Some(TpmiEccCurve::BnP256),
891            0x0011 => Some(TpmiEccCurve::BnP638),
892            0x0020 => Some(TpmiEccCurve::Sm2P256),
893            _ => None,
894        }
895    }
896}
897
898#[derive(Debug)]
899/// Symmetric crypto definition. Unused in webauthn
900pub struct TpmtKdfScheme {
901    _algorithm: TpmAlgId,
902}
903
904fn parse_tpmtkdfscheme(input: &[u8]) -> nom::IResult<&[u8], Option<TpmtKdfScheme>> {
905    let (data, algorithm) = map_opt(be_u16, TpmAlgId::new)(input)?;
906    match algorithm {
907        TpmAlgId::Null => Ok((data, None)),
908        _ => Err(nom::Err::Failure(nom::error::Error::from_error_kind(
909            input,
910            nom::error::ErrorKind::Fail,
911        ))),
912    }
913}
914
915#[derive(Debug)]
916/// The Rsa Scheme. Unused in webauthn.
917pub struct TpmtRsaScheme {
918    _algorithm: TpmAlgId,
919    // details
920}
921
922fn parse_tpmtrsascheme(input: &[u8]) -> nom::IResult<&[u8], Option<TpmtRsaScheme>> {
923    let (data, algorithm) = map_opt(be_u16, TpmAlgId::new)(input)?;
924    match algorithm {
925        TpmAlgId::Null => Ok((data, None)),
926        _ => Err(nom::Err::Failure(nom::error::Error::from_error_kind(
927            input,
928            nom::error::ErrorKind::Fail,
929        ))),
930    }
931}
932
933#[derive(Debug)]
934/// Rsa Parameters.
935pub(crate) struct TpmsRsaParms {
936    // TPMT_SYM_DEF_OBJECT + ALG_NULL
937    _symmetric: Option<TpmtSymDefObject>,
938    // TPMT_RSA_SCHEME+ (rsapss, rsassa, null)
939    _scheme: Option<TpmtRsaScheme>,
940    // TPMI_RSA_KEY_BITS
941    _keybits: u16,
942    // u32
943    /// The Rsa Exponent
944    _exponent: u32,
945}
946
947fn tpmsrsaparms_parser(i: &[u8]) -> nom::IResult<&[u8], TpmsRsaParms> {
948    let (i, symmetric) = parse_tpmtsymdefobject(i)?;
949    let (i, scheme) = parse_tpmtrsascheme(i)?;
950    let (i, keybits) = be_u16(i)?;
951    let (i, exponent) = be_u32(i)?;
952    Ok((
953        i,
954        TpmsRsaParms {
955            _symmetric: symmetric,
956            _scheme: scheme,
957            _keybits: keybits,
958            _exponent: exponent,
959        },
960    ))
961    /*
962    do_parse!(
963        symmetric: parse_tpmtsymdefobject >>
964        scheme: parse_tpmtrsascheme >>
965        keybits: u16!(nom::Endianness::Big) >>
966        exponent: u32!(nom::Endianness::Big) >>
967        (
968        TpmsRsaParms {
969            _symmetric: symmetric,
970            _scheme: scheme,
971            _keybits: keybits,
972            exponent
973        }
974        )
975    )
976    */
977}
978
979// 12.2.3.6 TPMS_ECC_PARMS in
980fn tpmseccparms_parser(i: &[u8]) -> nom::IResult<&[u8], TpmsEccParms> {
981    trace!(?i);
982    let (i, symmetric) = parse_tpmtsymdefobject(i)?;
983    let (i, scheme) = parse_tpmteccscheme(i)?;
984    let (i, curve_id) = map_opt(be_u16, TpmiEccCurve::new)(i)?;
985    let (i, kdf) = parse_tpmtkdfscheme(i)?;
986
987    Ok((
988        i,
989        TpmsEccParms {
990            _symmetric: symmetric,
991            _scheme: scheme,
992            curve_id,
993            _kdf: kdf,
994        },
995    ))
996}
997
998#[derive(Debug)]
999pub(crate) struct TpmsEccParms {
1000    _symmetric: Option<TpmtSymDefObject>,
1001    _scheme: Option<TpmtEccScheme>,
1002    /// The ID of the ECC curve in use
1003    pub curve_id: TpmiEccCurve,
1004    _kdf: Option<TpmtKdfScheme>,
1005}
1006
1007#[derive(Debug)]
1008/// Asymmetric Public Parameters
1009pub(crate) enum TpmuPublicParms {
1010    // KeyedHash
1011    // Symcipher
1012    /// Rsa
1013    Rsa(TpmsRsaParms),
1014    Ecc(TpmsEccParms),
1015    // Asym
1016}
1017
1018fn parse_tpmupublicparms(input: &[u8], alg: TpmAlgId) -> nom::IResult<&[u8], TpmuPublicParms> {
1019    trace!(?input, ?alg, "tpmupublicparms input");
1020    match alg {
1021        TpmAlgId::Rsa => {
1022            tpmsrsaparms_parser(input).map(|(data, inner)| (data, TpmuPublicParms::Rsa(inner)))
1023        }
1024        TpmAlgId::Ecc => {
1025            tpmseccparms_parser(input).map(|(data, inner)| (data, TpmuPublicParms::Ecc(inner)))
1026        }
1027        a => {
1028            debug!(?a, "unsuported alg in parse_tpmupublicparms");
1029            Err(nom::Err::Failure(nom::error::Error::from_error_kind(
1030                input,
1031                nom::error::ErrorKind::Fail,
1032            )))
1033        }
1034    }
1035}
1036
1037/// 11.2.5.2 TPMS_ECC_POINT
1038#[derive(Debug)]
1039pub(crate) struct TpmsEccPoint {
1040    pub x: Vec<u8>,
1041    pub y: Vec<u8>,
1042}
1043
1044fn tpmseccpoint_parser(i: &[u8]) -> nom::IResult<&[u8], TpmsEccPoint> {
1045    let (i, size) = be_u16(i)?;
1046    let (i, x) = match size {
1047        0 => (i, Vec::new()),
1048        size => {
1049            let (i, d) = take(size as usize)(i)?;
1050            (i, d.to_vec())
1051        }
1052    };
1053    let (i, size) = be_u16(i)?;
1054    let (i, y) = match size {
1055        0 => (i, Vec::new()),
1056        size => {
1057            let (i, d) = take(size as usize)(i)?;
1058            (i, d.to_vec())
1059        }
1060    };
1061    Ok((i, TpmsEccPoint { x, y }))
1062}
1063
1064#[derive(Debug)]
1065/// Asymmetric Public Key
1066pub(crate) enum TpmuPublicId {
1067    // KeyedHash
1068    // Symcipher
1069    /// Rsa
1070    Rsa(Vec<u8>),
1071    /// Ecc
1072    Ecc(TpmsEccPoint),
1073    // Asym
1074}
1075
1076fn tpmsrsapublickey_parser(i: &[u8]) -> nom::IResult<&[u8], Vec<u8>> {
1077    let (i, size) = be_u16(i)?;
1078    match size {
1079        0 => Ok((i, Vec::new())),
1080        size => {
1081            let (i, d) = take(size as usize)(i)?;
1082            Ok((i, d.to_vec()))
1083        }
1084    }
1085}
1086
1087fn parse_tpmupublicid(input: &[u8], alg: TpmAlgId) -> nom::IResult<&[u8], TpmuPublicId> {
1088    // eprintln!("tpmupublicparms input -> {:?}", input);
1089    match alg {
1090        TpmAlgId::Rsa => {
1091            tpmsrsapublickey_parser(input).map(|(data, inner)| (data, TpmuPublicId::Rsa(inner)))
1092        }
1093        TpmAlgId::Ecc => {
1094            tpmseccpoint_parser(input).map(|(data, inner)| (data, TpmuPublicId::Ecc(inner)))
1095        }
1096        a => {
1097            debug!(?a, "unsuported alg in parse_tpmupublicid");
1098            Err(nom::Err::Failure(nom::error::Error::from_error_kind(
1099                input,
1100                nom::error::ErrorKind::Fail,
1101            )))
1102        }
1103    }
1104}
1105
1106#[derive(Debug)]
1107/// Tpm Public Key Structure
1108pub(crate) struct TpmtPublic {
1109    /// The type of public parms and key IE Ecdsa or Rsa
1110    pub _type: TpmAlgId,
1111    /// The hash type over pubarea (webauthn specific)
1112    pub name_alg: TpmAlgId,
1113    // TPMA_OBJECT
1114    /// Unused in webauthn.
1115    pub _object_attributes: u32,
1116    /// Unused in webauthn.
1117    pub _auth_policy: Option<Vec<u8>>,
1118    //
1119    // TPMU_PUBLIC_PARMS
1120    /// Public Parameters
1121    pub parameters: TpmuPublicParms,
1122    // TPMU_PUBLIC_ID
1123    /// Public Key
1124    pub unique: TpmuPublicId,
1125}
1126
1127impl TryFrom<&[u8]> for TpmtPublic {
1128    type Error = WebauthnError;
1129
1130    fn try_from(data: &[u8]) -> Result<TpmtPublic, WebauthnError> {
1131        trace!(?data);
1132        tpmtpublic_parser(data)
1133            .map_err(|e| {
1134                error!(?e, "try_from tpmtpublic_parser");
1135                WebauthnError::ParseNOMFailure
1136            })
1137            .map(|(_, v)| v)
1138    }
1139}
1140
1141fn tpm2b_digest(i: &[u8]) -> nom::IResult<&[u8], Option<Vec<u8>>> {
1142    let (i, size) = be_u16(i)?;
1143    match size {
1144        0 => Ok((i, None)),
1145        size => {
1146            let (i, d) = take(size as usize)(i)?;
1147            Ok((i, Some(d.to_vec())))
1148        }
1149    }
1150}
1151
1152fn tpmtpublic_parser(i: &[u8]) -> nom::IResult<&[u8], TpmtPublic> {
1153    let (i, type_) = map_opt(be_u16, TpmAlgId::new)(i)?;
1154    let (i, name_alg) = map_opt(be_u16, TpmAlgId::new)(i)?;
1155    let (i, _object_attributes) = be_u32(i)?;
1156    let (i, _auth_policy) = tpm2b_digest(i)?;
1157    let (i, parameters) = parse_tpmupublicparms(i, type_)?;
1158    let (i, unique) = parse_tpmupublicid(i, type_)?;
1159
1160    Ok((
1161        i,
1162        TpmtPublic {
1163            _type: type_,
1164            name_alg,
1165            _object_attributes,
1166            _auth_policy,
1167            parameters,
1168            unique,
1169        },
1170    ))
1171}
1172
1173#[derive(Debug)]
1174/// A TPM Signature.
1175pub enum TpmtSignature {
1176    // if sigAlg has a type, parse as:
1177    // signature - TPMU_SIGNATURE
1178    // Else, due to how this work if no alg, just pass the raw bytes back.
1179    /// A raw signature, verifyied by a cert + hash combination. May be implementation
1180    /// specific.
1181    RawSignature(Vec<u8>),
1182}
1183
1184impl TryFrom<&[u8]> for TpmtSignature {
1185    type Error = WebauthnError;
1186
1187    fn try_from(data: &[u8]) -> Result<TpmtSignature, WebauthnError> {
1188        tpmtsignature_parser(data)
1189            .map_err(|e| {
1190                error!(?e, "try_from tpmtsignature_parser");
1191                WebauthnError::ParseNOMFailure
1192            })
1193            .map(|(_, v)| v)
1194    }
1195}
1196
1197fn tpmtsignature_parser(input: &[u8]) -> nom::IResult<&[u8], TpmtSignature> {
1198    let (_data, algorithm) = nom::combinator::map(be_u16, TpmAlgId::new)(input)?;
1199    match algorithm {
1200        None => Ok((&[], TpmtSignature::RawSignature(Vec::from(input)))),
1201        _ => Err(nom::Err::Failure(nom::error::Error::from_error_kind(
1202            input,
1203            nom::error::ErrorKind::Fail,
1204        ))),
1205    }
1206}
1207
1208/// TPM vendor identifier, from [the TPM Vendor ID Registry][1]
1209///
1210/// [1]: https://trustedcomputinggroup.org/wp-content/uploads/TCG-TPM-VendorIDRegistry-v1p06-r0p91-pub.pdf
1211#[derive(Debug)]
1212#[allow(clippy::upper_case_acronyms)]
1213pub(crate) enum TpmVendor {
1214    AMD,
1215    Atmel,
1216    Broadcom,
1217    Cisco,
1218    FlySliceTechnologies,
1219    FuzhouRockchip,
1220    Google,
1221    HPE,
1222    Huawei,
1223    IBM,
1224    Infineon,
1225    Intel,
1226    Lenovo,
1227    Microsoft,
1228    NationalSemi,
1229    Nationz,
1230    NuvotonTechnology,
1231    Qualcomm,
1232    Samsung,
1233    Sinosun,
1234    SMSC,
1235    StMicroelectronics,
1236    TexasInstruments,
1237    Winbond,
1238}
1239
1240// The value of the TPMManufacturer attribute MUST be the ASCII representation
1241// of the hexadecimal value of the 4 byte vendor identifier defined in the TCG
1242// Vendor ID Registry. Each byte is represented individually as a two digit
1243// unsigned hexadecimal number using the characters 0-9 and A-F.
1244impl TryFrom<&[u8; 8]> for TpmVendor {
1245    type Error = WebauthnError;
1246
1247    fn try_from(v: &[u8; 8]) -> Result<Self, Self::Error> {
1248        match v {
1249            b"414d4400" => Ok(Self::AMD),
1250            b"41544D4C" => Ok(Self::Atmel),
1251            b"4252434D" => Ok(Self::Broadcom),
1252            b"4353434F" => Ok(Self::Cisco),
1253            b"464C5953" => Ok(Self::FlySliceTechnologies),
1254            b"524F4343" => Ok(Self::FuzhouRockchip),
1255            b"474F4F47" => Ok(Self::Google),
1256            b"48504500" => Ok(Self::HPE),
1257            b"48495349" => Ok(Self::Huawei),
1258            b"49424D00" => Ok(Self::IBM),
1259            b"49465800" => Ok(Self::Infineon),
1260            b"494E5443" => Ok(Self::Intel),
1261            b"4C454E00" => Ok(Self::Lenovo),
1262            b"4D534654" => Ok(Self::Microsoft),
1263            b"4E534D20" => Ok(Self::NationalSemi),
1264            b"4E545A00" => Ok(Self::Nationz),
1265            b"4E544300" => Ok(Self::NuvotonTechnology),
1266            b"51434F4D" => Ok(Self::Qualcomm),
1267            b"534D534E" => Ok(Self::Samsung),
1268            b"534E5300" => Ok(Self::Sinosun),
1269            b"534D5343" => Ok(Self::SMSC),
1270            b"53544D20" => Ok(Self::StMicroelectronics),
1271            b"54584E00" => Ok(Self::TexasInstruments),
1272            b"57454300" => Ok(Self::Winbond),
1273            _ => Err(WebauthnError::ParseNOMFailure),
1274        }
1275    }
1276}
1277
1278// The result is concatenated together to form an 8 character name which is
1279// appended after the lower-case ASCII characters “id:”.
1280pub(crate) fn tpm_device_attribute_parser(i: &[u8]) -> nom::IResult<&[u8], &[u8; 8]> {
1281    let (i, _) = tag("id:")(i)?;
1282    let (i, vendor_code) = take(8usize)(i)?;
1283
1284    Ok((i, vendor_code.try_into().expect("took exactly 8 bytes")))
1285}
1286
1287impl TryFrom<&[u8]> for TpmVendor {
1288    type Error = WebauthnError;
1289    fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
1290        tpm_device_attribute_parser(data)
1291            .map_err(|e| {
1292                error!(?e, "try_from tpm_device_attribute_parser");
1293                WebauthnError::ParseNOMFailure
1294            })
1295            .and_then(|(_, v)| TpmVendor::try_from(v))
1296    }
1297}
1298
1299#[cfg(test)]
1300mod tests {
1301    use super::{
1302        AttestationObject, Authentication, AuthenticatorData, CredentialProtectionPolicy,
1303        RegisterPublicKeyCredential, Registration, RegistrationSignedExtensions, TpmsAttest,
1304        TpmtPublic, TpmtSignature, TPM_GENERATED_VALUE,
1305    };
1306    use crate::interface::*;
1307    use base64::{engine::general_purpose::STANDARD, Engine};
1308
1309    #[test]
1310    fn deserialise_register_response() {
1311        let x = r#"
1312        {   "id":"4oiUggKcrpRIlB-cFzFbfkx_BNeM7UAnz3wO7ZpT4I2GL_n-g8TICyJTHg11l0wyc-VkQUVnJ0yM08-1D5oXnw",
1313            "rawId":"4oiUggKcrpRIlB-cFzFbfkx_BNeM7UAnz3wO7ZpT4I2GL_n-g8TICyJTHg11l0wyc-VkQUVnJ0yM08-1D5oXnw",
1314            "response":{
1315                "attestationObject":"o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEEsoXtJryKJQ28wPgFmAwoh5SXSZuIJJnQzgBqP1AcaBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQOKIlIICnK6USJQfnBcxW35MfwTXjO1AJ898Du2aU-CNhi_5_oPEyAsiUx4NdZdMMnPlZEFFZydMjNPPtQ-aF5-lAQIDJiABIVggFo08FM4Je1yfCSuPsxP6h0zvlJSjfocUk75EvXw2oSMiWCArRwLD8doar0bACWS1PgVJKzp_wStyvOkTd4NlWHW8rQ",
1316                "clientDataJSON":"eyJjaGFsbGVuZ2UiOiJwZENXRDJWamRMSVkzN2VSYTVfazdhS3BqdkF2VmNOY04ycVozMjk0blpVIiwiY2xpZW50RXh0ZW5zaW9ucyI6e30sImhhc2hBbGdvcml0aG0iOiJTSEEtMjU2Iiwib3JpZ2luIjoiaHR0cDovLzEyNy4wLjAuMTo4MDgwIiwidHlwZSI6IndlYmF1dGhuLmNyZWF0ZSJ9"
1317            },
1318            "type":"public-key"
1319        }
1320        "#;
1321        let _y: RegisterPublicKeyCredential = serde_json::from_str(x).unwrap();
1322    }
1323
1324    #[test]
1325    fn deserialise_attestation_object() {
1326        let raw_ao = STANDARD.decode(
1327            "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVjEEsoXtJryKJQ28wPgFmAwoh5SXSZuIJJnQzgBqP1AcaBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAQCgxaVISCxE+DrcxP5/+aPM88CTI+04J+o61SK6mnepjGZYv062AbtydzWmbAxF00VSAyp0ImP94uoy+0y7w9yilAQIDJiABIVggGT9woA+UoX+jBxuiHQpdkm0kCVh75WTj3TXl4zLJuzoiWCBKiCneKgWJgWiwrZedNwl06GTaXyaGrYS4bPbBraInyg=="
1328        ).unwrap();
1329
1330        let _ao = AttestationObject::<Registration>::try_from(raw_ao.as_slice()).unwrap();
1331    }
1332
1333    // Add tests for when the objects are too short.
1334    //
1335    #[test]
1336    fn deserialise_tpms_attest() {
1337        let data: Vec<u8> = vec![
1338            255, 84, 67, 71, // magic
1339            128, 23, // type_
1340            0, 34, // 2b_name size
1341            0, 11, 174, 74, 152, 70, 1, 87, 191, 156, 96, 74, 177, 221, 37, 132, 6, 8, 101, 35,
1342            124, 216, 85, 173, 85, 195, 115, 137, 194, 247, 145, 61, 82, 40, // 2b_name data
1343            0, 20, // exdata size
1344            234, 98, 144, 49, 146, 39, 99, 47, 44, 82, 115, 48, 64, 40, 152, 224, 227, 42, 63,
1345            133, // ext data
1346            0, 0, 0, 2, 219, 215, 137, 38, // clock
1347            187, 106, 183, 8, // reset
1348            100, 145, 106, 200, // restart
1349            1,   // safe
1350            86, 5, 220, 81, 118, 234, 131, 141, // fw vers
1351            0, 34, // type attested.
1352            0, 11, 239, 53, 112, 255, 253, 12, 189, 168, 16, 253, 10, 149, 108, 7, 31, 212, 143,
1353            21, 153, 7, 7, 153, 99, 73, 205, 97, 90, 110, 182, 120, 4, 250, 0, 34, 0, 11, 249, 72,
1354            224, 84, 16, 96, 147, 197, 167, 195, 110, 181, 77, 207, 147, 16, 34, 64, 139, 185, 120,
1355            190, 196, 209, 213, 29, 1, 136, 76, 235, 223, 247,
1356        ];
1357
1358        let tpms_attest = TpmsAttest::try_from(data.as_slice()).unwrap();
1359        println!("{tpms_attest:?}");
1360        assert!(tpms_attest.magic == TPM_GENERATED_VALUE);
1361    }
1362
1363    #[test]
1364    fn deserialise_tpmt_public() {
1365        // The TPMT_PUBLIC structure (see [TPMv2-Part2] section 12.2.4) used by the TPM to represent the credential public key.
1366        let data: Vec<u8> = vec![
1367            0, 1, 0, 11, 0, 6, 4, 114, 0, 32, 157, 255, 203, 243, 108, 56, 58, 230, 153, 251, 152,
1368            104, 220, 109, 203, 137, 215, 21, 56, 132, 190, 40, 3, 146, 44, 18, 65, 88, 191, 173,
1369            34, 174, 0, 16, 0, 16, 8, 0, 0, 0, 0, 0, 1, 0, 220, 20, 243, 114, 251, 142, 90, 236,
1370            17, 204, 181, 223, 8, 72, 230, 209, 122, 44, 90, 55, 96, 134, 69, 16, 125, 139, 112,
1371            81, 154, 230, 133, 211, 129, 37, 75, 208, 222, 70, 210, 239, 209, 188, 152, 93, 222,
1372            222, 154, 169, 217, 160, 90, 243, 135, 151, 25, 87, 240, 178, 106, 119, 150, 89, 23,
1373            223, 158, 88, 107, 72, 101, 61, 184, 132, 19, 110, 144, 107, 22, 178, 252, 206, 50,
1374            207, 11, 177, 137, 35, 139, 68, 212, 148, 121, 249, 50, 35, 89, 52, 47, 26, 23, 6, 15,
1375            115, 155, 127, 59, 168, 208, 196, 78, 125, 205, 0, 98, 43, 223, 233, 65, 137, 103, 2,
1376            227, 35, 81, 107, 247, 230, 186, 111, 27, 4, 57, 42, 220, 32, 29, 181, 159, 6, 176,
1377            182, 94, 191, 222, 212, 235, 60, 101, 83, 86, 217, 203, 151, 251, 254, 219, 204, 195,
1378            10, 74, 147, 5, 27, 167, 127, 117, 149, 245, 157, 92, 124, 2, 196, 214, 107, 246, 228,
1379            171, 229, 100, 212, 67, 88, 215, 75, 33, 183, 199, 51, 171, 210, 213, 65, 45, 96, 96,
1380            226, 29, 130, 254, 58, 92, 252, 133, 207, 105, 63, 156, 208, 149, 142, 9, 83, 1, 193,
1381            217, 244, 35, 137, 43, 138, 137, 140, 82, 231, 195, 145, 213, 230, 185, 245, 104, 105,
1382            62, 142, 124, 34, 9, 157, 167, 188, 243, 112, 104, 248, 63, 50, 19, 53, 173, 69, 12,
1383            39, 252, 9, 69, 223,
1384        ];
1385        let tpmt_public = TpmtPublic::try_from(data.as_slice()).unwrap();
1386        println!("{tpmt_public:?}");
1387    }
1388
1389    #[test]
1390    fn deserialise_tpmt_signature() {
1391        // The attestation signature, in the form of a TPMT_SIGNATURE structure as specified in [TPMv2-Part2] section 11.3.4.
1392        let data: Vec<u8> = vec![
1393            5, 3, 162, 216, 151, 57, 210, 103, 145, 121, 161, 186, 63, 232, 221, 255, 89, 37, 17,
1394            59, 155, 241, 77, 30, 35, 201, 30, 140, 84, 214, 250, 185, 47, 248, 58, 89, 177, 187,
1395            231, 202, 220, 45, 167, 126, 243, 194, 94, 33, 39, 205, 163, 51, 40, 171, 35, 118, 196,
1396            244, 247, 143, 166, 193, 223, 94, 244, 157, 121, 220, 22, 94, 163, 15, 151, 223, 214,
1397            131, 105, 202, 40, 16, 176, 11, 154, 102, 100, 212, 174, 103, 166, 92, 90, 154, 224,
1398            20, 165, 106, 127, 53, 91, 230, 217, 199, 172, 195, 203, 242, 41, 158, 64, 252, 65, 9,
1399            155, 160, 63, 40, 94, 94, 64, 145, 173, 71, 85, 173, 2, 199, 18, 148, 88, 223, 93, 154,
1400            203, 197, 170, 142, 35, 249, 146, 107, 146, 2, 14, 54, 39, 151, 181, 10, 176, 216, 117,
1401            25, 196, 2, 205, 159, 140, 155, 56, 89, 87, 31, 135, 93, 97, 78, 95, 176, 228, 72, 237,
1402            130, 171, 23, 66, 232, 35, 115, 218, 105, 168, 6, 253, 121, 161, 129, 44, 78, 252, 44,
1403            11, 23, 172, 66, 37, 214, 113, 128, 28, 33, 209, 66, 34, 32, 196, 153, 80, 87, 243,
1404            162, 7, 25, 62, 252, 243, 174, 31, 168, 98, 123, 100, 2, 143, 134, 36, 154, 236, 18,
1405            128, 175, 185, 189, 177, 51, 53, 216, 190, 43, 63, 35, 84, 14, 64, 249, 23, 9, 125,
1406            147, 160, 176, 137, 30, 174, 245, 148, 189,
1407        ];
1408        let tpmt_sig = TpmtSignature::try_from(data.as_slice()).unwrap();
1409        println!("{tpmt_sig:?}");
1410    }
1411
1412    #[test]
1413    fn deserialize_extensions() {
1414        let data: Vec<u8> = vec![
1415            161, 107, 99, 114, 101, 100, 80, 114, 111, 116, 101, 99, 116, 3,
1416        ];
1417
1418        let extensions: RegistrationSignedExtensions = serde_cbor_2::from_slice(&data).unwrap();
1419
1420        let cred_protect = extensions
1421            .cred_protect
1422            .expect("should have cred protect extension");
1423        println!("{cred_protect:?}");
1424        assert_eq!(
1425            cred_protect.0,
1426            CredentialProtectionPolicy::UserVerificationRequired
1427        );
1428    }
1429
1430    #[test]
1431    fn credential_protection_policy_conversions() {
1432        use CredentialProtectionPolicy::*;
1433        assert_eq!(
1434            UserVerificationOptional,
1435            CredentialProtectionPolicy::try_from(UserVerificationOptional as u8).unwrap()
1436        );
1437        assert_eq!(
1438            UserVerificationOptionalWithCredentialIDList,
1439            CredentialProtectionPolicy::try_from(
1440                UserVerificationOptionalWithCredentialIDList as u8
1441            )
1442            .unwrap()
1443        );
1444        assert_eq!(
1445            UserVerificationRequired,
1446            CredentialProtectionPolicy::try_from(UserVerificationRequired as u8).unwrap()
1447        );
1448    }
1449
1450    #[test]
1451    fn authenticator_data_parser_extensions() {
1452        let _ = tracing_subscriber::fmt::try_init();
1453        let raw = [
1454            73, 150, 13, 229, 136, 14, 140, 104, 116, 52, 23, 15, 100, 118, 96, 91, 143, 228, 174,
1455            185, 162, 134, 50, 199, 153, 92, 243, 186, 131, 29, 151, 99, 133, 0, 0, 0, 6, 161, 104,
1456            99, 114, 101, 100, 66, 108, 111, 98, 64,
1457        ];
1458
1459        assert!(AuthenticatorData::<Authentication>::try_from(raw.as_slice()).is_ok());
1460    }
1461
1462    #[test]
1463    fn migrate_credentialv3() {
1464        let legacy_cred = r#"{"cred_id":[185,151,21,12,21,82,235,193,63,50,208,32,121,10,68,148,156,101,116,95,250,113,143,108,74,246,214,171,31,234,70,31,48,138,238,54,151,36,65,70,104,121,200,87,131,254,191,100,215,125,29,49,177,71,4,114,61,69,49,96,116,148,8,205],"cred":{"type_":"ES256","key":{"EC_EC2":{"curve":"SECP256R1","x":[194,126,127,109,252,23,131,21,252,6,223,99,44,254,140,27,230,17,94,5,133,28,104,41,144,69,171,149,161,26,200,243],"y":[143,123,183,156,24,178,21,248,117,159,162,69,171,52,188,252,26,59,6,47,103,92,19,58,117,103,249,0,219,8,95,196]}}},"counter":2,"verified":false,"registration_policy":"preferred"}"#;
1465
1466        let cred: CredentialV3 = serde_json::from_str(legacy_cred).unwrap();
1467
1468        println!("{cred:?}");
1469
1470        let cred_migrated: Credential = cred.into();
1471
1472        println!("{cred_migrated:?}");
1473    }
1474}