webauthn_rp

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

request.rs (137696B)


      1 #[cfg(doc)]
      2 use super::{
      3     request::{
      4         auth::{
      5             AllowedCredential, AllowedCredentials, CredentialSpecificExtension,
      6             PublicKeyCredentialRequestOptions,
      7         },
      8         register::PublicKeyCredentialCreationOptions,
      9     },
     10     response::register::ClientExtensionsOutputs,
     11 };
     12 use crate::{
     13     request::{
     14         auth::AuthenticationServerState,
     15         error::{AsciiDomainErr, DomainOriginParseErr, PortParseErr, SchemeParseErr, UrlErr},
     16         register::{RegistrationServerState, RegistrationVerificationOptions},
     17     },
     18     response::{
     19         AuthData as _, AuthDataContainer, AuthResponse, AuthTransports, Backup, CeremonyErr,
     20         CredentialId, Origin, Response, SentChallenge,
     21     },
     22 };
     23 #[cfg(any(doc, not(feature = "serializable_server_state")))]
     24 use core::hash::{BuildHasher, Hash, Hasher};
     25 use core::{
     26     borrow::Borrow,
     27     fmt::{self, Display, Formatter},
     28     num::NonZeroU32,
     29     str::FromStr,
     30 };
     31 use rsa::sha2::{Digest as _, Sha256};
     32 #[cfg(feature = "serializable_server_state")]
     33 use std::time::SystemTime;
     34 #[cfg(any(doc, not(feature = "serializable_server_state")))]
     35 use std::{collections::HashSet, time::Instant};
     36 use url::Url as Uri;
     37 /// Contains functionality for beginning the
     38 /// [authentication ceremony](https://www.w3.org/TR/webauthn-3/#authentication-ceremony).
     39 ///
     40 /// # Examples
     41 ///
     42 /// ```
     43 /// # #[cfg(not(feature = "serializable_server_state"))]
     44 /// # use webauthn_rp::request::{FixedCapHashSet, InsertResult};
     45 /// # use webauthn_rp::{
     46 /// #     request::{
     47 /// #         auth::{AllowedCredentials, PublicKeyCredentialRequestOptions},
     48 /// #         register::UserHandle,
     49 /// #         AsciiDomain, Credentials, PublicKeyCredentialDescriptor, RpId,
     50 /// #     },
     51 /// #     response::{AuthTransports, CredentialId, CRED_ID_MIN_LEN},
     52 /// #     AggErr,
     53 /// # };
     54 /// # #[cfg(not(feature = "serializable_server_state"))]
     55 /// let mut ceremonies = FixedCapHashSet::new(128);
     56 /// let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
     57 /// let (server, client) = PublicKeyCredentialRequestOptions::passkey(&rp_id).start_ceremony()?;
     58 /// # #[cfg(not(feature = "serializable_server_state"))]
     59 /// assert!(matches!(
     60 ///     ceremonies.insert_or_replace_all_expired(server),
     61 ///     InsertResult::Success
     62 /// ));
     63 /// # #[cfg(feature = "serde")]
     64 /// assert!(serde_json::to_string(&client).is_ok());
     65 /// let user_handle = get_user_handle();
     66 /// # #[cfg(feature = "custom")]
     67 /// let creds = get_registered_credentials((&user_handle).into())?;
     68 /// # #[cfg(feature = "custom")]
     69 /// let (server_2, client_2) =
     70 ///     PublicKeyCredentialRequestOptions::second_factor(&rp_id, creds)?.start_ceremony()?;
     71 /// # #[cfg(all(feature = "custom", not(feature = "serializable_server_state")))]
     72 /// assert!(matches!(
     73 ///     ceremonies.insert_or_replace_all_expired(server_2),
     74 ///     InsertResult::Success
     75 /// ));
     76 /// # #[cfg(all(feature = "custom", feature = "serde"))]
     77 /// assert!(serde_json::to_string(&client_2).is_ok());
     78 /// /// Extract `UserHandle` from session cookie.
     79 /// fn get_user_handle() -> UserHandle<Vec<u8>> {
     80 ///     // ⋮
     81 /// #     UserHandle::new()
     82 /// }
     83 /// # #[cfg(feature = "custom")]
     84 /// /// Fetch the `AllowedCredentials` associated with `user`.
     85 /// fn get_registered_credentials(user: UserHandle<&[u8]>) -> Result<AllowedCredentials, AggErr> {
     86 ///     // ⋮
     87 /// #     let mut creds = AllowedCredentials::new();
     88 /// #     creds.push(
     89 /// #         PublicKeyCredentialDescriptor {
     90 /// #             id: CredentialId::try_from(vec![0; CRED_ID_MIN_LEN])?,
     91 /// #             transports: AuthTransports::NONE,
     92 /// #         }
     93 /// #         .into(),
     94 /// #     );
     95 /// #     Ok(creds)
     96 /// }
     97 /// # Ok::<_, AggErr>(())
     98 /// ```
     99 pub mod auth;
    100 /// Contains error types.
    101 pub mod error;
    102 /// Contains functionality for beginning the
    103 /// [registration ceremony](https://www.w3.org/TR/webauthn-3/#registration-ceremony).
    104 ///
    105 /// # Examples
    106 ///
    107 /// ```
    108 /// # #[cfg(not(feature = "serializable_server_state"))]
    109 /// # use webauthn_rp::request::{FixedCapHashSet, InsertResult};
    110 /// # use webauthn_rp::{
    111 /// #     request::{
    112 /// #         register::{
    113 /// #             PublicKeyCredentialCreationOptions, PublicKeyCredentialUserEntity, UserHandle,
    114 /// #         },
    115 /// #         AsciiDomain, PublicKeyCredentialDescriptor, RpId
    116 /// #     },
    117 /// #     response::{AuthTransports, CredentialId, CRED_ID_MIN_LEN},
    118 /// #     AggErr,
    119 /// # };
    120 /// # #[cfg(not(feature = "serializable_server_state"))]
    121 /// let mut ceremonies = FixedCapHashSet::new(128);
    122 /// let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
    123 /// let user_handle = get_user_handle();
    124 /// let handle = (&user_handle).into();
    125 /// let user = get_user_entity(handle)?;
    126 /// let creds = get_registered_credentials(handle)?;
    127 /// let (server, client) = PublicKeyCredentialCreationOptions::passkey(&rp_id, user.clone(), creds)
    128 ///     .start_ceremony()?;
    129 /// # #[cfg(not(feature = "serializable_server_state"))]
    130 /// assert!(matches!(
    131 ///     ceremonies.insert_or_replace_all_expired(server),
    132 ///     InsertResult::Success
    133 /// ));
    134 /// # #[cfg(feature = "serde")]
    135 /// assert!(serde_json::to_string(&client).is_ok());
    136 /// let creds_2 = get_registered_credentials(handle)?;
    137 /// let (server_2, client_2) =
    138 ///     PublicKeyCredentialCreationOptions::second_factor(&rp_id, user, creds_2).start_ceremony()?;
    139 /// # #[cfg(not(feature = "serializable_server_state"))]
    140 /// assert!(matches!(
    141 ///     ceremonies.insert_or_replace_all_expired(server_2),
    142 ///     InsertResult::Success
    143 /// ));
    144 /// # #[cfg(feature = "serde")]
    145 /// assert!(serde_json::to_string(&client_2).is_ok());
    146 /// /// Extract `UserHandle` from session cookie if this is not the first credential registered.
    147 /// fn get_user_handle() -> UserHandle<Vec<u8>> {
    148 ///     // ⋮
    149 /// #     UserHandle::new()
    150 /// }
    151 /// /// Fetch `PublicKeyCredentialUserEntity` info associated with `user`.
    152 /// ///
    153 /// /// If this is the first time a credential is being registered, then `PublicKeyCredentialUserEntity`
    154 /// /// will need to be constructed with `name` and `display_name` passed from the client and `UserHandle::new`
    155 /// /// used for `id`. Once created, this info can be stored such that the entity information
    156 /// /// does not need to be requested for subsequent registrations.
    157 /// fn get_user_entity(user: UserHandle<&[u8]>) -> Result<PublicKeyCredentialUserEntity<&[u8]>, AggErr> {
    158 ///     // ⋮
    159 /// #     Ok(PublicKeyCredentialUserEntity {
    160 /// #         name: "foo".try_into()?,
    161 /// #         id: user,
    162 /// #         display_name: None,
    163 /// #     })
    164 /// }
    165 /// /// Fetch the `PublicKeyCredentialDescriptor`s associated with `user`.
    166 /// ///
    167 /// /// This doesn't need to be called when this is the first credential registered for `user`; instead
    168 /// /// an empty `Vec` should be passed.
    169 /// fn get_registered_credentials(
    170 ///     user: UserHandle<&[u8]>,
    171 /// ) -> Result<Vec<PublicKeyCredentialDescriptor<Vec<u8>>>, AggErr> {
    172 ///     // ⋮
    173 /// #     Ok(Vec::new())
    174 /// }
    175 /// # Ok::<_, AggErr>(())
    176 /// ```
    177 pub mod register;
    178 /// Contains functionality to serialize data to a client.
    179 #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
    180 #[cfg(feature = "serde")]
    181 mod ser;
    182 /// Contains functionality to (de)serialize data needed for [`RegistrationServerState`] and
    183 /// [`AuthenticationServerState`] to a data store.
    184 #[cfg_attr(docsrs, doc(cfg(feature = "serializable_server_state")))]
    185 #[cfg(feature = "serializable_server_state")]
    186 pub(super) mod ser_server_state;
    187 // `Challenge` must _never_ be constructable directly or indirectly; thus its tuple field must always be private,
    188 // and it must never implement `trait`s (e.g., `Clone`) that would allow indirect creation. It must only ever
    189 // be constructed via `Self::new` or `Self::default`. In contrast downstream code must be able to construct
    190 // `SentChallenge` since it is used during ceremony validation; thus we must keep `Challenge` and `SentChallenge`
    191 // as separate types.
    192 /// [Cryptographic challenge](https://www.w3.org/TR/webauthn-3/#sctn-cryptographic-challenges).
    193 #[derive(Debug)]
    194 pub struct Challenge(u128);
    195 impl Challenge {
    196     // This won't `panic` since 4/3 of 16 is less than `usize::MAX`.
    197     /// The number of bytes a `Challenge` takes to encode in base64url.
    198     #[expect(clippy::unwrap_used, reason = "we want to crash when there is a bug")]
    199     pub(super) const BASE64_LEN: usize = super::base64url_nopad_len(16).unwrap();
    200     /// Returns a new `Challenge` based on a randomly-generated `u128`.
    201     ///
    202     /// # Examples
    203     ///
    204     /// ```
    205     /// # use webauthn_rp::request::Challenge;
    206     /// // The probability of a `Challenge` being 0 (assuming a good entropy
    207     /// // source) is 2^-128 ≈ 2.9 x 10^-39.
    208     /// assert_ne!(Challenge::new().into_data(), 0);
    209     /// ```
    210     #[inline]
    211     #[must_use]
    212     pub fn new() -> Self {
    213         Self(rand::random())
    214     }
    215     /// Returns the contained `u128` consuming `self`.
    216     #[inline]
    217     #[must_use]
    218     pub const fn into_data(self) -> u128 {
    219         self.0
    220     }
    221     /// Returns the contained `u128`.
    222     #[inline]
    223     #[must_use]
    224     pub const fn as_data(&self) -> u128 {
    225         self.0
    226     }
    227 }
    228 impl Default for Challenge {
    229     /// Same as [`Self::new`].
    230     #[inline]
    231     fn default() -> Self {
    232         Self::new()
    233     }
    234 }
    235 impl From<Challenge> for u128 {
    236     #[inline]
    237     fn from(value: Challenge) -> Self {
    238         value.0
    239     }
    240 }
    241 impl From<&Challenge> for u128 {
    242     #[inline]
    243     fn from(value: &Challenge) -> Self {
    244         value.0
    245     }
    246 }
    247 /// A [domain](https://url.spec.whatwg.org/#concept-domain) in representation format consisting of only and any
    248 /// ASCII.
    249 ///
    250 /// The only ASCII character disallowed in a label is `'.'` since it is used exclusively as a separator. Every
    251 /// label must have length inclusively between 1 and 63, and the total length of the domain must be at most 253
    252 /// when a trailing `'.'` does not exist; otherwise the max length is 254. The root domain (i.e., `'.'`) is not
    253 /// allowed.
    254 #[derive(Clone, Debug, Eq, PartialEq)]
    255 pub struct AsciiDomain(String);
    256 impl AsRef<str> for AsciiDomain {
    257     #[inline]
    258     fn as_ref(&self) -> &str {
    259         self.0.as_str()
    260     }
    261 }
    262 impl Borrow<str> for AsciiDomain {
    263     #[inline]
    264     fn borrow(&self) -> &str {
    265         self.0.as_str()
    266     }
    267 }
    268 impl From<AsciiDomain> for String {
    269     #[inline]
    270     fn from(value: AsciiDomain) -> Self {
    271         value.0
    272     }
    273 }
    274 impl PartialEq<&Self> for AsciiDomain {
    275     #[inline]
    276     fn eq(&self, other: &&Self) -> bool {
    277         *self == **other
    278     }
    279 }
    280 impl PartialEq<AsciiDomain> for &AsciiDomain {
    281     #[inline]
    282     fn eq(&self, other: &AsciiDomain) -> bool {
    283         **self == *other
    284     }
    285 }
    286 impl TryFrom<String> for AsciiDomain {
    287     type Error = AsciiDomainErr;
    288     /// Verifies `value` is an ASCII domain in representation format converting any uppercase ASCII into
    289     /// lowercase.
    290     ///
    291     /// Note it is _strongly_ encouraged for `value` to only contain letters, numbers, hyphens, and underscores;
    292     /// otherwise certain applications may consider it not a domain. If the original domain contains non-ASCII, then
    293     /// one must encode it in Punycode _before_ calling this function. Domains that have a trailing `'.'` will be
    294     /// considered differently than domains without it; thus one will likely want to trim it if it does exist.
    295     /// Because this allows any ASCII, one may want to ensure `value` is not an IPv4 address.
    296     ///
    297     /// # Examples
    298     ///
    299     /// ```
    300     /// # use webauthn_rp::request::{error::AsciiDomainErr, AsciiDomain};
    301     /// // Root `'.'` is not removed if it exists.
    302     /// assert_ne!("example.com", AsciiDomain::try_from("example.com.".to_owned())?.as_ref());
    303     /// // Root domain (i.e., `'.'`) is not allowed.
    304     /// assert!(AsciiDomain::try_from(".".to_owned()).is_err());
    305     /// // Uppercase is transformed into lowercase.
    306     /// assert_eq!("example.com", AsciiDomain::try_from("ExAmPle.CoM".to_owned())?.as_ref());
    307     /// // The only ASCII character not allowed in a domain label is `'.'` as it is used exclusively to delimit
    308     /// // labels.
    309     /// assert_eq!("\x00", AsciiDomain::try_from("\x00".to_owned())?.as_ref());
    310     /// // Empty labels are not allowed.
    311     /// assert!(AsciiDomain::try_from("example..com".to_owned()).is_err());
    312     /// // Labels cannot have length greater than 63.
    313     /// let mut long_label = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".to_owned();
    314     /// assert_eq!(long_label.len(), 64);
    315     /// assert!(AsciiDomain::try_from(long_label.clone()).is_err());
    316     /// long_label.pop();
    317     /// assert_eq!(long_label, AsciiDomain::try_from(long_label.clone())?.as_ref());
    318     /// // The maximum length of a domain is 254 if a trailing `'.'` exists; otherwise the max length is 253.
    319     /// let mut long_domain = format!("{long_label}.{long_label}.{long_label}.{long_label}");
    320     /// long_domain.pop();
    321     /// long_domain.push('.');
    322     /// assert_eq!(long_domain.len(), 255);
    323     /// assert!(AsciiDomain::try_from(long_domain.clone()).is_err());
    324     /// long_domain.pop();
    325     /// long_domain.pop();
    326     /// long_domain.push('.');
    327     /// assert_eq!(long_domain.len(), 254);
    328     /// assert_eq!(long_domain, AsciiDomain::try_from(long_domain.clone())?.as_ref());
    329     /// long_domain.pop();
    330     /// long_domain.push('a');
    331     /// assert_eq!(long_domain.len(), 254);
    332     /// assert!(AsciiDomain::try_from(long_domain.clone()).is_err());
    333     /// long_domain.pop();
    334     /// assert_eq!(long_domain.len(), 253);
    335     /// assert_eq!(long_domain, AsciiDomain::try_from(long_domain.clone())?.as_ref());
    336     /// // Only ASCII is allowed; thus if a domain needs to be Punycode-encoded, then it must be _before_ calling
    337     /// // this function.
    338     /// assert!(AsciiDomain::try_from("λ.com".to_owned()).is_err());
    339     /// assert_eq!("xn--wxa.com", AsciiDomain::try_from("xn--wxa.com".to_owned())?.as_ref());
    340     /// # Ok::<_, AsciiDomainErr>(())
    341     /// ```
    342     #[expect(
    343         unsafe_code,
    344         reason = "need to transform uppercase ASCII into lowercase"
    345     )]
    346     #[expect(
    347         clippy::arithmetic_side_effects,
    348         reason = "comment justifies its correctness"
    349     )]
    350     #[inline]
    351     fn try_from(mut value: String) -> Result<Self, Self::Error> {
    352         value
    353             .as_bytes()
    354             .last()
    355             .ok_or(AsciiDomainErr::Empty)
    356             .and_then(|b| {
    357                 let len = value.len();
    358                 if *b == b'.' {
    359                     if len == 1 {
    360                         Err(AsciiDomainErr::RootDomain)
    361                     } else if len > 254 {
    362                         Err(AsciiDomainErr::Len)
    363                     } else {
    364                         Ok(())
    365                     }
    366                 } else if len > 253 {
    367                     Err(AsciiDomainErr::Len)
    368                 } else {
    369                     Ok(())
    370                 }
    371             })
    372             .and_then(|()| {
    373                 // SAFETY:
    374                 // The only possible mutation we perform is converting uppercase ASCII into lowercase which
    375                 // is entirely safe since ASCII is a subset of UTF-8, and ASCII characters are always encoded
    376                 // as a single UTF-8 code unit.
    377                 let utf8 = unsafe { value.as_bytes_mut() };
    378                 utf8.iter_mut()
    379                     .try_fold(0u8, |label_len, byt| {
    380                         let b = *byt;
    381                         if b == b'.' {
    382                             if label_len == 0 {
    383                                 Err(AsciiDomainErr::EmptyLabel)
    384                             } else {
    385                                 Ok(0)
    386                             }
    387                         } else if label_len == 63 {
    388                             Err(AsciiDomainErr::LabelLen)
    389                         } else if b.is_ascii() {
    390                             *byt = b.to_ascii_lowercase();
    391                             // This won't overflow since `label_len < 63`.
    392                             Ok(label_len + 1)
    393                         } else {
    394                             Err(AsciiDomainErr::NotAscii)
    395                         }
    396                     })
    397                     .map(|_| Self(value))
    398             })
    399     }
    400 }
    401 /// The output of the [URL serializer](https://url.spec.whatwg.org/#concept-url-serializer).
    402 ///
    403 /// The returned URL must consist of a [scheme](https://url.spec.whatwg.org/#concept-url-scheme) and
    404 /// optional [path](https://url.spec.whatwg.org/#url-path) but nothing else.
    405 #[derive(Clone, Debug, Eq, PartialEq)]
    406 pub struct Url(String);
    407 impl AsRef<str> for Url {
    408     #[inline]
    409     fn as_ref(&self) -> &str {
    410         self.0.as_str()
    411     }
    412 }
    413 impl Borrow<str> for Url {
    414     #[inline]
    415     fn borrow(&self) -> &str {
    416         self.0.as_str()
    417     }
    418 }
    419 impl From<Url> for String {
    420     #[inline]
    421     fn from(value: Url) -> Self {
    422         value.0
    423     }
    424 }
    425 impl PartialEq<&Self> for Url {
    426     #[inline]
    427     fn eq(&self, other: &&Self) -> bool {
    428         *self == **other
    429     }
    430 }
    431 impl PartialEq<Url> for &Url {
    432     #[inline]
    433     fn eq(&self, other: &Url) -> bool {
    434         **self == *other
    435     }
    436 }
    437 impl FromStr for Url {
    438     type Err = UrlErr;
    439     #[inline]
    440     fn from_str(s: &str) -> Result<Self, Self::Err> {
    441         Uri::from_str(s).map_err(|_e| UrlErr).and_then(|url| {
    442             if url.scheme().is_empty()
    443                 || url.has_host()
    444                 || url.query().is_some()
    445                 || url.fragment().is_some()
    446             {
    447                 Err(UrlErr)
    448             } else {
    449                 Ok(Self(url.into()))
    450             }
    451         })
    452     }
    453 }
    454 /// [RP ID](https://w3c.github.io/webauthn/#rp-id).
    455 #[derive(Clone, Debug, Eq, PartialEq)]
    456 pub enum RpId {
    457     /// An ASCII domain.
    458     ///
    459     /// Note web platforms MUST use this variant; and if possible, non-web platforms should too. Also despite
    460     /// the spec currently requiring RP IDs to be
    461     /// [valid domain strings](https://url.spec.whatwg.org/#valid-domain-string), this is unnecessarily strict
    462     /// and will likely be relaxed in a [future version](https://github.com/w3c/webauthn/issues/2206); thus
    463     /// any ASCII domain is allowed.
    464     Domain(AsciiDomain),
    465     /// A URL with only scheme and path.
    466     Url(Url),
    467 }
    468 impl RpId {
    469     /// Validates `hash` is the same as the SHA-256 hash of `self`.
    470     fn validate_rp_id_hash<E>(&self, hash: &[u8]) -> Result<(), CeremonyErr<E>> {
    471         if hash == Sha256::digest(self.as_ref()).as_slice() {
    472             Ok(())
    473         } else {
    474             Err(CeremonyErr::RpIdHashMismatch)
    475         }
    476     }
    477 }
    478 impl AsRef<str> for RpId {
    479     #[inline]
    480     fn as_ref(&self) -> &str {
    481         match *self {
    482             Self::Domain(ref dom) => dom.as_ref(),
    483             Self::Url(ref url) => url.as_ref(),
    484         }
    485     }
    486 }
    487 impl Borrow<str> for RpId {
    488     #[inline]
    489     fn borrow(&self) -> &str {
    490         match *self {
    491             Self::Domain(ref dom) => dom.borrow(),
    492             Self::Url(ref url) => url.borrow(),
    493         }
    494     }
    495 }
    496 impl From<RpId> for String {
    497     #[inline]
    498     fn from(value: RpId) -> Self {
    499         match value {
    500             RpId::Domain(dom) => dom.into(),
    501             RpId::Url(url) => url.into(),
    502         }
    503     }
    504 }
    505 impl PartialEq<&Self> for RpId {
    506     #[inline]
    507     fn eq(&self, other: &&Self) -> bool {
    508         *self == **other
    509     }
    510 }
    511 impl PartialEq<RpId> for &RpId {
    512     #[inline]
    513     fn eq(&self, other: &RpId) -> bool {
    514         **self == *other
    515     }
    516 }
    517 /// A URI scheme. This can be used to make
    518 /// [origin validation](https://www.w3.org/TR/webauthn-3/#sctn-validating-origin) more convenient.
    519 #[derive(Clone, Copy, Debug, Default)]
    520 pub enum Scheme<'a> {
    521     /// A scheme must not exist when validating the origin.
    522     None,
    523     /// Any scheme, or no scheme at all, is allowed to exist when validating the origin.
    524     Any,
    525     /// The HTTPS scheme must exist when validating the origin.
    526     #[default]
    527     Https,
    528     /// The SSH scheme must exist when validating the origin.
    529     Ssh,
    530     /// The contained `str` scheme must exist when validating the origin.
    531     Other(&'a str),
    532     /// [`Self::None`] or [`Self::Https`].
    533     NoneHttps,
    534     /// [`Self::None`] or [`Self::Ssh`].
    535     NoneSsh,
    536     /// [`Self::None`] or [`Self::Other`].
    537     NoneOther(&'a str),
    538 }
    539 impl Scheme<'_> {
    540     /// `self` is any `Scheme`; however `other` is assumed to only be a `Scheme` from a `DomainOrigin` returned
    541     /// from `DomainOrigin::try_from`. The latter implies that `other` is only `Scheme::None`, `Scheme::Https`,
    542     /// `Scheme::Ssh`, or `Scheme::Other`; furthermore when `Scheme::Other`, it won't contain a `str` that is
    543     /// empty or equal to "https" or "ssh".
    544     #[expect(clippy::unreachable, reason = "there is a bug, so we want to crash")]
    545     fn is_equal_to_origin_scheme(self, other: Self) -> bool {
    546         match self {
    547             Self::None => matches!(other, Self::None),
    548             Self::Any => true,
    549             Self::Https => matches!(other, Self::Https),
    550             Self::Ssh => matches!(other, Self::Ssh),
    551             Self::Other(scheme) => match other {
    552                 Self::None => false,
    553                 // We want to crash and burn since there is a bug in code.
    554                 Self::Any | Self::NoneHttps | Self::NoneSsh | Self::NoneOther(_) => {
    555                     unreachable!("there is a bug in DomainOrigin::try_from")
    556                 }
    557                 Self::Https => scheme == "https",
    558                 Self::Ssh => scheme == "ssh",
    559                 Self::Other(scheme_other) => scheme == scheme_other,
    560             },
    561             Self::NoneHttps => match other {
    562                 Self::None | Self::Https => true,
    563                 Self::Ssh | Self::Other(_) => false,
    564                 // We want to crash and burn since there is a bug in code.
    565                 Self::Any | Self::NoneHttps | Self::NoneSsh | Self::NoneOther(_) => {
    566                     unreachable!("there is a bug in DomainOrigin::try_from")
    567                 }
    568             },
    569             Self::NoneSsh => match other {
    570                 Self::None | Self::Ssh => true,
    571                 // We want to crash and burn since there is a bug in code.
    572                 Self::Any | Self::NoneHttps | Self::NoneSsh | Self::NoneOther(_) => {
    573                     unreachable!("there is a bug in DomainOrigin::try_from")
    574                 }
    575                 Self::Https | Self::Other(_) => false,
    576             },
    577             Self::NoneOther(scheme) => match other {
    578                 Self::None => true,
    579                 // We want to crash and burn since there is a bug in code.
    580                 Self::Any | Self::NoneHttps | Self::NoneSsh | Self::NoneOther(_) => {
    581                     unreachable!("there is a bug in DomainOrigin::try_from")
    582                 }
    583                 Self::Https => scheme == "https",
    584                 Self::Ssh => scheme == "ssh",
    585                 Self::Other(scheme_other) => scheme == scheme_other,
    586             },
    587         }
    588     }
    589 }
    590 impl<'a: 'b, 'b> TryFrom<&'a str> for Scheme<'b> {
    591     type Error = SchemeParseErr;
    592     /// `"https"` and `"ssh"` get mapped to [`Self::Https`] and [`Self::Ssh`] respectively. All other
    593     /// values get mapped to [`Self::Other`].
    594     ///
    595     /// # Errors
    596     ///
    597     /// Errors iff `s` is empty.
    598     ///
    599     /// # Examples
    600     ///
    601     /// ```
    602     /// # use webauthn_rp::request::Scheme;
    603     /// assert!(matches!(Scheme::try_from("https")?, Scheme::Https));
    604     /// assert!(matches!(Scheme::try_from("https ")?, Scheme::Other(scheme) if scheme == "https "));
    605     /// assert!(matches!(Scheme::try_from("ssh")?, Scheme::Ssh));
    606     /// assert!(matches!(Scheme::try_from("Ssh")?, Scheme::Other(scheme) if scheme == "Ssh"));
    607     /// // Even though one can construct an empty `Scheme` via `Scheme::Other` or `Scheme::NoneOther`,
    608     /// // one cannot parse one.
    609     /// assert!(Scheme::try_from("").is_err());
    610     /// # Ok::<_, webauthn_rp::AggErr>(())
    611     /// ```
    612     #[inline]
    613     fn try_from(value: &'a str) -> Result<Self, Self::Error> {
    614         match value {
    615             "" => Err(SchemeParseErr),
    616             "https" => Ok(Self::Https),
    617             "ssh" => Ok(Self::Ssh),
    618             _ => Ok(Self::Other(value)),
    619         }
    620     }
    621 }
    622 /// A TCP/UDP port. This can be used to make
    623 /// [origin validation](https://www.w3.org/TR/webauthn-3/#sctn-validating-origin) more convenient.
    624 #[derive(Clone, Copy, Debug, Default)]
    625 pub enum Port {
    626     /// A port must not exist when validating the origin.
    627     #[default]
    628     None,
    629     /// Any port, or no port at all, is allowed to exist when validating the origin.
    630     Any,
    631     /// The contained `u16` port must exist when validating the origin.
    632     Val(u16),
    633     /// [`Self::None`] or [`Self::Val`].
    634     NoneVal(u16),
    635 }
    636 impl Port {
    637     /// `self` is any `Port`; however `other` is assumed to only be a `Port` from a `DomainOrigin` returned
    638     /// from `DomainOrigin::try_from`. The latter implies that `other` is only `Port::None` or `Port::Val`.
    639     #[expect(clippy::unreachable, reason = "there is a bug, so we want to crash")]
    640     fn is_equal_to_origin_port(self, other: Self) -> bool {
    641         match self {
    642             Self::None => matches!(other, Self::None),
    643             Self::Any => true,
    644             Self::Val(port) => match other {
    645                 Self::None => false,
    646                 // There is a bug in code so we want to crash and burn.
    647                 Self::Any | Self::NoneVal(_) => {
    648                     unreachable!("there is a bug in DomainOrigin::try_from")
    649                 }
    650                 Self::Val(port_other) => port == port_other,
    651             },
    652             Self::NoneVal(port) => match other {
    653                 Self::None => true,
    654                 // There is a bug in code so we want to crash and burn.
    655                 Self::Any | Self::NoneVal(_) => {
    656                     unreachable!("there is a bug in DomainOrigin::try_from")
    657                 }
    658                 Self::Val(port_other) => port == port_other,
    659             },
    660         }
    661     }
    662 }
    663 impl FromStr for Port {
    664     type Err = PortParseErr;
    665     /// Parses `s` as a 16-bit unsigned integer without leading 0s returning [`Self::Val`] with the contained
    666     /// `u16`.
    667     ///
    668     /// # Errors
    669     ///
    670     /// Errors iff `s` is not a valid 16-bit unsigned integer in decimal notation without leading 0s.
    671     ///
    672     /// # Examples
    673     ///
    674     /// ```
    675     /// # use webauthn_rp::request::{error::PortParseErr, Port};
    676     /// assert!(matches!("443".parse()?, Port::Val(443)));
    677     /// // TCP/UDP ports have to be in canonical form:
    678     /// assert!("022"
    679     ///     .parse::<Port>()
    680     ///     .map_or_else(|err| matches!(err, PortParseErr::NotCanonical), |_| false));
    681     /// # Ok::<_, webauthn_rp::AggErr>(())
    682     /// ```
    683     #[inline]
    684     fn from_str(s: &str) -> Result<Self, Self::Err> {
    685         s.parse().map_err(PortParseErr::ParseInt).and_then(|port| {
    686             if s.len()
    687                 == match port {
    688                     ..=9 => 1,
    689                     10..=99 => 2,
    690                     100..=999 => 3,
    691                     1_000..=9_999 => 4,
    692                     10_000.. => 5,
    693                 }
    694             {
    695                 Ok(Self::Val(port))
    696             } else {
    697                 Err(PortParseErr::NotCanonical)
    698             }
    699         })
    700     }
    701 }
    702 /// A [`tuple origin`](https://html.spec.whatwg.org/multipage/browsers.html#concept-origin-tuple).
    703 ///
    704 /// This can be used to make [origin validation](https://www.w3.org/TR/webauthn-3/#sctn-validating-origin)
    705 /// more convenient.
    706 #[derive(Clone, Copy, Debug)]
    707 pub struct DomainOrigin<'a, 'b> {
    708     /// The scheme.
    709     pub scheme: Scheme<'a>,
    710     /// The host.
    711     pub host: &'b str,
    712     /// The TCP/UDP port.
    713     pub port: Port,
    714 }
    715 impl<'b> DomainOrigin<'_, 'b> {
    716     /// Returns a `DomainOrigin` with [`Self::scheme`] as [`Scheme::Https`], [`Self::host`] as `host`, and
    717     /// [`Self::port`] as [`Port::None`].
    718     ///
    719     /// # Examples
    720     ///
    721     /// ```
    722     /// # extern crate alloc;
    723     /// # use alloc::borrow::Cow;
    724     /// # use webauthn_rp::{request::DomainOrigin, response::Origin};
    725     /// assert_eq!(
    726     ///     DomainOrigin::new("www.example.com"),
    727     ///     Origin(Cow::Borrowed("https://www.example.com"))
    728     /// );
    729     /// // `DomainOrigin::new` does not allow _any_ port to exist.
    730     /// assert_ne!(
    731     ///     DomainOrigin::new("www.example.com"),
    732     ///     Origin(Cow::Borrowed("https://www.example.com:443"))
    733     /// );
    734     /// ```
    735     #[must_use]
    736     #[inline]
    737     pub const fn new<'c: 'b>(host: &'c str) -> Self {
    738         Self {
    739             scheme: Scheme::Https,
    740             host,
    741             port: Port::None,
    742         }
    743     }
    744     /// Returns a `DomainOrigin` with [`Self::scheme`] as [`Scheme::Https`], [`Self::host`] as `host`, and
    745     /// [`Self::port`] as [`Port::Any`].
    746     ///
    747     /// # Examples
    748     ///
    749     /// ```
    750     /// # extern crate alloc;
    751     /// # use alloc::borrow::Cow;
    752     /// # use webauthn_rp::{request::DomainOrigin, response::Origin};
    753     /// // Any port is allowed to exist.
    754     /// assert_eq!(
    755     ///     DomainOrigin::new_ignore_port("www.example.com"),
    756     ///     Origin(Cow::Borrowed("https://www.example.com:1234"))
    757     /// );
    758     /// // A port doesn't have to exist at all either.
    759     /// assert_eq!(
    760     ///     DomainOrigin::new_ignore_port("www.example.com"),
    761     ///     Origin(Cow::Borrowed("https://www.example.com"))
    762     /// );
    763     /// ```
    764     #[must_use]
    765     #[inline]
    766     pub const fn new_ignore_port<'c: 'b>(host: &'c str) -> Self {
    767         Self {
    768             scheme: Scheme::Https,
    769             host,
    770             port: Port::Any,
    771         }
    772     }
    773 }
    774 impl PartialEq<Origin<'_>> for DomainOrigin<'_, '_> {
    775     /// Returns `true` iff [`DomainOrigin::scheme`], [`DomainOrigin::host`], and [`DomainOrigin::port`] are the
    776     /// same after calling [`DomainOrigin::try_from`] on `other.0.as_str()`.
    777     ///
    778     /// Note that [`Scheme`] and [`Port`] need not be the same variant. For example [`Scheme::Https`] and
    779     /// [`Scheme::Other`] containing `"https"` will be treated the same.
    780     #[inline]
    781     fn eq(&self, other: &Origin<'_>) -> bool {
    782         DomainOrigin::try_from(other.0.as_ref()).is_ok_and(|dom| {
    783             self.scheme.is_equal_to_origin_scheme(dom.scheme)
    784                 && self.host == dom.host
    785                 && self.port.is_equal_to_origin_port(dom.port)
    786         })
    787     }
    788 }
    789 impl PartialEq<Origin<'_>> for &DomainOrigin<'_, '_> {
    790     #[inline]
    791     fn eq(&self, other: &Origin<'_>) -> bool {
    792         **self == *other
    793     }
    794 }
    795 impl PartialEq<&Origin<'_>> for DomainOrigin<'_, '_> {
    796     #[inline]
    797     fn eq(&self, other: &&Origin<'_>) -> bool {
    798         *self == **other
    799     }
    800 }
    801 impl PartialEq<DomainOrigin<'_, '_>> for Origin<'_> {
    802     #[inline]
    803     fn eq(&self, other: &DomainOrigin<'_, '_>) -> bool {
    804         *other == *self
    805     }
    806 }
    807 impl PartialEq<DomainOrigin<'_, '_>> for &Origin<'_> {
    808     #[inline]
    809     fn eq(&self, other: &DomainOrigin<'_, '_>) -> bool {
    810         *other == **self
    811     }
    812 }
    813 impl PartialEq<&DomainOrigin<'_, '_>> for Origin<'_> {
    814     #[inline]
    815     fn eq(&self, other: &&DomainOrigin<'_, '_>) -> bool {
    816         **other == *self
    817     }
    818 }
    819 impl<'a: 'b + 'c, 'b, 'c> TryFrom<&'a str> for DomainOrigin<'b, 'c> {
    820     type Error = DomainOriginParseErr;
    821     /// `value` is parsed according to the following extended regex:
    822     ///
    823     /// `^([^:]*:\/\/)?[^:]*(:.*)?$`
    824     ///
    825     /// where the `[^:]*` of the first capturing group is parsed according to [`Scheme::try_from`], and
    826     /// the `.*` of the second capturing group is parsed according to [`Port::from_str`].
    827     ///
    828     /// # Errors
    829     ///
    830     /// Errors iff `Scheme::try_from` or `Port::from_str` fail when applicable.
    831     ///
    832     /// # Examples
    833     ///
    834     /// ```
    835     /// # use webauthn_rp::request::{DomainOrigin, Port, Scheme};
    836     /// assert!(
    837     ///     DomainOrigin::try_from("https://www.example.com:443").map_or(false, |dom| matches!(
    838     ///         dom.scheme,
    839     ///         Scheme::Https
    840     ///     ) && dom.host
    841     ///         == "www.example.com"
    842     ///         && matches!(dom.port, Port::Val(port) if port == 443))
    843     /// );
    844     /// // Parsing is done in a case sensitive way.
    845     /// assert!(DomainOrigin::try_from("Https://www.EXample.com").map_or(
    846     ///     false,
    847     ///     |dom| matches!(dom.scheme, Scheme::Other(scheme) if scheme == "Https")
    848     ///         && dom.host == "www.EXample.com"
    849     ///         && matches!(dom.port, Port::None)
    850     /// ));
    851     /// ```
    852     #[inline]
    853     fn try_from(value: &'a str) -> Result<Self, Self::Error> {
    854         // Any string that contains `':'` is not a [valid domain](https://url.spec.whatwg.org/#valid-domain), and
    855         // and `"//"` never exists in a `Port`; thus if `"://"` exists, it's either invalid or delimits the scheme
    856         // from the rest of the origin.
    857         match value.split_once("://") {
    858             None => Ok((Scheme::None, value)),
    859             Some((poss_scheme, rem)) => Scheme::try_from(poss_scheme)
    860                 .map_err(DomainOriginParseErr::Scheme)
    861                 .map(|scheme| (scheme, rem)),
    862         }
    863         .and_then(|(scheme, rem)| {
    864             // `':'` never exists in a valid domain; thus if it exists, it's either invalid or
    865             // separates the domain from the port.
    866             rem.split_once(':')
    867                 .map_or_else(
    868                     || Ok((rem, Port::None)),
    869                     |(rem2, poss_port)| {
    870                         Port::from_str(poss_port)
    871                             .map_err(DomainOriginParseErr::Port)
    872                             .map(|port| (rem2, port))
    873                     },
    874                 )
    875                 .map(|(host, port)| Self { scheme, host, port })
    876         })
    877     }
    878 }
    879 /// [`PublicKeyCredentialDescriptor`](https://www.w3.org/TR/webauthn-3/#dictdef-publickeycredentialdescriptor)
    880 /// associated with a registered credential.
    881 #[derive(Debug)]
    882 pub struct PublicKeyCredentialDescriptor<T> {
    883     /// [`id`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialdescriptor-id).
    884     pub id: CredentialId<T>,
    885     /// [`transports`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialdescriptor-transports).
    886     pub transports: AuthTransports,
    887 }
    888 /// [`UserVerificationRequirement`](https://www.w3.org/TR/webauthn-3/#enumdef-userverificationrequirement).
    889 #[derive(Clone, Copy, Debug)]
    890 pub enum UserVerificationRequirement {
    891     /// [`required`](https://www.w3.org/TR/webauthn-3/#dom-userverificationrequirement-required).
    892     Required,
    893     /// [`discouraged`](https://www.w3.org/TR/webauthn-3/#dom-userverificationrequirement-discouraged).
    894     ///
    895     /// Note some authenticators always require user verification when registering a credential (e.g.,
    896     /// [CTAP 2.0](https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html)
    897     /// authenticators that have had a PIN enabled).
    898     Discouraged,
    899     /// [`preferred`](https://www.w3.org/TR/webauthn-3/#dom-userverificationrequirement-preferred).
    900     Preferred,
    901 }
    902 /// [`PublicKeyCredentialHints`](https://www.w3.org/TR/webauthn-3/#enumdef-publickeycredentialhints).
    903 #[derive(Clone, Copy, Debug, Default)]
    904 pub enum Hint {
    905     /// No hints.
    906     #[default]
    907     None,
    908     /// [`security-key`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialhints-security-key).
    909     SecurityKey,
    910     /// [`client-device`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialhints-client-device).
    911     ClientDevice,
    912     /// [`hybrid`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialhints-hybrid).
    913     Hybrid,
    914     /// [`Self::SecurityKey`] and [`Self::ClientDevice`].
    915     SecurityKeyClientDevice,
    916     /// [`Self::ClientDevice`] and [`Self::SecurityKey`].
    917     ClientDeviceSecurityKey,
    918     /// [`Self::SecurityKey`] and [`Self::Hybrid`].
    919     SecurityKeyHybrid,
    920     /// [`Self::Hybrid`] and [`Self::SecurityKey`].
    921     HybridSecurityKey,
    922     /// [`Self::ClientDevice`] and [`Self::Hybrid`].
    923     ClientDeviceHybrid,
    924     /// [`Self::Hybrid`] and [`Self::ClientDevice`].
    925     HybridClientDevice,
    926     /// [`Self::SecurityKeyClientDevice`] and [`Self::Hybrid`].
    927     SecurityKeyClientDeviceHybrid,
    928     /// [`Self::SecurityKeyHybrid`] and [`Self::ClientDevice`].
    929     SecurityKeyHybridClientDevice,
    930     /// [`Self::ClientDeviceSecurityKey`] and [`Self::Hybrid`].
    931     ClientDeviceSecurityKeyHybrid,
    932     /// [`Self::ClientDeviceHybrid`] and [`Self::SecurityKey`].
    933     ClientDeviceHybridSecurityKey,
    934     /// [`Self::HybridSecurityKey`] and [`Self::ClientDevice`].
    935     HybridSecurityKeyClientDevice,
    936     /// [`Self::HybridClientDevice`] and [`Self::SecurityKey`].
    937     HybridClientDeviceSecurityKey,
    938 }
    939 /// Controls if the response to a requested extension is required to be sent back.
    940 ///
    941 /// Note when requiring an extension, the extension must not only be sent back but also
    942 /// contain at least one expected field
    943 /// (e.g., [`ClientExtensionsOutputs::cred_props`] must be
    944 /// `Some(CredentialPropertiesOutput { rk: Some(_) })`.
    945 ///
    946 /// If one wants to additionally control the values of an extension, use [`ExtensionInfo`].
    947 #[derive(Clone, Copy, Debug)]
    948 pub enum ExtensionReq {
    949     /// The response to a requested extension is required to be sent back.
    950     Require,
    951     /// The response to a requested extension is allowed, but not required, to be sent back.
    952     Allow,
    953 }
    954 /// Dictates how an extension should be processed.
    955 ///
    956 /// If one wants to only control if the extension should be returned, use [`ExtensionReq`].
    957 #[derive(Clone, Copy, Debug)]
    958 pub enum ExtensionInfo {
    959     /// Require the associated extension and enforce its value.
    960     RequireEnforceValue,
    961     /// Require the associated extension but don't enforce its value.
    962     RequireDontEnforceValue,
    963     /// Allow the associated extension to exist and enforce its value when it does exist.
    964     AllowEnforceValue,
    965     /// Allow the associated extension to exist but don't enforce its value.
    966     AllowDontEnforceValue,
    967 }
    968 impl Display for ExtensionInfo {
    969     #[inline]
    970     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    971         f.write_str(match *self {
    972             Self::RequireEnforceValue => "require the corresponding extension response and enforce its value",
    973             Self::RequireDontEnforceValue => "require the corresponding extension response but don't enforce its value",
    974             Self::AllowEnforceValue => "don't require the corresponding extension response; but if sent, enforce its value",
    975             Self::AllowDontEnforceValue => "don't require the corresponding extension response; and if sent, don't enforce its value",
    976         })
    977     }
    978 }
    979 /// [`CredentialMediationRequirement`](https://www.w3.org/TR/credential-management-1/#enumdef-credentialmediationrequirement).
    980 #[derive(Clone, Copy, Debug)]
    981 pub enum CredentialMediationRequirement {
    982     /// [`silent`](https://www.w3.org/TR/credential-management-1/#dom-credentialmediationrequirement-silent).
    983     Silent,
    984     /// [`optional`](https://www.w3.org/TR/credential-management-1/#dom-credentialmediationrequirement-optional)
    985     Optional,
    986     /// [`conditional`](https://www.w3.org/TR/credential-management-1/#dom-credentialmediationrequirement-conditional)
    987     ///
    988     /// Note that when registering a new credential with [`PublicKeyCredentialCreationOptions::mediation`] set to
    989     /// `Self::Conditional`, [`UserVerificationRequirement::Discouraged`] MUST be used unless user verification
    990     /// can be explicitly performed during the ceremony.
    991     Conditional,
    992     /// [`required`](https://www.w3.org/TR/credential-management-1/#dom-credentialmediationrequirement-required)
    993     Required,
    994 }
    995 /// Backup requirements for the credential.
    996 #[derive(Clone, Copy, Debug, Default)]
    997 pub enum BackupReq {
    998     #[default]
    999     /// No requirements (i.e., any [`Backup`] is allowed).
   1000     None,
   1001     /// Credential must not be eligible for backup.
   1002     NotEligible,
   1003     /// Credential must be eligible for backup.
   1004     ///
   1005     /// Note the existence of a backup is ignored. If a backup must exist, then use [`Self::Exists`].
   1006     Eligible,
   1007     /// Credential must be backed up.
   1008     Exists,
   1009 }
   1010 impl From<Backup> for BackupReq {
   1011     /// One may want to create `BackupReq` based on the previous `Backup` such that the subsequent `Backup` is
   1012     /// essentially unchanged.
   1013     ///
   1014     /// Specifically this transforms [`Backup::NotEligible`] to [`Self::NotEligible`] and [`Backup::Eligible`] and
   1015     /// [`Backup::Exists`] to [`Self::Eligible`]. Note this means that a credential that
   1016     /// is eligible to be backed up but currently does not have a backup will be allowed to change such that it
   1017     /// is backed up. Similarly, a credential that is backed up is allowed to change such that a backup no longer
   1018     /// exists.
   1019     #[inline]
   1020     fn from(value: Backup) -> Self {
   1021         if matches!(value, Backup::NotEligible) {
   1022             Self::NotEligible
   1023         } else {
   1024             Self::Eligible
   1025         }
   1026     }
   1027 }
   1028 /// A container of "credentials".
   1029 ///
   1030 /// This is mainly a way to unify [`Vec`] of [`PublicKeyCredentialDescriptor`]
   1031 /// and [`AllowedCredentials`]. This can be useful in situations when one only
   1032 /// deals with [`AllowedCredential`]s with empty [`CredentialSpecificExtension`]s
   1033 /// essentially making them the same as [`PublicKeyCredentialDescriptor`]s.
   1034 ///
   1035 /// # Examples
   1036 ///
   1037 /// ```
   1038 /// # use webauthn_rp::{
   1039 /// #     request::{
   1040 /// #         auth::AllowedCredentials, register::UserHandle, Credentials, PublicKeyCredentialDescriptor,
   1041 /// #     },
   1042 /// #     response::{AuthTransports, CredentialId},
   1043 /// # };
   1044 /// /// Fetches all credentials under `user_handle` to be allowed during authentication for non-discoverable
   1045 /// /// requests.
   1046 /// # #[cfg(feature = "custom")]
   1047 /// fn get_allowed_credentials(user_handle: UserHandle<&[u8]>) -> AllowedCredentials {
   1048 ///     get_credentials(user_handle)
   1049 /// }
   1050 /// /// Fetches all credentials under `user_handle` to be excluded during registration.
   1051 /// # #[cfg(feature = "custom")]
   1052 /// fn get_excluded_credentials(
   1053 ///     user_handle: UserHandle<&[u8]>,
   1054 /// ) -> Vec<PublicKeyCredentialDescriptor<Vec<u8>>> {
   1055 ///     get_credentials(user_handle)
   1056 /// }
   1057 /// /// Used to fetch the excluded `PublicKeyCredentialDescriptor`s associated with `user_handle` during
   1058 /// /// registration as well as the `AllowedCredentials` containing `AllowedCredential`s with no credential-specific
   1059 /// /// extensions which is used for non-discoverable requests.
   1060 /// # #[cfg(feature = "custom")]
   1061 /// fn get_credentials<T>(user_handle: UserHandle<&[u8]>) -> T
   1062 /// where
   1063 ///     T: Credentials,
   1064 ///     PublicKeyCredentialDescriptor<Vec<u8>>: Into<T::Credential>,
   1065 /// {
   1066 ///     let iter = get_cred_parts(user_handle);
   1067 ///     let len = iter.size_hint().0;
   1068 ///     iter.fold(T::with_capacity(len), |mut creds, parts| {
   1069 ///         creds.push(
   1070 ///             PublicKeyCredentialDescriptor {
   1071 ///                 id: parts.0,
   1072 ///                 transports: parts.1,
   1073 ///             }
   1074 ///             .into(),
   1075 ///         );
   1076 ///         creds
   1077 ///     })
   1078 /// }
   1079 /// /// Fetches all `CredentialId`s and associated `AuthTransports` under `user_handle`
   1080 /// /// from the database.
   1081 /// # #[cfg(feature = "custom")]
   1082 /// fn get_cred_parts(
   1083 ///     user_handle: UserHandle<&[u8]>,
   1084 /// ) -> impl Iterator<Item = (CredentialId<Vec<u8>>, AuthTransports)> {
   1085 ///     // ⋮
   1086 /// #     [(
   1087 /// #         CredentialId::try_from(vec![0; 16]).unwrap(),
   1088 /// #         AuthTransports::NONE,
   1089 /// #     )]
   1090 /// #     .into_iter()
   1091 /// }
   1092 /// ```
   1093 pub trait Credentials: Sized {
   1094     /// The "credential"s that make up `Self`.
   1095     type Credential;
   1096     /// Returns `Self`.
   1097     #[inline]
   1098     #[must_use]
   1099     fn new() -> Self {
   1100         Self::with_capacity(0)
   1101     }
   1102     /// Returns `Self` with at least `capacity` allocated.
   1103     fn with_capacity(capacity: usize) -> Self;
   1104     /// Adds `cred` to `self`.
   1105     ///
   1106     /// Returns `true` iff `cred` was added.
   1107     fn push(&mut self, cred: Self::Credential) -> bool;
   1108     /// Returns the number of [`Self::Credential`]s in `Self`.
   1109     fn len(&self) -> usize;
   1110     /// Returns `true` iff [`Self::len`] is `0`.
   1111     #[inline]
   1112     fn is_empty(&self) -> bool {
   1113         self.len() == 0
   1114     }
   1115 }
   1116 impl<T> Credentials for Vec<T> {
   1117     type Credential = T;
   1118     #[inline]
   1119     fn with_capacity(capacity: usize) -> Self {
   1120         Self::with_capacity(capacity)
   1121     }
   1122     #[inline]
   1123     fn push(&mut self, cred: Self::Credential) -> bool {
   1124         self.push(cred);
   1125         true
   1126     }
   1127     #[inline]
   1128     fn len(&self) -> usize {
   1129         self.len()
   1130     }
   1131 }
   1132 /// Additional options that control how [`Ceremony::partial_validate`] works.
   1133 struct CeremonyOptions<'origins, 'top_origins, O, T> {
   1134     /// Origins to use for [origin validation](https://www.w3.org/TR/webauthn-3/#sctn-validating-origin).
   1135     ///
   1136     /// When this is empty, the origin that will be used will be based on
   1137     /// the [`RpId`] passed to [`RegistrationServerState::verify`]. If [`RpId::Domain`], then the [`DomainOrigin`] returned from
   1138     /// passing [`AsciiDomain::as_ref`] to [`DomainOrigin::new`] will be used; otherwise the [`Url`] in
   1139     /// [`RpId::Url`] will be used.
   1140     allowed_origins: &'origins [O],
   1141     /// [Top-level origins](https://html.spec.whatwg.org/multipage/webappapis.html#concept-environment-top-level-origin)
   1142     /// to use for [origin validation](https://www.w3.org/TR/webauthn-3/#sctn-validating-origin).
   1143     ///
   1144     /// When this is `Some`, [`CollectedClientData::cross_origin`] is allowed to be `true`. When the contained
   1145     /// `slice` is empty, [`CollectedClientData::top_origin`] must be `None`. When this is `None`,
   1146     /// `CollectedClientData::cross_origin` must be `false` and `CollectedClientData::top_origin` must be `None`.
   1147     allowed_top_origins: Option<&'top_origins [T]>,
   1148     /// The required [`Backup`] state of the credential.
   1149     backup_requirement: BackupReq,
   1150     /// [`CollectedClientData::from_client_data_json_relaxed`] is used to extract [`CollectedClientData`] iff `true`.
   1151     #[cfg(feature = "serde_relaxed")]
   1152     client_data_json_relaxed: bool,
   1153 }
   1154 impl<'o, 't, O, T> From<&RegistrationVerificationOptions<'o, 't, O, T>>
   1155     for CeremonyOptions<'o, 't, O, T>
   1156 {
   1157     fn from(value: &RegistrationVerificationOptions<'o, 't, O, T>) -> Self {
   1158         Self {
   1159             allowed_origins: value.allowed_origins,
   1160             allowed_top_origins: value.allowed_top_origins,
   1161             backup_requirement: value.backup_requirement,
   1162             #[cfg(feature = "serde_relaxed")]
   1163             client_data_json_relaxed: value.client_data_json_relaxed,
   1164         }
   1165     }
   1166 }
   1167 /// Functionality common to both registration and authentication ceremonies.
   1168 ///
   1169 /// Designed to be implemented on the _request_ side.
   1170 trait Ceremony {
   1171     /// The type of response that is associated with the ceremony.
   1172     type R: Response;
   1173     /// Challenge.
   1174     fn rand_challenge(&self) -> SentChallenge;
   1175     /// `Instant` the ceremony was expires.
   1176     #[cfg(not(feature = "serializable_server_state"))]
   1177     fn expiry(&self) -> Instant;
   1178     /// `Instant` the ceremony was expires.
   1179     #[cfg(feature = "serializable_server_state")]
   1180     fn expiry(&self) -> SystemTime;
   1181     /// User verification requirement.
   1182     fn user_verification(&self) -> UserVerificationRequirement;
   1183     /// Performs validation of ceremony criteria common to both ceremony types.
   1184     #[expect(
   1185         clippy::type_complexity,
   1186         reason = "type aliases with bounds are even more problematic at least until lazy_type_alias is stable"
   1187     )]
   1188     #[expect(clippy::too_many_lines, reason = "102 lines is fine")]
   1189     fn partial_validate<'a, O: PartialEq<Origin<'a>>, T: PartialEq<Origin<'a>>>(
   1190         &self,
   1191         rp_id: &RpId,
   1192         resp: &'a Self::R,
   1193         key: <<Self::R as Response>::Auth as AuthResponse>::CredKey<'_>,
   1194         options: &CeremonyOptions<'_, '_, O, T>,
   1195     ) -> Result<
   1196         <<Self::R as Response>::Auth as AuthResponse>::Auth<'a>,
   1197         CeremonyErr<
   1198             <<<Self::R as Response>::Auth as AuthResponse>::Auth<'a> as AuthDataContainer<'a>>::Err,
   1199         >,
   1200     > {
   1201         // [Registration ceremony](https://www.w3.org/TR/webauthn-3/#sctn-registering-a-new-credential)
   1202         // is handled by:
   1203         //
   1204         // 1. Calling code.
   1205         // 2. Client code and the construction of `resp` (hopefully via [`Registration::deserialize`]).
   1206         // 3. Client code and the construction of `resp` (hopefully via [`AuthenticatorAttestation::deserialize`]).
   1207         // 4. Client code and the construction of `resp` (hopefully via [`ClientExtensionsOutputs::deserialize`]).
   1208         // 5. Below via [`CollectedClientData::from_client_data_json_relaxed`].
   1209         // 6. Below via [`CollectedClientData::from_client_data_json_relaxed`] or [`CollectedClientData::from_client_data_json_relaxed`].
   1210         // 7. Below via [`CollectedClientData::from_client_data_json_relaxed`] or [`CollectedClientData::from_client_data_json_relaxed`].
   1211         // 8. Below.
   1212         // 9. Below.
   1213         // 10. Below.
   1214         // 11. Below.
   1215         // 12. Below via [`AuthenticatorAttestation::new`].
   1216         // 13. Below via [`AttestationObject::parse_data`].
   1217         // 14. Below.
   1218         // 15. [`RegistrationServerState::verify`].
   1219         // 16. Below.
   1220         // 17. Below via [`AuthenticatorData::from_cbor`].
   1221         // 18. Below.
   1222         // 19. Below.
   1223         // 20. [`RegistrationServerState::verify`].
   1224         // 21. Below via [`AttestationObject::parse_data`].
   1225         // 22. Below via [`AttestationObject::parse_data`].
   1226         // 23. N/A since only none and self attestations are supported.
   1227         // 24. Always satisfied since only none and self attestations are supported (Item 3 is N/A).
   1228         // 25. Below via [`AttestedCredentialData::from_cbor`].
   1229         // 26. Calling code.
   1230         // 27. [`RegistrationServerState::verify`].
   1231         // 28. N/A since only none and self attestations are supported.
   1232         // 29. [`RegistrationServerState::verify`].
   1233         //
   1234         //
   1235         // [Authentication ceremony](https://www.w3.org/TR/webauthn-3/#sctn-verifying-assertion)
   1236         // is handled by:
   1237         //
   1238         // 1. Calling code.
   1239         // 2. Client code and the construction of `resp` (hopefully via [`Authentication::deserialize`]).
   1240         // 3. Client code and the construction of `resp` (hopefully via [`AuthenticatorAssertion::deserialize`]).
   1241         // 4. Client code and the construction of `resp` (hopefully via [`ClientExtensionsOutputs::deserialize`]).
   1242         // 5. [`AuthenticationServerState::verify`].
   1243         // 6. [`AuthenticationServerState::verify`].
   1244         // 7. Informative only in that it defines variables.
   1245         // 8. Below via [`CollectedClientData::from_client_data_json_relaxed`].
   1246         // 9. Below via [`CollectedClientData::from_client_data_json_relaxed`] or [`CollectedClientData::from_client_data_json_relaxed`].
   1247         // 10. Below via [`CollectedClientData::from_client_data_json_relaxed`] or [`CollectedClientData::from_client_data_json_relaxed`].
   1248         // 11. Below.
   1249         // 12. Below.
   1250         // 13. Below.
   1251         // 14. Below.
   1252         // 15. Below.
   1253         // 16. Below via [`AuthenticatorData::from_cbor`].
   1254         // 17. Below.
   1255         // 18. Below via [`AuthenticatorData::from_cbor`].
   1256         // 19. Below.
   1257         // 20. Below via [`AuthenticatorAssertion::new`].
   1258         // 21. Below.
   1259         // 22. [`AuthenticationServerState::verify`].
   1260         // 23. [`AuthenticationServerState::verify`].
   1261         // 24. [`AuthenticationServerState::verify`].
   1262         // 25. [`AuthenticationServerState::verify`].
   1263 
   1264         // Enforce timeout.
   1265         #[cfg(not(feature = "serializable_server_state"))]
   1266         let active = self.expiry() >= Instant::now();
   1267         #[cfg(feature = "serializable_server_state")]
   1268         let active = self.expiry() >= SystemTime::now();
   1269         if active {
   1270             #[cfg(feature = "serde_relaxed")]
   1271             let relaxed = options.client_data_json_relaxed;
   1272             #[cfg(not(feature = "serde_relaxed"))]
   1273             let relaxed = false;
   1274             resp.auth()
   1275                 // Steps 5–7, 12–13, 17, 21–22, and 25 of the registration ceremony.
   1276                 // Steps 8–10, 16, 18, and 20–21 of the authentication ceremony.
   1277                 .parse_data_and_verify_sig(key, relaxed)
   1278                 .map_err(CeremonyErr::AuthResp)
   1279                 .and_then(|(client_data_json, auth_response)| {
   1280                     if options.allowed_origins.is_empty() {
   1281                         if match *rp_id {
   1282                             RpId::Domain(ref dom) => {
   1283                                 // Steps 9 and 12 of the registration and authentication ceremonies
   1284                                 // respectively.
   1285                                 DomainOrigin::new(dom.as_ref()) == client_data_json.origin
   1286                             }
   1287                             // Steps 9 and 12 of the registration and authentication ceremonies
   1288                             // respectively.
   1289                             RpId::Url(ref url) => url == client_data_json.origin,
   1290                         } {
   1291                             Ok(())
   1292                         } else {
   1293                             Err(CeremonyErr::OriginMismatch)
   1294                         }
   1295                     } else {
   1296                         options
   1297                             .allowed_origins
   1298                             .iter()
   1299                             // Steps 9 and 12 of the registration and authentication ceremonies
   1300                             // respectively.
   1301                             .find(|o| **o == client_data_json.origin)
   1302                             .ok_or(CeremonyErr::OriginMismatch)
   1303                             .map(|_| ())
   1304                     }
   1305                     .and_then(|()| {
   1306                         // Steps 10–11 of the registration ceremony.
   1307                         // Steps 13–14 of the authentication ceremony.
   1308                         match options.allowed_top_origins {
   1309                             None => {
   1310                                 if client_data_json.cross_origin {
   1311                                     Err(CeremonyErr::CrossOrigin)
   1312                                 } else if client_data_json.top_origin.is_some() {
   1313                                     Err(CeremonyErr::TopOriginMismatch)
   1314                                 } else {
   1315                                     Ok(())
   1316                                 }
   1317                             }
   1318                             Some(top_origins) => client_data_json.top_origin.map_or(Ok(()), |t| {
   1319                                 top_origins
   1320                                     .iter()
   1321                                     .find(|top| **top == t)
   1322                                     .ok_or(CeremonyErr::TopOriginMismatch)
   1323                                     .map(|_| ())
   1324                             }),
   1325                         }
   1326                         .and_then(|()| {
   1327                             // Steps 8 and 11 of the registration and authentication ceremonies
   1328                             // respectively.
   1329                             if self.rand_challenge() == client_data_json.challenge {
   1330                                 let auth_data = auth_response.authenticator_data();
   1331                                 rp_id
   1332                                     // Steps 14 and 15 of the registration and authentication ceremonies
   1333                                     // respectively.
   1334                                     .validate_rp_id_hash(auth_data.rp_hash())
   1335                                     .and_then(|()| {
   1336                                         let flag = auth_data.flag();
   1337                                         // Steps 16 and 17 of the registration and authentication ceremonies
   1338                                         // respectively.
   1339                                         if flag.user_verified
   1340                                             || !matches!(
   1341                                                 self.user_verification(),
   1342                                                 UserVerificationRequirement::Required
   1343                                             )
   1344                                         {
   1345                                             // Steps 18–19 of the registration ceremony.
   1346                                             // Step 19 of the authentication ceremony.
   1347                                             match options.backup_requirement {
   1348                                                 BackupReq::None => Ok(()),
   1349                                                 BackupReq::NotEligible => {
   1350                                                     if matches!(flag.backup, Backup::NotEligible) {
   1351                                                         Ok(())
   1352                                                     } else {
   1353                                                         Err(CeremonyErr::BackupEligible)
   1354                                                     }
   1355                                                 }
   1356                                                 BackupReq::Eligible => {
   1357                                                     if matches!(flag.backup, Backup::NotEligible) {
   1358                                                         Err(CeremonyErr::BackupNotEligible)
   1359                                                     } else {
   1360                                                         Ok(())
   1361                                                     }
   1362                                                 }
   1363                                                 BackupReq::Exists => {
   1364                                                     if matches!(flag.backup, Backup::Exists) {
   1365                                                         Ok(())
   1366                                                     } else {
   1367                                                         Err(CeremonyErr::BackupDoesNotExist)
   1368                                                     }
   1369                                                 }
   1370                                             }
   1371                                         } else {
   1372                                             Err(CeremonyErr::UserNotVerified)
   1373                                         }
   1374                                     })
   1375                                     .map(|()| auth_response)
   1376                             } else {
   1377                                 Err(CeremonyErr::ChallengeMismatch)
   1378                             }
   1379                         })
   1380                     })
   1381                 })
   1382         } else {
   1383             Err(CeremonyErr::Timeout)
   1384         }
   1385     }
   1386 }
   1387 /// `300_000` milliseconds is equal to five minutes.
   1388 #[expect(
   1389     clippy::unwrap_used,
   1390     reason = "clearly correct, Option::unwrap is const, and better than unsafe"
   1391 )]
   1392 pub(super) const THREE_HUNDRED_THOUSAND: NonZeroU32 = NonZeroU32::new(300_000).unwrap();
   1393 
   1394 /// [`Hasher`] whose `write_*` methods simply store up to 64 bits of the passed argument _as is_ overwriting
   1395 /// any previous state.
   1396 ///
   1397 /// This is designed to only be used indirectly via a hash map whose keys are randomly generated on the server
   1398 /// based on at least 64 bits—the size of the integer returned from [`Self::finish`]—of entropy.
   1399 /// This makes this `Hasher` usable (and ideal) in only the most niche circumstances.
   1400 ///
   1401 /// [`RegistrationServerState`] and [`AuthenticationServerState`] both implement [`Hash`] by simply writing the
   1402 /// contained [`Challenge`]; thus when they are stored in a hashed collection (e.g., [`FixedCapHashSet`]), one can
   1403 /// optimize without fear by using this `Hasher` since `Challenge`s are immutable and can only ever be created on
   1404 /// the server via [`Challenge::new`] (and equivalently [`Challenge::default`]). `RegistrationServerState` and
   1405 /// `AuthenticationServerState` are also immutable and only constructable via
   1406 /// [`PublicKeyCredentialCreationOptions::start_ceremony`] and
   1407 /// [`PublicKeyCredentialRequestOptions::start_ceremony`] respectively. Since `Challenge` is already based on
   1408 /// a random `u128`, other `Hasher`s will be slower and likely produce lower-quality hashes (and never
   1409 /// higher quality).
   1410 #[cfg_attr(docsrs, doc(cfg(not(feature = "serializable_server_state"))))]
   1411 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1412 #[derive(Debug)]
   1413 pub struct IdentityHasher(u64);
   1414 // Note it is _not_ required for `write_*` methods to do the same thing as other `write_*` methods
   1415 // (e.g., `Self::write_u64` may not be the same thing as 8 calls to `Self::write_u8`).
   1416 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1417 impl Hasher for IdentityHasher {
   1418     /// Returns `0` if no `write_*` calls have been made; otherwise returns the result of the most recent
   1419     /// `write_*` call.
   1420     #[inline]
   1421     fn finish(&self) -> u64 {
   1422         self.0
   1423     }
   1424     /// Writes `i` to `self`.
   1425     #[inline]
   1426     fn write_u64(&mut self, i: u64) {
   1427         self.0 = i;
   1428     }
   1429     /// Sign-extends `i` to a [`u64`] before redirecting to [`Self::write_u64`].
   1430     #[expect(
   1431         clippy::as_conversions,
   1432         clippy::cast_sign_loss,
   1433         reason = "we simply need to convert into a u64 in a deterministic way"
   1434     )]
   1435     #[inline]
   1436     fn write_i8(&mut self, i: i8) {
   1437         self.write_u64(i as u64);
   1438     }
   1439     /// Sign-extends `i` to a [`u64`] before redirecting to [`Self::write_u64`].
   1440     #[expect(
   1441         clippy::as_conversions,
   1442         clippy::cast_sign_loss,
   1443         reason = "we simply need to convert into a u64 in a deterministic way"
   1444     )]
   1445     #[inline]
   1446     fn write_i16(&mut self, i: i16) {
   1447         self.write_u64(i as u64);
   1448     }
   1449     /// Sign-extends `i` to a [`u64`] before redirecting to [`Self::write_u64`].
   1450     #[expect(
   1451         clippy::as_conversions,
   1452         clippy::cast_sign_loss,
   1453         reason = "we simply need to convert into a u64 in a deterministic way"
   1454     )]
   1455     #[inline]
   1456     fn write_i32(&mut self, i: i32) {
   1457         self.write_u64(i as u64);
   1458     }
   1459     /// Redirects to [`Self::write_u64`].
   1460     #[expect(
   1461         clippy::as_conversions,
   1462         clippy::cast_sign_loss,
   1463         reason = "we simply need to convert into a u64 in a deterministic way"
   1464     )]
   1465     #[inline]
   1466     fn write_i64(&mut self, i: i64) {
   1467         self.write_u64(i as u64);
   1468     }
   1469     /// Truncates `i` to a [`u64`] before redirecting to [`Self::write_u64`].
   1470     #[expect(
   1471         clippy::as_conversions,
   1472         clippy::cast_possible_truncation,
   1473         clippy::cast_sign_loss,
   1474         reason = "we simply need to convert into a u64 in a deterministic way"
   1475     )]
   1476     #[inline]
   1477     fn write_i128(&mut self, i: i128) {
   1478         self.write_u64(i as u64);
   1479     }
   1480     /// Zero-extends `i` to a [`u64`] before redirecting to [`Self::write_u64`].
   1481     #[inline]
   1482     fn write_u8(&mut self, i: u8) {
   1483         self.write_u64(u64::from(i));
   1484     }
   1485     /// Zero-extends `i` to a [`u64`] before redirecting to [`Self::write_u64`].
   1486     #[inline]
   1487     fn write_u16(&mut self, i: u16) {
   1488         self.write_u64(u64::from(i));
   1489     }
   1490     /// Zero-extends `i` to a [`u64`] before redirecting to [`Self::write_u64`].
   1491     #[inline]
   1492     fn write_u32(&mut self, i: u32) {
   1493         self.write_u64(u64::from(i));
   1494     }
   1495     /// Truncates `i` to a [`u64`] before redirecting to [`Self::write_u64`].
   1496     #[expect(
   1497         clippy::as_conversions,
   1498         clippy::cast_possible_truncation,
   1499         reason = "we simply need to convert into a u64 in a deterministic way"
   1500     )]
   1501     #[inline]
   1502     fn write_u128(&mut self, i: u128) {
   1503         self.write_u64(i as u64);
   1504     }
   1505     /// This does nothing iff `bytes.len() < 8`; otherwise the first 8 bytes are converted
   1506     /// to a [`u64`] that is written via [`Self::write_u64`];
   1507     #[expect(clippy::host_endian_bytes, reason = "endianness does not matter")]
   1508     #[inline]
   1509     fn write(&mut self, bytes: &[u8]) {
   1510         if let Some(data) = bytes.get(..8) {
   1511             let mut val = [0; 8];
   1512             val.copy_from_slice(data);
   1513             self.write_u64(u64::from_ne_bytes(val));
   1514         }
   1515     }
   1516 }
   1517 /// [`BuildHasher`] of an [`IdentityHasher`].
   1518 ///
   1519 /// This MUST only be used with hash maps with keys that are randomly generated on the server based on at least 64
   1520 /// bits of entropy.
   1521 #[cfg_attr(docsrs, doc(cfg(not(feature = "serializable_server_state"))))]
   1522 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1523 #[derive(Clone, Copy, Debug)]
   1524 pub struct BuildIdentityHasher;
   1525 #[cfg_attr(docsrs, doc(cfg(not(feature = "serializable_server_state"))))]
   1526 #[cfg(not(feature = "serializable_server_state"))]
   1527 impl BuildHasher for BuildIdentityHasher {
   1528     type Hasher = IdentityHasher;
   1529     #[inline]
   1530     fn build_hasher(&self) -> Self::Hasher {
   1531         IdentityHasher(0)
   1532     }
   1533 }
   1534 /// Prevent users from implementing [`ServerState`].
   1535 mod private {
   1536     /// Marker trait used as a supertrait of `ServerState`.
   1537     pub trait Sealed {}
   1538     impl Sealed for super::AuthenticationServerState {}
   1539     impl Sealed for super::RegistrationServerState {}
   1540 }
   1541 /// Subset of data shared by both [`RegistrationServerState`] and [`AuthenticationServerState`].
   1542 ///
   1543 /// This trait is sealed and cannot be implemented for types outside of `webauthn_rp`.
   1544 pub trait ServerState: private::Sealed {
   1545     /// Returns the `Instant` the ceremony expires.
   1546     ///
   1547     /// Note when `serializable_server_state` is enabled, [`SystemTime`] is returned instead.
   1548     #[cfg_attr(docsrs, doc(cfg(not(feature = "serializable_server_state"))))]
   1549     #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1550     fn expiration(&self) -> Instant;
   1551     /// Returns the `SystemTime` the ceremony expires.
   1552     #[cfg(all(not(doc), feature = "serializable_server_state"))]
   1553     fn expiration(&self) -> SystemTime;
   1554     /// Returns the `SentChallenge` associated with the ceremony.
   1555     fn sent_challenge(&self) -> SentChallenge;
   1556 }
   1557 /// Fixed-capacity hash set that only inserts items when there is available capacity.
   1558 ///
   1559 /// This should only be used if _both_ of the following conditions are met:
   1560 ///
   1561 /// * Application is already protected from memory exhaustion attacks (e.g., users must be connected
   1562 ///   via VPN).
   1563 /// * There are legitimate reasons for an in-memory collection to grow unbounded.
   1564 ///
   1565 /// The first point is necessary; otherwise an attacker could trivially slow down the application
   1566 /// by causing repeated inserts forcing repeated calls to functions like [`Self::retain`]. The second
   1567 /// point is necessary; otherwise any in-memory collection would suffice.
   1568 ///
   1569 /// When `T` is a [`ServerState`], there are legitimate reasons why a ceremony will never finish (e.g.,
   1570 /// an outage could kill a user's connection after starting a ceremony). The longer the application
   1571 /// runs the more such instances occur to the point where the in-memory collection is full of expired
   1572 /// ceremonies. Since this should rarely occur and as long as [`Self::capacity`] is appropriate,
   1573 /// [`Self::insert`] should almost always succeed; however very rarely there will be a point when
   1574 /// one will have to [`Self::remove_expired_ceremonies`]. A vast majority of the time a user
   1575 /// will complete the ceremony which requires ownership of the `ServerState` which in turn requires
   1576 /// [`Self::take`] which will add an available slot.
   1577 #[cfg_attr(docsrs, doc(cfg(not(feature = "serializable_server_state"))))]
   1578 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1579 #[derive(Debug)]
   1580 pub struct FixedCapHashSet<T, S = BuildIdentityHasher>(HashSet<T, S>);
   1581 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1582 impl<T> FixedCapHashSet<T, BuildIdentityHasher> {
   1583     /// Creates an empty `FixedCapHashSet` with at least the specified capacity.
   1584     ///
   1585     /// The hash set will be able to hold at least `capacity` elements without reallocating. This method is allowed
   1586     /// to allocate for more elements than `capacity`.
   1587     #[inline]
   1588     #[must_use]
   1589     pub fn new(capacity: usize) -> Self {
   1590         Self(HashSet::with_capacity_and_hasher(
   1591             capacity,
   1592             BuildIdentityHasher,
   1593         ))
   1594     }
   1595 }
   1596 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1597 impl<T, S> FixedCapHashSet<T, S> {
   1598     /// Creates an empty `FixedCapHashSet` with at least the specified capacity, using `hasher` to hash the keys.
   1599     ///
   1600     /// The hash set will be able to hold at least `capacity` elements without reallocating. This method is allowed
   1601     /// to allocate for more elements than `capacity`.
   1602     #[inline]
   1603     #[must_use]
   1604     pub fn new_with_hasher(capacity: usize, hasher: S) -> Self {
   1605         Self(HashSet::with_capacity_and_hasher(capacity, hasher))
   1606     }
   1607     /// Returns the immutable capacity.
   1608     ///
   1609     /// This number is a lower bound; the `FixedCapHashSet` might be able to hold more, but is guaranteed to be
   1610     /// able to hold at least this many.
   1611     #[inline]
   1612     #[must_use]
   1613     pub fn capacity(&self) -> usize {
   1614         self.0.capacity()
   1615     }
   1616     /// Clears the set, removing all values.
   1617     #[inline]
   1618     pub fn clear(&mut self) {
   1619         self.0.clear();
   1620     }
   1621     /// Returns the number of elements in the set.
   1622     #[inline]
   1623     #[must_use]
   1624     pub fn len(&self) -> usize {
   1625         self.0.len()
   1626     }
   1627     /// Returns `true` iff the set contains no elements.
   1628     #[inline]
   1629     #[must_use]
   1630     pub fn is_empty(&self) -> bool {
   1631         self.0.is_empty()
   1632     }
   1633     /// Retains only the elements specified by the predicate.
   1634     ///
   1635     /// In other words, remove all elements `e` for which `f(&e)` returns `false`. The elements are visited in
   1636     /// unsorted (and unspecified) order.
   1637     #[inline]
   1638     pub fn retain<F>(&mut self, f: F)
   1639     where
   1640         F: FnMut(&T) -> bool,
   1641     {
   1642         self.0.retain(f);
   1643     }
   1644 }
   1645 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1646 impl<T: ServerState, S> FixedCapHashSet<T, S> {
   1647     /// Removes all expired ceremonies.
   1648     #[inline]
   1649     pub fn remove_expired_ceremonies(&mut self) {
   1650         // Even though it's more accurate to check the current `Instant` for each ceremony, we elect to capture
   1651         // the `Instant` we begin iteration for performance reasons. It's unlikely an appreciable amount of
   1652         // additional ceremonies would be removed.
   1653         let now = Instant::now();
   1654         self.retain(|v| v.expiration() >= now);
   1655     }
   1656 }
   1657 /// Result returned from [`FixedCapHashSet::insert`], [`FixedCapHashSet::insert_or_replace_expired`], and
   1658 /// [`FixedCapHashSet::insert_or_replace_all_expired`].
   1659 #[cfg_attr(docsrs, doc(cfg(not(feature = "serializable_server_state"))))]
   1660 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1661 #[derive(Clone, Copy, Debug)]
   1662 pub enum InsertResult {
   1663     /// Value was successfully inserted.
   1664     Success,
   1665     /// Value was not inserted since the capacity was full.
   1666     CapacityFull,
   1667     /// Value was not inserted since the value already existed.
   1668     ///
   1669     /// When the keys are based on [`Challenge`]s, this should almost never occur since `Challenge`s
   1670     /// are 16 bytes of random data.
   1671     Duplicate,
   1672 }
   1673 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1674 impl<T: Eq + Hash, S: BuildHasher> FixedCapHashSet<T, S> {
   1675     /// Returns `true` iff the set contains a value.
   1676     ///
   1677     /// The value may be any borrowed form of the set's value type, but `Hash` and `Eq` on the borrowed form _must_
   1678     /// match those for the value type.
   1679     #[inline]
   1680     #[must_use]
   1681     pub fn contains<Q>(&self, value: &Q) -> bool
   1682     where
   1683         T: Borrow<Q>,
   1684         Q: Eq + Hash + ?Sized,
   1685     {
   1686         self.0.contains(value)
   1687     }
   1688     /// Returns a reference to the value in the set, if any, that is equal to the given value.
   1689     ///
   1690     /// The value may be any borrowed form of the set's value type, but `Hash` and `Eq` on the borrowed form _must_
   1691     /// match those for the value type.
   1692     #[inline]
   1693     #[must_use]
   1694     pub fn get<Q>(&self, value: &Q) -> Option<&T>
   1695     where
   1696         T: Borrow<Q>,
   1697         Q: Eq + Hash + ?Sized,
   1698     {
   1699         self.0.get(value)
   1700     }
   1701     /// Removes a value from the set. Returns whether the value was present in the set.
   1702     ///
   1703     /// The value may be any borrowed form of the set's value type, but `Hash` and `Eq` on the borrowed form _must_
   1704     /// match those for the value type.
   1705     #[inline]
   1706     pub fn remove<Q>(&mut self, value: &Q) -> bool
   1707     where
   1708         T: Borrow<Q>,
   1709         Q: Eq + Hash + ?Sized,
   1710     {
   1711         self.0.remove(value)
   1712     }
   1713     /// Removes and returns the value in the set, if any, that is equal to the given one.
   1714     ///
   1715     /// The value may be any borrowed form of the set's value type, but `Hash` and `Eq` on the borrowed form _must_
   1716     /// match those for the value type.
   1717     #[inline]
   1718     pub fn take<Q>(&mut self, value: &Q) -> Option<T>
   1719     where
   1720         T: Borrow<Q>,
   1721         Q: Eq + Hash + ?Sized,
   1722     {
   1723         self.0.take(value)
   1724     }
   1725     /// Adds `value` to the set iff [`Self::capacity`] `>` [`Self::len`].
   1726     #[inline]
   1727     pub fn insert(&mut self, value: T) -> InsertResult {
   1728         if self.len() == self.capacity() {
   1729             InsertResult::CapacityFull
   1730         } else if self.0.insert(value) {
   1731             InsertResult::Success
   1732         } else {
   1733             InsertResult::Duplicate
   1734         }
   1735     }
   1736 }
   1737 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1738 impl<T: Borrow<SentChallenge> + Eq + Hash + ServerState, S: BuildHasher> FixedCapHashSet<T, S> {
   1739     /// Adds a ceremony to the set.
   1740     ///
   1741     /// This will only insert `value` iff [`Self::capacity`] `>` [`Self::len`]. When [`Self::len`] `==`
   1742     /// [`Self::capacity`], this will iterate items in the set until an expired ceremony is encountered; at which
   1743     /// point, the expired ceremony will be removed before `value` is inserted. In the event no expired ceremonies
   1744     /// exist, [`InsertResult::CapacityFull`] will be returned.
   1745     ///
   1746     /// If one wants to avoid the potentially expensive operation of iterating the set for an expired ceremony,
   1747     /// call [`Self::insert`]. Alternatively one can call [`Self::insert_or_replace_all_expired`] to avoid
   1748     /// repeatedly iterating the hash set once its capacity is full.
   1749     #[inline]
   1750     pub fn insert_or_replace_expired(&mut self, value: T) -> InsertResult {
   1751         if self.len() == self.capacity() {
   1752             let now = Instant::now();
   1753             self.0
   1754                 .iter()
   1755                 .try_fold((), |(), v| {
   1756                     if v.expiration() < now {
   1757                         Err(v.sent_challenge())
   1758                     } else {
   1759                         Ok(())
   1760                     }
   1761                 })
   1762                 .map_or_else(
   1763                     |chall| {
   1764                         self.remove(&chall);
   1765                         if self.0.insert(value) {
   1766                             InsertResult::Success
   1767                         } else {
   1768                             InsertResult::Duplicate
   1769                         }
   1770                     },
   1771                     |()| InsertResult::CapacityFull,
   1772                 )
   1773         } else if self.0.insert(value) {
   1774             InsertResult::Success
   1775         } else {
   1776             InsertResult::Duplicate
   1777         }
   1778     }
   1779     /// Adds a ceremony to the set.
   1780     ///
   1781     /// This will only insert `value` iff [`Self::capacity`] `>` [`Self::len`]. When [`Self::len`] `==`
   1782     /// [`Self::capacity`], this will [`Self::remove_expired_ceremonies`] before `value` is inserted. In the event
   1783     /// no expired ceremonies exist, [`InsertResult::CapacityFull`] will be returned.
   1784     #[inline]
   1785     pub fn insert_or_replace_all_expired(&mut self, value: T) -> InsertResult {
   1786         if self.len() == self.capacity() {
   1787             self.remove_expired_ceremonies();
   1788         }
   1789         if self.len() == self.capacity() {
   1790             InsertResult::CapacityFull
   1791         } else if self.0.insert(value) {
   1792             InsertResult::Success
   1793         } else {
   1794             InsertResult::Duplicate
   1795         }
   1796     }
   1797 }
   1798 #[cfg(test)]
   1799 mod tests {
   1800     #[cfg(feature = "custom")]
   1801     use super::{
   1802         super::{
   1803             response::{
   1804                 auth::{Authentication, AuthenticatorAssertion},
   1805                 register::{
   1806                     AuthenticationExtensionsPrfOutputs, AuthenticatorAttestation,
   1807                     AuthenticatorExtensionOutputStaticState, ClientExtensionsOutputs,
   1808                     CompressedP256PubKey, CompressedP384PubKey, CompressedPubKey,
   1809                     CredentialProtectionPolicy, DynamicState, Ed25519PubKey, Registration,
   1810                     RsaPubKey, StaticState, UncompressedPubKey,
   1811                 },
   1812                 AuthTransports, AuthenticatorAttachment, Backup, CredentialId,
   1813             },
   1814             AggErr, AuthenticatedCredential,
   1815         },
   1816         auth::{
   1817             AllowedCredential, AllowedCredentials, AuthenticationVerificationOptions,
   1818             CredentialSpecificExtension, Extension as AuthExt, PrfInputOwned,
   1819             PublicKeyCredentialRequestOptions,
   1820         },
   1821         register::{
   1822             CredProtect, Extension as RegExt, PublicKeyCredentialCreationOptions,
   1823             PublicKeyCredentialUserEntity, RegistrationVerificationOptions, UserHandle,
   1824         },
   1825         AsciiDomain, Challenge, Credentials, ExtensionInfo, ExtensionReq,
   1826         PublicKeyCredentialDescriptor, RpId, UserVerificationRequirement,
   1827     };
   1828     #[cfg(feature = "custom")]
   1829     use ed25519_dalek::{Signer, SigningKey};
   1830     #[cfg(feature = "custom")]
   1831     use p256::{
   1832         ecdsa::{DerSignature as P256DerSig, SigningKey as P256Key},
   1833         elliptic_curve::sec1::Tag,
   1834     };
   1835     #[cfg(feature = "custom")]
   1836     use p384::ecdsa::{DerSignature as P384DerSig, SigningKey as P384Key};
   1837     #[cfg(feature = "custom")]
   1838     use rsa::{
   1839         pkcs1v15::SigningKey as RsaKey,
   1840         sha2::{Digest, Sha256},
   1841         signature::{Keypair, SignatureEncoding},
   1842         traits::PublicKeyParts,
   1843         BigUint, RsaPrivateKey,
   1844     };
   1845     #[cfg(feature = "custom")]
   1846     const CBOR_UINT: u8 = 0b000_00000;
   1847     #[cfg(feature = "custom")]
   1848     const CBOR_NEG: u8 = 0b001_00000;
   1849     #[cfg(feature = "custom")]
   1850     const CBOR_BYTES: u8 = 0b010_00000;
   1851     #[cfg(feature = "custom")]
   1852     const CBOR_TEXT: u8 = 0b011_00000;
   1853     #[cfg(feature = "custom")]
   1854     const CBOR_MAP: u8 = 0b101_00000;
   1855     #[cfg(feature = "custom")]
   1856     const CBOR_SIMPLE: u8 = 0b111_00000;
   1857     #[cfg(feature = "custom")]
   1858     const CBOR_TRUE: u8 = CBOR_SIMPLE | 21;
   1859     #[test]
   1860     #[cfg(feature = "custom")]
   1861     fn ed25519_reg() -> Result<(), AggErr> {
   1862         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   1863         let id = UserHandle::try_from([0; 1].as_slice())?;
   1864         let mut opts = PublicKeyCredentialCreationOptions::passkey(
   1865             &rp_id,
   1866             PublicKeyCredentialUserEntity {
   1867                 name: "foo".try_into()?,
   1868                 id,
   1869                 display_name: None,
   1870             },
   1871             Vec::new(),
   1872         );
   1873         opts.challenge = Challenge(0);
   1874         opts.extensions = RegExt {
   1875             cred_props: None,
   1876             cred_protect: CredProtect::UserVerificationRequired(ExtensionInfo::RequireEnforceValue),
   1877             min_pin_length: Some((10, ExtensionInfo::RequireEnforceValue)),
   1878             prf: Some(ExtensionInfo::RequireEnforceValue),
   1879         };
   1880         let client_data_json = br#"{"type":"webauthn.create","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   1881         // We over-allocate by 32 bytes. See [`AuthenticatorAttestation::new`] for more information.
   1882         let mut attestation_object = Vec::new();
   1883         attestation_object.extend_from_slice(
   1884             [
   1885                 CBOR_MAP | 3,
   1886                 CBOR_TEXT | 3,
   1887                 b'f',
   1888                 b'm',
   1889                 b't',
   1890                 CBOR_TEXT | 6,
   1891                 b'p',
   1892                 b'a',
   1893                 b'c',
   1894                 b'k',
   1895                 b'e',
   1896                 b'd',
   1897                 CBOR_TEXT | 7,
   1898                 b'a',
   1899                 b't',
   1900                 b't',
   1901                 b'S',
   1902                 b't',
   1903                 b'm',
   1904                 b't',
   1905                 CBOR_MAP | 2,
   1906                 CBOR_TEXT | 3,
   1907                 b'a',
   1908                 b'l',
   1909                 b'g',
   1910                 // COSE EdDSA.
   1911                 CBOR_NEG | 7,
   1912                 CBOR_TEXT | 3,
   1913                 b's',
   1914                 b'i',
   1915                 b'g',
   1916                 CBOR_BYTES | 24,
   1917                 64,
   1918                 0,
   1919                 0,
   1920                 0,
   1921                 0,
   1922                 0,
   1923                 0,
   1924                 0,
   1925                 0,
   1926                 0,
   1927                 0,
   1928                 0,
   1929                 0,
   1930                 0,
   1931                 0,
   1932                 0,
   1933                 0,
   1934                 0,
   1935                 0,
   1936                 0,
   1937                 0,
   1938                 0,
   1939                 0,
   1940                 0,
   1941                 0,
   1942                 0,
   1943                 0,
   1944                 0,
   1945                 0,
   1946                 0,
   1947                 0,
   1948                 0,
   1949                 0,
   1950                 0,
   1951                 0,
   1952                 0,
   1953                 0,
   1954                 0,
   1955                 0,
   1956                 0,
   1957                 0,
   1958                 0,
   1959                 0,
   1960                 0,
   1961                 0,
   1962                 0,
   1963                 0,
   1964                 0,
   1965                 0,
   1966                 0,
   1967                 0,
   1968                 0,
   1969                 0,
   1970                 0,
   1971                 0,
   1972                 0,
   1973                 0,
   1974                 0,
   1975                 0,
   1976                 0,
   1977                 0,
   1978                 0,
   1979                 0,
   1980                 0,
   1981                 0,
   1982                 CBOR_TEXT | 8,
   1983                 b'a',
   1984                 b'u',
   1985                 b't',
   1986                 b'h',
   1987                 b'D',
   1988                 b'a',
   1989                 b't',
   1990                 b'a',
   1991                 CBOR_BYTES | 24,
   1992                 // Length is 154.
   1993                 154,
   1994                 // RP ID HASH.
   1995                 // This will be overwritten later.
   1996                 0,
   1997                 0,
   1998                 0,
   1999                 0,
   2000                 0,
   2001                 0,
   2002                 0,
   2003                 0,
   2004                 0,
   2005                 0,
   2006                 0,
   2007                 0,
   2008                 0,
   2009                 0,
   2010                 0,
   2011                 0,
   2012                 0,
   2013                 0,
   2014                 0,
   2015                 0,
   2016                 0,
   2017                 0,
   2018                 0,
   2019                 0,
   2020                 0,
   2021                 0,
   2022                 0,
   2023                 0,
   2024                 0,
   2025                 0,
   2026                 0,
   2027                 0,
   2028                 // FLAGS.
   2029                 // UP, UV, AT, and ED (right-to-left).
   2030                 0b1100_0101,
   2031                 // COUNTER.
   2032                 // 0 as 32-bit big endian.
   2033                 0,
   2034                 0,
   2035                 0,
   2036                 0,
   2037                 // AAGUID.
   2038                 0,
   2039                 0,
   2040                 0,
   2041                 0,
   2042                 0,
   2043                 0,
   2044                 0,
   2045                 0,
   2046                 0,
   2047                 0,
   2048                 0,
   2049                 0,
   2050                 0,
   2051                 0,
   2052                 0,
   2053                 0,
   2054                 // L.
   2055                 // CREDENTIAL ID length is 16 as 16-bit big endian.
   2056                 0,
   2057                 16,
   2058                 // CREDENTIAL ID.
   2059                 0,
   2060                 0,
   2061                 0,
   2062                 0,
   2063                 0,
   2064                 0,
   2065                 0,
   2066                 0,
   2067                 0,
   2068                 0,
   2069                 0,
   2070                 0,
   2071                 0,
   2072                 0,
   2073                 0,
   2074                 0,
   2075                 CBOR_MAP | 4,
   2076                 // COSE kty.
   2077                 CBOR_UINT | 1,
   2078                 // COSE OKP.
   2079                 CBOR_UINT | 1,
   2080                 // COSE alg.
   2081                 CBOR_UINT | 3,
   2082                 // COSE EdDSA.
   2083                 CBOR_NEG | 7,
   2084                 // COSE OKP crv.
   2085                 CBOR_NEG,
   2086                 // COSE Ed25519.
   2087                 CBOR_UINT | 6,
   2088                 // COSE OKP x.
   2089                 CBOR_NEG | 1,
   2090                 CBOR_BYTES | 24,
   2091                 // Length is 32.
   2092                 32,
   2093                 // Compressed-y coordinate.
   2094                 // This will be overwritten later.
   2095                 0,
   2096                 0,
   2097                 0,
   2098                 0,
   2099                 0,
   2100                 0,
   2101                 0,
   2102                 0,
   2103                 0,
   2104                 0,
   2105                 0,
   2106                 0,
   2107                 0,
   2108                 0,
   2109                 0,
   2110                 0,
   2111                 0,
   2112                 0,
   2113                 0,
   2114                 0,
   2115                 0,
   2116                 0,
   2117                 0,
   2118                 0,
   2119                 0,
   2120                 0,
   2121                 0,
   2122                 0,
   2123                 0,
   2124                 0,
   2125                 0,
   2126                 0,
   2127                 CBOR_MAP | 3,
   2128                 CBOR_TEXT | 11,
   2129                 b'c',
   2130                 b'r',
   2131                 b'e',
   2132                 b'd',
   2133                 b'P',
   2134                 b'r',
   2135                 b'o',
   2136                 b't',
   2137                 b'e',
   2138                 b'c',
   2139                 b't',
   2140                 // userVerificationRequired.
   2141                 CBOR_UINT | 3,
   2142                 // CBOR text of length 11.
   2143                 CBOR_TEXT | 11,
   2144                 b'h',
   2145                 b'm',
   2146                 b'a',
   2147                 b'c',
   2148                 b'-',
   2149                 b's',
   2150                 b'e',
   2151                 b'c',
   2152                 b'r',
   2153                 b'e',
   2154                 b't',
   2155                 CBOR_TRUE,
   2156                 CBOR_TEXT | 12,
   2157                 b'm',
   2158                 b'i',
   2159                 b'n',
   2160                 b'P',
   2161                 b'i',
   2162                 b'n',
   2163                 b'L',
   2164                 b'e',
   2165                 b'n',
   2166                 b'g',
   2167                 b't',
   2168                 b'h',
   2169                 CBOR_UINT | 16,
   2170             ]
   2171             .as_slice(),
   2172         );
   2173         attestation_object
   2174             .extend_from_slice(Sha256::digest(client_data_json.as_slice()).as_slice());
   2175         let sig_key = SigningKey::from_bytes(&[0; 32]);
   2176         let ver_key = sig_key.verifying_key();
   2177         let pub_key = ver_key.as_bytes();
   2178         attestation_object[107..139]
   2179             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   2180         attestation_object[188..220].copy_from_slice(pub_key);
   2181         let sig = sig_key.sign(&attestation_object[107..]);
   2182         attestation_object[32..96].copy_from_slice(sig.to_bytes().as_slice());
   2183         attestation_object.truncate(261);
   2184         assert!(matches!(opts.start_ceremony()?.0.verify(
   2185             &rp_id,
   2186             id,
   2187             &Registration {
   2188                 response: AuthenticatorAttestation::new(
   2189                     client_data_json,
   2190                     attestation_object,
   2191                     AuthTransports::NONE,
   2192                 ),
   2193                 authenticator_attachment: AuthenticatorAttachment::None,
   2194                 client_extension_results: ClientExtensionsOutputs {
   2195                     cred_props: None,
   2196                     prf: Some(AuthenticationExtensionsPrfOutputs { enabled: true, }),
   2197                 },
   2198             },
   2199             &RegistrationVerificationOptions::<&str, &str>::default(),
   2200         )?.static_state.credential_public_key, UncompressedPubKey::Ed25519(k) if k.into_inner() == pub_key));
   2201         Ok(())
   2202     }
   2203     #[test]
   2204     #[cfg(feature = "custom")]
   2205     fn ed25519_auth() -> Result<(), AggErr> {
   2206         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   2207         let mut creds = AllowedCredentials::with_capacity(1);
   2208         creds.push(AllowedCredential {
   2209             credential: PublicKeyCredentialDescriptor {
   2210                 id: CredentialId::try_from(vec![0; 16])?,
   2211                 transports: AuthTransports::NONE,
   2212             },
   2213             extension: CredentialSpecificExtension {
   2214                 prf: Some(PrfInputOwned {
   2215                     first: Vec::new(),
   2216                     second: Some(Vec::new()),
   2217                     ext_info: ExtensionReq::Require,
   2218                 }),
   2219             },
   2220         });
   2221         let mut opts = PublicKeyCredentialRequestOptions::second_factor(&rp_id, creds)?;
   2222         opts.user_verification = UserVerificationRequirement::Required;
   2223         opts.challenge = Challenge(0);
   2224         opts.extensions = AuthExt { prf: None };
   2225         let client_data_json = br#"{"type":"webauthn.get","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   2226         // We over-allocate by 32 bytes. See [`AuthenticatorAssertion::new`] for more information.
   2227         let mut authenticator_data = Vec::with_capacity(164);
   2228         authenticator_data.extend_from_slice(
   2229             [
   2230                 // rpIdHash.
   2231                 // This will be overwritten later.
   2232                 0,
   2233                 0,
   2234                 0,
   2235                 0,
   2236                 0,
   2237                 0,
   2238                 0,
   2239                 0,
   2240                 0,
   2241                 0,
   2242                 0,
   2243                 0,
   2244                 0,
   2245                 0,
   2246                 0,
   2247                 0,
   2248                 0,
   2249                 0,
   2250                 0,
   2251                 0,
   2252                 0,
   2253                 0,
   2254                 0,
   2255                 0,
   2256                 0,
   2257                 0,
   2258                 0,
   2259                 0,
   2260                 0,
   2261                 0,
   2262                 0,
   2263                 0,
   2264                 // flags.
   2265                 // UP, UV, and ED (right-to-left).
   2266                 0b1000_0101,
   2267                 // signCount.
   2268                 // 0 as 32-bit big endian.
   2269                 0,
   2270                 0,
   2271                 0,
   2272                 0,
   2273                 CBOR_MAP | 1,
   2274                 CBOR_TEXT | 11,
   2275                 b'h',
   2276                 b'm',
   2277                 b'a',
   2278                 b'c',
   2279                 b'-',
   2280                 b's',
   2281                 b'e',
   2282                 b'c',
   2283                 b'r',
   2284                 b'e',
   2285                 b't',
   2286                 CBOR_BYTES | 24,
   2287                 // Length is 80.
   2288                 80,
   2289                 // Two HMAC outputs concatenated and encrypted.
   2290                 0,
   2291                 0,
   2292                 0,
   2293                 0,
   2294                 0,
   2295                 0,
   2296                 0,
   2297                 0,
   2298                 0,
   2299                 0,
   2300                 0,
   2301                 0,
   2302                 0,
   2303                 0,
   2304                 0,
   2305                 0,
   2306                 0,
   2307                 0,
   2308                 0,
   2309                 0,
   2310                 0,
   2311                 0,
   2312                 0,
   2313                 0,
   2314                 0,
   2315                 0,
   2316                 0,
   2317                 0,
   2318                 0,
   2319                 0,
   2320                 0,
   2321                 0,
   2322                 0,
   2323                 0,
   2324                 0,
   2325                 0,
   2326                 0,
   2327                 0,
   2328                 0,
   2329                 0,
   2330                 0,
   2331                 0,
   2332                 0,
   2333                 0,
   2334                 0,
   2335                 0,
   2336                 0,
   2337                 0,
   2338                 0,
   2339                 0,
   2340                 0,
   2341                 0,
   2342                 0,
   2343                 0,
   2344                 0,
   2345                 0,
   2346                 0,
   2347                 0,
   2348                 0,
   2349                 0,
   2350                 0,
   2351                 0,
   2352                 0,
   2353                 0,
   2354                 0,
   2355                 0,
   2356                 0,
   2357                 0,
   2358                 0,
   2359                 0,
   2360                 0,
   2361                 0,
   2362                 0,
   2363                 0,
   2364                 0,
   2365                 0,
   2366                 0,
   2367                 0,
   2368                 0,
   2369                 0,
   2370             ]
   2371             .as_slice(),
   2372         );
   2373         authenticator_data[..32]
   2374             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   2375         authenticator_data
   2376             .extend_from_slice(Sha256::digest(client_data_json.as_slice()).as_slice());
   2377         let ed_priv = SigningKey::from([0; 32]);
   2378         let sig = ed_priv.sign(authenticator_data.as_slice()).to_vec();
   2379         authenticator_data.truncate(132);
   2380         assert!(!opts.start_ceremony()?.0.verify(
   2381             &rp_id,
   2382             &Authentication {
   2383                 raw_id: CredentialId::try_from(vec![0; 16])?,
   2384                 response: AuthenticatorAssertion::new(
   2385                     client_data_json,
   2386                     authenticator_data,
   2387                     sig,
   2388                     Some(UserHandle::try_from(vec![0])?),
   2389                 ),
   2390                 authenticator_attachment: AuthenticatorAttachment::None,
   2391             },
   2392             &mut AuthenticatedCredential::new(
   2393                 CredentialId::try_from([0; 16].as_slice())?,
   2394                 UserHandle::try_from([0].as_slice())?,
   2395                 StaticState {
   2396                     credential_public_key: CompressedPubKey::<_, &[u8], &[u8], &[u8]>::Ed25519(
   2397                         Ed25519PubKey::from(ed_priv.verifying_key().to_bytes()),
   2398                     ),
   2399                     extensions: AuthenticatorExtensionOutputStaticState {
   2400                         cred_protect: CredentialProtectionPolicy::None,
   2401                         hmac_secret: Some(true),
   2402                     },
   2403                 },
   2404                 DynamicState {
   2405                     user_verified: true,
   2406                     backup: Backup::NotEligible,
   2407                     sign_count: 0,
   2408                     authenticator_attachment: AuthenticatorAttachment::None,
   2409                 },
   2410             )?,
   2411             &AuthenticationVerificationOptions::<&str, &str>::default(),
   2412         )?);
   2413         Ok(())
   2414     }
   2415     #[test]
   2416     #[cfg(feature = "custom")]
   2417     fn p256_reg() -> Result<(), AggErr> {
   2418         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   2419         let id = UserHandle::try_from([0; 1].as_slice())?;
   2420         let mut opts = PublicKeyCredentialCreationOptions::passkey(
   2421             &rp_id,
   2422             PublicKeyCredentialUserEntity {
   2423                 name: "foo".try_into()?,
   2424                 id,
   2425                 display_name: None,
   2426             },
   2427             Vec::new(),
   2428         );
   2429         opts.challenge = Challenge(0);
   2430         let client_data_json = br#"{"type":"webauthn.create","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   2431         // We over-allocate by 32 bytes. See [`AuthenticatorAttestation::new`] for more information.
   2432         let mut attestation_object = Vec::with_capacity(210);
   2433         attestation_object.extend_from_slice(
   2434             [
   2435                 CBOR_MAP | 3,
   2436                 CBOR_TEXT | 3,
   2437                 b'f',
   2438                 b'm',
   2439                 b't',
   2440                 CBOR_TEXT | 4,
   2441                 b'n',
   2442                 b'o',
   2443                 b'n',
   2444                 b'e',
   2445                 CBOR_TEXT | 7,
   2446                 b'a',
   2447                 b't',
   2448                 b't',
   2449                 b'S',
   2450                 b't',
   2451                 b'm',
   2452                 b't',
   2453                 CBOR_MAP,
   2454                 CBOR_TEXT | 8,
   2455                 b'a',
   2456                 b'u',
   2457                 b't',
   2458                 b'h',
   2459                 b'D',
   2460                 b'a',
   2461                 b't',
   2462                 b'a',
   2463                 CBOR_BYTES | 24,
   2464                 // Length is 148.
   2465                 148,
   2466                 // RP ID HASH.
   2467                 // This will be overwritten later.
   2468                 0,
   2469                 0,
   2470                 0,
   2471                 0,
   2472                 0,
   2473                 0,
   2474                 0,
   2475                 0,
   2476                 0,
   2477                 0,
   2478                 0,
   2479                 0,
   2480                 0,
   2481                 0,
   2482                 0,
   2483                 0,
   2484                 0,
   2485                 0,
   2486                 0,
   2487                 0,
   2488                 0,
   2489                 0,
   2490                 0,
   2491                 0,
   2492                 0,
   2493                 0,
   2494                 0,
   2495                 0,
   2496                 0,
   2497                 0,
   2498                 0,
   2499                 0,
   2500                 // FLAGS.
   2501                 // UP, UV, and AT (right-to-left).
   2502                 0b0100_0101,
   2503                 // COUNTER.
   2504                 // 0 as 32-bit big endian.
   2505                 0,
   2506                 0,
   2507                 0,
   2508                 0,
   2509                 // AAGUID.
   2510                 0,
   2511                 0,
   2512                 0,
   2513                 0,
   2514                 0,
   2515                 0,
   2516                 0,
   2517                 0,
   2518                 0,
   2519                 0,
   2520                 0,
   2521                 0,
   2522                 0,
   2523                 0,
   2524                 0,
   2525                 0,
   2526                 // L.
   2527                 // CREDENTIAL ID length is 16 as 16-bit big endian.
   2528                 0,
   2529                 16,
   2530                 // CREDENTIAL ID.
   2531                 0,
   2532                 0,
   2533                 0,
   2534                 0,
   2535                 0,
   2536                 0,
   2537                 0,
   2538                 0,
   2539                 0,
   2540                 0,
   2541                 0,
   2542                 0,
   2543                 0,
   2544                 0,
   2545                 0,
   2546                 0,
   2547                 CBOR_MAP | 5,
   2548                 // COSE kty.
   2549                 CBOR_UINT | 1,
   2550                 // COSE EC2.
   2551                 CBOR_UINT | 2,
   2552                 // COSE alg.
   2553                 CBOR_UINT | 3,
   2554                 // COSE ES256.
   2555                 CBOR_NEG | 6,
   2556                 // COSE EC2 crv.
   2557                 CBOR_NEG,
   2558                 // COSE P-256.
   2559                 CBOR_UINT | 1,
   2560                 // COSE EC2 x.
   2561                 CBOR_NEG | 1,
   2562                 CBOR_BYTES | 24,
   2563                 // Length is 32.
   2564                 32,
   2565                 // X-coordinate. This will be overwritten later.
   2566                 0,
   2567                 0,
   2568                 0,
   2569                 0,
   2570                 0,
   2571                 0,
   2572                 0,
   2573                 0,
   2574                 0,
   2575                 0,
   2576                 0,
   2577                 0,
   2578                 0,
   2579                 0,
   2580                 0,
   2581                 0,
   2582                 0,
   2583                 0,
   2584                 0,
   2585                 0,
   2586                 0,
   2587                 0,
   2588                 0,
   2589                 0,
   2590                 0,
   2591                 0,
   2592                 0,
   2593                 0,
   2594                 0,
   2595                 0,
   2596                 0,
   2597                 0,
   2598                 // COSE EC2 y.
   2599                 CBOR_NEG | 2,
   2600                 CBOR_BYTES | 24,
   2601                 // Length is 32.
   2602                 32,
   2603                 // Y-coordinate. This will be overwritten later.
   2604                 0,
   2605                 0,
   2606                 0,
   2607                 0,
   2608                 0,
   2609                 0,
   2610                 0,
   2611                 0,
   2612                 0,
   2613                 0,
   2614                 0,
   2615                 0,
   2616                 0,
   2617                 0,
   2618                 0,
   2619                 0,
   2620                 0,
   2621                 0,
   2622                 0,
   2623                 0,
   2624                 0,
   2625                 0,
   2626                 0,
   2627                 0,
   2628                 0,
   2629                 0,
   2630                 0,
   2631                 0,
   2632                 0,
   2633                 0,
   2634                 0,
   2635                 0,
   2636             ]
   2637             .as_slice(),
   2638         );
   2639         attestation_object[30..62]
   2640             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   2641         let p256_key = P256Key::from_bytes(
   2642             &[
   2643                 137, 133, 36, 206, 163, 47, 255, 5, 76, 144, 163, 141, 40, 109, 108, 240, 246, 115,
   2644                 178, 237, 169, 68, 6, 129, 92, 21, 238, 127, 55, 158, 207, 95,
   2645             ]
   2646             .into(),
   2647         )
   2648         .unwrap()
   2649         .verifying_key()
   2650         .to_encoded_point(false);
   2651         let x = p256_key.x().unwrap();
   2652         let y = p256_key.y().unwrap();
   2653         attestation_object[111..143].copy_from_slice(x);
   2654         attestation_object[146..].copy_from_slice(y);
   2655         assert!(matches!(opts.start_ceremony()?.0.verify(
   2656             &rp_id,
   2657             id,
   2658             &Registration {
   2659                 response: AuthenticatorAttestation::new(
   2660                     client_data_json,
   2661                     attestation_object,
   2662                     AuthTransports::NONE,
   2663                 ),
   2664                 authenticator_attachment: AuthenticatorAttachment::None,
   2665                 client_extension_results: ClientExtensionsOutputs {
   2666                     cred_props: None,
   2667                     prf: None,
   2668                 },
   2669             },
   2670             &RegistrationVerificationOptions::<&str, &str>::default(),
   2671         )?.static_state.credential_public_key, UncompressedPubKey::P256(k) if k.x() == x.as_slice() && k.y() == y.as_slice()));
   2672         Ok(())
   2673     }
   2674     #[test]
   2675     #[cfg(feature = "custom")]
   2676     fn p256_auth() -> Result<(), AggErr> {
   2677         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   2678         let mut opts = PublicKeyCredentialRequestOptions::passkey(&rp_id);
   2679         opts.challenge = Challenge(0);
   2680         let client_data_json = br#"{"type":"webauthn.get","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   2681         // We over-allocate by 32 bytes. See [`AuthenticatorAssertion::new`] for more information.
   2682         let mut authenticator_data = Vec::with_capacity(69);
   2683         authenticator_data.extend_from_slice(
   2684             [
   2685                 // rpIdHash.
   2686                 // This will be overwritten later.
   2687                 0,
   2688                 0,
   2689                 0,
   2690                 0,
   2691                 0,
   2692                 0,
   2693                 0,
   2694                 0,
   2695                 0,
   2696                 0,
   2697                 0,
   2698                 0,
   2699                 0,
   2700                 0,
   2701                 0,
   2702                 0,
   2703                 0,
   2704                 0,
   2705                 0,
   2706                 0,
   2707                 0,
   2708                 0,
   2709                 0,
   2710                 0,
   2711                 0,
   2712                 0,
   2713                 0,
   2714                 0,
   2715                 0,
   2716                 0,
   2717                 0,
   2718                 0,
   2719                 // flags.
   2720                 // UP and UV (right-to-left).
   2721                 0b0000_0101,
   2722                 // signCount.
   2723                 // 0 as 32-bit big endian.
   2724                 0,
   2725                 0,
   2726                 0,
   2727                 0,
   2728             ]
   2729             .as_slice(),
   2730         );
   2731         authenticator_data[..32]
   2732             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   2733         authenticator_data
   2734             .extend_from_slice(Sha256::digest(client_data_json.as_slice()).as_slice());
   2735         let p256_key = P256Key::from_bytes(
   2736             &[
   2737                 137, 133, 36, 206, 163, 47, 255, 5, 76, 144, 163, 141, 40, 109, 108, 240, 246, 115,
   2738                 178, 237, 169, 68, 6, 129, 92, 21, 238, 127, 55, 158, 207, 95,
   2739             ]
   2740             .into(),
   2741         )
   2742         .unwrap();
   2743         let der_sig: P256DerSig = p256_key.sign(authenticator_data.as_slice());
   2744         let pub_key = p256_key.verifying_key().to_encoded_point(true);
   2745         authenticator_data.truncate(37);
   2746         assert!(!opts.start_ceremony()?.0.verify(
   2747             &rp_id,
   2748             &Authentication {
   2749                 raw_id: CredentialId::try_from(vec![0; 16])?,
   2750                 response: AuthenticatorAssertion::new(
   2751                     client_data_json,
   2752                     authenticator_data,
   2753                     der_sig.as_bytes().into(),
   2754                     Some(UserHandle::try_from(vec![0])?),
   2755                 ),
   2756                 authenticator_attachment: AuthenticatorAttachment::None,
   2757             },
   2758             &mut AuthenticatedCredential::new(
   2759                 CredentialId::try_from([0; 16].as_slice())?,
   2760                 UserHandle::try_from([0].as_slice())?,
   2761                 StaticState {
   2762                     credential_public_key: CompressedPubKey::<&[u8], _, &[u8], &[u8]>::P256(
   2763                         CompressedP256PubKey::from((
   2764                             (*pub_key.x().unwrap()).into(),
   2765                             pub_key.tag() == Tag::CompressedOddY
   2766                         )),
   2767                     ),
   2768                     extensions: AuthenticatorExtensionOutputStaticState {
   2769                         cred_protect: CredentialProtectionPolicy::None,
   2770                         hmac_secret: None,
   2771                     },
   2772                 },
   2773                 DynamicState {
   2774                     user_verified: true,
   2775                     backup: Backup::NotEligible,
   2776                     sign_count: 0,
   2777                     authenticator_attachment: AuthenticatorAttachment::None,
   2778                 },
   2779             )?,
   2780             &AuthenticationVerificationOptions::<&str, &str>::default(),
   2781         )?);
   2782         Ok(())
   2783     }
   2784     #[test]
   2785     #[cfg(feature = "custom")]
   2786     fn p384_reg() -> Result<(), AggErr> {
   2787         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   2788         let id = UserHandle::try_from([0; 1].as_slice())?;
   2789         let mut opts = PublicKeyCredentialCreationOptions::passkey(
   2790             &rp_id,
   2791             PublicKeyCredentialUserEntity {
   2792                 name: "foo".try_into()?,
   2793                 id,
   2794                 display_name: None,
   2795             },
   2796             Vec::new(),
   2797         );
   2798         opts.challenge = Challenge(0);
   2799         let client_data_json = br#"{"type":"webauthn.create","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   2800         // We over-allocate by 32 bytes. See [`AuthenticatorAttestation::new`] for more information.
   2801         let mut attestation_object = Vec::with_capacity(243);
   2802         attestation_object.extend_from_slice(
   2803             [
   2804                 CBOR_MAP | 3,
   2805                 CBOR_TEXT | 3,
   2806                 b'f',
   2807                 b'm',
   2808                 b't',
   2809                 CBOR_TEXT | 4,
   2810                 b'n',
   2811                 b'o',
   2812                 b'n',
   2813                 b'e',
   2814                 // CBOR text of length 7.
   2815                 CBOR_TEXT | 7,
   2816                 b'a',
   2817                 b't',
   2818                 b't',
   2819                 b'S',
   2820                 b't',
   2821                 b'm',
   2822                 b't',
   2823                 CBOR_MAP,
   2824                 CBOR_TEXT | 8,
   2825                 b'a',
   2826                 b'u',
   2827                 b't',
   2828                 b'h',
   2829                 b'D',
   2830                 b'a',
   2831                 b't',
   2832                 b'a',
   2833                 CBOR_BYTES | 24,
   2834                 // Length is 181.
   2835                 181,
   2836                 // RP ID HASH.
   2837                 // This will be overwritten later.
   2838                 0,
   2839                 0,
   2840                 0,
   2841                 0,
   2842                 0,
   2843                 0,
   2844                 0,
   2845                 0,
   2846                 0,
   2847                 0,
   2848                 0,
   2849                 0,
   2850                 0,
   2851                 0,
   2852                 0,
   2853                 0,
   2854                 0,
   2855                 0,
   2856                 0,
   2857                 0,
   2858                 0,
   2859                 0,
   2860                 0,
   2861                 0,
   2862                 0,
   2863                 0,
   2864                 0,
   2865                 0,
   2866                 0,
   2867                 0,
   2868                 0,
   2869                 0,
   2870                 // FLAGS.
   2871                 // UP, UV, and AT (right-to-left).
   2872                 0b0100_0101,
   2873                 // COUNTER.
   2874                 // 0 as 32-bit big-endian.
   2875                 0,
   2876                 0,
   2877                 0,
   2878                 0,
   2879                 // AAGUID.
   2880                 0,
   2881                 0,
   2882                 0,
   2883                 0,
   2884                 0,
   2885                 0,
   2886                 0,
   2887                 0,
   2888                 0,
   2889                 0,
   2890                 0,
   2891                 0,
   2892                 0,
   2893                 0,
   2894                 0,
   2895                 0,
   2896                 // L.
   2897                 // CREDENTIAL ID length is 16 as 16-bit big endian.
   2898                 0,
   2899                 16,
   2900                 // CREDENTIAL ID.
   2901                 0,
   2902                 0,
   2903                 0,
   2904                 0,
   2905                 0,
   2906                 0,
   2907                 0,
   2908                 0,
   2909                 0,
   2910                 0,
   2911                 0,
   2912                 0,
   2913                 0,
   2914                 0,
   2915                 0,
   2916                 0,
   2917                 CBOR_MAP | 5,
   2918                 // COSE kty.
   2919                 CBOR_UINT | 1,
   2920                 // COSE EC2.
   2921                 CBOR_UINT | 2,
   2922                 // COSE alg.
   2923                 CBOR_UINT | 3,
   2924                 CBOR_NEG | 24,
   2925                 // COSE ES384.
   2926                 34,
   2927                 // COSE EC2 crv.
   2928                 CBOR_NEG,
   2929                 // COSE P-384.
   2930                 CBOR_UINT | 2,
   2931                 // COSE EC2 x.
   2932                 CBOR_NEG | 1,
   2933                 CBOR_BYTES | 24,
   2934                 // Length is 48.
   2935                 48,
   2936                 // X-coordinate. This will be overwritten later.
   2937                 0,
   2938                 0,
   2939                 0,
   2940                 0,
   2941                 0,
   2942                 0,
   2943                 0,
   2944                 0,
   2945                 0,
   2946                 0,
   2947                 0,
   2948                 0,
   2949                 0,
   2950                 0,
   2951                 0,
   2952                 0,
   2953                 0,
   2954                 0,
   2955                 0,
   2956                 0,
   2957                 0,
   2958                 0,
   2959                 0,
   2960                 0,
   2961                 0,
   2962                 0,
   2963                 0,
   2964                 0,
   2965                 0,
   2966                 0,
   2967                 0,
   2968                 0,
   2969                 0,
   2970                 0,
   2971                 0,
   2972                 0,
   2973                 0,
   2974                 0,
   2975                 0,
   2976                 0,
   2977                 0,
   2978                 0,
   2979                 0,
   2980                 0,
   2981                 0,
   2982                 0,
   2983                 0,
   2984                 0,
   2985                 // COSE EC2 y.
   2986                 CBOR_NEG | 2,
   2987                 CBOR_BYTES | 24,
   2988                 // Length is 48.
   2989                 48,
   2990                 // Y-coordinate. This will be overwritten later.
   2991                 0,
   2992                 0,
   2993                 0,
   2994                 0,
   2995                 0,
   2996                 0,
   2997                 0,
   2998                 0,
   2999                 0,
   3000                 0,
   3001                 0,
   3002                 0,
   3003                 0,
   3004                 0,
   3005                 0,
   3006                 0,
   3007                 0,
   3008                 0,
   3009                 0,
   3010                 0,
   3011                 0,
   3012                 0,
   3013                 0,
   3014                 0,
   3015                 0,
   3016                 0,
   3017                 0,
   3018                 0,
   3019                 0,
   3020                 0,
   3021                 0,
   3022                 0,
   3023                 0,
   3024                 0,
   3025                 0,
   3026                 0,
   3027                 0,
   3028                 0,
   3029                 0,
   3030                 0,
   3031                 0,
   3032                 0,
   3033                 0,
   3034                 0,
   3035                 0,
   3036                 0,
   3037                 0,
   3038                 0,
   3039             ]
   3040             .as_slice(),
   3041         );
   3042         attestation_object[30..62]
   3043             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   3044         let p384_key = P384Key::from_bytes(
   3045             &[
   3046                 158, 99, 156, 49, 190, 211, 85, 167, 28, 2, 80, 57, 31, 22, 17, 38, 85, 78, 232,
   3047                 42, 45, 199, 154, 243, 136, 251, 84, 34, 5, 120, 208, 91, 61, 248, 64, 144, 87, 1,
   3048                 32, 86, 220, 68, 182, 11, 105, 223, 75, 70,
   3049             ]
   3050             .into(),
   3051         )
   3052         .unwrap()
   3053         .verifying_key()
   3054         .to_encoded_point(false);
   3055         let x = p384_key.x().unwrap();
   3056         let y = p384_key.y().unwrap();
   3057         attestation_object[112..160].copy_from_slice(x);
   3058         attestation_object[163..].copy_from_slice(y);
   3059         assert!(matches!(opts.start_ceremony()?.0.verify(
   3060             &rp_id,
   3061             id,
   3062             &Registration {
   3063                 response: AuthenticatorAttestation::new(
   3064                     client_data_json,
   3065                     attestation_object,
   3066                     AuthTransports::NONE,
   3067                 ),
   3068                 authenticator_attachment: AuthenticatorAttachment::None,
   3069                 client_extension_results: ClientExtensionsOutputs {
   3070                     cred_props: None,
   3071                     prf: None,
   3072                 },
   3073             },
   3074             &RegistrationVerificationOptions::<&str, &str>::default(),
   3075         )?.static_state.credential_public_key, UncompressedPubKey::P384(k) if k.x() == x.as_slice() && k.y() == y.as_slice()));
   3076         Ok(())
   3077     }
   3078     #[test]
   3079     #[cfg(feature = "custom")]
   3080     fn p384_auth() -> Result<(), AggErr> {
   3081         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   3082         let mut opts = PublicKeyCredentialRequestOptions::passkey(&rp_id);
   3083         opts.challenge = Challenge(0);
   3084         let client_data_json = br#"{"type":"webauthn.get","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   3085         // We over-allocate by 32 bytes. See [`AuthenticatorAssertion::new`] for more information.
   3086         let mut authenticator_data = Vec::with_capacity(69);
   3087         authenticator_data.extend_from_slice(
   3088             [
   3089                 // rpIdHash.
   3090                 // This will be overwritten later.
   3091                 0,
   3092                 0,
   3093                 0,
   3094                 0,
   3095                 0,
   3096                 0,
   3097                 0,
   3098                 0,
   3099                 0,
   3100                 0,
   3101                 0,
   3102                 0,
   3103                 0,
   3104                 0,
   3105                 0,
   3106                 0,
   3107                 0,
   3108                 0,
   3109                 0,
   3110                 0,
   3111                 0,
   3112                 0,
   3113                 0,
   3114                 0,
   3115                 0,
   3116                 0,
   3117                 0,
   3118                 0,
   3119                 0,
   3120                 0,
   3121                 0,
   3122                 0,
   3123                 // flags.
   3124                 // UP and UV (right-to-left).
   3125                 0b0000_0101,
   3126                 // signCount.
   3127                 // 0 as 32-bit big-endian.
   3128                 0,
   3129                 0,
   3130                 0,
   3131                 0,
   3132             ]
   3133             .as_slice(),
   3134         );
   3135         authenticator_data[..32]
   3136             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   3137         authenticator_data
   3138             .extend_from_slice(Sha256::digest(client_data_json.as_slice()).as_slice());
   3139         let p384_key = P384Key::from_bytes(
   3140             &[
   3141                 158, 99, 156, 49, 190, 211, 85, 167, 28, 2, 80, 57, 31, 22, 17, 38, 85, 78, 232,
   3142                 42, 45, 199, 154, 243, 136, 251, 84, 34, 5, 120, 208, 91, 61, 248, 64, 144, 87, 1,
   3143                 32, 86, 220, 68, 182, 11, 105, 223, 75, 70,
   3144             ]
   3145             .into(),
   3146         )
   3147         .unwrap();
   3148         let der_sig: P384DerSig = p384_key.sign(authenticator_data.as_slice());
   3149         let pub_key = p384_key.verifying_key().to_encoded_point(true);
   3150         authenticator_data.truncate(37);
   3151         assert!(!opts.start_ceremony()?.0.verify(
   3152             &rp_id,
   3153             &Authentication {
   3154                 raw_id: CredentialId::try_from(vec![0; 16])?,
   3155                 response: AuthenticatorAssertion::new(
   3156                     client_data_json,
   3157                     authenticator_data,
   3158                     der_sig.as_bytes().into(),
   3159                     Some(UserHandle::try_from(vec![0])?),
   3160                 ),
   3161                 authenticator_attachment: AuthenticatorAttachment::None,
   3162             },
   3163             &mut AuthenticatedCredential::new(
   3164                 CredentialId::try_from([0; 16].as_slice())?,
   3165                 UserHandle::try_from([0].as_slice())?,
   3166                 StaticState {
   3167                     credential_public_key: CompressedPubKey::<&[u8], &[u8], _, &[u8]>::P384(
   3168                         CompressedP384PubKey::from((
   3169                             (*pub_key.x().unwrap()).into(),
   3170                             pub_key.tag() == Tag::CompressedOddY
   3171                         )),
   3172                     ),
   3173                     extensions: AuthenticatorExtensionOutputStaticState {
   3174                         cred_protect: CredentialProtectionPolicy::None,
   3175                         hmac_secret: None,
   3176                     },
   3177                 },
   3178                 DynamicState {
   3179                     user_verified: true,
   3180                     backup: Backup::NotEligible,
   3181                     sign_count: 0,
   3182                     authenticator_attachment: AuthenticatorAttachment::None,
   3183                 },
   3184             )?,
   3185             &AuthenticationVerificationOptions::<&str, &str>::default(),
   3186         )?);
   3187         Ok(())
   3188     }
   3189     #[test]
   3190     #[cfg(feature = "custom")]
   3191     fn rsa_reg() -> Result<(), AggErr> {
   3192         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   3193         let id = UserHandle::try_from([0; 1].as_slice())?;
   3194         let mut opts = PublicKeyCredentialCreationOptions::passkey(
   3195             &rp_id,
   3196             PublicKeyCredentialUserEntity {
   3197                 name: "foo".try_into()?,
   3198                 id,
   3199                 display_name: None,
   3200             },
   3201             Vec::new(),
   3202         );
   3203         opts.challenge = Challenge(0);
   3204         let client_data_json = br#"{"type":"webauthn.create","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   3205         // We over-allocate by 32 bytes. See [`AuthenticatorAttestation::new`] for more information.
   3206         let mut attestation_object = Vec::with_capacity(406);
   3207         attestation_object.extend_from_slice(
   3208             [
   3209                 CBOR_MAP | 3,
   3210                 CBOR_TEXT | 3,
   3211                 b'f',
   3212                 b'm',
   3213                 b't',
   3214                 CBOR_TEXT | 4,
   3215                 b'n',
   3216                 b'o',
   3217                 b'n',
   3218                 b'e',
   3219                 CBOR_TEXT | 7,
   3220                 b'a',
   3221                 b't',
   3222                 b't',
   3223                 b'S',
   3224                 b't',
   3225                 b'm',
   3226                 b't',
   3227                 CBOR_MAP,
   3228                 CBOR_TEXT | 8,
   3229                 b'a',
   3230                 b'u',
   3231                 b't',
   3232                 b'h',
   3233                 b'D',
   3234                 b'a',
   3235                 b't',
   3236                 b'a',
   3237                 CBOR_BYTES | 25,
   3238                 // Length is 343 as 16-bit big-endian.
   3239                 1,
   3240                 87,
   3241                 // RP ID HASH.
   3242                 // This will be overwritten later.
   3243                 0,
   3244                 0,
   3245                 0,
   3246                 0,
   3247                 0,
   3248                 0,
   3249                 0,
   3250                 0,
   3251                 0,
   3252                 0,
   3253                 0,
   3254                 0,
   3255                 0,
   3256                 0,
   3257                 0,
   3258                 0,
   3259                 0,
   3260                 0,
   3261                 0,
   3262                 0,
   3263                 0,
   3264                 0,
   3265                 0,
   3266                 0,
   3267                 0,
   3268                 0,
   3269                 0,
   3270                 0,
   3271                 0,
   3272                 0,
   3273                 0,
   3274                 0,
   3275                 // FLAGS.
   3276                 // UP, UV, and AT (right-to-left).
   3277                 0b0100_0101,
   3278                 // COUNTER.
   3279                 // 0 as 32-bit big-endian.
   3280                 0,
   3281                 0,
   3282                 0,
   3283                 0,
   3284                 // AAGUID.
   3285                 0,
   3286                 0,
   3287                 0,
   3288                 0,
   3289                 0,
   3290                 0,
   3291                 0,
   3292                 0,
   3293                 0,
   3294                 0,
   3295                 0,
   3296                 0,
   3297                 0,
   3298                 0,
   3299                 0,
   3300                 0,
   3301                 // L.
   3302                 // CREDENTIAL ID length is 16 as 16-bit big endian.
   3303                 0,
   3304                 16,
   3305                 // CREDENTIAL ID.
   3306                 0,
   3307                 0,
   3308                 0,
   3309                 0,
   3310                 0,
   3311                 0,
   3312                 0,
   3313                 0,
   3314                 0,
   3315                 0,
   3316                 0,
   3317                 0,
   3318                 0,
   3319                 0,
   3320                 0,
   3321                 0,
   3322                 CBOR_MAP | 4,
   3323                 // COSE kty.
   3324                 CBOR_UINT | 1,
   3325                 // COSE RSA.
   3326                 CBOR_UINT | 3,
   3327                 // COSE alg.
   3328                 CBOR_UINT | 3,
   3329                 CBOR_NEG | 25,
   3330                 // COSE RS256.
   3331                 1,
   3332                 0,
   3333                 // COSE n.
   3334                 CBOR_NEG,
   3335                 CBOR_BYTES | 25,
   3336                 // Length is 256 as 16-bit big-endian.
   3337                 1,
   3338                 0,
   3339                 // N. This will be overwritten later.
   3340                 0,
   3341                 0,
   3342                 0,
   3343                 0,
   3344                 0,
   3345                 0,
   3346                 0,
   3347                 0,
   3348                 0,
   3349                 0,
   3350                 0,
   3351                 0,
   3352                 0,
   3353                 0,
   3354                 0,
   3355                 0,
   3356                 0,
   3357                 0,
   3358                 0,
   3359                 0,
   3360                 0,
   3361                 0,
   3362                 0,
   3363                 0,
   3364                 0,
   3365                 0,
   3366                 0,
   3367                 0,
   3368                 0,
   3369                 0,
   3370                 0,
   3371                 0,
   3372                 0,
   3373                 0,
   3374                 0,
   3375                 0,
   3376                 0,
   3377                 0,
   3378                 0,
   3379                 0,
   3380                 0,
   3381                 0,
   3382                 0,
   3383                 0,
   3384                 0,
   3385                 0,
   3386                 0,
   3387                 0,
   3388                 0,
   3389                 0,
   3390                 0,
   3391                 0,
   3392                 0,
   3393                 0,
   3394                 0,
   3395                 0,
   3396                 0,
   3397                 0,
   3398                 0,
   3399                 0,
   3400                 0,
   3401                 0,
   3402                 0,
   3403                 0,
   3404                 0,
   3405                 0,
   3406                 0,
   3407                 0,
   3408                 0,
   3409                 0,
   3410                 0,
   3411                 0,
   3412                 0,
   3413                 0,
   3414                 0,
   3415                 0,
   3416                 0,
   3417                 0,
   3418                 0,
   3419                 0,
   3420                 0,
   3421                 0,
   3422                 0,
   3423                 0,
   3424                 0,
   3425                 0,
   3426                 0,
   3427                 0,
   3428                 0,
   3429                 0,
   3430                 0,
   3431                 0,
   3432                 0,
   3433                 0,
   3434                 0,
   3435                 0,
   3436                 0,
   3437                 0,
   3438                 0,
   3439                 0,
   3440                 0,
   3441                 0,
   3442                 0,
   3443                 0,
   3444                 0,
   3445                 0,
   3446                 0,
   3447                 0,
   3448                 0,
   3449                 0,
   3450                 0,
   3451                 0,
   3452                 0,
   3453                 0,
   3454                 0,
   3455                 0,
   3456                 0,
   3457                 0,
   3458                 0,
   3459                 0,
   3460                 0,
   3461                 0,
   3462                 0,
   3463                 0,
   3464                 0,
   3465                 0,
   3466                 0,
   3467                 0,
   3468                 0,
   3469                 0,
   3470                 0,
   3471                 0,
   3472                 0,
   3473                 0,
   3474                 0,
   3475                 0,
   3476                 0,
   3477                 0,
   3478                 0,
   3479                 0,
   3480                 0,
   3481                 0,
   3482                 0,
   3483                 0,
   3484                 0,
   3485                 0,
   3486                 0,
   3487                 0,
   3488                 0,
   3489                 0,
   3490                 0,
   3491                 0,
   3492                 0,
   3493                 0,
   3494                 0,
   3495                 0,
   3496                 0,
   3497                 0,
   3498                 0,
   3499                 0,
   3500                 0,
   3501                 0,
   3502                 0,
   3503                 0,
   3504                 0,
   3505                 0,
   3506                 0,
   3507                 0,
   3508                 0,
   3509                 0,
   3510                 0,
   3511                 0,
   3512                 0,
   3513                 0,
   3514                 0,
   3515                 0,
   3516                 0,
   3517                 0,
   3518                 0,
   3519                 0,
   3520                 0,
   3521                 0,
   3522                 0,
   3523                 0,
   3524                 0,
   3525                 0,
   3526                 0,
   3527                 0,
   3528                 0,
   3529                 0,
   3530                 0,
   3531                 0,
   3532                 0,
   3533                 0,
   3534                 0,
   3535                 0,
   3536                 0,
   3537                 0,
   3538                 0,
   3539                 0,
   3540                 0,
   3541                 0,
   3542                 0,
   3543                 0,
   3544                 0,
   3545                 0,
   3546                 0,
   3547                 0,
   3548                 0,
   3549                 0,
   3550                 0,
   3551                 0,
   3552                 0,
   3553                 0,
   3554                 0,
   3555                 0,
   3556                 0,
   3557                 0,
   3558                 0,
   3559                 0,
   3560                 0,
   3561                 0,
   3562                 0,
   3563                 0,
   3564                 0,
   3565                 0,
   3566                 0,
   3567                 0,
   3568                 0,
   3569                 0,
   3570                 0,
   3571                 0,
   3572                 0,
   3573                 0,
   3574                 0,
   3575                 0,
   3576                 0,
   3577                 0,
   3578                 0,
   3579                 0,
   3580                 0,
   3581                 0,
   3582                 0,
   3583                 0,
   3584                 0,
   3585                 0,
   3586                 0,
   3587                 0,
   3588                 0,
   3589                 0,
   3590                 0,
   3591                 0,
   3592                 0,
   3593                 0,
   3594                 0,
   3595                 0,
   3596                 // COSE e.
   3597                 CBOR_NEG | 1,
   3598                 CBOR_BYTES | 3,
   3599                 // 65537 as 24-bit big-endian.
   3600                 1,
   3601                 0,
   3602                 1,
   3603             ]
   3604             .as_slice(),
   3605         );
   3606         attestation_object[31..63]
   3607             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   3608         let n = [
   3609             111, 183, 124, 133, 38, 167, 70, 148, 44, 50, 30, 60, 121, 14, 38, 37, 96, 114, 107,
   3610             195, 248, 64, 79, 36, 237, 140, 43, 27, 94, 74, 102, 152, 135, 102, 184, 150, 186, 206,
   3611             185, 19, 165, 209, 48, 98, 98, 9, 3, 205, 208, 82, 250, 105, 132, 201, 73, 62, 60, 165,
   3612             100, 128, 153, 9, 41, 118, 66, 95, 236, 214, 73, 135, 197, 68, 184, 10, 27, 116, 204,
   3613             145, 50, 174, 58, 42, 183, 181, 119, 232, 126, 252, 217, 96, 162, 190, 103, 122, 64,
   3614             87, 145, 45, 32, 207, 17, 239, 223, 3, 35, 14, 112, 119, 124, 141, 123, 208, 239, 105,
   3615             81, 217, 151, 162, 190, 17, 88, 182, 176, 158, 81, 200, 42, 166, 133, 48, 23, 236, 55,
   3616             117, 248, 233, 151, 203, 122, 155, 231, 46, 177, 20, 20, 151, 64, 222, 239, 226, 7, 21,
   3617             254, 81, 202, 64, 232, 161, 235, 22, 51, 246, 207, 213, 0, 229, 138, 46, 222, 205, 157,
   3618             108, 139, 253, 230, 80, 50, 2, 122, 212, 163, 100, 180, 114, 12, 113, 52, 56, 99, 188,
   3619             42, 198, 212, 23, 182, 222, 56, 221, 200, 79, 96, 239, 221, 135, 10, 17, 106, 183, 56,
   3620             104, 68, 94, 198, 196, 35, 200, 83, 204, 26, 185, 204, 212, 31, 183, 19, 111, 233, 13,
   3621             72, 93, 53, 65, 111, 59, 242, 122, 160, 244, 162, 126, 38, 235, 156, 47, 88, 39, 132,
   3622             153, 79, 0, 133, 78, 7, 218, 165, 241,
   3623         ];
   3624         let e = 65537;
   3625         let d = [
   3626             145, 79, 21, 97, 233, 3, 192, 194, 177, 68, 181, 80, 120, 197, 23, 44, 185, 74, 144, 0,
   3627             132, 149, 139, 11, 16, 224, 4, 112, 236, 94, 238, 97, 121, 124, 213, 145, 24, 253, 168,
   3628             35, 190, 205, 132, 115, 33, 201, 38, 253, 246, 180, 66, 155, 165, 46, 3, 254, 68, 108,
   3629             154, 247, 246, 45, 187, 0, 204, 96, 185, 157, 249, 174, 158, 38, 62, 244, 183, 76, 102,
   3630             6, 219, 92, 212, 138, 59, 147, 163, 219, 111, 39, 105, 21, 236, 196, 38, 255, 114, 247,
   3631             82, 104, 113, 204, 29, 152, 209, 219, 48, 239, 74, 129, 19, 247, 33, 239, 119, 166,
   3632             216, 152, 94, 138, 238, 164, 242, 129, 50, 150, 57, 20, 53, 224, 56, 241, 138, 97, 111,
   3633             215, 107, 212, 195, 146, 108, 143, 0, 229, 181, 171, 73, 152, 105, 146, 25, 243, 242,
   3634             140, 252, 248, 162, 247, 63, 168, 180, 20, 153, 120, 10, 248, 211, 1, 71, 127, 212,
   3635             249, 237, 203, 202, 48, 26, 216, 226, 228, 186, 13, 204, 70, 255, 240, 89, 255, 59, 83,
   3636             31, 253, 55, 43, 158, 90, 248, 83, 32, 159, 105, 57, 134, 34, 96, 18, 255, 245, 153,
   3637             162, 60, 91, 99, 220, 51, 44, 85, 114, 67, 125, 202, 65, 217, 245, 40, 8, 81, 165, 142,
   3638             24, 245, 127, 122, 247, 152, 212, 75, 45, 59, 90, 184, 234, 31, 147, 36, 8, 212, 45,
   3639             50, 23, 3, 25, 253, 87, 227, 79, 119, 161,
   3640         ];
   3641         let p = BigUint::from_slice(
   3642             [
   3643                 352691927, 1294578443, 816143558, 690659917, 1161596366, 1544791087, 3999549486,
   3644                 3319149924, 2349250979, 1304689381, 3959753736, 3377900978, 866506027, 1671521644,
   3645                 3926847564, 898221388, 3448219846, 494454484, 3915534864, 2869735916, 2456511629,
   3646                 3397234721, 3012775852, 3472309790, 1923617705, 2993441050, 3210302569, 3605331368,
   3647                 3352563766, 688081007, 4104512503, 4145593376,
   3648             ]
   3649             .as_slice(),
   3650         );
   3651         let p_2 = BigUint::from_slice(
   3652             [
   3653                 4039514409, 964284038, 3230008587, 3320139220, 3562360334, 3165876926, 212773653,
   3654                 2752465512, 2973674888, 1717425549, 2084262803, 3585031058, 4162394935, 1428626842,
   3655                 1015474994, 3283774155, 2840050110, 190639246, 147241978, 2994256073, 4081014755,
   3656                 3102401369, 3547397148, 1545029057, 895305733, 2689179461, 1593439337, 3960057302,
   3657                 193068804, 2835123424, 4054880057, 4200258364,
   3658             ]
   3659             .as_slice(),
   3660         );
   3661         let rsa_key = RsaKey::<Sha256>::new(
   3662             RsaPrivateKey::from_components(
   3663                 BigUint::from_bytes_le(n.as_slice()),
   3664                 e.into(),
   3665                 BigUint::from_bytes_le(d.as_slice()),
   3666                 vec![p, p_2],
   3667             )
   3668             .unwrap(),
   3669         )
   3670         .verifying_key();
   3671         let n = rsa_key.as_ref().n().to_bytes_be();
   3672         attestation_object[113..369].copy_from_slice(n.as_slice());
   3673         assert!(matches!(opts.start_ceremony()?.0.verify(
   3674             &rp_id,
   3675             id,
   3676             &Registration {
   3677                 response: AuthenticatorAttestation::new(
   3678                     client_data_json,
   3679                     attestation_object,
   3680                     AuthTransports::NONE,
   3681                 ),
   3682                 authenticator_attachment: AuthenticatorAttachment::None,
   3683                 client_extension_results: ClientExtensionsOutputs {
   3684                     cred_props: None,
   3685                     prf: None,
   3686                 },
   3687             },
   3688             &RegistrationVerificationOptions::<&str, &str>::default(),
   3689         )?.static_state.credential_public_key, UncompressedPubKey::Rsa(k) if *k.n() == n.as_slice() && k.e() == e));
   3690         Ok(())
   3691     }
   3692     #[test]
   3693     #[cfg(feature = "custom")]
   3694     fn rsa_auth() -> Result<(), AggErr> {
   3695         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   3696         let mut opts = PublicKeyCredentialRequestOptions::passkey(&rp_id);
   3697         opts.challenge = Challenge(0);
   3698         let client_data_json = br#"{"type":"webauthn.get","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   3699         // We over-allocate by 32 bytes. See [`AuthenticatorAssertion::new`] for more information.
   3700         let mut authenticator_data = Vec::with_capacity(69);
   3701         authenticator_data.extend_from_slice(
   3702             [
   3703                 // rpIdHash.
   3704                 // This will be overwritten later.
   3705                 0,
   3706                 0,
   3707                 0,
   3708                 0,
   3709                 0,
   3710                 0,
   3711                 0,
   3712                 0,
   3713                 0,
   3714                 0,
   3715                 0,
   3716                 0,
   3717                 0,
   3718                 0,
   3719                 0,
   3720                 0,
   3721                 0,
   3722                 0,
   3723                 0,
   3724                 0,
   3725                 0,
   3726                 0,
   3727                 0,
   3728                 0,
   3729                 0,
   3730                 0,
   3731                 0,
   3732                 0,
   3733                 0,
   3734                 0,
   3735                 0,
   3736                 0,
   3737                 // flags.
   3738                 // UP and UV (right-to-left).
   3739                 0b0000_0101,
   3740                 // signCount.
   3741                 // 0 as 32-bit big-endian.
   3742                 0,
   3743                 0,
   3744                 0,
   3745                 0,
   3746             ]
   3747             .as_slice(),
   3748         );
   3749         authenticator_data[..32]
   3750             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   3751         authenticator_data
   3752             .extend_from_slice(Sha256::digest(client_data_json.as_slice()).as_slice());
   3753         let n = [
   3754             111, 183, 124, 133, 38, 167, 70, 148, 44, 50, 30, 60, 121, 14, 38, 37, 96, 114, 107,
   3755             195, 248, 64, 79, 36, 237, 140, 43, 27, 94, 74, 102, 152, 135, 102, 184, 150, 186, 206,
   3756             185, 19, 165, 209, 48, 98, 98, 9, 3, 205, 208, 82, 250, 105, 132, 201, 73, 62, 60, 165,
   3757             100, 128, 153, 9, 41, 118, 66, 95, 236, 214, 73, 135, 197, 68, 184, 10, 27, 116, 204,
   3758             145, 50, 174, 58, 42, 183, 181, 119, 232, 126, 252, 217, 96, 162, 190, 103, 122, 64,
   3759             87, 145, 45, 32, 207, 17, 239, 223, 3, 35, 14, 112, 119, 124, 141, 123, 208, 239, 105,
   3760             81, 217, 151, 162, 190, 17, 88, 182, 176, 158, 81, 200, 42, 166, 133, 48, 23, 236, 55,
   3761             117, 248, 233, 151, 203, 122, 155, 231, 46, 177, 20, 20, 151, 64, 222, 239, 226, 7, 21,
   3762             254, 81, 202, 64, 232, 161, 235, 22, 51, 246, 207, 213, 0, 229, 138, 46, 222, 205, 157,
   3763             108, 139, 253, 230, 80, 50, 2, 122, 212, 163, 100, 180, 114, 12, 113, 52, 56, 99, 188,
   3764             42, 198, 212, 23, 182, 222, 56, 221, 200, 79, 96, 239, 221, 135, 10, 17, 106, 183, 56,
   3765             104, 68, 94, 198, 196, 35, 200, 83, 204, 26, 185, 204, 212, 31, 183, 19, 111, 233, 13,
   3766             72, 93, 53, 65, 111, 59, 242, 122, 160, 244, 162, 126, 38, 235, 156, 47, 88, 39, 132,
   3767             153, 79, 0, 133, 78, 7, 218, 165, 241,
   3768         ];
   3769         let e = 65537;
   3770         let d = [
   3771             145, 79, 21, 97, 233, 3, 192, 194, 177, 68, 181, 80, 120, 197, 23, 44, 185, 74, 144, 0,
   3772             132, 149, 139, 11, 16, 224, 4, 112, 236, 94, 238, 97, 121, 124, 213, 145, 24, 253, 168,
   3773             35, 190, 205, 132, 115, 33, 201, 38, 253, 246, 180, 66, 155, 165, 46, 3, 254, 68, 108,
   3774             154, 247, 246, 45, 187, 0, 204, 96, 185, 157, 249, 174, 158, 38, 62, 244, 183, 76, 102,
   3775             6, 219, 92, 212, 138, 59, 147, 163, 219, 111, 39, 105, 21, 236, 196, 38, 255, 114, 247,
   3776             82, 104, 113, 204, 29, 152, 209, 219, 48, 239, 74, 129, 19, 247, 33, 239, 119, 166,
   3777             216, 152, 94, 138, 238, 164, 242, 129, 50, 150, 57, 20, 53, 224, 56, 241, 138, 97, 111,
   3778             215, 107, 212, 195, 146, 108, 143, 0, 229, 181, 171, 73, 152, 105, 146, 25, 243, 242,
   3779             140, 252, 248, 162, 247, 63, 168, 180, 20, 153, 120, 10, 248, 211, 1, 71, 127, 212,
   3780             249, 237, 203, 202, 48, 26, 216, 226, 228, 186, 13, 204, 70, 255, 240, 89, 255, 59, 83,
   3781             31, 253, 55, 43, 158, 90, 248, 83, 32, 159, 105, 57, 134, 34, 96, 18, 255, 245, 153,
   3782             162, 60, 91, 99, 220, 51, 44, 85, 114, 67, 125, 202, 65, 217, 245, 40, 8, 81, 165, 142,
   3783             24, 245, 127, 122, 247, 152, 212, 75, 45, 59, 90, 184, 234, 31, 147, 36, 8, 212, 45,
   3784             50, 23, 3, 25, 253, 87, 227, 79, 119, 161,
   3785         ];
   3786         let p = BigUint::from_slice(
   3787             [
   3788                 352691927, 1294578443, 816143558, 690659917, 1161596366, 1544791087, 3999549486,
   3789                 3319149924, 2349250979, 1304689381, 3959753736, 3377900978, 866506027, 1671521644,
   3790                 3926847564, 898221388, 3448219846, 494454484, 3915534864, 2869735916, 2456511629,
   3791                 3397234721, 3012775852, 3472309790, 1923617705, 2993441050, 3210302569, 3605331368,
   3792                 3352563766, 688081007, 4104512503, 4145593376,
   3793             ]
   3794             .as_slice(),
   3795         );
   3796         let p_2 = BigUint::from_slice(
   3797             [
   3798                 4039514409, 964284038, 3230008587, 3320139220, 3562360334, 3165876926, 212773653,
   3799                 2752465512, 2973674888, 1717425549, 2084262803, 3585031058, 4162394935, 1428626842,
   3800                 1015474994, 3283774155, 2840050110, 190639246, 147241978, 2994256073, 4081014755,
   3801                 3102401369, 3547397148, 1545029057, 895305733, 2689179461, 1593439337, 3960057302,
   3802                 193068804, 2835123424, 4054880057, 4200258364,
   3803             ]
   3804             .as_slice(),
   3805         );
   3806         let rsa_key = RsaKey::<Sha256>::new(
   3807             RsaPrivateKey::from_components(
   3808                 BigUint::from_bytes_le(n.as_slice()),
   3809                 e.into(),
   3810                 BigUint::from_bytes_le(d.as_slice()),
   3811                 vec![p, p_2],
   3812             )
   3813             .unwrap(),
   3814         );
   3815         let rsa_pub = rsa_key.verifying_key();
   3816         let sig = rsa_key.sign(authenticator_data.as_slice()).to_vec();
   3817         authenticator_data.truncate(37);
   3818         assert!(!opts.start_ceremony()?.0.verify(
   3819             &rp_id,
   3820             &Authentication {
   3821                 raw_id: CredentialId::try_from(vec![0; 16])?,
   3822                 response: AuthenticatorAssertion::new(
   3823                     client_data_json,
   3824                     authenticator_data,
   3825                     sig,
   3826                     Some(UserHandle::try_from(vec![0])?),
   3827                 ),
   3828                 authenticator_attachment: AuthenticatorAttachment::None,
   3829             },
   3830             &mut AuthenticatedCredential::new(
   3831                 CredentialId::try_from([0; 16].as_slice())?,
   3832                 UserHandle::try_from([0].as_slice())?,
   3833                 StaticState {
   3834                     credential_public_key: CompressedPubKey::<&[u8], &[u8], &[u8], _>::Rsa(
   3835                         RsaPubKey::try_from((rsa_pub.as_ref().n().to_bytes_be(), e)).unwrap(),
   3836                     ),
   3837                     extensions: AuthenticatorExtensionOutputStaticState {
   3838                         cred_protect: CredentialProtectionPolicy::None,
   3839                         hmac_secret: None,
   3840                     },
   3841                 },
   3842                 DynamicState {
   3843                     user_verified: true,
   3844                     backup: Backup::NotEligible,
   3845                     sign_count: 0,
   3846                     authenticator_attachment: AuthenticatorAttachment::None,
   3847                 },
   3848             )?,
   3849             &AuthenticationVerificationOptions::<&str, &str>::default(),
   3850         )?);
   3851         Ok(())
   3852     }
   3853 }