webauthn_rs_core/
interface.rs

1//! Extended Structs and representations for Webauthn Operations. These types are designed
2//! to allow persistence and should not change.
3
4use crate::attestation::verify_attestation_ca_chain;
5use crate::error::*;
6pub use crate::internals::AttestationObject;
7use std::fmt;
8use webauthn_rs_proto::cose::*;
9use webauthn_rs_proto::extensions::*;
10use webauthn_rs_proto::options::*;
11
12pub use webauthn_attestation_ca::*;
13
14use base64urlsafedata::HumanBinaryData;
15
16use serde::de::DeserializeOwned;
17use serde::{Deserialize, Serialize};
18use std::collections::BTreeMap;
19
20use openssl::{bn, ec, nid, pkey, x509};
21use uuid::Uuid;
22
23/// Representation of an AAGUID
24/// <https://www.w3.org/TR/webauthn/#aaguid>
25pub type Aaguid = [u8; 16];
26
27/// Representation of a credentials activation counter.
28pub type Counter = u32;
29
30/// The in progress state of a credential registration attempt. You must persist this in a server
31/// side location associated to the active session requesting the registration. This contains the
32/// user unique id which you can use to reference the user requesting the registration.
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct RegistrationState {
35    pub(crate) policy: UserVerificationPolicy,
36    pub(crate) exclude_credentials: Vec<CredentialID>,
37    pub(crate) challenge: HumanBinaryData,
38    pub(crate) credential_algorithms: Vec<COSEAlgorithm>,
39    pub(crate) require_resident_key: bool,
40    pub(crate) authenticator_attachment: Option<AuthenticatorAttachment>,
41    pub(crate) extensions: RequestRegistrationExtensions,
42    pub(crate) allow_synchronised_authenticators: bool,
43}
44
45/// The in progress state of an authentication attempt. You must persist this associated to the UserID
46/// requesting the registration.
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct AuthenticationState {
49    pub(crate) credentials: Vec<Credential>,
50    pub(crate) policy: UserVerificationPolicy,
51    pub(crate) challenge: HumanBinaryData,
52    pub(crate) appid: Option<String>,
53    pub(crate) allow_backup_eligible_upgrade: bool,
54}
55
56impl AuthenticationState {
57    /// set which credentials the user is allowed to authenticate with. This
58    /// is used as part of resident key authentication flows where we need
59    /// to inject the set of viable credentials after the client has sent us
60    /// their public key credential and we identify the user.
61    pub fn set_allowed_credentials(&mut self, credentials: Vec<Credential>) {
62        self.credentials = credentials;
63    }
64}
65
66/// An EDDSACurve identifier. You probably will never need to alter
67/// or use this value, as it is set inside the Credential for you.
68#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
69pub enum EDDSACurve {
70    // +---------+-------+----------+------------------------------------+
71    // | Name    | Value | Key Type | Description                        |
72    // +---------+-------+----------+------------------------------------+
73    // | X25519  | 4     | OKP      | X25519 for use w/ ECDH only        |
74    // | X448    | 5     | OKP      | X448 for use w/ ECDH only          |
75    // | Ed25519 | 6     | OKP      | Ed25519 for use w/ EdDSA only      |
76    // | Ed448   | 7     | OKP      | Ed448 for use w/ EdDSA only        |
77    // +---------+-------+----------+------------------------------------+
78    // /// Identifies this curve as X25519 ECDH only
79    // X25519 = 4,
80    // /// Identifies this curve as X448 ECDH only
81    // X448 = 5,
82    /// Identifies this OKP as ED25519
83    ED25519 = 6,
84    /// Identifies this OKP as ED448
85    ED448 = 7,
86}
87
88impl EDDSACurve {
89    /// Returns the size in bytes of the coordinate for the specified curve
90    pub(crate) fn coordinate_size(&self) -> usize {
91        match self {
92            Self::ED25519 => 32,
93            Self::ED448 => 57,
94        }
95    }
96}
97
98/// An ECDSACurve identifier. You probably will never need to alter
99/// or use this value, as it is set inside the Credential for you.
100#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
101pub enum ECDSACurve {
102    // +---------+-------+----------+------------------------------------+
103    // | Name    | Value | Key Type | Description                        |
104    // +---------+-------+----------+------------------------------------+
105    // | P-256   | 1     | EC2      | NIST P-256 also known as secp256r1 |
106    // | P-384   | 2     | EC2      | NIST P-384 also known as secp384r1 |
107    // | P-521   | 3     | EC2      | NIST P-521 also known as secp521r1 |
108    // +---------+-------+----------+------------------------------------+
109    /// Identifies this curve as SECP256R1 (X9_62_PRIME256V1 in OpenSSL)
110    SECP256R1 = 1,
111    /// Identifies this curve as SECP384R1
112    SECP384R1 = 2,
113    /// Identifies this curve as SECP521R1
114    SECP521R1 = 3,
115}
116
117impl ECDSACurve {
118    /// Returns the size in bytes of the coordinate components (x and y) for the specified curve
119    pub(crate) fn coordinate_size(&self) -> usize {
120        match self {
121            Self::SECP256R1 => 32,
122            Self::SECP384R1 => 48,
123            Self::SECP521R1 => 66,
124        }
125    }
126}
127
128impl From<&ECDSACurve> for nid::Nid {
129    fn from(c: &ECDSACurve) -> Self {
130        use ECDSACurve::*;
131        match c {
132            SECP256R1 => nid::Nid::X9_62_PRIME256V1,
133            SECP384R1 => nid::Nid::SECP384R1,
134            SECP521R1 => nid::Nid::SECP521R1,
135        }
136    }
137}
138
139/// A COSE Elliptic Curve Public Key. This is generally the provided credential
140/// that an authenticator registers, and is used to authenticate the user.
141/// You will likely never need to interact with this value, as it is part of the Credential
142/// API.
143#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
144pub struct COSEEC2Key {
145    /// The curve that this key references.
146    pub curve: ECDSACurve,
147    /// The key's public X coordinate.
148    pub x: HumanBinaryData,
149    /// The key's public Y coordinate.
150    pub y: HumanBinaryData,
151}
152
153impl TryFrom<&COSEEC2Key> for ec::EcKey<pkey::Public> {
154    type Error = openssl::error::ErrorStack;
155
156    fn try_from(k: &COSEEC2Key) -> Result<Self, Self::Error> {
157        let group = ec::EcGroup::from_curve_name((&k.curve).into())?;
158        let mut ctx = bn::BigNumContext::new()?;
159        let mut point = ec::EcPoint::new(&group)?;
160        let x = bn::BigNum::from_slice(k.x.as_slice())?;
161        let y = bn::BigNum::from_slice(k.y.as_slice())?;
162        point.set_affine_coordinates_gfp(&group, &x, &y, &mut ctx)?;
163
164        ec::EcKey::from_public_key(&group, &point)
165    }
166}
167
168/// A COSE Elliptic Curve Public Key. This is generally the provided credential
169/// that an authenticator registers, and is used to authenticate the user.
170/// You will likely never need to interact with this value, as it is part of the Credential
171/// API.
172#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
173pub struct COSEOKPKey {
174    /// The curve that this key references.
175    pub curve: EDDSACurve,
176    /// The key's public X coordinate.
177    pub x: HumanBinaryData,
178}
179
180/// A COSE RSA PublicKey. This is a provided credential from a registered
181/// authenticator.
182/// You will likely never need to interact with this value, as it is part of the Credential
183/// API.
184#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
185pub struct COSERSAKey {
186    /// An RSA modulus
187    pub n: HumanBinaryData,
188    /// An RSA exponent
189    pub e: [u8; 3],
190}
191
192/// The type of Key contained within a COSE value. You should never need
193/// to alter or change this type.
194#[allow(non_camel_case_types)]
195#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
196pub enum COSEKeyType {
197    //    +-----------+-------+-----------------------------------------------+
198    //    | Name      | Value | Description                                   |
199    //    +-----------+-------+-----------------------------------------------+
200    //    | OKP       | 1     | Octet Key Pair                                |
201    //    | EC2       | 2     | Elliptic Curve Keys w/ x- and y-coordinate    |
202    //    |           |       | pair                                          |
203    //    | Symmetric | 4     | Symmetric Keys                                |
204    //    | Reserved  | 0     | This value is reserved                        |
205    //    +-----------+-------+-----------------------------------------------+
206    /// Identifies this as an Elliptic Curve octet key pair
207    EC_OKP(COSEOKPKey),
208    /// Identifies this as an Elliptic Curve EC2 key
209    EC_EC2(COSEEC2Key),
210    // EC_Symmetric,
211    // EC_Reserved, // should always be invalid.
212    /// Identifies this as an RSA key
213    RSA(COSERSAKey),
214}
215
216/// The numeric if of the COSEKeyType used in the CBOR fields.
217#[allow(non_camel_case_types)]
218#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
219#[repr(i64)]
220pub enum COSEKeyTypeId {
221    /// Reserved
222    EC_Reserved = 0,
223    /// Octet Key Pair
224    EC_OKP = 1,
225    /// Elliptic Curve Keys w/ x- and y-coordinate
226    EC_EC2 = 2,
227    /// RSA
228    EC_RSA = 3,
229    /// Symmetric
230    EC_Symmetric = 4,
231}
232
233/// A COSE Key as provided by the Authenticator. You should never need
234/// to alter or change these values.
235#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
236pub struct COSEKey {
237    /// The type of key that this contains
238    pub type_: COSEAlgorithm,
239    /// The public key
240    pub key: COSEKeyType,
241}
242
243/// The ID of this Credential
244pub type CredentialID = HumanBinaryData;
245
246/// The current latest Credential Format
247pub type Credential = CredentialV5;
248
249/// A user's authenticator credential. It contains an id, the public key
250/// and a counter of how many times the authenticator has been used.
251#[derive(Clone, Debug, Serialize, Deserialize)]
252pub struct CredentialV5 {
253    /// The ID of this credential.
254    pub cred_id: CredentialID,
255    /// The public key of this credential
256    pub cred: COSEKey,
257    /// The counter for this credential
258    pub counter: Counter,
259    /// The set of transports this credential indicated it could use. This is NOT
260    /// a security property, but a hint for the browser and the user experience to
261    /// how to communicate to this specific device.
262    pub transports: Option<Vec<AuthenticatorTransport>>,
263    /// During registration, if this credential was verified
264    /// then this is true. If not it is false. This is based on
265    /// the policy at the time of registration of the credential.
266    ///
267    /// This is a deviation from the Webauthn specification, because
268    /// it clarifies the user experience of the credentials to UV
269    /// being a per-credential attribute, rather than a per-authentication
270    /// ceremony attribute. For example it can be surprising to register
271    /// a credential as un-verified but then to use verification with it
272    /// in the future.
273    pub user_verified: bool,
274    /// During registration, this credential indicated that it *may* be possible
275    /// for it to exist between multiple hardware authenticators, or be backed up.
276    ///
277    /// This means the private key is NOT sealed within a hardware cryptograhic
278    /// processor, and may have impacts on your risk assessments and modeling.
279    pub backup_eligible: bool,
280    /// This credential has indicated that it is currently backed up OR that it
281    /// is shared between multiple devices.
282    pub backup_state: bool,
283    /// During registration, the policy that was requested from this
284    /// credential. This is used to understand if the how the verified
285    /// component interacts with the device, i.e. an always verified authenticator
286    /// vs one that can dynamically request it.
287    pub registration_policy: UserVerificationPolicy,
288    /// The set of extensions that were verified at registration, that can
289    /// be used in future authentication attempts
290    pub extensions: RegisteredExtensions,
291    /// The attestation certificate of this credential, including parsed metadata from the
292    /// credential.
293    pub attestation: ParsedAttestation,
294    /// the format of the attestation
295    pub attestation_format: AttestationFormat,
296}
297
298impl Credential {
299    /// Re-verify this Credential's attestation chain. This re-applies the same process
300    /// for certificate authority verification that occurred at registration. This can
301    /// be useful if you want to re-assert your credentials match an updated or changed
302    /// ca_list from the time that registration occurred. This can also be useful to
303    /// re-determine certain properties of your device that may exist.
304    pub fn verify_attestation<'a>(
305        &'_ self,
306        ca_list: &'a AttestationCaList,
307    ) -> Result<Option<&'a AttestationCa>, WebauthnError> {
308        // Formerly we disabled this due to apple, but they no longer provide
309        // meaningful attestation so we can re-enable it.
310        let danger_disable_certificate_time_checks = false;
311        verify_attestation_ca_chain(
312            &self.attestation.data,
313            ca_list,
314            danger_disable_certificate_time_checks,
315        )
316    }
317}
318
319impl From<CredentialV3> for Credential {
320    fn from(other: CredentialV3) -> Credential {
321        let CredentialV3 {
322            cred_id,
323            cred,
324            counter,
325            verified,
326            registration_policy,
327        } = other;
328
329        // prior to 20220520 no multi-device credentials existed to migrate from.
330        Credential {
331            cred_id: HumanBinaryData::from(cred_id),
332            cred,
333            counter,
334            transports: None,
335            user_verified: verified,
336            backup_eligible: false,
337            backup_state: false,
338            registration_policy,
339            extensions: RegisteredExtensions::none(),
340            attestation: ParsedAttestation {
341                data: ParsedAttestationData::None,
342                metadata: AttestationMetadata::None,
343            },
344            attestation_format: AttestationFormat::None,
345        }
346    }
347}
348
349/// A legacy serialisation from version 3 of Webauthn RS. Only useful for migrations.
350#[derive(Clone, Debug, Serialize, Deserialize)]
351pub struct CredentialV3 {
352    /// The ID of this credential.
353    pub cred_id: Vec<u8>,
354    /// The public key of this credential
355    pub cred: COSEKey,
356    /// The counter for this credential
357    pub counter: u32,
358    /// During registration, if this credential was verified
359    /// then this is true. If not it is false. This is based on
360    /// the policy at the time of registration of the credential.
361    ///
362    /// This is a deviation from the Webauthn specification, because
363    /// it clarifies the user experience of the credentials to UV
364    /// being a per-credential attribute, rather than a per-authentication
365    /// ceremony attribute. For example it can be surprising to register
366    /// a credential as un-verified but then to use verification with it
367    /// in the future.
368    pub verified: bool,
369    /// During registration, the policy that was requested from this
370    /// credential. This is used to understand if the how the verified
371    /// component interacts with the device, IE an always verified authenticator
372    /// vs one that can dynamically request it.
373    pub registration_policy: UserVerificationPolicy,
374}
375
376/// Serialised Attestation Data which can be stored in a stable database or similar.
377#[derive(Clone, Serialize, Deserialize)]
378pub enum SerialisableAttestationData {
379    /// See [ParsedAttestationData::Basic]
380    Basic(Vec<HumanBinaryData>),
381    /// See [ParsedAttestationData::Self_]
382    Self_,
383    /// See [ParsedAttestationData::AttCa]
384    AttCa(Vec<HumanBinaryData>),
385    /// See [ParsedAttestationData::AnonCa]
386    AnonCa(Vec<HumanBinaryData>),
387    /// See [ParsedAttestationData::ECDAA]
388    ECDAA,
389    /// See [ParsedAttestationData::None]
390    None,
391    /// See [ParsedAttestationData::Uncertain]
392    Uncertain,
393}
394
395impl fmt::Debug for SerialisableAttestationData {
396    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
397        match self {
398            SerialisableAttestationData::Basic(_) => {
399                write!(f, "SerialisableAttestationData::Basic")
400            }
401            SerialisableAttestationData::Self_ => write!(f, "SerialisableAttestationData::Self_"),
402            SerialisableAttestationData::AttCa(_) => {
403                write!(f, "SerialisableAttestationData::AttCa")
404            }
405            SerialisableAttestationData::AnonCa(_) => {
406                write!(f, "SerialisableAttestationData::AnonCa")
407            }
408            SerialisableAttestationData::ECDAA => write!(f, "SerialisableAttestationData::ECDAA"),
409            SerialisableAttestationData::None => write!(f, "SerialisableAttestationData::None"),
410            SerialisableAttestationData::Uncertain => {
411                write!(f, "SerialisableAttestationData::Uncertain")
412            }
413        }
414    }
415}
416
417/// The processed attestation and its metadata
418#[derive(Debug, Clone, Serialize, Deserialize)]
419pub struct ParsedAttestation {
420    /// the attestation chain data
421    pub data: ParsedAttestationData,
422    /// possible metadata (i.e. flags set) about the attestation
423    pub metadata: AttestationMetadata,
424}
425
426impl Default for ParsedAttestation {
427    fn default() -> Self {
428        ParsedAttestation {
429            data: ParsedAttestationData::None,
430            metadata: AttestationMetadata::None,
431        }
432    }
433}
434
435/// The processed Attestation that the Authenticator is providing in its AttestedCredentialData. This
436/// metadata may allow identification of the device and its specific properties.
437#[derive(Debug, Clone, Serialize, Deserialize)]
438pub enum AttestationMetadata {
439    /// no metadata available for this device.
440    None,
441    /// This is commonly found on Fido Authenticators.
442    Packed {
443        /// This is the unique id of the class/type of device. Often this id can imply the
444        /// properties of the device.
445        aaguid: Uuid,
446    },
447    /// This is found on TPM authenticators.
448    Tpm {
449        /// This is the unique id of the class/type of device. Often this id can imply the
450        /// properties of the device.
451        aaguid: Uuid,
452        /// The firmware version of the device at registration. It can NOT be determined
453        /// if this updates later, which may require you to re-register the device if
454        /// you need to enforce a version update.
455        firmware_version: u64,
456    },
457    /// various attestation flags set by the device (attested by OS)
458    AndroidKey {
459        /// is the key master running in a Trusted Execution Environment
460        is_km_tee: bool,
461        /// did the attestation come from a Trusted Execution Environment
462        is_attest_tee: bool,
463    },
464    /// various attestation flags set by the device (attested via safety-net)
465    /// <https://developer.android.com/training/safetynet/attestation#use-response-server>
466    AndroidSafetyNet {
467        /// the name of apk that originated this key operation
468        apk_package_name: String,
469        /// cert chain for this apk
470        apk_certificate_digest_sha256: Vec<HumanBinaryData>,
471        /// A stricter verdict of device integrity. If the value of ctsProfileMatch is true, then the profile of the device running your app matches the profile of a device that has passed Android compatibility testing and has been approved as a Google-certified Android device.
472        cts_profile_match: bool,
473        /// A more lenient verdict of device integrity. If only the value of basicIntegrity is true, then the device running your app likely wasn't tampered with. However, the device hasn't necessarily passed Android compatibility testing.
474        basic_integrity: bool,
475        /// Types of measurements that contributed to the current API response
476        evaluation_type: Option<String>,
477    },
478}
479
480/// The processed Attestation that the Authenticator is providing in its AttestedCredentialData
481#[derive(Debug, Clone, Serialize, Deserialize)]
482#[serde(
483    try_from = "SerialisableAttestationData",
484    into = "SerialisableAttestationData"
485)]
486pub enum ParsedAttestationData {
487    /// The credential is authenticated by a signing X509 Certificate
488    /// from a vendor or provider.
489    Basic(Vec<x509::X509>),
490    /// The credential is authenticated using surrogate basic attestation
491    /// it uses the credential private key to create the attestation signature
492    Self_,
493    /// The credential is authenticated using a CA, and may provide a
494    /// ca chain to validate to its root.
495    AttCa(Vec<x509::X509>),
496    /// The credential is authenticated using an anonymization CA, and may provide a ca chain to
497    /// validate to its root.
498    AnonCa(Vec<x509::X509>),
499    /// Unimplemented
500    ECDAA,
501    /// No Attestation type was provided with this Credential. If in doubt
502    /// reject this Credential.
503    None,
504    /// Uncertain Attestation was provided with this Credential, which may not
505    /// be trustworthy in all cases. If in doubt, reject this type.
506    Uncertain,
507}
508
509#[allow(clippy::from_over_into)]
510impl Into<SerialisableAttestationData> for ParsedAttestationData {
511    fn into(self) -> SerialisableAttestationData {
512        match self {
513            ParsedAttestationData::Basic(chain) => SerialisableAttestationData::Basic(
514                chain
515                    .into_iter()
516                    .map(|c| HumanBinaryData::from(c.to_der().expect("Invalid DER")))
517                    .collect(),
518            ),
519            ParsedAttestationData::Self_ => SerialisableAttestationData::Self_,
520            ParsedAttestationData::AttCa(chain) => SerialisableAttestationData::AttCa(
521                // HumanBinaryData::from(c.to_der().expect("Invalid DER")),
522                chain
523                    .into_iter()
524                    .map(|c| HumanBinaryData::from(c.to_der().expect("Invalid DER")))
525                    .collect(),
526            ),
527            ParsedAttestationData::AnonCa(chain) => SerialisableAttestationData::AnonCa(
528                // HumanBinaryData::from(c.to_der().expect("Invalid DER")),
529                chain
530                    .into_iter()
531                    .map(|c| HumanBinaryData::from(c.to_der().expect("Invalid DER")))
532                    .collect(),
533            ),
534            ParsedAttestationData::ECDAA => SerialisableAttestationData::ECDAA,
535            ParsedAttestationData::None => SerialisableAttestationData::None,
536            ParsedAttestationData::Uncertain => SerialisableAttestationData::Uncertain,
537        }
538    }
539}
540
541impl TryFrom<SerialisableAttestationData> for ParsedAttestationData {
542    type Error = WebauthnError;
543
544    fn try_from(data: SerialisableAttestationData) -> Result<Self, Self::Error> {
545        Ok(match data {
546            SerialisableAttestationData::Basic(chain) => ParsedAttestationData::Basic(
547                chain
548                    .into_iter()
549                    .map(|c| {
550                        x509::X509::from_der(c.as_slice()).map_err(WebauthnError::OpenSSLError)
551                    })
552                    .collect::<WebauthnResult<_>>()?,
553            ),
554            SerialisableAttestationData::Self_ => ParsedAttestationData::Self_,
555            SerialisableAttestationData::AttCa(chain) => ParsedAttestationData::AttCa(
556                // x509::X509::from_der(&c.0).map_err(WebauthnError::OpenSSLError)?,
557                chain
558                    .into_iter()
559                    .map(|c| {
560                        x509::X509::from_der(c.as_slice()).map_err(WebauthnError::OpenSSLError)
561                    })
562                    .collect::<WebauthnResult<_>>()?,
563            ),
564            SerialisableAttestationData::AnonCa(chain) => ParsedAttestationData::AnonCa(
565                // x509::X509::from_der(&c.0).map_err(WebauthnError::OpenSSLError)?,
566                chain
567                    .into_iter()
568                    .map(|c| {
569                        x509::X509::from_der(c.as_slice()).map_err(WebauthnError::OpenSSLError)
570                    })
571                    .collect::<WebauthnResult<_>>()?,
572            ),
573            SerialisableAttestationData::ECDAA => ParsedAttestationData::ECDAA,
574            SerialisableAttestationData::None => ParsedAttestationData::None,
575            SerialisableAttestationData::Uncertain => ParsedAttestationData::Uncertain,
576        })
577    }
578}
579
580/// Marker type parameter for data related to registration ceremony
581#[derive(Debug)]
582pub struct Registration;
583
584/// Marker type parameter for data related to authentication ceremony
585#[derive(Debug)]
586pub struct Authentication;
587
588/// Trait for ceremony marker structs
589pub trait Ceremony {
590    /// The type of the extension outputs of the ceremony
591    type SignedExtensions: DeserializeOwned + std::fmt::Debug + std::default::Default;
592}
593
594impl Ceremony for Registration {
595    type SignedExtensions = RegistrationSignedExtensions;
596}
597
598impl Ceremony for Authentication {
599    type SignedExtensions = AuthenticationSignedExtensions;
600}
601
602/// The client's response to the request that it use the `credProtect` extension
603///
604/// Implemented as wrapper struct to (de)serialize
605/// [CredentialProtectionPolicy] as a number
606#[derive(Debug, Serialize, Clone, Deserialize)]
607#[serde(try_from = "u8", into = "u8")]
608pub struct CredProtectResponse(pub CredentialProtectionPolicy);
609
610/// The output for registration ceremony extensions.
611///
612/// Implements the registration bits of \[AuthenticatorExtensionsClientOutputs\]
613/// from the spec
614#[derive(Debug, Clone, Serialize, Deserialize, Default)]
615pub struct RegistrationSignedExtensions {
616    /// The `credProtect` extension
617    #[serde(rename = "credProtect")]
618    pub cred_protect: Option<CredProtectResponse>,
619    /// The `hmac-secret` extension response to a create request
620    #[serde(rename = "hmac-secret")]
621    pub hmac_secret: Option<bool>,
622    /// Extension key-values that we have parsed, but don't strictly recognise.
623    #[serde(flatten)]
624    pub unknown_keys: BTreeMap<String, serde_cbor_2::Value>,
625}
626
627/// The output for authentication cermeony extensions.
628///
629/// Implements the authentication bits of
630/// \[AuthenticationExtensionsClientOutputs] from the spec
631#[derive(Debug, Clone, Serialize, Deserialize, Default)]
632#[serde(rename_all = "camelCase")]
633pub struct AuthenticationSignedExtensions {
634    /// Extension key-values that we have parsed, but don't strictly recognise.
635    #[serde(flatten)]
636    pub unknown_keys: BTreeMap<String, serde_cbor_2::Value>,
637}
638
639/// Attested Credential Data
640#[derive(Debug, Clone)]
641pub struct AttestedCredentialData {
642    /// The guid of the authenticator. May indicate manufacturer.
643    pub aaguid: Aaguid,
644    /// The credential ID.
645    pub credential_id: CredentialID,
646    /// The credentials public Key.
647    pub credential_pk: serde_cbor_2::Value,
648}
649
650/// Information about the authentication that occurred.
651#[derive(Debug, Serialize, Clone, Deserialize)]
652pub struct AuthenticationResult {
653    /// The credential ID that was used to authenticate.
654    pub(crate) cred_id: CredentialID,
655    /// If the credential associated needs updating
656    pub(crate) needs_update: bool,
657    /// If the authentication provided user_verification.
658    pub(crate) user_verified: bool,
659    /// The current backup state of the authenticator. It may have
660    /// changed since registration.
661    pub(crate) backup_state: bool,
662    /// The current backup eligibility of the authenticator. It may have
663    /// changed since registration in rare cases. This transition may ONLY
664    /// be false to true, never the reverse. This is common on passkeys
665    /// during some upgrades.
666    pub(crate) backup_eligible: bool,
667    /// The state of the counter
668    pub(crate) counter: Counter,
669    /// The response from associated extensions.
670    pub(crate) extensions: AuthenticationExtensions,
671}
672
673impl AuthenticationResult {
674    /// The credential ID that was used to authenticate.
675    pub fn cred_id(&self) -> &CredentialID {
676        &self.cred_id
677    }
678
679    /// If this authentication result should be applied to the associated
680    /// credential to update its properties.
681    pub fn needs_update(&self) -> bool {
682        self.needs_update
683    }
684
685    /// If the authentication provided user_verification.
686    pub fn user_verified(&self) -> bool {
687        self.user_verified
688    }
689
690    /// The current backup state of the authenticator. It may have
691    /// changed since registration.
692    pub fn backup_state(&self) -> bool {
693        self.backup_state
694    }
695
696    /// The current backup eligibility of the authenticator. It may have
697    /// changed since registration in rare cases. This transition may ONLY
698    /// be false to true, never the reverse. This is common on passkeys
699    /// during some upgrades.
700    pub fn backup_eligible(&self) -> bool {
701        self.backup_eligible
702    }
703
704    /// The state of the counter
705    pub fn counter(&self) -> Counter {
706        self.counter
707    }
708
709    /// The response from associated extensions.
710    pub fn extensions(&self) -> &AuthenticationExtensions {
711        &self.extensions
712    }
713}