webauthn_rp

WebAuthn Level 3 RP library.
git clone https://git.philomathiclife.com/repos/webauthn_rp
Log | Files | Refs | README

auth.rs (57435B)


      1 #[cfg(doc)]
      2 use super::{
      3     super::response::{
      4         Backup, CollectedClientData, Flag,
      5         auth::AuthenticatorData,
      6         register::{DynamicState, StaticState},
      7     },
      8     AsciiDomain, DomainOrigin, Url,
      9     register::{self, PublicKeyCredentialCreationOptions},
     10 };
     11 use super::{
     12     super::{
     13         AuthenticatedCredential,
     14         request::register::User,
     15         response::{
     16             AuthenticatorAttachment,
     17             auth::{
     18                 Authentication, AuthenticatorExtensionOutput, HmacSecret,
     19                 error::{AuthCeremonyErr, ExtensionErr, OneOrTwo},
     20             },
     21             register::CompressedPubKey,
     22         },
     23     },
     24     BackupReq, Ceremony, CeremonyOptions, Challenge, CredentialId, Credentials, ExtensionReq, Hint,
     25     Origin, PublicKeyCredentialDescriptor, RpId, SentChallenge, ServerState,
     26     THREE_HUNDRED_THOUSAND, UserVerificationRequirement,
     27     auth::error::{RequestOptionsErr, SecondFactorErr},
     28 };
     29 use core::{
     30     borrow::Borrow,
     31     cmp::Ordering,
     32     hash::{Hash, Hasher},
     33     num::{NonZeroU32, NonZeroU64},
     34     time::Duration,
     35 };
     36 #[cfg(any(doc, not(feature = "serializable_server_state")))]
     37 use std::time::Instant;
     38 #[cfg(any(doc, feature = "serializable_server_state"))]
     39 use std::time::SystemTime;
     40 /// Contains error types.
     41 pub mod error;
     42 /// Contains functionality to serialize data to a client.
     43 #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
     44 #[cfg(feature = "serde")]
     45 mod ser;
     46 /// Contains functionality to (de)serialize [`AuthenticationServerState`] to a data store.
     47 #[cfg_attr(docsrs, doc(cfg(feature = "serializable_server_state")))]
     48 #[cfg(feature = "serializable_server_state")]
     49 pub mod ser_server_state;
     50 /// Controls how [signature counter](https://www.w3.org/TR/webauthn-3/#signature-counter) is enforced.
     51 ///
     52 /// Note that if the previous signature counter is positive and the new counter is not strictly greater, then the
     53 /// authenticator is likely a clone (i.e., there are at least two copies of the private key).
     54 #[derive(Clone, Copy, Debug, Default)]
     55 pub enum SignatureCounterEnforcement {
     56     /// Fail the authentication ceremony if the counter is less than or equal to the previous value when the
     57     /// previous value is positive.
     58     #[default]
     59     Fail,
     60     /// When the counter is less than the previous value, don't fail and update the value.
     61     ///
     62     /// Note in the special case that the new signature counter is 0, [`DynamicState::sign_count`] _won't_
     63     /// be updated since that would allow an attacker to permanently disable the counter.
     64     Update,
     65     /// When the counter is less than the previous value, don't fail but don't update the value.
     66     Ignore,
     67 }
     68 impl SignatureCounterEnforcement {
     69     /// Validates the signature counter based on `self`.
     70     const fn validate(self, prev: u32, cur: u32) -> Result<u32, AuthCeremonyErr> {
     71         if prev == 0 || cur > prev {
     72             Ok(cur)
     73         } else {
     74             match self {
     75                 Self::Fail => Err(AuthCeremonyErr::SignatureCounter),
     76                 // When the new counter is `0`, we use the previous counter to avoid an attacker from
     77                 // being able to permanently disable it.
     78                 Self::Update => Ok(if cur == 0 { prev } else { cur }),
     79                 Self::Ignore => Ok(prev),
     80             }
     81         }
     82     }
     83 }
     84 /// [`AuthenticationExtensionsPRFValues`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsprfvalues).
     85 ///
     86 /// This is only applicable if
     87 /// [`hmac-secret`](https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html#sctn-hmac-secret-extension)
     88 /// is `true` when registering a new credential with [`register::Extension::prf`] and
     89 /// [`PublicKeyCredentialRequestOptions::user_verification`] is [`UserVerificationRequirement::Required`].
     90 ///
     91 /// Unlike the spec, it is forbidden for
     92 /// [the decrypted outputs](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsprfoutputs) to be
     93 /// passed back in an effort to ensure sensitive data remains client-side. This means
     94 /// [`prf`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsprfoutputs) must not exist,
     95 /// be `null`, or be an
     96 /// [`AuthenticationExtensionsPRFOutputs`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsprfoutputs)
     97 /// such that [`results`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfoutputs-results) does not exist,
     98 /// is `null`, or is an
     99 /// [`AuthenticationExtensionsPRFValues`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsprfvalues) such
    100 /// that [`first`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfvalues-first) is `null` and
    101 /// [`second`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfvalues-second) does not exist or is `null`.
    102 ///
    103 /// For the owned analog, see [`PrfInputOwned`].
    104 ///
    105 /// When relying on discoverable requests
    106 /// (i.e., [`PublicKeyCredentialRequestOptions::allow_credentials`] is empty),
    107 /// one will likely use a static PRF input for _all_ credentials since rolling over PRF inputs
    108 /// is not feasible. One uses this type for such a thing. In other words, `'a` will likely
    109 /// be `'static` and [`Self::second`] will likely be `None`.
    110 #[derive(Clone, Copy, Debug)]
    111 pub struct PrfInput<'a> {
    112     /// [`first`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfvalues-first).
    113     pub first: &'a [u8],
    114     /// [`second`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfvalues-second).
    115     pub second: Option<&'a [u8]>,
    116     /// Response requirements.
    117     pub ext_info: ExtensionReq,
    118 }
    119 /// Owned version of [`PrfInput`].
    120 ///
    121 /// When relying on non-discoverable requests
    122 /// (i.e., [`PublicKeyCredentialRequestOptions::allow_credentials`] is non-empty),
    123 /// it's recommended to use credential-specific PRF inputs that are continuously rolled over.
    124 /// One uses this type for such a thing.
    125 #[derive(Debug)]
    126 pub struct PrfInputOwned {
    127     /// [`first`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfvalues-first).
    128     pub first: Vec<u8>,
    129     /// [`second`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfvalues-second).
    130     pub second: Option<Vec<u8>>,
    131     /// Response requirements.
    132     pub ext_info: ExtensionReq,
    133 }
    134 /// The [defined extensions](https://www.w3.org/TR/webauthn-3/#sctn-defined-extensions) to send to the client.
    135 #[derive(Clone, Copy, Debug, Default)]
    136 pub struct Extension<'prf> {
    137     /// [`prf`](https://www.w3.org/TR/webauthn-3/#prf-extension).
    138     ///
    139     /// If both [`CredentialSpecificExtension::prf`] and this are [`Some`], then `CredentialSpecificExtension::prf`
    140     /// takes priority.
    141     pub prf: Option<PrfInput<'prf>>,
    142 }
    143 /// The [defined extensions](https://www.w3.org/TR/webauthn-3/#sctn-defined-extensions) to send to the client that
    144 /// are credential-specific which among other things implies a non-discoverable request.
    145 #[derive(Debug, Default)]
    146 pub struct CredentialSpecificExtension {
    147     /// [`prf`](https://www.w3.org/TR/webauthn-3/#prf-extension).
    148     ///
    149     /// If both [`Extension::prf`] and this are [`Some`], then this take priority.
    150     pub prf: Option<PrfInputOwned>,
    151 }
    152 /// Registered credential used in
    153 /// [`allowCredentials`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialrequestoptions-allowcredentials).
    154 #[derive(Debug)]
    155 pub struct AllowedCredential {
    156     /// The registered credential.
    157     pub credential: PublicKeyCredentialDescriptor<Vec<u8>>,
    158     /// Credential-specific extensions.
    159     pub extension: CredentialSpecificExtension,
    160 }
    161 impl From<PublicKeyCredentialDescriptor<Vec<u8>>> for AllowedCredential {
    162     #[inline]
    163     fn from(credential: PublicKeyCredentialDescriptor<Vec<u8>>) -> Self {
    164         Self {
    165             credential,
    166             extension: CredentialSpecificExtension::default(),
    167         }
    168     }
    169 }
    170 /// Queue of unique [`AllowedCredential`]s.
    171 #[derive(Debug, Default)]
    172 pub struct AllowedCredentials {
    173     /// Allowed credentials.
    174     creds: Vec<AllowedCredential>,
    175     /// Number of `AllowedCredential`s that have PRF inputs.
    176     ///
    177     /// Useful to help serialization.
    178     prf_count: usize,
    179 }
    180 impl Credentials for AllowedCredentials {
    181     type Credential = AllowedCredential;
    182     /// # Examples
    183     ///
    184     /// ```
    185     /// # use webauthn_rp::request::{auth::AllowedCredentials, Credentials};
    186     /// assert!(AllowedCredentials::with_capacity(1).as_ref().is_empty());
    187     /// ```
    188     #[inline]
    189     fn with_capacity(capacity: usize) -> Self {
    190         Self {
    191             creds: Vec::with_capacity(capacity),
    192             prf_count: 0,
    193         }
    194     }
    195     /// # Examples
    196     ///
    197     /// ```
    198     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    199     /// # use webauthn_rp::{bin::Decode, response::bin::DecodeAuthTransportsErr};
    200     /// # use webauthn_rp::{
    201     /// #     request::{auth::AllowedCredentials, PublicKeyCredentialDescriptor, Credentials},
    202     /// #     response::{AuthTransports, CredentialId},
    203     /// # };
    204     /// /// Retrieves the `AuthTransports` associated with the unique `cred_id`
    205     /// /// from the database.
    206     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    207     /// fn get_transports(cred_id: CredentialId<&[u8]>) -> Result<AuthTransports, DecodeAuthTransportsErr> {
    208     ///     // ⋮
    209     /// #     AuthTransports::decode(32)
    210     /// }
    211     /// let mut creds = AllowedCredentials::with_capacity(1);
    212     /// assert!(creds.as_ref().is_empty());
    213     /// // `CredentialId::try_from` only exists when `custom` is enabled; and even then, it is
    214     /// // likely never needed since the `CredentialId` was originally sent from the client and is likely
    215     /// // stored in a database which would be fetched by `UserHandle` or `Authentication::raw_id`.
    216     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    217     /// let id = CredentialId::try_from(vec![0; 16])?;
    218     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    219     /// let transports = get_transports((&id).into())?;
    220     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    221     /// assert!(creds.push(PublicKeyCredentialDescriptor { id, transports }.into()));
    222     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    223     /// let id_copy = CredentialId::try_from(vec![0; 16])?;
    224     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    225     /// let transports_2 = AuthTransports::NONE;
    226     /// // Duplicate `CredentialId`s don't get added.
    227     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    228     /// assert!(!creds.push(
    229     ///     PublicKeyCredentialDescriptor {
    230     ///         id: id_copy,
    231     ///         transports: transports_2
    232     ///     }
    233     ///     .into()
    234     /// ));
    235     /// # Ok::<_, webauthn_rp::AggErr>(())
    236     /// ```
    237     #[expect(
    238         clippy::arithmetic_side_effects,
    239         reason = "comment explains how overflow is not possible"
    240     )]
    241     #[inline]
    242     fn push(&mut self, cred: Self::Credential) -> bool {
    243         self.creds
    244             .iter()
    245             .try_fold((), |(), c| {
    246                 if c.credential.id == cred.credential.id {
    247                     Err(())
    248                 } else {
    249                     Ok(())
    250                 }
    251             })
    252             .is_ok_and(|()| {
    253                 // This can't overflow since `self.creds.push` would `panic` since
    254                 // `self.prf_count <= self.creds.len()`.
    255                 self.prf_count += usize::from(cred.extension.prf.is_some());
    256                 self.creds.push(cred);
    257                 true
    258             })
    259     }
    260     #[inline]
    261     fn len(&self) -> usize {
    262         self.creds.len()
    263     }
    264 }
    265 impl AsRef<[AllowedCredential]> for AllowedCredentials {
    266     #[inline]
    267     fn as_ref(&self) -> &[AllowedCredential] {
    268         self.creds.as_slice()
    269     }
    270 }
    271 impl From<&AllowedCredentials> for Vec<CredInfo> {
    272     #[inline]
    273     fn from(value: &AllowedCredentials) -> Self {
    274         let len = value.creds.len();
    275         value
    276             .creds
    277             .iter()
    278             .fold(Self::with_capacity(len), |mut creds, cred| {
    279                 creds.push(CredInfo {
    280                     id: cred.credential.id.clone(),
    281                     ext: (&cred.extension).into(),
    282                 });
    283                 creds
    284             })
    285     }
    286 }
    287 /// Helper that verifies the overlap of [`PublicKeyCredentialRequestOptions::start_ceremony`] and
    288 /// [`AuthenticationServerState::decode`].
    289 fn validate_options_helper(
    290     ext: ServerExtensionInfo,
    291     uv: UserVerificationRequirement,
    292     creds: &[CredInfo],
    293 ) -> Result<(), RequestOptionsErr> {
    294     // If PRF is set, the user has to verify themselves.
    295     ext.prf
    296         .as_ref()
    297         .map_or(Ok(()), |_| {
    298             if matches!(uv, UserVerificationRequirement::Required) {
    299                 Ok(())
    300             } else {
    301                 Err(RequestOptionsErr::PrfWithoutUserVerification)
    302             }
    303         })
    304         .and_then(|()| {
    305             creds.iter().try_fold((), |(), cred| {
    306                 // If PRF is set, the user has to verify themselves.
    307                 cred.ext.prf.as_ref().map_or(Ok(()), |_| {
    308                     if matches!(uv, UserVerificationRequirement::Required) {
    309                         Ok(())
    310                     } else {
    311                         Err(RequestOptionsErr::PrfWithoutUserVerification)
    312                     }
    313                 })
    314             })
    315         })
    316 }
    317 /// The [`PublicKeyCredentialRequestOptions`](https://www.w3.org/TR/webauthn-3/#dictdef-publickeycredentialrequestoptions)
    318 /// to send to the client when authenticating a credential.
    319 ///
    320 /// Upon saving the [`AuthenticationServerState`] returned from [`Self::start_ceremony`], one MUST send
    321 /// [`AuthenticationClientState`] to the client ASAP. After receiving the newly created [`Authentication`], it
    322 /// is validated using [`AuthenticationServerState::verify`].
    323 #[derive(Debug)]
    324 pub struct PublicKeyCredentialRequestOptions<'rp_id, 'prf> {
    325     /// [`challenge`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialrequestoptions-challenge).
    326     pub challenge: Challenge,
    327     /// [`timeout`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialrequestoptions-timeout).
    328     ///
    329     /// Note we require a positive value despite the spec allowing an optional nonnegative value. This jives
    330     /// with the fact that in-memory storage is required when `serializable_server_state` is not enabled
    331     /// when authenticating credentials as no timeout would make out-of-memory (OOM) conditions more likely.
    332     pub timeout: NonZeroU32,
    333     /// [`rpId`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialrequestoptions-rpid).
    334     ///
    335     /// This MUST be the same as the [`PublicKeyCredentialCreationOptions::rp_id`] used when the credential was registered.
    336     pub rp_id: &'rp_id RpId,
    337     /// [`allowCredentials`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialrequestoptions-allowcredentials).
    338     pub allow_credentials: AllowedCredentials,
    339     /// [`userVerification`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialrequestoptions-userverification).
    340     pub user_verification: UserVerificationRequirement,
    341     /// [`hints`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialrequestoptions-hints).
    342     pub hints: Hint,
    343     /// [`extensions`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialrequestoptions-extensions).
    344     pub extensions: Extension<'prf>,
    345 }
    346 impl<'rp_id, 'prf> PublicKeyCredentialRequestOptions<'rp_id, 'prf> {
    347     /// Creates a `PublicKeyCredentialRequestOptions` with [`Self::user_verification`] set to
    348     /// [`UserVerificationRequirement::Required`] and [`Self::timeout`] set to 5 minutes,
    349     ///
    350     /// Note `rp_id` _must_ be the same as the [`PublicKeyCredentialCreationOptions::rp_id`] when the
    351     /// credential was registered.
    352     ///
    353     /// # Examples
    354     ///
    355     /// ```
    356     /// # use webauthn_rp::request::{auth::PublicKeyCredentialRequestOptions, AsciiDomain, RpId, UserVerificationRequirement};
    357     /// assert!(matches!(
    358     ///     PublicKeyCredentialRequestOptions::passkey(&RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?)).user_verification,
    359     ///     UserVerificationRequirement::Required
    360     /// ));
    361     /// # Ok::<_, webauthn_rp::AggErr>(())
    362     /// ```
    363     #[inline]
    364     #[must_use]
    365     pub fn passkey<'a: 'rp_id>(rp_id: &'a RpId) -> Self {
    366         Self {
    367             challenge: Challenge::new(),
    368             timeout: THREE_HUNDRED_THOUSAND,
    369             rp_id,
    370             allow_credentials: AllowedCredentials::new(),
    371             user_verification: UserVerificationRequirement::Required,
    372             hints: Hint::None,
    373             extensions: Extension::default(),
    374         }
    375     }
    376     /// Creates a `PublicKeyCredentialRequestOptions` with [`Self::user_verification`] set to
    377     /// [`UserVerificationRequirement::Discouraged`] and [`Self::timeout`] set to 5 minutes.
    378     ///
    379     /// Note `rp_id` _must_ be the same as the [`PublicKeyCredentialCreationOptions::rp_id`] when the
    380     /// [`AllowedCredential`]s were registered.
    381     ///
    382     /// # Errors
    383     ///
    384     /// Errors iff [`AllowedCredentials`] is empty.
    385     ///
    386     /// # Examples
    387     ///
    388     /// ```
    389     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    390     /// # use webauthn_rp::{bin::Decode, response::bin::DecodeAuthTransportsErr};
    391     /// # use webauthn_rp::{
    392     /// #     request::{
    393     /// #         auth::{AllowedCredentials, PublicKeyCredentialRequestOptions},
    394     /// #         AsciiDomain, RpId, PublicKeyCredentialDescriptor, Credentials
    395     /// #     },
    396     /// #     response::{AuthTransports, CredentialId},
    397     /// # };
    398     /// /// Retrieves the `AuthTransports` associated with the unique `cred_id`
    399     /// /// from the database.
    400     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    401     /// fn get_transports(cred_id: CredentialId<&[u8]>) -> Result<AuthTransports, DecodeAuthTransportsErr> {
    402     ///     // ⋮
    403     /// #     AuthTransports::decode(32)
    404     /// }
    405     /// let mut creds = AllowedCredentials::with_capacity(1);
    406     /// assert!(creds.as_ref().is_empty());
    407     /// // `CredentialId::try_from` only exists when `custom` is enabled; and even then, it is
    408     /// // likely never needed since the `CredentialId` was originally sent from the client and is likely
    409     /// // stored in a database which would be fetched by `UserHandle` or `Authentication::raw_id`.
    410     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    411     /// let id = CredentialId::try_from(vec![0; 16])?;
    412     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    413     /// let transports = get_transports((&id).into())?;
    414     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    415     /// assert!(creds.push(PublicKeyCredentialDescriptor { id, transports }.into()));
    416     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    417     /// assert_eq!(
    418     ///     PublicKeyCredentialRequestOptions::second_factor(&RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?), creds)?
    419     ///         .allow_credentials
    420     ///         .as_ref()
    421     ///         .len(),
    422     ///     1
    423     /// );
    424     /// # Ok::<_, webauthn_rp::AggErr>(())
    425     /// ```
    426     #[inline]
    427     pub fn second_factor<'a: 'rp_id>(
    428         rp_id: &'a RpId,
    429         creds: AllowedCredentials,
    430     ) -> Result<Self, SecondFactorErr> {
    431         if creds.as_ref().is_empty() {
    432             Err(SecondFactorErr)
    433         } else {
    434             let mut opts = Self::passkey(rp_id);
    435             opts.allow_credentials = creds;
    436             opts.user_verification = UserVerificationRequirement::Discouraged;
    437             Ok(opts)
    438         }
    439     }
    440     /// Begins the [authentication ceremony](https://www.w3.org/TR/webauthn-3/#authentication-ceremony) consuming
    441     /// `self`. Note that the expiration [`Instant`]/[`SystemTime`] is saved, so `AuthenticationClientState` MUST be
    442     /// sent ASAP. In order to complete authentication, the returned `AuthenticationServerState` MUST be saved so
    443     /// that it can later be used to verify the credential assertion with [`AuthenticationServerState::verify`].
    444     ///
    445     /// # Errors
    446     ///
    447     /// Errors iff `self` contains incompatible configuration.
    448     ///
    449     /// # Examples
    450     ///
    451     /// ```
    452     /// # #[cfg(not(feature = "serializable_server_state"))]
    453     /// # use std::time::Instant;
    454     /// # #[cfg(not(feature = "serializable_server_state"))]
    455     /// # use webauthn_rp::request::ServerState;
    456     /// # use webauthn_rp::request::{auth::PublicKeyCredentialRequestOptions, AsciiDomain, RpId};
    457     /// # #[cfg(not(feature = "serializable_server_state"))]
    458     /// assert!(
    459     ///     PublicKeyCredentialRequestOptions::passkey(&RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?))
    460     ///         .start_ceremony()?
    461     ///         .0
    462     ///         .expiration() > Instant::now()
    463     /// );
    464     /// # Ok::<_, webauthn_rp::AggErr>(())
    465     /// ```
    466     #[inline]
    467     pub fn start_ceremony(
    468         self,
    469     ) -> Result<
    470         (
    471             AuthenticationServerState,
    472             AuthenticationClientState<'rp_id, 'prf>,
    473         ),
    474         RequestOptionsErr,
    475     > {
    476         let extensions = self.extensions.into();
    477         let allow_credentials = Vec::from(&self.allow_credentials);
    478         validate_options_helper(extensions, self.user_verification, &allow_credentials).and_then(
    479             |()| {
    480                 #[cfg(not(feature = "serializable_server_state"))]
    481                 let res = Instant::now();
    482                 #[cfg(feature = "serializable_server_state")]
    483                 let res = SystemTime::now();
    484                 res.checked_add(Duration::from_millis(NonZeroU64::from(self.timeout).get()))
    485                     .ok_or(RequestOptionsErr::InvalidTimeout)
    486                     .map(|expiration| {
    487                         (
    488                             AuthenticationServerState {
    489                                 challenge: SentChallenge(self.challenge.0),
    490                                 allow_credentials,
    491                                 user_verification: self.user_verification,
    492                                 extensions,
    493                                 expiration,
    494                             },
    495                             AuthenticationClientState(self),
    496                         )
    497                     })
    498             },
    499         )
    500     }
    501 }
    502 /// Container of a [`PublicKeyCredentialRequestOptions`] that has been used to start the authentication ceremony.
    503 /// This gets sent to the client ASAP.
    504 #[derive(Debug)]
    505 pub struct AuthenticationClientState<'rp_id, 'prf>(PublicKeyCredentialRequestOptions<'rp_id, 'prf>);
    506 impl<'rp_id, 'prf> AuthenticationClientState<'rp_id, 'prf> {
    507     /// Returns the `PublicKeyCredentialRequestOptions` that was used to start an authentication ceremony.
    508     ///
    509     /// # Examples
    510     ///
    511     /// ```
    512     /// # use webauthn_rp::request::{auth::PublicKeyCredentialRequestOptions, AsciiDomain, RpId};
    513     /// assert!(
    514     ///     PublicKeyCredentialRequestOptions::passkey(&RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?))
    515     ///         .start_ceremony()?
    516     ///         .1
    517     ///         .options()
    518     ///         .allow_credentials
    519     ///         .as_ref()
    520     ///         .is_empty()
    521     /// );
    522     /// # Ok::<_, webauthn_rp::AggErr>(())
    523     /// ```
    524     #[inline]
    525     #[must_use]
    526     pub const fn options(&self) -> &PublicKeyCredentialRequestOptions<'rp_id, 'prf> {
    527         &self.0
    528     }
    529 }
    530 /// `PrfInput` and `PrfInputOwned` without the actual data sent to reduce memory usage when storing [`AuthenticationServerState`]
    531 /// in an in-memory collection.
    532 #[derive(Clone, Copy, Debug)]
    533 enum ServerPrfInfo {
    534     /// `PrfInput::second` was `None`.
    535     One(ExtensionReq),
    536     /// `PrfInput::second` was `Some`.
    537     Two(ExtensionReq),
    538 }
    539 impl ServerPrfInfo {
    540     /// Returns the `ExtensionReq` sent to the client.
    541     const fn ext_info(self) -> ExtensionReq {
    542         match self {
    543             Self::One(info) | Self::Two(info) => info,
    544         }
    545     }
    546     /// Validates `val` based on the passed arguments.
    547     fn validate(
    548         val: Option<Self>,
    549         prf_capable: bool,
    550         hmac: HmacSecret,
    551         err_unsolicited: bool,
    552     ) -> Result<(), ExtensionErr> {
    553         match hmac {
    554             HmacSecret::None => {
    555                 if prf_capable {
    556                     val.map_or(Ok(()), |input| {
    557                         if matches!(input.ext_info(), ExtensionReq::Allow) {
    558                             Ok(())
    559                         } else {
    560                             Err(ExtensionErr::MissingHmacSecret)
    561                         }
    562                     })
    563                 } else {
    564                     // We check if the PRF extension was requested on an incapable credential;
    565                     // if so, we error.
    566                     val.map_or(Ok(()), |_| Err(ExtensionErr::HmacSecretForPrfIncapableCred))
    567                 }
    568             }
    569             HmacSecret::One => {
    570                 if prf_capable {
    571                     val.map_or_else(
    572                         || {
    573                             if err_unsolicited {
    574                                 Err(ExtensionErr::ForbiddenHmacSecret)
    575                             } else {
    576                                 Ok(())
    577                             }
    578                         },
    579                         |input| match input {
    580                             Self::One(_) => Ok(()),
    581                             Self::Two(_) => Err(ExtensionErr::InvalidHmacSecretValue(
    582                                 OneOrTwo::Two,
    583                                 OneOrTwo::One,
    584                             )),
    585                         },
    586                     )
    587                 } else {
    588                     Err(ExtensionErr::HmacSecretForPrfIncapableCred)
    589                 }
    590             }
    591             HmacSecret::Two => {
    592                 if prf_capable {
    593                     val.map_or_else(
    594                         || {
    595                             if err_unsolicited {
    596                                 Err(ExtensionErr::ForbiddenHmacSecret)
    597                             } else {
    598                                 Ok(())
    599                             }
    600                         },
    601                         |input| match input {
    602                             Self::One(_) => Err(ExtensionErr::InvalidHmacSecretValue(
    603                                 OneOrTwo::One,
    604                                 OneOrTwo::Two,
    605                             )),
    606                             Self::Two(_) => Ok(()),
    607                         },
    608                     )
    609                 } else {
    610                     Err(ExtensionErr::HmacSecretForPrfIncapableCred)
    611                 }
    612             }
    613         }
    614     }
    615 }
    616 #[cfg(test)]
    617 impl PartialEq for ServerPrfInfo {
    618     fn eq(&self, other: &Self) -> bool {
    619         match *self {
    620             Self::One(req) => matches!(*other, Self::One(req2) if req == req2),
    621             Self::Two(req) => matches!(*other, Self::Two(req2) if req == req2),
    622         }
    623     }
    624 }
    625 impl From<PrfInput<'_>> for ServerPrfInfo {
    626     fn from(value: PrfInput<'_>) -> Self {
    627         value
    628             .second
    629             .map_or_else(|| Self::One(value.ext_info), |_| Self::Two(value.ext_info))
    630     }
    631 }
    632 impl From<&PrfInputOwned> for ServerPrfInfo {
    633     fn from(value: &PrfInputOwned) -> Self {
    634         value
    635             .second
    636             .as_ref()
    637             .map_or_else(|| Self::One(value.ext_info), |_| Self::Two(value.ext_info))
    638     }
    639 }
    640 /// `Extension` without the actual data sent to reduce memory usage when storing [`AuthenticationServerState`]
    641 /// in an in-memory collection.
    642 #[derive(Clone, Copy, Debug)]
    643 struct ServerExtensionInfo {
    644     /// `Extension::prf`.
    645     prf: Option<ServerPrfInfo>,
    646 }
    647 impl From<Extension<'_>> for ServerExtensionInfo {
    648     fn from(value: Extension<'_>) -> Self {
    649         Self {
    650             prf: value.prf.map(ServerPrfInfo::from),
    651         }
    652     }
    653 }
    654 #[cfg(test)]
    655 impl PartialEq for ServerExtensionInfo {
    656     fn eq(&self, other: &Self) -> bool {
    657         self.prf == other.prf
    658     }
    659 }
    660 /// `CredentialSpecificExtension` without the actual data sent to reduce memory usage when storing [`AuthenticationServerState`]
    661 /// in an in-memory collection.
    662 #[derive(Clone, Copy, Debug)]
    663 struct ServerCredSpecificExtensionInfo {
    664     /// `CredentialSpecificExtension::prf`.
    665     prf: Option<ServerPrfInfo>,
    666 }
    667 #[cfg(test)]
    668 impl PartialEq for ServerCredSpecificExtensionInfo {
    669     fn eq(&self, other: &Self) -> bool {
    670         self.prf == other.prf
    671     }
    672 }
    673 impl From<&CredentialSpecificExtension> for ServerCredSpecificExtensionInfo {
    674     fn from(value: &CredentialSpecificExtension) -> Self {
    675         Self {
    676             prf: value.prf.as_ref().map(ServerPrfInfo::from),
    677         }
    678     }
    679 }
    680 impl ServerExtensionInfo {
    681     /// Validates the extensions.
    682     ///
    683     /// Note that this MUST only be called internally by `auth::validate_extensions`.
    684     fn validate_extensions(
    685         self,
    686         auth_ext: AuthenticatorExtensionOutput,
    687         error_unsolicited: bool,
    688         prf_capable: bool,
    689     ) -> Result<(), ExtensionErr> {
    690         ServerPrfInfo::validate(
    691             self.prf,
    692             prf_capable,
    693             auth_ext.hmac_secret,
    694             error_unsolicited,
    695         )
    696     }
    697 }
    698 /// Validates the extensions.
    699 fn validate_extensions(
    700     ext: ServerExtensionInfo,
    701     cred_ext: Option<ServerCredSpecificExtensionInfo>,
    702     auth_ext: AuthenticatorExtensionOutput,
    703     error_unsolicited: bool,
    704     prf_capable: bool,
    705 ) -> Result<(), ExtensionErr> {
    706     cred_ext.map_or_else(
    707         || {
    708             // No client-specific extensions, so we can simply focus on `ext`.
    709             ext.validate_extensions(auth_ext, error_unsolicited, prf_capable)
    710         },
    711         |c_ext| {
    712             // Must carefully process each extension based on overlap and which gets priority over the other.
    713             c_ext.prf.as_ref().map_or_else(
    714                 || {
    715                     ServerPrfInfo::validate(
    716                         ext.prf,
    717                         prf_capable,
    718                         auth_ext.hmac_secret,
    719                         error_unsolicited,
    720                     )
    721                 },
    722                 |_| {
    723                     ServerPrfInfo::validate(
    724                         c_ext.prf,
    725                         prf_capable,
    726                         auth_ext.hmac_secret,
    727                         error_unsolicited,
    728                     )
    729                 },
    730             )
    731         },
    732     )
    733 }
    734 /// [`AllowedCredential`] with less data to reduce memory usage when storing [`AuthenticationServerState`]
    735 /// in an in-memory collection.
    736 #[derive(Debug)]
    737 struct CredInfo {
    738     /// The Credential ID.
    739     id: CredentialId<Vec<u8>>,
    740     /// Any credential-specific extensions.
    741     ext: ServerCredSpecificExtensionInfo,
    742 }
    743 #[cfg(test)]
    744 impl PartialEq for CredInfo {
    745     fn eq(&self, other: &Self) -> bool {
    746         self.id == other.id && self.ext == other.ext
    747     }
    748 }
    749 /// Controls how to handle a change in [`DynamicState::authenticator_attachment`].
    750 ///
    751 /// Note when `DynamicState::authenticator_attachment` is [`AuthenticatorAttachment::None`], then it will
    752 /// be updated regardless. Similarly when [`Authentication::authenticator_attachment`] is
    753 /// `AuthenticatorAttachment::None`, it will never update `DynamicState::authenticator_attachment`.
    754 #[derive(Clone, Copy, Debug)]
    755 pub enum AuthenticatorAttachmentEnforcement {
    756     /// Fail the authentication ceremony if [`AuthenticatorAttachment`] is not the same.
    757     ///
    758     /// The contained `bool` represents if `AuthenticatorAttachment` must be sent.
    759     Fail(bool),
    760     /// Update [`DynamicState::authenticator_attachment`] to the sent [`AuthenticatorAttachment`].
    761     ///
    762     /// The contained `bool` represents if `AuthenticatorAttachment` must be sent.
    763     Update(bool),
    764     /// Do not update [`DynamicState::authenticator_attachment`] to the sent [`AuthenticatorAttachment`].
    765     ///
    766     /// The contained `bool` represents if `AuthenticatorAttachment` must be sent.
    767     Ignore(bool),
    768 }
    769 impl AuthenticatorAttachmentEnforcement {
    770     /// Validates `cur` based on `self` and `prev`.
    771     const fn validate(
    772         self,
    773         prev: AuthenticatorAttachment,
    774         cur: AuthenticatorAttachment,
    775     ) -> Result<AuthenticatorAttachment, AuthCeremonyErr> {
    776         match cur {
    777             AuthenticatorAttachment::None => match self {
    778                 Self::Fail(require) | Self::Update(require) | Self::Ignore(require) => {
    779                     if require {
    780                         Err(AuthCeremonyErr::MissingAuthenticatorAttachment)
    781                     } else {
    782                         // We don't overwrite the previous one with [`AuthenticatorAttachment::None`].
    783                         Ok(prev)
    784                     }
    785                 }
    786             },
    787             AuthenticatorAttachment::Platform => match self {
    788                 Self::Fail(_) => {
    789                     if matches!(prev, AuthenticatorAttachment::CrossPlatform) {
    790                         Err(AuthCeremonyErr::AuthenticatorAttachmentMismatch)
    791                     } else {
    792                         // We don't fail when we previously had [`AuthenticatorAttachment::None`].
    793                         Ok(cur)
    794                     }
    795                 }
    796                 Self::Update(_) => Ok(cur),
    797                 Self::Ignore(_) => {
    798                     if matches!(prev, AuthenticatorAttachment::None) {
    799                         // We overwrite the previous one when it is [`AuthenticatorAttachment::None`].
    800                         Ok(cur)
    801                     } else {
    802                         Ok(prev)
    803                     }
    804                 }
    805             },
    806             AuthenticatorAttachment::CrossPlatform => match self {
    807                 Self::Fail(_) => {
    808                     if matches!(prev, AuthenticatorAttachment::Platform) {
    809                         Err(AuthCeremonyErr::AuthenticatorAttachmentMismatch)
    810                     } else {
    811                         // We don't fail when we previously had [`AuthenticatorAttachment::None`].
    812                         Ok(cur)
    813                     }
    814                 }
    815                 Self::Update(_) => Ok(cur),
    816                 Self::Ignore(_) => {
    817                     if matches!(prev, AuthenticatorAttachment::None) {
    818                         // We overwrite the previous one when it is [`AuthenticatorAttachment::None`].
    819                         Ok(cur)
    820                     } else {
    821                         Ok(prev)
    822                     }
    823                 }
    824             },
    825         }
    826     }
    827 }
    828 impl Default for AuthenticatorAttachmentEnforcement {
    829     /// Returns [`Self::Ignore`] containing `false`.
    830     #[inline]
    831     fn default() -> Self {
    832         Self::Ignore(false)
    833     }
    834 }
    835 /// Additional verification options to perform in [`AuthenticationServerState::verify`].
    836 #[derive(Clone, Copy, Debug)]
    837 pub struct AuthenticationVerificationOptions<'origins, 'top_origins, O, T> {
    838     /// Origins to use for [origin validation](https://www.w3.org/TR/webauthn-3/#sctn-validating-origin).
    839     ///
    840     /// When this is empty, the origin that will be used will be based on
    841     /// the [`RpId`] passed to [`AuthenticationServerState::verify`]. If [`RpId::Domain`], then the [`DomainOrigin`] returned from
    842     /// passing [`AsciiDomain::as_ref`] to [`DomainOrigin::new`] will be used; otherwise the [`Url`] in
    843     /// [`RpId::Url`] will be used.
    844     pub allowed_origins: &'origins [O],
    845     /// [Top-level origins](https://html.spec.whatwg.org/multipage/webappapis.html#concept-environment-top-level-origin)
    846     /// to use for [origin validation](https://www.w3.org/TR/webauthn-3/#sctn-validating-origin).
    847     ///
    848     /// When this is `Some`, [`CollectedClientData::cross_origin`] is allowed to be `true`. When the contained
    849     /// `slice` is empty, [`CollectedClientData::top_origin`] must be `None`. When this is `None`,
    850     /// `CollectedClientData::cross_origin` must be `false` and `CollectedClientData::top_origin` must be `None`.
    851     pub allowed_top_origins: Option<&'top_origins [T]>,
    852     /// The required [`Backup`] state of the credential.
    853     ///
    854     /// Note that `None` is _not_ the same as `Some(BackupReq::None)` as the latter indicates that any [`Backup`]
    855     /// is allowed. This is rarely what you want; instead, `None` indicates that [`BackupReq::from`] applied to
    856     /// [`DynamicState::backup`] will be used in [`AuthenticationServerState::verify`].
    857     pub backup_requirement: Option<BackupReq>,
    858     /// Error when unsolicited extensions are sent back iff `true`.
    859     pub error_on_unsolicited_extensions: bool,
    860     /// Dictates what happens when [`Authentication::authenticator_attachment`] is not the same as
    861     /// [`DynamicState::authenticator_attachment`].
    862     pub auth_attachment_enforcement: AuthenticatorAttachmentEnforcement,
    863     /// [`DynamicState::user_verified`] will be set to `true` iff [`Flag::user_verified`] when `true`.
    864     pub update_uv: bool,
    865     /// Dictates what happens when [`AuthenticatorData::sign_count`] is not updated to a strictly greater value.
    866     pub sig_counter_enforcement: SignatureCounterEnforcement,
    867     /// [`CollectedClientData::from_client_data_json_relaxed`] is used to extract [`CollectedClientData`] iff `true`.
    868     #[cfg_attr(docsrs, doc(cfg(feature = "serde_relaxed")))]
    869     #[cfg(feature = "serde_relaxed")]
    870     pub client_data_json_relaxed: bool,
    871 }
    872 impl<O, T> Default for AuthenticationVerificationOptions<'_, '_, O, T> {
    873     /// Returns `Self` such that [`Self::allowed_origins`] is empty, [`Self::allowed_top_origins`] is `None`,
    874     /// [`Self::backup_requirement`] is `None`, [`Self::error_on_unsolicited_extensions`] is `true`,
    875     /// [`Self::auth_attachment_enforcement`] is [`AuthenticatorAttachmentEnforcement::default`],
    876     /// [`Self::update_uv`] is `false`, [`Self::sig_counter_enforcement`] is
    877     /// [`SignatureCounterEnforcement::default`], and [`Self::client_data_json_relaxed`] is `true`.
    878     #[inline]
    879     fn default() -> Self {
    880         Self {
    881             allowed_origins: &[],
    882             allowed_top_origins: None,
    883             backup_requirement: None,
    884             error_on_unsolicited_extensions: true,
    885             auth_attachment_enforcement: AuthenticatorAttachmentEnforcement::default(),
    886             update_uv: false,
    887             sig_counter_enforcement: SignatureCounterEnforcement::default(),
    888             #[cfg(feature = "serde_relaxed")]
    889             client_data_json_relaxed: true,
    890         }
    891     }
    892 }
    893 // This is essentially the `PublicKeyCredentialRequestOptions` used to create it; however to reduce
    894 // memory usage, we remove all unnecessary data making an instance of this 64 bytes in size when
    895 // `Self::allow_credentials` is empty on `x86_64-unknown-linux-gnu` platforms.
    896 //
    897 // The total memory used is dependent on the number of `AllowedCredential`s and the size of each `CredentialId`.
    898 // To be exact, it is the following:
    899 // 64 + i(32 + 56n + Σj_k from k=0 to k=m-1) where i is 0 iff `AllowedCredentials` has capacity 0; otherwise 1,
    900 // n is `AllowedCredentials` capacity, j_k is the kth `CredentialId` in `AllowedCredentials` and `m` is
    901 // `AllowedCredentials::len`.
    902 /// State needed to be saved when beginning the authentication ceremony.
    903 ///
    904 /// Saves the necessary information associated with the [`PublicKeyCredentialRequestOptions`] used to create it
    905 /// via [`PublicKeyCredentialRequestOptions::start_ceremony`] so that authentication of a credential can be
    906 /// performed with [`Self::verify`].
    907 ///
    908 /// `AuthenticationServerState` implements [`Borrow`] of [`SentChallenge`]; thus to obtain the correct
    909 /// `AuthenticationServerState` associated with an [`Authentication`], one should use its corresponding
    910 /// [`Authentication::challenge`].
    911 #[derive(Debug)]
    912 pub struct AuthenticationServerState {
    913     // This is a `SentChallenge` since we need `AuthenticationServerState` to be fetchable after receiving the
    914     // response from the client. This response must obviously be constructable; thus its challenge is a
    915     // `SentChallenge`.
    916     //
    917     // This must never be mutated since we want to ensure it is actually a `Challenge` (which
    918     // can only be constructed via `Challenge::new`). This is guaranteed to be true iff
    919     // `serializable_server_state` is not enabled.
    920     /// [`challenge`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialrequestoptions-challenge).
    921     challenge: SentChallenge,
    922     /// [`allowCredentials`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialrequestoptions-allowcredentials).
    923     allow_credentials: Vec<CredInfo>,
    924     /// [`userVerification`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialrequestoptions-userverification).
    925     user_verification: UserVerificationRequirement,
    926     /// [`extensions`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialrequestoptions-extensions).
    927     extensions: ServerExtensionInfo,
    928     /// `Instant` the ceremony expires.
    929     #[cfg(not(feature = "serializable_server_state"))]
    930     expiration: Instant,
    931     /// `SystemTime` the ceremony expires.
    932     #[cfg(feature = "serializable_server_state")]
    933     expiration: SystemTime,
    934 }
    935 impl AuthenticationServerState {
    936     /// Verifies `response` is valid based on `self` consuming `self` and updating `cred`. Returns `true`
    937     /// iff `cred` was mutated.
    938     ///
    939     /// `rp_id` MUST be the same as the [`PublicKeyCredentialRequestOptions::rp_id`] used when starting the
    940     /// ceremony.
    941     ///
    942     /// It is _essential_ to save [`AuthenticatedCredential::dynamic_state`] overwriting the original value iff `Ok(true)`
    943     /// is returned.
    944     ///
    945     /// # Errors
    946     ///
    947     /// Errors iff `response` is not valid according to the
    948     /// [authentication ceremony](https://www.w3.org/TR/webauthn-3/#sctn-verifying-assertion) or violates any
    949     /// of the settings in `options`.
    950     #[inline]
    951     pub fn verify<
    952         'a,
    953         'user,
    954         O: PartialEq<Origin<'a>>,
    955         T: PartialEq<Origin<'a>>,
    956         EdKey: AsRef<[u8]>,
    957         P256Key: AsRef<[u8]>,
    958         P384Key: AsRef<[u8]>,
    959         RsaKey: AsRef<[u8]>,
    960         U: User,
    961     >(
    962         self,
    963         rp_id: &RpId,
    964         response: &'a Authentication<U>,
    965         cred: &mut AuthenticatedCredential<
    966             'a,
    967             'user,
    968             CompressedPubKey<EdKey, P256Key, P384Key, RsaKey>,
    969         >,
    970         options: &AuthenticationVerificationOptions<'_, '_, O, T>,
    971     ) -> Result<bool, AuthCeremonyErr> {
    972         // [Authentication ceremony](https://www.w3.org/TR/webauthn-3/#sctn-verifying-assertion)
    973         // is handled by:
    974         //
    975         // 1. Calling code.
    976         // 2. Client code and the construction of `resp` (hopefully via [`Authentication::deserialize`]).
    977         // 3. Client code and the construction of `resp` (hopefully via [`AuthenticatorAssertion::deserialize`]).
    978         // 4. Client code and the construction of `resp` (hopefully via [`ClientExtensionsOutputs::deserialize`]).
    979         // 5. Below.
    980         // 6. Below.
    981         // 7. Informative only in that it defines variables.
    982         // 8. [`Self::partial_validate`].
    983         // 9. [`Self::partial_validate`].
    984         // 10. [`Self::partial_validate`].
    985         // 11. [`Self::partial_validate`].
    986         // 12. [`Self::partial_validate`].
    987         // 13. [`Self::partial_validate`].
    988         // 14. [`Self::partial_validate`].
    989         // 15. [`Self::partial_validate`].
    990         // 16. [`Self::partial_validate`].
    991         // 17. [`Self::partial_validate`].
    992         // 18. [`Self::partial_validate`].
    993         // 19. [`Self::partial_validate`].
    994         // 20. [`Self::partial_validate`].
    995         // 21. [`Self::partial_validate`].
    996         // 22. Below.
    997         // 23. Below.
    998         // 24. Below.
    999         // 25. Below.
   1000 
   1001         if self.allow_credentials.is_empty() {
   1002             // Step 6.
   1003             response
   1004                 .response
   1005                 .user_handle()
   1006                 .is_same(cred.user_id)
   1007                 .ok_or(AuthCeremonyErr::MissingUserHandle)
   1008                 .and_then(|same| {
   1009                     if same {
   1010                         if cred.id == response.raw_id {
   1011                             Ok(None)
   1012                         } else {
   1013                             Err(AuthCeremonyErr::CredentialIdMismatch)
   1014                         }
   1015                     } else {
   1016                         Err(AuthCeremonyErr::UserHandleMismatch)
   1017                     }
   1018                 })
   1019         } else {
   1020             // Steps 5–6.
   1021             self.verify_nondiscoverable(response, cred)
   1022         }
   1023         .and_then(|ext| {
   1024             // Steps 8–21.
   1025             self.partial_validate(
   1026                 rp_id,
   1027                 response,
   1028                 (&cred.static_state.credential_public_key).into(),
   1029                 &CeremonyOptions {
   1030                     allowed_origins: options.allowed_origins,
   1031                     allowed_top_origins: options.allowed_top_origins,
   1032                     backup_requirement: options
   1033                         .backup_requirement
   1034                         .unwrap_or_else(|| BackupReq::from(cred.dynamic_state.backup)),
   1035                     #[cfg(feature = "serde_relaxed")]
   1036                     client_data_json_relaxed: options.client_data_json_relaxed,
   1037                 },
   1038             )
   1039             .map_err(AuthCeremonyErr::from)
   1040             .and_then(|auth_data| {
   1041                 options
   1042                     .auth_attachment_enforcement
   1043                     .validate(
   1044                         cred.dynamic_state.authenticator_attachment,
   1045                         response.authenticator_attachment,
   1046                     )
   1047                     .and_then(|auth_attachment| {
   1048                         // Step 23.
   1049                         validate_extensions(
   1050                             self.extensions,
   1051                             ext,
   1052                             auth_data.extensions(),
   1053                             options.error_on_unsolicited_extensions,
   1054                             cred.static_state.extensions.hmac_secret.unwrap_or_default(),
   1055                         )
   1056                         .map_err(AuthCeremonyErr::Extension)
   1057                         .and_then(|()| {
   1058                             // Step 22.
   1059                             options
   1060                                 .sig_counter_enforcement
   1061                                 .validate(cred.dynamic_state.sign_count, auth_data.sign_count())
   1062                                 .and_then(|sig_counter| {
   1063                                     let flags = auth_data.flags();
   1064                                     let prev_dyn_state = cred.dynamic_state;
   1065                                     // Step 24 item 2.
   1066                                     cred.dynamic_state.backup = flags.backup;
   1067                                     if options.update_uv && flags.user_verified {
   1068                                         // Step 24 item 3.
   1069                                         cred.dynamic_state.user_verified = true;
   1070                                     }
   1071                                     // Step 24 item 1.
   1072                                     cred.dynamic_state.sign_count = sig_counter;
   1073                                     cred.dynamic_state.authenticator_attachment = auth_attachment;
   1074                                     // Step 25.
   1075                                     crate::verify_static_and_dynamic_state(
   1076                                         &cred.static_state,
   1077                                         cred.dynamic_state,
   1078                                     )
   1079                                     .map_err(|e| {
   1080                                         cred.dynamic_state = prev_dyn_state;
   1081                                         AuthCeremonyErr::Credential(e)
   1082                                     })
   1083                                     .map(|()| prev_dyn_state != cred.dynamic_state)
   1084                                 })
   1085                         })
   1086                     })
   1087             })
   1088         })
   1089     }
   1090     /// Retrieves the corresponding [`CredInfo`] used for a non-discoverable request that corresponds to
   1091     /// `response`. Since this is a non-discoverable request, one must have an external way of identifying the
   1092     /// `UserHandle`.
   1093     ///
   1094     /// This MUST be called iff a non-discoverable request was sent to the client (e.g.,
   1095     /// [`PublicKeyCredentialRequestOptions::second_factor`]).
   1096     ///
   1097     /// # Errors
   1098     ///
   1099     /// Errors iff [`AuthenticatedCredential::user_handle`] does not match [`Authentication::user_handle`] or
   1100     /// [`PublicKeyCredentialRequestOptions::allow_credentials`] does not have a [`CredInfo`] such that
   1101     /// [`CredInfo::id`] matches [`Authentication::raw_id`].
   1102     fn verify_nondiscoverable<'a, PublicKey, U: User>(
   1103         &self,
   1104         response: &'a Authentication<U>,
   1105         cred: &AuthenticatedCredential<'a, '_, PublicKey>,
   1106     ) -> Result<Option<ServerCredSpecificExtensionInfo>, AuthCeremonyErr> {
   1107         response
   1108             .response
   1109             .user_handle()
   1110             .is_same(cred.user_id())
   1111             .map_or(Ok(()), |same| {
   1112                 if same {
   1113                     Ok(())
   1114                 } else {
   1115                     Err(AuthCeremonyErr::UserHandleMismatch)
   1116                 }
   1117             })
   1118             .and_then(|()| {
   1119                 self.allow_credentials
   1120                     .iter()
   1121                     .find(|c| c.id == response.raw_id)
   1122                     .ok_or(AuthCeremonyErr::NoMatchingAllowedCredential)
   1123                     .map(|c| Some(c.ext))
   1124             })
   1125     }
   1126     #[cfg(all(test, feature = "custom", feature = "serializable_server_state"))]
   1127     fn is_eq(&self, other: &Self) -> bool {
   1128         self.challenge == other.challenge
   1129             && self.allow_credentials == other.allow_credentials
   1130             && self.user_verification == other.user_verification
   1131             && self.extensions == other.extensions
   1132             && self.expiration == other.expiration
   1133     }
   1134 }
   1135 impl ServerState for AuthenticationServerState {
   1136     #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1137     #[inline]
   1138     fn expiration(&self) -> Instant {
   1139         self.expiration
   1140     }
   1141     #[cfg(all(not(doc), feature = "serializable_server_state"))]
   1142     #[inline]
   1143     fn expiration(&self) -> SystemTime {
   1144         self.expiration
   1145     }
   1146     #[inline]
   1147     fn sent_challenge(&self) -> SentChallenge {
   1148         self.challenge
   1149     }
   1150 }
   1151 impl<User> Ceremony<User> for AuthenticationServerState {
   1152     type R = Authentication<User>;
   1153     fn rand_challenge(&self) -> SentChallenge {
   1154         self.challenge
   1155     }
   1156     #[cfg(not(feature = "serializable_server_state"))]
   1157     fn expiry(&self) -> Instant {
   1158         self.expiration
   1159     }
   1160     #[cfg(feature = "serializable_server_state")]
   1161     fn expiry(&self) -> SystemTime {
   1162         self.expiration
   1163     }
   1164     fn user_verification(&self) -> UserVerificationRequirement {
   1165         self.user_verification
   1166     }
   1167 }
   1168 impl Borrow<SentChallenge> for AuthenticationServerState {
   1169     #[inline]
   1170     fn borrow(&self) -> &SentChallenge {
   1171         &self.challenge
   1172     }
   1173 }
   1174 impl PartialEq for AuthenticationServerState {
   1175     #[inline]
   1176     fn eq(&self, other: &Self) -> bool {
   1177         self.challenge == other.challenge
   1178     }
   1179 }
   1180 impl PartialEq<&Self> for AuthenticationServerState {
   1181     #[inline]
   1182     fn eq(&self, other: &&Self) -> bool {
   1183         *self == **other
   1184     }
   1185 }
   1186 impl PartialEq<AuthenticationServerState> for &AuthenticationServerState {
   1187     #[inline]
   1188     fn eq(&self, other: &AuthenticationServerState) -> bool {
   1189         **self == *other
   1190     }
   1191 }
   1192 impl Eq for AuthenticationServerState {}
   1193 impl Hash for AuthenticationServerState {
   1194     #[inline]
   1195     fn hash<H: Hasher>(&self, state: &mut H) {
   1196         self.challenge.hash(state);
   1197     }
   1198 }
   1199 impl PartialOrd for AuthenticationServerState {
   1200     #[inline]
   1201     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
   1202         Some(self.cmp(other))
   1203     }
   1204 }
   1205 impl Ord for AuthenticationServerState {
   1206     #[inline]
   1207     fn cmp(&self, other: &Self) -> Ordering {
   1208         self.challenge.cmp(&other.challenge)
   1209     }
   1210 }
   1211 #[cfg(test)]
   1212 mod tests {
   1213     #[cfg(all(feature = "custom", feature = "serializable_server_state"))]
   1214     use super::{
   1215         super::{
   1216             super::{
   1217                 AggErr,
   1218                 bin::{Decode as _, Encode as _},
   1219             },
   1220             AsciiDomain, AuthTransports,
   1221         },
   1222         AllowedCredential, AllowedCredentials, AuthenticationServerState, Challenge, CredentialId,
   1223         CredentialSpecificExtension, Credentials as _, Extension, ExtensionReq, PrfInputOwned,
   1224         PublicKeyCredentialDescriptor, PublicKeyCredentialRequestOptions, RpId,
   1225         UserVerificationRequirement,
   1226     };
   1227     #[cfg(all(feature = "custom", feature = "serializable_server_state"))]
   1228     use rsa::sha2::{Digest as _, Sha256};
   1229     #[cfg(all(feature = "custom", feature = "serializable_server_state"))]
   1230     const CBOR_BYTES: u8 = 0b010_00000;
   1231     #[cfg(all(feature = "custom", feature = "serializable_server_state"))]
   1232     const CBOR_TEXT: u8 = 0b011_00000;
   1233     #[cfg(all(feature = "custom", feature = "serializable_server_state"))]
   1234     const CBOR_MAP: u8 = 0b101_00000;
   1235     #[test]
   1236     #[cfg(all(feature = "custom", feature = "serializable_server_state"))]
   1237     fn ed25519_auth_ser() -> Result<(), AggErr> {
   1238         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   1239         let mut creds = AllowedCredentials::with_capacity(1);
   1240         creds.push(AllowedCredential {
   1241             credential: PublicKeyCredentialDescriptor {
   1242                 id: CredentialId::try_from(vec![0; 16])?,
   1243                 transports: AuthTransports::NONE,
   1244             },
   1245             extension: CredentialSpecificExtension {
   1246                 prf: Some(PrfInputOwned {
   1247                     first: Vec::new(),
   1248                     second: Some(Vec::new()),
   1249                     ext_info: ExtensionReq::Require,
   1250                 }),
   1251             },
   1252         });
   1253         let mut opts = PublicKeyCredentialRequestOptions::second_factor(&rp_id, creds)?;
   1254         opts.user_verification = UserVerificationRequirement::Required;
   1255         opts.challenge = Challenge(0);
   1256         opts.extensions = Extension { prf: None };
   1257         let client_data_json = br#"{"type":"webauthn.get","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   1258         // We over-allocate by 32 bytes. See [`AuthenticatorAssertion::new`] for more information.
   1259         let mut authenticator_data = Vec::with_capacity(164);
   1260         authenticator_data.extend_from_slice(
   1261             [
   1262                 // rpIdHash.
   1263                 // This will be overwritten later.
   1264                 0,
   1265                 0,
   1266                 0,
   1267                 0,
   1268                 0,
   1269                 0,
   1270                 0,
   1271                 0,
   1272                 0,
   1273                 0,
   1274                 0,
   1275                 0,
   1276                 0,
   1277                 0,
   1278                 0,
   1279                 0,
   1280                 0,
   1281                 0,
   1282                 0,
   1283                 0,
   1284                 0,
   1285                 0,
   1286                 0,
   1287                 0,
   1288                 0,
   1289                 0,
   1290                 0,
   1291                 0,
   1292                 0,
   1293                 0,
   1294                 0,
   1295                 0,
   1296                 // flags.
   1297                 // UP, UV, and ED (right-to-left).
   1298                 0b1000_0101,
   1299                 // signCount.
   1300                 // 0 as 32-bit big endian.
   1301                 0,
   1302                 0,
   1303                 0,
   1304                 0,
   1305                 CBOR_MAP | 1,
   1306                 CBOR_TEXT | 11,
   1307                 b'h',
   1308                 b'm',
   1309                 b'a',
   1310                 b'c',
   1311                 b'-',
   1312                 b's',
   1313                 b'e',
   1314                 b'c',
   1315                 b'r',
   1316                 b'e',
   1317                 b't',
   1318                 CBOR_BYTES | 24,
   1319                 // Length is 80.
   1320                 80,
   1321                 // Two HMAC outputs concatenated and encrypted.
   1322                 0,
   1323                 0,
   1324                 0,
   1325                 0,
   1326                 0,
   1327                 0,
   1328                 0,
   1329                 0,
   1330                 0,
   1331                 0,
   1332                 0,
   1333                 0,
   1334                 0,
   1335                 0,
   1336                 0,
   1337                 0,
   1338                 0,
   1339                 0,
   1340                 0,
   1341                 0,
   1342                 0,
   1343                 0,
   1344                 0,
   1345                 0,
   1346                 0,
   1347                 0,
   1348                 0,
   1349                 0,
   1350                 0,
   1351                 0,
   1352                 0,
   1353                 0,
   1354                 0,
   1355                 0,
   1356                 0,
   1357                 0,
   1358                 0,
   1359                 0,
   1360                 0,
   1361                 0,
   1362                 0,
   1363                 0,
   1364                 0,
   1365                 0,
   1366                 0,
   1367                 0,
   1368                 0,
   1369                 0,
   1370                 0,
   1371                 0,
   1372                 0,
   1373                 0,
   1374                 0,
   1375                 0,
   1376                 0,
   1377                 0,
   1378                 0,
   1379                 0,
   1380                 0,
   1381                 0,
   1382                 0,
   1383                 0,
   1384                 0,
   1385                 0,
   1386                 0,
   1387                 0,
   1388                 0,
   1389                 0,
   1390                 0,
   1391                 0,
   1392                 0,
   1393                 0,
   1394                 0,
   1395                 0,
   1396                 0,
   1397                 0,
   1398                 0,
   1399                 0,
   1400                 0,
   1401                 0,
   1402             ]
   1403             .as_slice(),
   1404         );
   1405         authenticator_data[..32]
   1406             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   1407         authenticator_data
   1408             .extend_from_slice(Sha256::digest(client_data_json.as_slice()).as_slice());
   1409         authenticator_data.truncate(132);
   1410         let server = opts.start_ceremony()?.0;
   1411         assert!(server.is_eq(&AuthenticationServerState::decode(
   1412             server.encode()?.as_slice()
   1413         )?));
   1414         Ok(())
   1415     }
   1416 }