webauthn_rp

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

request.rs (137759B)


      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 rand::Rng as _;
     32 use rsa::sha2::{Digest as _, Sha256};
     33 #[cfg(feature = "serializable_server_state")]
     34 use std::time::SystemTime;
     35 #[cfg(any(doc, not(feature = "serializable_server_state")))]
     36 use std::{collections::HashSet, time::Instant};
     37 use url::Url as Uri;
     38 /// Contains functionality for beginning the
     39 /// [authentication ceremony](https://www.w3.org/TR/webauthn-3/#authentication-ceremony).
     40 ///
     41 /// # Examples
     42 ///
     43 /// ```
     44 /// # #[cfg(not(feature = "serializable_server_state"))]
     45 /// # use webauthn_rp::request::{FixedCapHashSet, InsertResult};
     46 /// # use webauthn_rp::{
     47 /// #     request::{
     48 /// #         auth::{AllowedCredentials, PublicKeyCredentialRequestOptions},
     49 /// #         register::UserHandle,
     50 /// #         AsciiDomain, Credentials, PublicKeyCredentialDescriptor, RpId,
     51 /// #     },
     52 /// #     response::{AuthTransports, CredentialId, CRED_ID_MIN_LEN},
     53 /// #     AggErr,
     54 /// # };
     55 /// # #[cfg(not(feature = "serializable_server_state"))]
     56 /// let mut ceremonies = FixedCapHashSet::new(128);
     57 /// let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
     58 /// let (server, client) = PublicKeyCredentialRequestOptions::passkey(&rp_id).start_ceremony()?;
     59 /// # #[cfg(not(feature = "serializable_server_state"))]
     60 /// assert!(matches!(
     61 ///     ceremonies.insert_or_replace_all_expired(server),
     62 ///     InsertResult::Success
     63 /// ));
     64 /// # #[cfg(feature = "serde")]
     65 /// assert!(serde_json::to_string(&client).is_ok());
     66 /// let user_handle = get_user_handle();
     67 /// # #[cfg(feature = "custom")]
     68 /// let creds = get_registered_credentials((&user_handle).into())?;
     69 /// # #[cfg(feature = "custom")]
     70 /// let (server_2, client_2) =
     71 ///     PublicKeyCredentialRequestOptions::second_factor(&rp_id, creds)?.start_ceremony()?;
     72 /// # #[cfg(all(feature = "custom", not(feature = "serializable_server_state")))]
     73 /// assert!(matches!(
     74 ///     ceremonies.insert_or_replace_all_expired(server_2),
     75 ///     InsertResult::Success
     76 /// ));
     77 /// # #[cfg(all(feature = "custom", feature = "serde"))]
     78 /// assert!(serde_json::to_string(&client_2).is_ok());
     79 /// /// Extract `UserHandle` from session cookie.
     80 /// fn get_user_handle() -> UserHandle<Vec<u8>> {
     81 ///     // ⋮
     82 /// #     UserHandle::new()
     83 /// }
     84 /// # #[cfg(feature = "custom")]
     85 /// /// Fetch the `AllowedCredentials` associated with `user`.
     86 /// fn get_registered_credentials(user: UserHandle<&[u8]>) -> Result<AllowedCredentials, AggErr> {
     87 ///     // ⋮
     88 /// #     let mut creds = AllowedCredentials::new();
     89 /// #     creds.push(
     90 /// #         PublicKeyCredentialDescriptor {
     91 /// #             id: CredentialId::try_from(vec![0; CRED_ID_MIN_LEN])?,
     92 /// #             transports: AuthTransports::NONE,
     93 /// #         }
     94 /// #         .into(),
     95 /// #     );
     96 /// #     Ok(creds)
     97 /// }
     98 /// # Ok::<_, AggErr>(())
     99 /// ```
    100 pub mod auth;
    101 /// Contains error types.
    102 pub mod error;
    103 /// Contains functionality for beginning the
    104 /// [registration ceremony](https://www.w3.org/TR/webauthn-3/#registration-ceremony).
    105 ///
    106 /// # Examples
    107 ///
    108 /// ```
    109 /// # #[cfg(not(feature = "serializable_server_state"))]
    110 /// # use webauthn_rp::request::{FixedCapHashSet, InsertResult};
    111 /// # use webauthn_rp::{
    112 /// #     request::{
    113 /// #         register::{
    114 /// #             PublicKeyCredentialCreationOptions, PublicKeyCredentialUserEntity, UserHandle,
    115 /// #         },
    116 /// #         AsciiDomain, PublicKeyCredentialDescriptor, RpId
    117 /// #     },
    118 /// #     response::{AuthTransports, CredentialId, CRED_ID_MIN_LEN},
    119 /// #     AggErr,
    120 /// # };
    121 /// # #[cfg(not(feature = "serializable_server_state"))]
    122 /// let mut ceremonies = FixedCapHashSet::new(128);
    123 /// let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
    124 /// let user_handle = get_user_handle();
    125 /// let handle = (&user_handle).into();
    126 /// let user = get_user_entity(handle)?;
    127 /// let creds = get_registered_credentials(handle)?;
    128 /// let (server, client) = PublicKeyCredentialCreationOptions::passkey(&rp_id, user.clone(), creds)
    129 ///     .start_ceremony()?;
    130 /// # #[cfg(not(feature = "serializable_server_state"))]
    131 /// assert!(matches!(
    132 ///     ceremonies.insert_or_replace_all_expired(server),
    133 ///     InsertResult::Success
    134 /// ));
    135 /// # #[cfg(feature = "serde")]
    136 /// assert!(serde_json::to_string(&client).is_ok());
    137 /// let creds_2 = get_registered_credentials(handle)?;
    138 /// let (server_2, client_2) =
    139 ///     PublicKeyCredentialCreationOptions::second_factor(&rp_id, user, creds_2).start_ceremony()?;
    140 /// # #[cfg(not(feature = "serializable_server_state"))]
    141 /// assert!(matches!(
    142 ///     ceremonies.insert_or_replace_all_expired(server_2),
    143 ///     InsertResult::Success
    144 /// ));
    145 /// # #[cfg(feature = "serde")]
    146 /// assert!(serde_json::to_string(&client_2).is_ok());
    147 /// /// Extract `UserHandle` from session cookie if this is not the first credential registered.
    148 /// fn get_user_handle() -> UserHandle<Vec<u8>> {
    149 ///     // ⋮
    150 /// #     UserHandle::new()
    151 /// }
    152 /// /// Fetch `PublicKeyCredentialUserEntity` info associated with `user`.
    153 /// ///
    154 /// /// If this is the first time a credential is being registered, then `PublicKeyCredentialUserEntity`
    155 /// /// will need to be constructed with `name` and `display_name` passed from the client and `UserHandle::new`
    156 /// /// used for `id`. Once created, this info can be stored such that the entity information
    157 /// /// does not need to be requested for subsequent registrations.
    158 /// fn get_user_entity(user: UserHandle<&[u8]>) -> Result<PublicKeyCredentialUserEntity<&[u8]>, AggErr> {
    159 ///     // ⋮
    160 /// #     Ok(PublicKeyCredentialUserEntity {
    161 /// #         name: "foo".try_into()?,
    162 /// #         id: user,
    163 /// #         display_name: None,
    164 /// #     })
    165 /// }
    166 /// /// Fetch the `PublicKeyCredentialDescriptor`s associated with `user`.
    167 /// ///
    168 /// /// This doesn't need to be called when this is the first credential registered for `user`; instead
    169 /// /// an empty `Vec` should be passed.
    170 /// fn get_registered_credentials(
    171 ///     user: UserHandle<&[u8]>,
    172 /// ) -> Result<Vec<PublicKeyCredentialDescriptor<Vec<u8>>>, AggErr> {
    173 ///     // ⋮
    174 /// #     Ok(Vec::new())
    175 /// }
    176 /// # Ok::<_, AggErr>(())
    177 /// ```
    178 pub mod register;
    179 /// Contains functionality to serialize data to a client.
    180 #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
    181 #[cfg(feature = "serde")]
    182 mod ser;
    183 /// Contains functionality to (de)serialize data needed for [`RegistrationServerState`] and
    184 /// [`AuthenticationServerState`] to a data store.
    185 #[cfg_attr(docsrs, doc(cfg(feature = "serializable_server_state")))]
    186 #[cfg(feature = "serializable_server_state")]
    187 pub(super) mod ser_server_state;
    188 // `Challenge` must _never_ be constructable directly or indirectly; thus its tuple field must always be private,
    189 // and it must never implement `trait`s (e.g., `Clone`) that would allow indirect creation. It must only ever
    190 // be constructed via `Self::new` or `Self::default`. In contrast downstream code must be able to construct
    191 // `SentChallenge` since it is used during ceremony validation; thus we must keep `Challenge` and `SentChallenge`
    192 // as separate types.
    193 /// [Cryptographic challenge](https://www.w3.org/TR/webauthn-3/#sctn-cryptographic-challenges).
    194 #[derive(Debug)]
    195 pub struct Challenge(u128);
    196 impl Challenge {
    197     // This won't `panic` since `16 < 0x4000`.
    198     /// The number of bytes a `Challenge` takes to encode in base64url.
    199     pub(super) const BASE64_LEN: usize = super::base64url_nopad_len(16);
    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::thread_rng().r#gen())
    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(unsafe_code, reason = "we want a const, and this is completely safe")]
   1389 pub(super) const THREE_HUNDRED_THOUSAND: NonZeroU32 = {
   1390     // SAFETY:
   1391     // `300_000 > 0`.
   1392     // Compilation always fails when using a constant value of 0,
   1393     // so there is _nothing_ wrong with this use of `unsafe`.
   1394     unsafe { NonZeroU32::new_unchecked(300_000) }
   1395 };
   1396 /// [`Hasher`] whose `write_*` methods simply store up to 64 bits of the passed argument _as is_ overwriting
   1397 /// any previous state.
   1398 ///
   1399 /// This is designed to only be used indirectly via a hash map whose keys are randomly generated on the server
   1400 /// based on at least 64 bits—the size of the integer returned from [`Self::finish`]—of entropy.
   1401 /// This makes this `Hasher` usable (and ideal) in only the most niche circumstances.
   1402 ///
   1403 /// [`RegistrationServerState`] and [`AuthenticationServerState`] both implement [`Hash`] by simply writing the
   1404 /// contained [`Challenge`]; thus when they are stored in a hashed collection (e.g., [`FixedCapHashSet`]), one can
   1405 /// optimize without fear by using this `Hasher` since `Challenge`s are immutable and can only ever be created on
   1406 /// the server via [`Challenge::new`] (and equivalently [`Challenge::default`]). `RegistrationServerState` and
   1407 /// `AuthenticationServerState` are also immutable and only constructable via
   1408 /// [`PublicKeyCredentialCreationOptions::start_ceremony`] and
   1409 /// [`PublicKeyCredentialRequestOptions::start_ceremony`] respectively. Since `Challenge` is already based on
   1410 /// a random `u128`, other `Hasher`s will be slower and likely produce lower-quality hashes (and never
   1411 /// higher quality).
   1412 #[cfg_attr(docsrs, doc(cfg(not(feature = "serializable_server_state"))))]
   1413 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1414 #[derive(Debug)]
   1415 pub struct IdentityHasher(u64);
   1416 // Note it is _not_ required for `write_*` methods to do the same thing as other `write_*` methods
   1417 // (e.g., `Self::write_u64` may not be the same thing as 8 calls to `Self::write_u8`).
   1418 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1419 impl Hasher for IdentityHasher {
   1420     /// Returns `0` if no `write_*` calls have been made; otherwise returns the result of the most recent
   1421     /// `write_*` call.
   1422     #[inline]
   1423     fn finish(&self) -> u64 {
   1424         self.0
   1425     }
   1426     /// Writes `i` to `self`.
   1427     #[inline]
   1428     fn write_u64(&mut self, i: u64) {
   1429         self.0 = i;
   1430     }
   1431     /// Sign-extends `i` to a [`u64`] before redirecting to [`Self::write_u64`].
   1432     #[expect(
   1433         clippy::as_conversions,
   1434         clippy::cast_sign_loss,
   1435         reason = "we simply need to convert into a u64 in a deterministic way"
   1436     )]
   1437     #[inline]
   1438     fn write_i8(&mut self, i: i8) {
   1439         self.write_u64(i as u64);
   1440     }
   1441     /// Sign-extends `i` to a [`u64`] before redirecting to [`Self::write_u64`].
   1442     #[expect(
   1443         clippy::as_conversions,
   1444         clippy::cast_sign_loss,
   1445         reason = "we simply need to convert into a u64 in a deterministic way"
   1446     )]
   1447     #[inline]
   1448     fn write_i16(&mut self, i: i16) {
   1449         self.write_u64(i as u64);
   1450     }
   1451     /// Sign-extends `i` to a [`u64`] before redirecting to [`Self::write_u64`].
   1452     #[expect(
   1453         clippy::as_conversions,
   1454         clippy::cast_sign_loss,
   1455         reason = "we simply need to convert into a u64 in a deterministic way"
   1456     )]
   1457     #[inline]
   1458     fn write_i32(&mut self, i: i32) {
   1459         self.write_u64(i as u64);
   1460     }
   1461     /// Redirects to [`Self::write_u64`].
   1462     #[expect(
   1463         clippy::as_conversions,
   1464         clippy::cast_sign_loss,
   1465         reason = "we simply need to convert into a u64 in a deterministic way"
   1466     )]
   1467     #[inline]
   1468     fn write_i64(&mut self, i: i64) {
   1469         self.write_u64(i as u64);
   1470     }
   1471     /// Truncates `i` to a [`u64`] before redirecting to [`Self::write_u64`].
   1472     #[expect(
   1473         clippy::as_conversions,
   1474         clippy::cast_possible_truncation,
   1475         clippy::cast_sign_loss,
   1476         reason = "we simply need to convert into a u64 in a deterministic way"
   1477     )]
   1478     #[inline]
   1479     fn write_i128(&mut self, i: i128) {
   1480         self.write_u64(i as u64);
   1481     }
   1482     /// Zero-extends `i` to a [`u64`] before redirecting to [`Self::write_u64`].
   1483     #[inline]
   1484     fn write_u8(&mut self, i: u8) {
   1485         self.write_u64(u64::from(i));
   1486     }
   1487     /// Zero-extends `i` to a [`u64`] before redirecting to [`Self::write_u64`].
   1488     #[inline]
   1489     fn write_u16(&mut self, i: u16) {
   1490         self.write_u64(u64::from(i));
   1491     }
   1492     /// Zero-extends `i` to a [`u64`] before redirecting to [`Self::write_u64`].
   1493     #[inline]
   1494     fn write_u32(&mut self, i: u32) {
   1495         self.write_u64(u64::from(i));
   1496     }
   1497     /// Truncates `i` to a [`u64`] before redirecting to [`Self::write_u64`].
   1498     #[expect(
   1499         clippy::as_conversions,
   1500         clippy::cast_possible_truncation,
   1501         reason = "we simply need to convert into a u64 in a deterministic way"
   1502     )]
   1503     #[inline]
   1504     fn write_u128(&mut self, i: u128) {
   1505         self.write_u64(i as u64);
   1506     }
   1507     /// This does nothing iff `bytes.len() < 8`; otherwise the first 8 bytes are converted
   1508     /// to a [`u64`] that is written via [`Self::write_u64`];
   1509     #[expect(clippy::host_endian_bytes, reason = "endianness does not matter")]
   1510     #[inline]
   1511     fn write(&mut self, bytes: &[u8]) {
   1512         if let Some(data) = bytes.get(..8) {
   1513             let mut val = [0; 8];
   1514             val.copy_from_slice(data);
   1515             self.write_u64(u64::from_ne_bytes(val));
   1516         }
   1517     }
   1518 }
   1519 /// [`BuildHasher`] of an [`IdentityHasher`].
   1520 ///
   1521 /// This MUST only be used with hash maps with keys that are randomly generated on the server based on at least 64
   1522 /// bits of entropy.
   1523 #[cfg_attr(docsrs, doc(cfg(not(feature = "serializable_server_state"))))]
   1524 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1525 #[derive(Clone, Copy, Debug)]
   1526 pub struct BuildIdentityHasher;
   1527 #[cfg_attr(docsrs, doc(cfg(not(feature = "serializable_server_state"))))]
   1528 #[cfg(not(feature = "serializable_server_state"))]
   1529 impl BuildHasher for BuildIdentityHasher {
   1530     type Hasher = IdentityHasher;
   1531     #[inline]
   1532     fn build_hasher(&self) -> Self::Hasher {
   1533         IdentityHasher(0)
   1534     }
   1535 }
   1536 /// Prevent users from implementing [`ServerState`].
   1537 mod private {
   1538     /// Marker trait used as a supertrait of `ServerState`.
   1539     pub trait Sealed {}
   1540     impl Sealed for super::AuthenticationServerState {}
   1541     impl Sealed for super::RegistrationServerState {}
   1542 }
   1543 /// Subset of data shared by both [`RegistrationServerState`] and [`AuthenticationServerState`].
   1544 ///
   1545 /// This trait is sealed and cannot be implemented for types outside of `webauthn_rp`.
   1546 pub trait ServerState: private::Sealed {
   1547     /// Returns the `Instant` the ceremony expires.
   1548     ///
   1549     /// Note when `serializable_server_state` is enabled, [`SystemTime`] is returned instead.
   1550     #[cfg_attr(docsrs, doc(cfg(not(feature = "serializable_server_state"))))]
   1551     #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1552     fn expiration(&self) -> Instant;
   1553     /// Returns the `SystemTime` the ceremony expires.
   1554     #[cfg(all(not(doc), feature = "serializable_server_state"))]
   1555     fn expiration(&self) -> SystemTime;
   1556     /// Returns the `SentChallenge` associated with the ceremony.
   1557     fn sent_challenge(&self) -> SentChallenge;
   1558 }
   1559 /// Fixed-capacity hash set that only inserts items when there is available capacity.
   1560 ///
   1561 /// This should only be used if _both_ of the following conditions are met:
   1562 ///
   1563 /// * Application is already protected from memory exhaustion attacks (e.g., users must be connected
   1564 ///   via VPN).
   1565 /// * There are legitimate reasons for an in-memory collection to grow unbounded.
   1566 ///
   1567 /// The first point is necessary; otherwise an attacker could trivially slow down the application
   1568 /// by causing repeated inserts forcing repeated calls to functions like [`Self::retain`]. The second
   1569 /// point is necessary; otherwise any in-memory collection would suffice.
   1570 ///
   1571 /// When `T` is a [`ServerState`], there are legitimate reasons why a ceremony will never finish (e.g.,
   1572 /// an outage could kill a user's connection after starting a ceremony). The longer the application
   1573 /// runs the more such instances occur to the point where the in-memory collection is full of expired
   1574 /// ceremonies. Since this should rarely occur and as long as [`Self::capacity`] is appropriate,
   1575 /// [`Self::insert`] should almost always succeed; however very rarely there will be a point when
   1576 /// one will have to [`Self::remove_expired_ceremonies`]. A vast majority of the time a user
   1577 /// will complete the ceremony which requires ownership of the `ServerState` which in turn requires
   1578 /// [`Self::take`] which will add an available slot.
   1579 #[cfg_attr(docsrs, doc(cfg(not(feature = "serializable_server_state"))))]
   1580 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1581 #[derive(Debug)]
   1582 pub struct FixedCapHashSet<T, S = BuildIdentityHasher>(HashSet<T, S>);
   1583 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1584 impl<T> FixedCapHashSet<T, BuildIdentityHasher> {
   1585     /// Creates an empty `FixedCapHashSet` with at least the specified capacity.
   1586     ///
   1587     /// The hash set will be able to hold at least `capacity` elements without reallocating. This method is allowed
   1588     /// to allocate for more elements than `capacity`.
   1589     #[inline]
   1590     #[must_use]
   1591     pub fn new(capacity: usize) -> Self {
   1592         Self(HashSet::with_capacity_and_hasher(
   1593             capacity,
   1594             BuildIdentityHasher,
   1595         ))
   1596     }
   1597 }
   1598 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1599 impl<T, S> FixedCapHashSet<T, S> {
   1600     /// Creates an empty `FixedCapHashSet` with at least the specified capacity, using `hasher` to hash the keys.
   1601     ///
   1602     /// The hash set will be able to hold at least `capacity` elements without reallocating. This method is allowed
   1603     /// to allocate for more elements than `capacity`.
   1604     #[inline]
   1605     #[must_use]
   1606     pub fn new_with_hasher(capacity: usize, hasher: S) -> Self {
   1607         Self(HashSet::with_capacity_and_hasher(capacity, hasher))
   1608     }
   1609     /// Returns the immutable capacity.
   1610     ///
   1611     /// This number is a lower bound; the `FixedCapHashSet` might be able to hold more, but is guaranteed to be
   1612     /// able to hold at least this many.
   1613     #[inline]
   1614     #[must_use]
   1615     pub fn capacity(&self) -> usize {
   1616         self.0.capacity()
   1617     }
   1618     /// Clears the set, removing all values.
   1619     #[inline]
   1620     pub fn clear(&mut self) {
   1621         self.0.clear();
   1622     }
   1623     /// Returns the number of elements in the set.
   1624     #[inline]
   1625     #[must_use]
   1626     pub fn len(&self) -> usize {
   1627         self.0.len()
   1628     }
   1629     /// Returns `true` iff the set contains no elements.
   1630     #[inline]
   1631     #[must_use]
   1632     pub fn is_empty(&self) -> bool {
   1633         self.0.is_empty()
   1634     }
   1635     /// Retains only the elements specified by the predicate.
   1636     ///
   1637     /// In other words, remove all elements `e` for which `f(&e)` returns `false`. The elements are visited in
   1638     /// unsorted (and unspecified) order.
   1639     #[inline]
   1640     pub fn retain<F>(&mut self, f: F)
   1641     where
   1642         F: FnMut(&T) -> bool,
   1643     {
   1644         self.0.retain(f);
   1645     }
   1646 }
   1647 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1648 impl<T: ServerState, S> FixedCapHashSet<T, S> {
   1649     /// Removes all expired ceremonies.
   1650     #[inline]
   1651     pub fn remove_expired_ceremonies(&mut self) {
   1652         // Even though it's more accurate to check the current `Instant` for each ceremony, we elect to capture
   1653         // the `Instant` we begin iteration for performance reasons. It's unlikely an appreciable amount of
   1654         // additional ceremonies would be removed.
   1655         let now = Instant::now();
   1656         self.retain(|v| v.expiration() >= now);
   1657     }
   1658 }
   1659 /// Result returned from [`FixedCapHashSet::insert`], [`FixedCapHashSet::insert_or_replace_expired`], and
   1660 /// [`FixedCapHashSet::insert_or_replace_all_expired`].
   1661 #[cfg_attr(docsrs, doc(cfg(not(feature = "serializable_server_state"))))]
   1662 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1663 #[derive(Clone, Copy, Debug)]
   1664 pub enum InsertResult {
   1665     /// Value was successfully inserted.
   1666     Success,
   1667     /// Value was not inserted since the capacity was full.
   1668     CapacityFull,
   1669     /// Value was not inserted since the value already existed.
   1670     ///
   1671     /// When the keys are based on [`Challenge`]s, this should almost never occur since `Challenge`s
   1672     /// are 16 bytes of random data.
   1673     Duplicate,
   1674 }
   1675 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1676 impl<T: Eq + Hash, S: BuildHasher> FixedCapHashSet<T, S> {
   1677     /// Returns `true` iff the set contains a value.
   1678     ///
   1679     /// The value may be any borrowed form of the set's value type, but `Hash` and `Eq` on the borrowed form _must_
   1680     /// match those for the value type.
   1681     #[inline]
   1682     #[must_use]
   1683     pub fn contains<Q>(&self, value: &Q) -> bool
   1684     where
   1685         T: Borrow<Q>,
   1686         Q: Eq + Hash + ?Sized,
   1687     {
   1688         self.0.contains(value)
   1689     }
   1690     /// Returns a reference to the value in the set, if any, that is equal to the given value.
   1691     ///
   1692     /// The value may be any borrowed form of the set's value type, but `Hash` and `Eq` on the borrowed form _must_
   1693     /// match those for the value type.
   1694     #[inline]
   1695     #[must_use]
   1696     pub fn get<Q>(&self, value: &Q) -> Option<&T>
   1697     where
   1698         T: Borrow<Q>,
   1699         Q: Eq + Hash + ?Sized,
   1700     {
   1701         self.0.get(value)
   1702     }
   1703     /// Removes a value from the set. Returns whether the value was present in the set.
   1704     ///
   1705     /// The value may be any borrowed form of the set's value type, but `Hash` and `Eq` on the borrowed form _must_
   1706     /// match those for the value type.
   1707     #[inline]
   1708     pub fn remove<Q>(&mut self, value: &Q) -> bool
   1709     where
   1710         T: Borrow<Q>,
   1711         Q: Eq + Hash + ?Sized,
   1712     {
   1713         self.0.remove(value)
   1714     }
   1715     /// Removes and returns the value in the set, if any, that is equal to the given one.
   1716     ///
   1717     /// The value may be any borrowed form of the set's value type, but `Hash` and `Eq` on the borrowed form _must_
   1718     /// match those for the value type.
   1719     #[inline]
   1720     pub fn take<Q>(&mut self, value: &Q) -> Option<T>
   1721     where
   1722         T: Borrow<Q>,
   1723         Q: Eq + Hash + ?Sized,
   1724     {
   1725         self.0.take(value)
   1726     }
   1727     /// Adds `value` to the set iff [`Self::capacity`] `>` [`Self::len`].
   1728     #[inline]
   1729     pub fn insert(&mut self, value: T) -> InsertResult {
   1730         if self.len() == self.capacity() {
   1731             InsertResult::CapacityFull
   1732         } else if self.0.insert(value) {
   1733             InsertResult::Success
   1734         } else {
   1735             InsertResult::Duplicate
   1736         }
   1737     }
   1738 }
   1739 #[cfg(any(doc, not(feature = "serializable_server_state")))]
   1740 impl<T: Borrow<SentChallenge> + Eq + Hash + ServerState, S: BuildHasher> FixedCapHashSet<T, S> {
   1741     /// Adds a ceremony to the set.
   1742     ///
   1743     /// This will only insert `value` iff [`Self::capacity`] `>` [`Self::len`]. When [`Self::len`] `==`
   1744     /// [`Self::capacity`], this will iterate items in the set until an expired ceremony is encountered; at which
   1745     /// point, the expired ceremony will be removed before `value` is inserted. In the event no expired ceremonies
   1746     /// exist, [`InsertResult::CapacityFull`] will be returned.
   1747     ///
   1748     /// If one wants to avoid the potentially expensive operation of iterating the set for an expired ceremony,
   1749     /// call [`Self::insert`]. Alternatively one can call [`Self::insert_or_replace_all_expired`] to avoid
   1750     /// repeatedly iterating the hash set once its capacity is full.
   1751     #[inline]
   1752     pub fn insert_or_replace_expired(&mut self, value: T) -> InsertResult {
   1753         if self.len() == self.capacity() {
   1754             let now = Instant::now();
   1755             self.0
   1756                 .iter()
   1757                 .try_fold((), |(), v| {
   1758                     if v.expiration() < now {
   1759                         Err(v.sent_challenge())
   1760                     } else {
   1761                         Ok(())
   1762                     }
   1763                 })
   1764                 .map_or_else(
   1765                     |chall| {
   1766                         self.remove(&chall);
   1767                         if self.0.insert(value) {
   1768                             InsertResult::Success
   1769                         } else {
   1770                             InsertResult::Duplicate
   1771                         }
   1772                     },
   1773                     |()| InsertResult::CapacityFull,
   1774                 )
   1775         } else if self.0.insert(value) {
   1776             InsertResult::Success
   1777         } else {
   1778             InsertResult::Duplicate
   1779         }
   1780     }
   1781     /// Adds a ceremony to the set.
   1782     ///
   1783     /// This will only insert `value` iff [`Self::capacity`] `>` [`Self::len`]. When [`Self::len`] `==`
   1784     /// [`Self::capacity`], this will [`Self::remove_expired_ceremonies`] before `value` is inserted. In the event
   1785     /// no expired ceremonies exist, [`InsertResult::CapacityFull`] will be returned.
   1786     #[inline]
   1787     pub fn insert_or_replace_all_expired(&mut self, value: T) -> InsertResult {
   1788         if self.len() == self.capacity() {
   1789             self.remove_expired_ceremonies();
   1790         }
   1791         if self.len() == self.capacity() {
   1792             InsertResult::CapacityFull
   1793         } else if self.0.insert(value) {
   1794             InsertResult::Success
   1795         } else {
   1796             InsertResult::Duplicate
   1797         }
   1798     }
   1799 }
   1800 #[cfg(test)]
   1801 mod tests {
   1802     #[cfg(feature = "custom")]
   1803     use super::{
   1804         super::{
   1805             AggErr, AuthenticatedCredential,
   1806             response::{
   1807                 AuthTransports, AuthenticatorAttachment, Backup, CredentialId,
   1808                 auth::{Authentication, AuthenticatorAssertion},
   1809                 register::{
   1810                     AuthenticationExtensionsPrfOutputs, AuthenticatorAttestation,
   1811                     AuthenticatorExtensionOutputStaticState, ClientExtensionsOutputs,
   1812                     CompressedP256PubKey, CompressedP384PubKey, CompressedPubKey,
   1813                     CredentialProtectionPolicy, DynamicState, Ed25519PubKey, Registration,
   1814                     RsaPubKey, StaticState, UncompressedPubKey,
   1815                 },
   1816             },
   1817         },
   1818         AsciiDomain, Challenge, Credentials, ExtensionInfo, ExtensionReq,
   1819         PublicKeyCredentialDescriptor, RpId, UserVerificationRequirement,
   1820         auth::{
   1821             AllowedCredential, AllowedCredentials, AuthenticationVerificationOptions,
   1822             CredentialSpecificExtension, Extension as AuthExt, PrfInputOwned,
   1823             PublicKeyCredentialRequestOptions,
   1824         },
   1825         register::{
   1826             CredProtect, Extension as RegExt, PublicKeyCredentialCreationOptions,
   1827             PublicKeyCredentialUserEntity, RegistrationVerificationOptions, UserHandle,
   1828         },
   1829     };
   1830     #[cfg(feature = "custom")]
   1831     use ed25519_dalek::{Signer, SigningKey};
   1832     #[cfg(feature = "custom")]
   1833     use p256::{
   1834         ecdsa::{DerSignature as P256DerSig, SigningKey as P256Key},
   1835         elliptic_curve::sec1::Tag,
   1836     };
   1837     #[cfg(feature = "custom")]
   1838     use p384::ecdsa::{DerSignature as P384DerSig, SigningKey as P384Key};
   1839     #[cfg(feature = "custom")]
   1840     use rsa::{
   1841         BigUint, RsaPrivateKey,
   1842         pkcs1v15::SigningKey as RsaKey,
   1843         sha2::{Digest, Sha256},
   1844         signature::{Keypair, SignatureEncoding},
   1845         traits::PublicKeyParts,
   1846     };
   1847     #[cfg(feature = "custom")]
   1848     const CBOR_UINT: u8 = 0b000_00000;
   1849     #[cfg(feature = "custom")]
   1850     const CBOR_NEG: u8 = 0b001_00000;
   1851     #[cfg(feature = "custom")]
   1852     const CBOR_BYTES: u8 = 0b010_00000;
   1853     #[cfg(feature = "custom")]
   1854     const CBOR_TEXT: u8 = 0b011_00000;
   1855     #[cfg(feature = "custom")]
   1856     const CBOR_MAP: u8 = 0b101_00000;
   1857     #[cfg(feature = "custom")]
   1858     const CBOR_SIMPLE: u8 = 0b111_00000;
   1859     #[cfg(feature = "custom")]
   1860     const CBOR_TRUE: u8 = CBOR_SIMPLE | 21;
   1861     #[test]
   1862     #[cfg(feature = "custom")]
   1863     fn ed25519_reg() -> Result<(), AggErr> {
   1864         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   1865         let id = UserHandle::try_from([0; 1].as_slice())?;
   1866         let mut opts = PublicKeyCredentialCreationOptions::passkey(
   1867             &rp_id,
   1868             PublicKeyCredentialUserEntity {
   1869                 name: "foo".try_into()?,
   1870                 id,
   1871                 display_name: None,
   1872             },
   1873             Vec::new(),
   1874         );
   1875         opts.challenge = Challenge(0);
   1876         opts.extensions = RegExt {
   1877             cred_props: None,
   1878             cred_protect: CredProtect::UserVerificationRequired(ExtensionInfo::RequireEnforceValue),
   1879             min_pin_length: Some((10, ExtensionInfo::RequireEnforceValue)),
   1880             prf: Some(ExtensionInfo::RequireEnforceValue),
   1881         };
   1882         let client_data_json = br#"{"type":"webauthn.create","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   1883         // We over-allocate by 32 bytes. See [`AuthenticatorAttestation::new`] for more information.
   1884         let mut attestation_object = Vec::new();
   1885         attestation_object.extend_from_slice(
   1886             [
   1887                 CBOR_MAP | 3,
   1888                 CBOR_TEXT | 3,
   1889                 b'f',
   1890                 b'm',
   1891                 b't',
   1892                 CBOR_TEXT | 6,
   1893                 b'p',
   1894                 b'a',
   1895                 b'c',
   1896                 b'k',
   1897                 b'e',
   1898                 b'd',
   1899                 CBOR_TEXT | 7,
   1900                 b'a',
   1901                 b't',
   1902                 b't',
   1903                 b'S',
   1904                 b't',
   1905                 b'm',
   1906                 b't',
   1907                 CBOR_MAP | 2,
   1908                 CBOR_TEXT | 3,
   1909                 b'a',
   1910                 b'l',
   1911                 b'g',
   1912                 // COSE EdDSA.
   1913                 CBOR_NEG | 7,
   1914                 CBOR_TEXT | 3,
   1915                 b's',
   1916                 b'i',
   1917                 b'g',
   1918                 CBOR_BYTES | 24,
   1919                 64,
   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                 0,
   1983                 0,
   1984                 CBOR_TEXT | 8,
   1985                 b'a',
   1986                 b'u',
   1987                 b't',
   1988                 b'h',
   1989                 b'D',
   1990                 b'a',
   1991                 b't',
   1992                 b'a',
   1993                 CBOR_BYTES | 24,
   1994                 // Length is 154.
   1995                 154,
   1996                 // RP ID HASH.
   1997                 // This will be overwritten later.
   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                 0,
   2029                 0,
   2030                 // FLAGS.
   2031                 // UP, UV, AT, and ED (right-to-left).
   2032                 0b1100_0101,
   2033                 // COUNTER.
   2034                 // 0 as 32-bit big endian.
   2035                 0,
   2036                 0,
   2037                 0,
   2038                 0,
   2039                 // AAGUID.
   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                 0,
   2055                 0,
   2056                 // L.
   2057                 // CREDENTIAL ID length is 16 as 16-bit big endian.
   2058                 0,
   2059                 16,
   2060                 // CREDENTIAL ID.
   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                 0,
   2076                 0,
   2077                 CBOR_MAP | 4,
   2078                 // COSE kty.
   2079                 CBOR_UINT | 1,
   2080                 // COSE OKP.
   2081                 CBOR_UINT | 1,
   2082                 // COSE alg.
   2083                 CBOR_UINT | 3,
   2084                 // COSE EdDSA.
   2085                 CBOR_NEG | 7,
   2086                 // COSE OKP crv.
   2087                 CBOR_NEG,
   2088                 // COSE Ed25519.
   2089                 CBOR_UINT | 6,
   2090                 // COSE OKP x.
   2091                 CBOR_NEG | 1,
   2092                 CBOR_BYTES | 24,
   2093                 // Length is 32.
   2094                 32,
   2095                 // Compressed-y coordinate.
   2096                 // This will be overwritten later.
   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                 0,
   2128                 0,
   2129                 CBOR_MAP | 3,
   2130                 CBOR_TEXT | 11,
   2131                 b'c',
   2132                 b'r',
   2133                 b'e',
   2134                 b'd',
   2135                 b'P',
   2136                 b'r',
   2137                 b'o',
   2138                 b't',
   2139                 b'e',
   2140                 b'c',
   2141                 b't',
   2142                 // userVerificationRequired.
   2143                 CBOR_UINT | 3,
   2144                 // CBOR text of length 11.
   2145                 CBOR_TEXT | 11,
   2146                 b'h',
   2147                 b'm',
   2148                 b'a',
   2149                 b'c',
   2150                 b'-',
   2151                 b's',
   2152                 b'e',
   2153                 b'c',
   2154                 b'r',
   2155                 b'e',
   2156                 b't',
   2157                 CBOR_TRUE,
   2158                 CBOR_TEXT | 12,
   2159                 b'm',
   2160                 b'i',
   2161                 b'n',
   2162                 b'P',
   2163                 b'i',
   2164                 b'n',
   2165                 b'L',
   2166                 b'e',
   2167                 b'n',
   2168                 b'g',
   2169                 b't',
   2170                 b'h',
   2171                 CBOR_UINT | 16,
   2172             ]
   2173             .as_slice(),
   2174         );
   2175         attestation_object
   2176             .extend_from_slice(Sha256::digest(client_data_json.as_slice()).as_slice());
   2177         let sig_key = SigningKey::from_bytes(&[0; 32]);
   2178         let ver_key = sig_key.verifying_key();
   2179         let pub_key = ver_key.as_bytes();
   2180         attestation_object[107..139]
   2181             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   2182         attestation_object[188..220].copy_from_slice(pub_key);
   2183         let sig = sig_key.sign(&attestation_object[107..]);
   2184         attestation_object[32..96].copy_from_slice(sig.to_bytes().as_slice());
   2185         attestation_object.truncate(261);
   2186         assert!(matches!(opts.start_ceremony()?.0.verify(
   2187             &rp_id,
   2188             id,
   2189             &Registration {
   2190                 response: AuthenticatorAttestation::new(
   2191                     client_data_json,
   2192                     attestation_object,
   2193                     AuthTransports::NONE,
   2194                 ),
   2195                 authenticator_attachment: AuthenticatorAttachment::None,
   2196                 client_extension_results: ClientExtensionsOutputs {
   2197                     cred_props: None,
   2198                     prf: Some(AuthenticationExtensionsPrfOutputs { enabled: true, }),
   2199                 },
   2200             },
   2201             &RegistrationVerificationOptions::<&str, &str>::default(),
   2202         )?.static_state.credential_public_key, UncompressedPubKey::Ed25519(k) if k.into_inner() == pub_key));
   2203         Ok(())
   2204     }
   2205     #[test]
   2206     #[cfg(feature = "custom")]
   2207     fn ed25519_auth() -> Result<(), AggErr> {
   2208         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   2209         let mut creds = AllowedCredentials::with_capacity(1);
   2210         creds.push(AllowedCredential {
   2211             credential: PublicKeyCredentialDescriptor {
   2212                 id: CredentialId::try_from(vec![0; 16])?,
   2213                 transports: AuthTransports::NONE,
   2214             },
   2215             extension: CredentialSpecificExtension {
   2216                 prf: Some(PrfInputOwned {
   2217                     first: Vec::new(),
   2218                     second: Some(Vec::new()),
   2219                     ext_info: ExtensionReq::Require,
   2220                 }),
   2221             },
   2222         });
   2223         let mut opts = PublicKeyCredentialRequestOptions::second_factor(&rp_id, creds)?;
   2224         opts.user_verification = UserVerificationRequirement::Required;
   2225         opts.challenge = Challenge(0);
   2226         opts.extensions = AuthExt { prf: None };
   2227         let client_data_json = br#"{"type":"webauthn.get","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   2228         // We over-allocate by 32 bytes. See [`AuthenticatorAssertion::new`] for more information.
   2229         let mut authenticator_data = Vec::with_capacity(164);
   2230         authenticator_data.extend_from_slice(
   2231             [
   2232                 // rpIdHash.
   2233                 // This will be overwritten later.
   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                 0,
   2265                 0,
   2266                 // flags.
   2267                 // UP, UV, and ED (right-to-left).
   2268                 0b1000_0101,
   2269                 // signCount.
   2270                 // 0 as 32-bit big endian.
   2271                 0,
   2272                 0,
   2273                 0,
   2274                 0,
   2275                 CBOR_MAP | 1,
   2276                 CBOR_TEXT | 11,
   2277                 b'h',
   2278                 b'm',
   2279                 b'a',
   2280                 b'c',
   2281                 b'-',
   2282                 b's',
   2283                 b'e',
   2284                 b'c',
   2285                 b'r',
   2286                 b'e',
   2287                 b't',
   2288                 CBOR_BYTES | 24,
   2289                 // Length is 80.
   2290                 80,
   2291                 // Two HMAC outputs concatenated and encrypted.
   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                 0,
   2371                 0,
   2372             ]
   2373             .as_slice(),
   2374         );
   2375         authenticator_data[..32]
   2376             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   2377         authenticator_data
   2378             .extend_from_slice(Sha256::digest(client_data_json.as_slice()).as_slice());
   2379         let ed_priv = SigningKey::from([0; 32]);
   2380         let sig = ed_priv.sign(authenticator_data.as_slice()).to_vec();
   2381         authenticator_data.truncate(132);
   2382         assert!(!opts.start_ceremony()?.0.verify(
   2383             &rp_id,
   2384             &Authentication {
   2385                 raw_id: CredentialId::try_from(vec![0; 16])?,
   2386                 response: AuthenticatorAssertion::new(
   2387                     client_data_json,
   2388                     authenticator_data,
   2389                     sig,
   2390                     Some(UserHandle::try_from(vec![0])?),
   2391                 ),
   2392                 authenticator_attachment: AuthenticatorAttachment::None,
   2393             },
   2394             &mut AuthenticatedCredential::new(
   2395                 CredentialId::try_from([0; 16].as_slice())?,
   2396                 UserHandle::try_from([0].as_slice())?,
   2397                 StaticState {
   2398                     credential_public_key: CompressedPubKey::<_, &[u8], &[u8], &[u8]>::Ed25519(
   2399                         Ed25519PubKey::from(ed_priv.verifying_key().to_bytes()),
   2400                     ),
   2401                     extensions: AuthenticatorExtensionOutputStaticState {
   2402                         cred_protect: CredentialProtectionPolicy::None,
   2403                         hmac_secret: Some(true),
   2404                     },
   2405                 },
   2406                 DynamicState {
   2407                     user_verified: true,
   2408                     backup: Backup::NotEligible,
   2409                     sign_count: 0,
   2410                     authenticator_attachment: AuthenticatorAttachment::None,
   2411                 },
   2412             )?,
   2413             &AuthenticationVerificationOptions::<&str, &str>::default(),
   2414         )?);
   2415         Ok(())
   2416     }
   2417     #[test]
   2418     #[cfg(feature = "custom")]
   2419     fn p256_reg() -> Result<(), AggErr> {
   2420         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   2421         let id = UserHandle::try_from([0; 1].as_slice())?;
   2422         let mut opts = PublicKeyCredentialCreationOptions::passkey(
   2423             &rp_id,
   2424             PublicKeyCredentialUserEntity {
   2425                 name: "foo".try_into()?,
   2426                 id,
   2427                 display_name: None,
   2428             },
   2429             Vec::new(),
   2430         );
   2431         opts.challenge = Challenge(0);
   2432         let client_data_json = br#"{"type":"webauthn.create","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   2433         // We over-allocate by 32 bytes. See [`AuthenticatorAttestation::new`] for more information.
   2434         let mut attestation_object = Vec::with_capacity(210);
   2435         attestation_object.extend_from_slice(
   2436             [
   2437                 CBOR_MAP | 3,
   2438                 CBOR_TEXT | 3,
   2439                 b'f',
   2440                 b'm',
   2441                 b't',
   2442                 CBOR_TEXT | 4,
   2443                 b'n',
   2444                 b'o',
   2445                 b'n',
   2446                 b'e',
   2447                 CBOR_TEXT | 7,
   2448                 b'a',
   2449                 b't',
   2450                 b't',
   2451                 b'S',
   2452                 b't',
   2453                 b'm',
   2454                 b't',
   2455                 CBOR_MAP,
   2456                 CBOR_TEXT | 8,
   2457                 b'a',
   2458                 b'u',
   2459                 b't',
   2460                 b'h',
   2461                 b'D',
   2462                 b'a',
   2463                 b't',
   2464                 b'a',
   2465                 CBOR_BYTES | 24,
   2466                 // Length is 148.
   2467                 148,
   2468                 // RP ID HASH.
   2469                 // This will be overwritten later.
   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                 0,
   2501                 0,
   2502                 // FLAGS.
   2503                 // UP, UV, and AT (right-to-left).
   2504                 0b0100_0101,
   2505                 // COUNTER.
   2506                 // 0 as 32-bit big endian.
   2507                 0,
   2508                 0,
   2509                 0,
   2510                 0,
   2511                 // AAGUID.
   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                 0,
   2527                 0,
   2528                 // L.
   2529                 // CREDENTIAL ID length is 16 as 16-bit big endian.
   2530                 0,
   2531                 16,
   2532                 // CREDENTIAL ID.
   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                 0,
   2548                 0,
   2549                 CBOR_MAP | 5,
   2550                 // COSE kty.
   2551                 CBOR_UINT | 1,
   2552                 // COSE EC2.
   2553                 CBOR_UINT | 2,
   2554                 // COSE alg.
   2555                 CBOR_UINT | 3,
   2556                 // COSE ES256.
   2557                 CBOR_NEG | 6,
   2558                 // COSE EC2 crv.
   2559                 CBOR_NEG,
   2560                 // COSE P-256.
   2561                 CBOR_UINT | 1,
   2562                 // COSE EC2 x.
   2563                 CBOR_NEG | 1,
   2564                 CBOR_BYTES | 24,
   2565                 // Length is 32.
   2566                 32,
   2567                 // X-coordinate. This will be overwritten later.
   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                 0,
   2599                 0,
   2600                 // COSE EC2 y.
   2601                 CBOR_NEG | 2,
   2602                 CBOR_BYTES | 24,
   2603                 // Length is 32.
   2604                 32,
   2605                 // Y-coordinate. This will be overwritten later.
   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                 0,
   2637                 0,
   2638             ]
   2639             .as_slice(),
   2640         );
   2641         attestation_object[30..62]
   2642             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   2643         let p256_key = P256Key::from_bytes(
   2644             &[
   2645                 137, 133, 36, 206, 163, 47, 255, 5, 76, 144, 163, 141, 40, 109, 108, 240, 246, 115,
   2646                 178, 237, 169, 68, 6, 129, 92, 21, 238, 127, 55, 158, 207, 95,
   2647             ]
   2648             .into(),
   2649         )
   2650         .unwrap()
   2651         .verifying_key()
   2652         .to_encoded_point(false);
   2653         let x = p256_key.x().unwrap();
   2654         let y = p256_key.y().unwrap();
   2655         attestation_object[111..143].copy_from_slice(x);
   2656         attestation_object[146..].copy_from_slice(y);
   2657         assert!(matches!(opts.start_ceremony()?.0.verify(
   2658             &rp_id,
   2659             id,
   2660             &Registration {
   2661                 response: AuthenticatorAttestation::new(
   2662                     client_data_json,
   2663                     attestation_object,
   2664                     AuthTransports::NONE,
   2665                 ),
   2666                 authenticator_attachment: AuthenticatorAttachment::None,
   2667                 client_extension_results: ClientExtensionsOutputs {
   2668                     cred_props: None,
   2669                     prf: None,
   2670                 },
   2671             },
   2672             &RegistrationVerificationOptions::<&str, &str>::default(),
   2673         )?.static_state.credential_public_key, UncompressedPubKey::P256(k) if k.x() == x.as_slice() && k.y() == y.as_slice()));
   2674         Ok(())
   2675     }
   2676     #[test]
   2677     #[cfg(feature = "custom")]
   2678     fn p256_auth() -> Result<(), AggErr> {
   2679         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   2680         let mut opts = PublicKeyCredentialRequestOptions::passkey(&rp_id);
   2681         opts.challenge = Challenge(0);
   2682         let client_data_json = br#"{"type":"webauthn.get","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   2683         // We over-allocate by 32 bytes. See [`AuthenticatorAssertion::new`] for more information.
   2684         let mut authenticator_data = Vec::with_capacity(69);
   2685         authenticator_data.extend_from_slice(
   2686             [
   2687                 // rpIdHash.
   2688                 // This will be overwritten later.
   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                 0,
   2720                 0,
   2721                 // flags.
   2722                 // UP and UV (right-to-left).
   2723                 0b0000_0101,
   2724                 // signCount.
   2725                 // 0 as 32-bit big endian.
   2726                 0,
   2727                 0,
   2728                 0,
   2729                 0,
   2730             ]
   2731             .as_slice(),
   2732         );
   2733         authenticator_data[..32]
   2734             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   2735         authenticator_data
   2736             .extend_from_slice(Sha256::digest(client_data_json.as_slice()).as_slice());
   2737         let p256_key = P256Key::from_bytes(
   2738             &[
   2739                 137, 133, 36, 206, 163, 47, 255, 5, 76, 144, 163, 141, 40, 109, 108, 240, 246, 115,
   2740                 178, 237, 169, 68, 6, 129, 92, 21, 238, 127, 55, 158, 207, 95,
   2741             ]
   2742             .into(),
   2743         )
   2744         .unwrap();
   2745         let der_sig: P256DerSig = p256_key.sign(authenticator_data.as_slice());
   2746         let pub_key = p256_key.verifying_key().to_encoded_point(true);
   2747         authenticator_data.truncate(37);
   2748         assert!(!opts.start_ceremony()?.0.verify(
   2749             &rp_id,
   2750             &Authentication {
   2751                 raw_id: CredentialId::try_from(vec![0; 16])?,
   2752                 response: AuthenticatorAssertion::new(
   2753                     client_data_json,
   2754                     authenticator_data,
   2755                     der_sig.as_bytes().into(),
   2756                     Some(UserHandle::try_from(vec![0])?),
   2757                 ),
   2758                 authenticator_attachment: AuthenticatorAttachment::None,
   2759             },
   2760             &mut AuthenticatedCredential::new(
   2761                 CredentialId::try_from([0; 16].as_slice())?,
   2762                 UserHandle::try_from([0].as_slice())?,
   2763                 StaticState {
   2764                     credential_public_key: CompressedPubKey::<&[u8], _, &[u8], &[u8]>::P256(
   2765                         CompressedP256PubKey::from((
   2766                             (*pub_key.x().unwrap()).into(),
   2767                             pub_key.tag() == Tag::CompressedOddY
   2768                         )),
   2769                     ),
   2770                     extensions: AuthenticatorExtensionOutputStaticState {
   2771                         cred_protect: CredentialProtectionPolicy::None,
   2772                         hmac_secret: None,
   2773                     },
   2774                 },
   2775                 DynamicState {
   2776                     user_verified: true,
   2777                     backup: Backup::NotEligible,
   2778                     sign_count: 0,
   2779                     authenticator_attachment: AuthenticatorAttachment::None,
   2780                 },
   2781             )?,
   2782             &AuthenticationVerificationOptions::<&str, &str>::default(),
   2783         )?);
   2784         Ok(())
   2785     }
   2786     #[test]
   2787     #[cfg(feature = "custom")]
   2788     fn p384_reg() -> Result<(), AggErr> {
   2789         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   2790         let id = UserHandle::try_from([0; 1].as_slice())?;
   2791         let mut opts = PublicKeyCredentialCreationOptions::passkey(
   2792             &rp_id,
   2793             PublicKeyCredentialUserEntity {
   2794                 name: "foo".try_into()?,
   2795                 id,
   2796                 display_name: None,
   2797             },
   2798             Vec::new(),
   2799         );
   2800         opts.challenge = Challenge(0);
   2801         let client_data_json = br#"{"type":"webauthn.create","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   2802         // We over-allocate by 32 bytes. See [`AuthenticatorAttestation::new`] for more information.
   2803         let mut attestation_object = Vec::with_capacity(243);
   2804         attestation_object.extend_from_slice(
   2805             [
   2806                 CBOR_MAP | 3,
   2807                 CBOR_TEXT | 3,
   2808                 b'f',
   2809                 b'm',
   2810                 b't',
   2811                 CBOR_TEXT | 4,
   2812                 b'n',
   2813                 b'o',
   2814                 b'n',
   2815                 b'e',
   2816                 // CBOR text of length 7.
   2817                 CBOR_TEXT | 7,
   2818                 b'a',
   2819                 b't',
   2820                 b't',
   2821                 b'S',
   2822                 b't',
   2823                 b'm',
   2824                 b't',
   2825                 CBOR_MAP,
   2826                 CBOR_TEXT | 8,
   2827                 b'a',
   2828                 b'u',
   2829                 b't',
   2830                 b'h',
   2831                 b'D',
   2832                 b'a',
   2833                 b't',
   2834                 b'a',
   2835                 CBOR_BYTES | 24,
   2836                 // Length is 181.
   2837                 181,
   2838                 // RP ID HASH.
   2839                 // This will be overwritten later.
   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                 0,
   2871                 0,
   2872                 // FLAGS.
   2873                 // UP, UV, and AT (right-to-left).
   2874                 0b0100_0101,
   2875                 // COUNTER.
   2876                 // 0 as 32-bit big-endian.
   2877                 0,
   2878                 0,
   2879                 0,
   2880                 0,
   2881                 // AAGUID.
   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                 0,
   2897                 0,
   2898                 // L.
   2899                 // CREDENTIAL ID length is 16 as 16-bit big endian.
   2900                 0,
   2901                 16,
   2902                 // CREDENTIAL ID.
   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                 0,
   2918                 0,
   2919                 CBOR_MAP | 5,
   2920                 // COSE kty.
   2921                 CBOR_UINT | 1,
   2922                 // COSE EC2.
   2923                 CBOR_UINT | 2,
   2924                 // COSE alg.
   2925                 CBOR_UINT | 3,
   2926                 CBOR_NEG | 24,
   2927                 // COSE ES384.
   2928                 34,
   2929                 // COSE EC2 crv.
   2930                 CBOR_NEG,
   2931                 // COSE P-384.
   2932                 CBOR_UINT | 2,
   2933                 // COSE EC2 x.
   2934                 CBOR_NEG | 1,
   2935                 CBOR_BYTES | 24,
   2936                 // Length is 48.
   2937                 48,
   2938                 // X-coordinate. This will be overwritten later.
   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                 0,
   2986                 0,
   2987                 // COSE EC2 y.
   2988                 CBOR_NEG | 2,
   2989                 CBOR_BYTES | 24,
   2990                 // Length is 48.
   2991                 48,
   2992                 // Y-coordinate. This will be overwritten later.
   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                 0,
   3040                 0,
   3041             ]
   3042             .as_slice(),
   3043         );
   3044         attestation_object[30..62]
   3045             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   3046         let p384_key = P384Key::from_bytes(
   3047             &[
   3048                 158, 99, 156, 49, 190, 211, 85, 167, 28, 2, 80, 57, 31, 22, 17, 38, 85, 78, 232,
   3049                 42, 45, 199, 154, 243, 136, 251, 84, 34, 5, 120, 208, 91, 61, 248, 64, 144, 87, 1,
   3050                 32, 86, 220, 68, 182, 11, 105, 223, 75, 70,
   3051             ]
   3052             .into(),
   3053         )
   3054         .unwrap()
   3055         .verifying_key()
   3056         .to_encoded_point(false);
   3057         let x = p384_key.x().unwrap();
   3058         let y = p384_key.y().unwrap();
   3059         attestation_object[112..160].copy_from_slice(x);
   3060         attestation_object[163..].copy_from_slice(y);
   3061         assert!(matches!(opts.start_ceremony()?.0.verify(
   3062             &rp_id,
   3063             id,
   3064             &Registration {
   3065                 response: AuthenticatorAttestation::new(
   3066                     client_data_json,
   3067                     attestation_object,
   3068                     AuthTransports::NONE,
   3069                 ),
   3070                 authenticator_attachment: AuthenticatorAttachment::None,
   3071                 client_extension_results: ClientExtensionsOutputs {
   3072                     cred_props: None,
   3073                     prf: None,
   3074                 },
   3075             },
   3076             &RegistrationVerificationOptions::<&str, &str>::default(),
   3077         )?.static_state.credential_public_key, UncompressedPubKey::P384(k) if k.x() == x.as_slice() && k.y() == y.as_slice()));
   3078         Ok(())
   3079     }
   3080     #[test]
   3081     #[cfg(feature = "custom")]
   3082     fn p384_auth() -> Result<(), AggErr> {
   3083         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   3084         let mut opts = PublicKeyCredentialRequestOptions::passkey(&rp_id);
   3085         opts.challenge = Challenge(0);
   3086         let client_data_json = br#"{"type":"webauthn.get","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   3087         // We over-allocate by 32 bytes. See [`AuthenticatorAssertion::new`] for more information.
   3088         let mut authenticator_data = Vec::with_capacity(69);
   3089         authenticator_data.extend_from_slice(
   3090             [
   3091                 // rpIdHash.
   3092                 // This will be overwritten later.
   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                 0,
   3124                 0,
   3125                 // flags.
   3126                 // UP and UV (right-to-left).
   3127                 0b0000_0101,
   3128                 // signCount.
   3129                 // 0 as 32-bit big-endian.
   3130                 0,
   3131                 0,
   3132                 0,
   3133                 0,
   3134             ]
   3135             .as_slice(),
   3136         );
   3137         authenticator_data[..32]
   3138             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   3139         authenticator_data
   3140             .extend_from_slice(Sha256::digest(client_data_json.as_slice()).as_slice());
   3141         let p384_key = P384Key::from_bytes(
   3142             &[
   3143                 158, 99, 156, 49, 190, 211, 85, 167, 28, 2, 80, 57, 31, 22, 17, 38, 85, 78, 232,
   3144                 42, 45, 199, 154, 243, 136, 251, 84, 34, 5, 120, 208, 91, 61, 248, 64, 144, 87, 1,
   3145                 32, 86, 220, 68, 182, 11, 105, 223, 75, 70,
   3146             ]
   3147             .into(),
   3148         )
   3149         .unwrap();
   3150         let der_sig: P384DerSig = p384_key.sign(authenticator_data.as_slice());
   3151         let pub_key = p384_key.verifying_key().to_encoded_point(true);
   3152         authenticator_data.truncate(37);
   3153         assert!(!opts.start_ceremony()?.0.verify(
   3154             &rp_id,
   3155             &Authentication {
   3156                 raw_id: CredentialId::try_from(vec![0; 16])?,
   3157                 response: AuthenticatorAssertion::new(
   3158                     client_data_json,
   3159                     authenticator_data,
   3160                     der_sig.as_bytes().into(),
   3161                     Some(UserHandle::try_from(vec![0])?),
   3162                 ),
   3163                 authenticator_attachment: AuthenticatorAttachment::None,
   3164             },
   3165             &mut AuthenticatedCredential::new(
   3166                 CredentialId::try_from([0; 16].as_slice())?,
   3167                 UserHandle::try_from([0].as_slice())?,
   3168                 StaticState {
   3169                     credential_public_key: CompressedPubKey::<&[u8], &[u8], _, &[u8]>::P384(
   3170                         CompressedP384PubKey::from((
   3171                             (*pub_key.x().unwrap()).into(),
   3172                             pub_key.tag() == Tag::CompressedOddY
   3173                         )),
   3174                     ),
   3175                     extensions: AuthenticatorExtensionOutputStaticState {
   3176                         cred_protect: CredentialProtectionPolicy::None,
   3177                         hmac_secret: None,
   3178                     },
   3179                 },
   3180                 DynamicState {
   3181                     user_verified: true,
   3182                     backup: Backup::NotEligible,
   3183                     sign_count: 0,
   3184                     authenticator_attachment: AuthenticatorAttachment::None,
   3185                 },
   3186             )?,
   3187             &AuthenticationVerificationOptions::<&str, &str>::default(),
   3188         )?);
   3189         Ok(())
   3190     }
   3191     #[test]
   3192     #[cfg(feature = "custom")]
   3193     fn rsa_reg() -> Result<(), AggErr> {
   3194         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   3195         let id = UserHandle::try_from([0; 1].as_slice())?;
   3196         let mut opts = PublicKeyCredentialCreationOptions::passkey(
   3197             &rp_id,
   3198             PublicKeyCredentialUserEntity {
   3199                 name: "foo".try_into()?,
   3200                 id,
   3201                 display_name: None,
   3202             },
   3203             Vec::new(),
   3204         );
   3205         opts.challenge = Challenge(0);
   3206         let client_data_json = br#"{"type":"webauthn.create","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   3207         // We over-allocate by 32 bytes. See [`AuthenticatorAttestation::new`] for more information.
   3208         let mut attestation_object = Vec::with_capacity(406);
   3209         attestation_object.extend_from_slice(
   3210             [
   3211                 CBOR_MAP | 3,
   3212                 CBOR_TEXT | 3,
   3213                 b'f',
   3214                 b'm',
   3215                 b't',
   3216                 CBOR_TEXT | 4,
   3217                 b'n',
   3218                 b'o',
   3219                 b'n',
   3220                 b'e',
   3221                 CBOR_TEXT | 7,
   3222                 b'a',
   3223                 b't',
   3224                 b't',
   3225                 b'S',
   3226                 b't',
   3227                 b'm',
   3228                 b't',
   3229                 CBOR_MAP,
   3230                 CBOR_TEXT | 8,
   3231                 b'a',
   3232                 b'u',
   3233                 b't',
   3234                 b'h',
   3235                 b'D',
   3236                 b'a',
   3237                 b't',
   3238                 b'a',
   3239                 CBOR_BYTES | 25,
   3240                 // Length is 343 as 16-bit big-endian.
   3241                 1,
   3242                 87,
   3243                 // RP ID HASH.
   3244                 // This will be overwritten later.
   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                 0,
   3276                 0,
   3277                 // FLAGS.
   3278                 // UP, UV, and AT (right-to-left).
   3279                 0b0100_0101,
   3280                 // COUNTER.
   3281                 // 0 as 32-bit big-endian.
   3282                 0,
   3283                 0,
   3284                 0,
   3285                 0,
   3286                 // AAGUID.
   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                 0,
   3302                 0,
   3303                 // L.
   3304                 // CREDENTIAL ID length is 16 as 16-bit big endian.
   3305                 0,
   3306                 16,
   3307                 // CREDENTIAL ID.
   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                 0,
   3323                 0,
   3324                 CBOR_MAP | 4,
   3325                 // COSE kty.
   3326                 CBOR_UINT | 1,
   3327                 // COSE RSA.
   3328                 CBOR_UINT | 3,
   3329                 // COSE alg.
   3330                 CBOR_UINT | 3,
   3331                 CBOR_NEG | 25,
   3332                 // COSE RS256.
   3333                 1,
   3334                 0,
   3335                 // COSE n.
   3336                 CBOR_NEG,
   3337                 CBOR_BYTES | 25,
   3338                 // Length is 256 as 16-bit big-endian.
   3339                 1,
   3340                 0,
   3341                 // N. This will be overwritten later.
   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                 0,
   3597                 0,
   3598                 // COSE e.
   3599                 CBOR_NEG | 1,
   3600                 CBOR_BYTES | 3,
   3601                 // 65537 as 24-bit big-endian.
   3602                 1,
   3603                 0,
   3604                 1,
   3605             ]
   3606             .as_slice(),
   3607         );
   3608         attestation_object[31..63]
   3609             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   3610         let n = [
   3611             111, 183, 124, 133, 38, 167, 70, 148, 44, 50, 30, 60, 121, 14, 38, 37, 96, 114, 107,
   3612             195, 248, 64, 79, 36, 237, 140, 43, 27, 94, 74, 102, 152, 135, 102, 184, 150, 186, 206,
   3613             185, 19, 165, 209, 48, 98, 98, 9, 3, 205, 208, 82, 250, 105, 132, 201, 73, 62, 60, 165,
   3614             100, 128, 153, 9, 41, 118, 66, 95, 236, 214, 73, 135, 197, 68, 184, 10, 27, 116, 204,
   3615             145, 50, 174, 58, 42, 183, 181, 119, 232, 126, 252, 217, 96, 162, 190, 103, 122, 64,
   3616             87, 145, 45, 32, 207, 17, 239, 223, 3, 35, 14, 112, 119, 124, 141, 123, 208, 239, 105,
   3617             81, 217, 151, 162, 190, 17, 88, 182, 176, 158, 81, 200, 42, 166, 133, 48, 23, 236, 55,
   3618             117, 248, 233, 151, 203, 122, 155, 231, 46, 177, 20, 20, 151, 64, 222, 239, 226, 7, 21,
   3619             254, 81, 202, 64, 232, 161, 235, 22, 51, 246, 207, 213, 0, 229, 138, 46, 222, 205, 157,
   3620             108, 139, 253, 230, 80, 50, 2, 122, 212, 163, 100, 180, 114, 12, 113, 52, 56, 99, 188,
   3621             42, 198, 212, 23, 182, 222, 56, 221, 200, 79, 96, 239, 221, 135, 10, 17, 106, 183, 56,
   3622             104, 68, 94, 198, 196, 35, 200, 83, 204, 26, 185, 204, 212, 31, 183, 19, 111, 233, 13,
   3623             72, 93, 53, 65, 111, 59, 242, 122, 160, 244, 162, 126, 38, 235, 156, 47, 88, 39, 132,
   3624             153, 79, 0, 133, 78, 7, 218, 165, 241,
   3625         ];
   3626         let e = 65537;
   3627         let d = [
   3628             145, 79, 21, 97, 233, 3, 192, 194, 177, 68, 181, 80, 120, 197, 23, 44, 185, 74, 144, 0,
   3629             132, 149, 139, 11, 16, 224, 4, 112, 236, 94, 238, 97, 121, 124, 213, 145, 24, 253, 168,
   3630             35, 190, 205, 132, 115, 33, 201, 38, 253, 246, 180, 66, 155, 165, 46, 3, 254, 68, 108,
   3631             154, 247, 246, 45, 187, 0, 204, 96, 185, 157, 249, 174, 158, 38, 62, 244, 183, 76, 102,
   3632             6, 219, 92, 212, 138, 59, 147, 163, 219, 111, 39, 105, 21, 236, 196, 38, 255, 114, 247,
   3633             82, 104, 113, 204, 29, 152, 209, 219, 48, 239, 74, 129, 19, 247, 33, 239, 119, 166,
   3634             216, 152, 94, 138, 238, 164, 242, 129, 50, 150, 57, 20, 53, 224, 56, 241, 138, 97, 111,
   3635             215, 107, 212, 195, 146, 108, 143, 0, 229, 181, 171, 73, 152, 105, 146, 25, 243, 242,
   3636             140, 252, 248, 162, 247, 63, 168, 180, 20, 153, 120, 10, 248, 211, 1, 71, 127, 212,
   3637             249, 237, 203, 202, 48, 26, 216, 226, 228, 186, 13, 204, 70, 255, 240, 89, 255, 59, 83,
   3638             31, 253, 55, 43, 158, 90, 248, 83, 32, 159, 105, 57, 134, 34, 96, 18, 255, 245, 153,
   3639             162, 60, 91, 99, 220, 51, 44, 85, 114, 67, 125, 202, 65, 217, 245, 40, 8, 81, 165, 142,
   3640             24, 245, 127, 122, 247, 152, 212, 75, 45, 59, 90, 184, 234, 31, 147, 36, 8, 212, 45,
   3641             50, 23, 3, 25, 253, 87, 227, 79, 119, 161,
   3642         ];
   3643         let p = BigUint::from_slice(
   3644             [
   3645                 352691927, 1294578443, 816143558, 690659917, 1161596366, 1544791087, 3999549486,
   3646                 3319149924, 2349250979, 1304689381, 3959753736, 3377900978, 866506027, 1671521644,
   3647                 3926847564, 898221388, 3448219846, 494454484, 3915534864, 2869735916, 2456511629,
   3648                 3397234721, 3012775852, 3472309790, 1923617705, 2993441050, 3210302569, 3605331368,
   3649                 3352563766, 688081007, 4104512503, 4145593376,
   3650             ]
   3651             .as_slice(),
   3652         );
   3653         let p_2 = BigUint::from_slice(
   3654             [
   3655                 4039514409, 964284038, 3230008587, 3320139220, 3562360334, 3165876926, 212773653,
   3656                 2752465512, 2973674888, 1717425549, 2084262803, 3585031058, 4162394935, 1428626842,
   3657                 1015474994, 3283774155, 2840050110, 190639246, 147241978, 2994256073, 4081014755,
   3658                 3102401369, 3547397148, 1545029057, 895305733, 2689179461, 1593439337, 3960057302,
   3659                 193068804, 2835123424, 4054880057, 4200258364,
   3660             ]
   3661             .as_slice(),
   3662         );
   3663         let rsa_key = RsaKey::<Sha256>::new(
   3664             RsaPrivateKey::from_components(
   3665                 BigUint::from_bytes_le(n.as_slice()),
   3666                 e.into(),
   3667                 BigUint::from_bytes_le(d.as_slice()),
   3668                 vec![p, p_2],
   3669             )
   3670             .unwrap(),
   3671         )
   3672         .verifying_key();
   3673         let n = rsa_key.as_ref().n().to_bytes_be();
   3674         attestation_object[113..369].copy_from_slice(n.as_slice());
   3675         assert!(matches!(opts.start_ceremony()?.0.verify(
   3676             &rp_id,
   3677             id,
   3678             &Registration {
   3679                 response: AuthenticatorAttestation::new(
   3680                     client_data_json,
   3681                     attestation_object,
   3682                     AuthTransports::NONE,
   3683                 ),
   3684                 authenticator_attachment: AuthenticatorAttachment::None,
   3685                 client_extension_results: ClientExtensionsOutputs {
   3686                     cred_props: None,
   3687                     prf: None,
   3688                 },
   3689             },
   3690             &RegistrationVerificationOptions::<&str, &str>::default(),
   3691         )?.static_state.credential_public_key, UncompressedPubKey::Rsa(k) if *k.n() == n.as_slice() && k.e() == e));
   3692         Ok(())
   3693     }
   3694     #[test]
   3695     #[cfg(feature = "custom")]
   3696     fn rsa_auth() -> Result<(), AggErr> {
   3697         let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
   3698         let mut opts = PublicKeyCredentialRequestOptions::passkey(&rp_id);
   3699         opts.challenge = Challenge(0);
   3700         let client_data_json = br#"{"type":"webauthn.get","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.to_vec();
   3701         // We over-allocate by 32 bytes. See [`AuthenticatorAssertion::new`] for more information.
   3702         let mut authenticator_data = Vec::with_capacity(69);
   3703         authenticator_data.extend_from_slice(
   3704             [
   3705                 // rpIdHash.
   3706                 // This will be overwritten later.
   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                 0,
   3738                 0,
   3739                 // flags.
   3740                 // UP and UV (right-to-left).
   3741                 0b0000_0101,
   3742                 // signCount.
   3743                 // 0 as 32-bit big-endian.
   3744                 0,
   3745                 0,
   3746                 0,
   3747                 0,
   3748             ]
   3749             .as_slice(),
   3750         );
   3751         authenticator_data[..32]
   3752             .copy_from_slice(Sha256::digest(rp_id.as_ref().as_bytes()).as_slice());
   3753         authenticator_data
   3754             .extend_from_slice(Sha256::digest(client_data_json.as_slice()).as_slice());
   3755         let n = [
   3756             111, 183, 124, 133, 38, 167, 70, 148, 44, 50, 30, 60, 121, 14, 38, 37, 96, 114, 107,
   3757             195, 248, 64, 79, 36, 237, 140, 43, 27, 94, 74, 102, 152, 135, 102, 184, 150, 186, 206,
   3758             185, 19, 165, 209, 48, 98, 98, 9, 3, 205, 208, 82, 250, 105, 132, 201, 73, 62, 60, 165,
   3759             100, 128, 153, 9, 41, 118, 66, 95, 236, 214, 73, 135, 197, 68, 184, 10, 27, 116, 204,
   3760             145, 50, 174, 58, 42, 183, 181, 119, 232, 126, 252, 217, 96, 162, 190, 103, 122, 64,
   3761             87, 145, 45, 32, 207, 17, 239, 223, 3, 35, 14, 112, 119, 124, 141, 123, 208, 239, 105,
   3762             81, 217, 151, 162, 190, 17, 88, 182, 176, 158, 81, 200, 42, 166, 133, 48, 23, 236, 55,
   3763             117, 248, 233, 151, 203, 122, 155, 231, 46, 177, 20, 20, 151, 64, 222, 239, 226, 7, 21,
   3764             254, 81, 202, 64, 232, 161, 235, 22, 51, 246, 207, 213, 0, 229, 138, 46, 222, 205, 157,
   3765             108, 139, 253, 230, 80, 50, 2, 122, 212, 163, 100, 180, 114, 12, 113, 52, 56, 99, 188,
   3766             42, 198, 212, 23, 182, 222, 56, 221, 200, 79, 96, 239, 221, 135, 10, 17, 106, 183, 56,
   3767             104, 68, 94, 198, 196, 35, 200, 83, 204, 26, 185, 204, 212, 31, 183, 19, 111, 233, 13,
   3768             72, 93, 53, 65, 111, 59, 242, 122, 160, 244, 162, 126, 38, 235, 156, 47, 88, 39, 132,
   3769             153, 79, 0, 133, 78, 7, 218, 165, 241,
   3770         ];
   3771         let e = 65537;
   3772         let d = [
   3773             145, 79, 21, 97, 233, 3, 192, 194, 177, 68, 181, 80, 120, 197, 23, 44, 185, 74, 144, 0,
   3774             132, 149, 139, 11, 16, 224, 4, 112, 236, 94, 238, 97, 121, 124, 213, 145, 24, 253, 168,
   3775             35, 190, 205, 132, 115, 33, 201, 38, 253, 246, 180, 66, 155, 165, 46, 3, 254, 68, 108,
   3776             154, 247, 246, 45, 187, 0, 204, 96, 185, 157, 249, 174, 158, 38, 62, 244, 183, 76, 102,
   3777             6, 219, 92, 212, 138, 59, 147, 163, 219, 111, 39, 105, 21, 236, 196, 38, 255, 114, 247,
   3778             82, 104, 113, 204, 29, 152, 209, 219, 48, 239, 74, 129, 19, 247, 33, 239, 119, 166,
   3779             216, 152, 94, 138, 238, 164, 242, 129, 50, 150, 57, 20, 53, 224, 56, 241, 138, 97, 111,
   3780             215, 107, 212, 195, 146, 108, 143, 0, 229, 181, 171, 73, 152, 105, 146, 25, 243, 242,
   3781             140, 252, 248, 162, 247, 63, 168, 180, 20, 153, 120, 10, 248, 211, 1, 71, 127, 212,
   3782             249, 237, 203, 202, 48, 26, 216, 226, 228, 186, 13, 204, 70, 255, 240, 89, 255, 59, 83,
   3783             31, 253, 55, 43, 158, 90, 248, 83, 32, 159, 105, 57, 134, 34, 96, 18, 255, 245, 153,
   3784             162, 60, 91, 99, 220, 51, 44, 85, 114, 67, 125, 202, 65, 217, 245, 40, 8, 81, 165, 142,
   3785             24, 245, 127, 122, 247, 152, 212, 75, 45, 59, 90, 184, 234, 31, 147, 36, 8, 212, 45,
   3786             50, 23, 3, 25, 253, 87, 227, 79, 119, 161,
   3787         ];
   3788         let p = BigUint::from_slice(
   3789             [
   3790                 352691927, 1294578443, 816143558, 690659917, 1161596366, 1544791087, 3999549486,
   3791                 3319149924, 2349250979, 1304689381, 3959753736, 3377900978, 866506027, 1671521644,
   3792                 3926847564, 898221388, 3448219846, 494454484, 3915534864, 2869735916, 2456511629,
   3793                 3397234721, 3012775852, 3472309790, 1923617705, 2993441050, 3210302569, 3605331368,
   3794                 3352563766, 688081007, 4104512503, 4145593376,
   3795             ]
   3796             .as_slice(),
   3797         );
   3798         let p_2 = BigUint::from_slice(
   3799             [
   3800                 4039514409, 964284038, 3230008587, 3320139220, 3562360334, 3165876926, 212773653,
   3801                 2752465512, 2973674888, 1717425549, 2084262803, 3585031058, 4162394935, 1428626842,
   3802                 1015474994, 3283774155, 2840050110, 190639246, 147241978, 2994256073, 4081014755,
   3803                 3102401369, 3547397148, 1545029057, 895305733, 2689179461, 1593439337, 3960057302,
   3804                 193068804, 2835123424, 4054880057, 4200258364,
   3805             ]
   3806             .as_slice(),
   3807         );
   3808         let rsa_key = RsaKey::<Sha256>::new(
   3809             RsaPrivateKey::from_components(
   3810                 BigUint::from_bytes_le(n.as_slice()),
   3811                 e.into(),
   3812                 BigUint::from_bytes_le(d.as_slice()),
   3813                 vec![p, p_2],
   3814             )
   3815             .unwrap(),
   3816         );
   3817         let rsa_pub = rsa_key.verifying_key();
   3818         let sig = rsa_key.sign(authenticator_data.as_slice()).to_vec();
   3819         authenticator_data.truncate(37);
   3820         assert!(!opts.start_ceremony()?.0.verify(
   3821             &rp_id,
   3822             &Authentication {
   3823                 raw_id: CredentialId::try_from(vec![0; 16])?,
   3824                 response: AuthenticatorAssertion::new(
   3825                     client_data_json,
   3826                     authenticator_data,
   3827                     sig,
   3828                     Some(UserHandle::try_from(vec![0])?),
   3829                 ),
   3830                 authenticator_attachment: AuthenticatorAttachment::None,
   3831             },
   3832             &mut AuthenticatedCredential::new(
   3833                 CredentialId::try_from([0; 16].as_slice())?,
   3834                 UserHandle::try_from([0].as_slice())?,
   3835                 StaticState {
   3836                     credential_public_key: CompressedPubKey::<&[u8], &[u8], &[u8], _>::Rsa(
   3837                         RsaPubKey::try_from((rsa_pub.as_ref().n().to_bytes_be(), e)).unwrap(),
   3838                     ),
   3839                     extensions: AuthenticatorExtensionOutputStaticState {
   3840                         cred_protect: CredentialProtectionPolicy::None,
   3841                         hmac_secret: None,
   3842                     },
   3843                 },
   3844                 DynamicState {
   3845                     user_verified: true,
   3846                     backup: Backup::NotEligible,
   3847                     sign_count: 0,
   3848                     authenticator_attachment: AuthenticatorAttachment::None,
   3849                 },
   3850             )?,
   3851             &AuthenticationVerificationOptions::<&str, &str>::default(),
   3852         )?);
   3853         Ok(())
   3854     }
   3855 }