webauthn_rp

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

bin.rs (28095B)


      1 use super::{
      2     super::super::bin::{
      3         Decode, DecodeBuffer, EncDecErr, Encode, EncodeBuffer, EncodeBufferFallible as _,
      4     },
      5     Aaguid, Attestation, AuthenticationExtensionsPrfOutputs, AuthenticatorAttachment,
      6     AuthenticatorExtensionOutputMetadata, AuthenticatorExtensionOutputStaticState, Backup,
      7     ClientExtensionsOutputsMetadata, ClientExtensionsOutputsStaticState, CompressedP256PubKey,
      8     CompressedP384PubKey, CompressedPubKey, CredentialPropertiesOutput, CredentialProtectionPolicy,
      9     DynamicState, Ed25519PubKey, FourToSixtyThree, Metadata, ResidentKeyRequirement, RsaPubKey,
     10     StaticState, UncompressedP256PubKey, UncompressedP384PubKey, UncompressedPubKey,
     11 };
     12 use core::{
     13     convert::Infallible,
     14     error::Error,
     15     fmt::{self, Display, Formatter},
     16 };
     17 use p256::{
     18     NistP256,
     19     elliptic_curve::{Curve, generic_array::typenum::ToInt as _},
     20 };
     21 use p384::NistP384;
     22 impl EncodeBuffer for CredentialProtectionPolicy {
     23     fn encode_into_buffer(&self, buffer: &mut Vec<u8>) {
     24         match *self {
     25             Self::None => 0u8,
     26             Self::UserVerificationOptional => 1,
     27             Self::UserVerificationOptionalWithCredentialIdList => 2,
     28             Self::UserVerificationRequired => 3,
     29         }
     30         .encode_into_buffer(buffer);
     31     }
     32 }
     33 impl<'a> DecodeBuffer<'a> for CredentialProtectionPolicy {
     34     type Err = EncDecErr;
     35     fn decode_from_buffer(data: &mut &'a [u8]) -> Result<Self, Self::Err> {
     36         u8::decode_from_buffer(data).and_then(|val| match val {
     37             0 => Ok(Self::None),
     38             1 => Ok(Self::UserVerificationOptional),
     39             2 => Ok(Self::UserVerificationOptionalWithCredentialIdList),
     40             3 => Ok(Self::UserVerificationRequired),
     41             _ => Err(EncDecErr),
     42         })
     43     }
     44 }
     45 impl EncodeBuffer for ResidentKeyRequirement {
     46     fn encode_into_buffer(&self, buffer: &mut Vec<u8>) {
     47         match *self {
     48             Self::Required => 0u8,
     49             Self::Discouraged => 1,
     50             Self::Preferred => 2,
     51         }
     52         .encode_into_buffer(buffer);
     53     }
     54 }
     55 impl<'a> DecodeBuffer<'a> for ResidentKeyRequirement {
     56     type Err = EncDecErr;
     57     fn decode_from_buffer(data: &mut &'a [u8]) -> Result<Self, Self::Err> {
     58         u8::decode_from_buffer(data).and_then(|val| match val {
     59             0 => Ok(Self::Required),
     60             1 => Ok(Self::Discouraged),
     61             2 => Ok(Self::Preferred),
     62             _ => Err(EncDecErr),
     63         })
     64     }
     65 }
     66 impl EncodeBuffer for Ed25519PubKey<&[u8]> {
     67     fn encode_into_buffer(&self, buffer: &mut Vec<u8>) {
     68         // We don't rely on `[u8]::encode_into_buffer` since
     69         // we always know the `slice` has length 32; thus
     70         // we want to "pretend" this is an array (i.e., don't encode the length).
     71         buffer.extend_from_slice(self.0);
     72     }
     73 }
     74 impl<'a> DecodeBuffer<'a> for Ed25519PubKey<[u8; ed25519_dalek::PUBLIC_KEY_LENGTH]> {
     75     type Err = EncDecErr;
     76     // We don't verify `Self` is in fact "valid" (i.e., we don't call
     77     // [`Self::validate`]) since that's expensive and an error will
     78     // happen later during authentication anyway. Note even if we did,
     79     // that wouldn't detect a public key that was altered in persistent
     80     // storage in such a way that it's still valid; thus there is no
     81     // benefit in performing "expensive" validation checks.
     82     fn decode_from_buffer(data: &mut &'a [u8]) -> Result<Self, Self::Err> {
     83         <[u8; ed25519_dalek::PUBLIC_KEY_LENGTH]>::decode_from_buffer(data).map(Self)
     84     }
     85 }
     86 impl EncodeBuffer for UncompressedP256PubKey<'_> {
     87     #[expect(clippy::indexing_slicing, reason = "comment justifies its correctness")]
     88     fn encode_into_buffer(&self, buffer: &mut Vec<u8>) {
     89         /// Number of bytes the y-coordinate takes.
     90         const Y_LEN: usize = <NistP256 as Curve>::FieldBytesSize::INT;
     91         /// The index of the least significant byte of the y-coordinate.
     92         const ODD_BYTE_INDEX: usize = Y_LEN - 1;
     93         // We don't rely on `[u8]::encode_into_buffer` since
     94         // we always know the `slice` has length 32; thus
     95         // we want to "pretend" this is an array (i.e., don't encode the length).
     96         buffer.extend_from_slice(self.0);
     97         // `self.1.len() == 32` and `ODD_BYTE_INDEX == 31`, so indexing is fine.
     98         (self.1[ODD_BYTE_INDEX] & 1 == 1).encode_into_buffer(buffer);
     99     }
    100 }
    101 impl<'a> DecodeBuffer<'a> for CompressedP256PubKey<[u8; <NistP256 as Curve>::FieldBytesSize::INT]> {
    102     type Err = EncDecErr;
    103     // We don't verify `Self` is in fact "valid" (i.e., we don't call
    104     // [`Self::validate`]) since that's expensive and an error will
    105     // happen later during authentication anyway. Note even if we did,
    106     // that wouldn't detect a public key that was altered in persistent
    107     // storage in such a way that it's still valid; thus there is no
    108     // benefit in performing "expensive" validation checks.
    109     fn decode_from_buffer(data: &mut &'a [u8]) -> Result<Self, Self::Err> {
    110         <[u8; <NistP256 as Curve>::FieldBytesSize::INT]>::decode_from_buffer(data)
    111             .and_then(|x| bool::decode_from_buffer(data).map(|y_is_odd| Self { x, y_is_odd }))
    112     }
    113 }
    114 impl EncodeBuffer for UncompressedP384PubKey<'_> {
    115     #[expect(clippy::indexing_slicing, reason = "comment justifies its correctness")]
    116     fn encode_into_buffer(&self, buffer: &mut Vec<u8>) {
    117         /// Number of bytes the y-coordinate takes.
    118         const Y_LEN: usize = <NistP384 as Curve>::FieldBytesSize::INT;
    119         /// The index of the least significant byte of the y-coordinate.
    120         const ODD_BYTE_INDEX: usize = Y_LEN - 1;
    121         // We don't rely on `[u8]::encode_into_buffer` since
    122         // we always know the `slice` has length 48; thus
    123         // we want to "pretend" this is an array (i.e., don't encode the length).
    124         buffer.extend_from_slice(self.0);
    125         // `self.1.len() == 48` and `ODD_BYTE_INDEX == 47`, so indexing is fine.
    126         (self.1[ODD_BYTE_INDEX] & 1 == 1).encode_into_buffer(buffer);
    127     }
    128 }
    129 impl<'a> DecodeBuffer<'a> for CompressedP384PubKey<[u8; <NistP384 as Curve>::FieldBytesSize::INT]> {
    130     type Err = EncDecErr;
    131     // We don't verify `Self` is in fact "valid" (i.e., we don't call
    132     // [`Self::validate`]) since that's expensive and an error will
    133     // happen later during authentication anyway. Note even if we did,
    134     // that wouldn't detect a public key that was altered in persistent
    135     // storage in such a way that it's still valid; thus there is no
    136     // benefit in performing "expensive" validation checks.
    137     fn decode_from_buffer(data: &mut &'a [u8]) -> Result<Self, Self::Err> {
    138         // Only `array`s that implement `Default` implement `DecodeBuffer`;
    139         // thus we must manually implement it.
    140         let mut x = [0; <NistP384 as Curve>::FieldBytesSize::INT];
    141         data.split_at_checked(x.len())
    142             .ok_or(EncDecErr)
    143             .and_then(|(x_slice, rem)| {
    144                 *data = rem;
    145                 bool::decode_from_buffer(data).map(|y_is_odd| {
    146                     x.copy_from_slice(x_slice);
    147                     Self { x, y_is_odd }
    148                 })
    149             })
    150     }
    151 }
    152 impl EncodeBuffer for RsaPubKey<&[u8]> {
    153     #[expect(clippy::unreachable, reason = "we want to crash when there is a bug")]
    154     fn encode_into_buffer(&self, buffer: &mut Vec<u8>) {
    155         // Max length is 2048, so this won't error.
    156         self.0
    157             .encode_into_buffer(buffer)
    158             .unwrap_or_else(|_e| unreachable!("there is a bug in [u8]::encode_into_buffer"));
    159         self.1.encode_into_buffer(buffer);
    160     }
    161 }
    162 impl<'a> DecodeBuffer<'a> for RsaPubKey<Vec<u8>> {
    163     type Err = EncDecErr;
    164     // We don't verify `Self` is in fact "valid" (i.e., we don't call
    165     // [`Self::validate`]) since that's expensive and an error will
    166     // happen later during authentication anyway. Note even if we did,
    167     // that wouldn't detect a public key that was altered in persistent
    168     // storage in such a way that it's still valid; thus there is no
    169     // benefit in performing "expensive" validation checks.
    170     fn decode_from_buffer(data: &mut &'a [u8]) -> Result<Self, Self::Err> {
    171         Vec::decode_from_buffer(data).and_then(|n| {
    172             u32::decode_from_buffer(data)
    173                 .and_then(|e| Self::try_from((n, e)).map_err(|_e| EncDecErr))
    174         })
    175     }
    176 }
    177 impl EncodeBuffer for UncompressedPubKey<'_> {
    178     fn encode_into_buffer(&self, buffer: &mut Vec<u8>) {
    179         match *self {
    180             Self::Ed25519(key) => {
    181                 0u8.encode_into_buffer(buffer);
    182                 key.encode_into_buffer(buffer);
    183             }
    184             Self::P256(key) => {
    185                 1u8.encode_into_buffer(buffer);
    186                 key.encode_into_buffer(buffer);
    187             }
    188             Self::P384(key) => {
    189                 2u8.encode_into_buffer(buffer);
    190                 key.encode_into_buffer(buffer);
    191             }
    192             Self::Rsa(key) => {
    193                 3u8.encode_into_buffer(buffer);
    194                 key.encode_into_buffer(buffer);
    195             }
    196         }
    197     }
    198 }
    199 impl<'a> DecodeBuffer<'a>
    200     for CompressedPubKey<
    201         [u8; ed25519_dalek::PUBLIC_KEY_LENGTH],
    202         [u8; <NistP256 as Curve>::FieldBytesSize::INT],
    203         [u8; <NistP384 as Curve>::FieldBytesSize::INT],
    204         Vec<u8>,
    205     >
    206 {
    207     type Err = EncDecErr;
    208     // We don't verify `Self` is in fact "valid" (i.e., we don't call
    209     // [`Self::validate`]) since that's expensive and an error will
    210     // happen later during authentication anyway. Note even if we did,
    211     // that wouldn't detect a public key that was altered in persistent
    212     // storage in such a way that it's still valid; thus there is no
    213     // benefit in performing "expensive" validation checks.
    214     fn decode_from_buffer(data: &mut &'a [u8]) -> Result<Self, Self::Err> {
    215         u8::decode_from_buffer(data).and_then(|val| match val {
    216             0 => Ed25519PubKey::decode_from_buffer(data).map(Self::Ed25519),
    217             1 => CompressedP256PubKey::decode_from_buffer(data).map(Self::P256),
    218             2 => CompressedP384PubKey::decode_from_buffer(data).map(Self::P384),
    219             3 => RsaPubKey::decode_from_buffer(data).map(Self::Rsa),
    220             _ => Err(EncDecErr),
    221         })
    222     }
    223 }
    224 impl EncodeBuffer for AuthenticatorExtensionOutputStaticState {
    225     fn encode_into_buffer(&self, buffer: &mut Vec<u8>) {
    226         self.cred_protect.encode_into_buffer(buffer);
    227         self.hmac_secret.encode_into_buffer(buffer);
    228     }
    229 }
    230 impl<'a> DecodeBuffer<'a> for AuthenticatorExtensionOutputStaticState {
    231     type Err = EncDecErr;
    232     fn decode_from_buffer(data: &mut &'a [u8]) -> Result<Self, Self::Err> {
    233         CredentialProtectionPolicy::decode_from_buffer(data).and_then(|cred_protect| {
    234             Option::decode_from_buffer(data).map(|hmac_secret| Self {
    235                 cred_protect,
    236                 hmac_secret,
    237             })
    238         })
    239     }
    240 }
    241 impl EncodeBuffer for Attestation {
    242     fn encode_into_buffer(&self, buffer: &mut Vec<u8>) {
    243         match *self {
    244             Self::None => 0u8,
    245             Self::Surrogate => 1,
    246         }
    247         .encode_into_buffer(buffer);
    248     }
    249 }
    250 impl<'a> DecodeBuffer<'a> for Attestation {
    251     type Err = EncDecErr;
    252     fn decode_from_buffer(data: &mut &'a [u8]) -> Result<Self, Self::Err> {
    253         u8::decode_from_buffer(data).and_then(|val| match val {
    254             0 => Ok(Self::None),
    255             1 => Ok(Self::Surrogate),
    256             _ => Err(EncDecErr),
    257         })
    258     }
    259 }
    260 impl EncodeBuffer for Aaguid<'_> {
    261     fn encode_into_buffer(&self, buffer: &mut Vec<u8>) {
    262         buffer.extend_from_slice(self.0);
    263     }
    264 }
    265 /// Owned version of [`Aaguid`] that exists for [`MetadataOwned::aaguid`].
    266 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
    267 pub struct AaguidOwned(pub [u8; super::AAGUID_LEN]);
    268 impl<'a: 'b, 'b> From<&'a AaguidOwned> for Aaguid<'b> {
    269     #[inline]
    270     fn from(value: &'a AaguidOwned) -> Self {
    271         Self(value.0.as_slice())
    272     }
    273 }
    274 impl<'a> DecodeBuffer<'a> for AaguidOwned {
    275     type Err = EncDecErr;
    276     fn decode_from_buffer(data: &mut &'a [u8]) -> Result<Self, Self::Err> {
    277         <[u8; super::AAGUID_LEN]>::decode_from_buffer(data).map(Self)
    278     }
    279 }
    280 impl EncodeBuffer for FourToSixtyThree {
    281     fn encode_into_buffer(&self, buffer: &mut Vec<u8>) {
    282         self.into_u8().encode_into_buffer(buffer);
    283     }
    284 }
    285 impl EncodeBuffer for AuthenticatorExtensionOutputMetadata {
    286     fn encode_into_buffer(&self, buffer: &mut Vec<u8>) {
    287         self.min_pin_length.encode_into_buffer(buffer);
    288     }
    289 }
    290 impl<'a> DecodeBuffer<'a> for FourToSixtyThree {
    291     type Err = EncDecErr;
    292     fn decode_from_buffer(data: &mut &'a [u8]) -> Result<Self, Self::Err> {
    293         u8::decode_from_buffer(data).and_then(|val| Self::from_u8(val).ok_or(EncDecErr))
    294     }
    295 }
    296 impl<'a> DecodeBuffer<'a> for AuthenticatorExtensionOutputMetadata {
    297     type Err = EncDecErr;
    298     fn decode_from_buffer(data: &mut &'a [u8]) -> Result<Self, Self::Err> {
    299         Option::decode_from_buffer(data).map(|min_pin_length| Self { min_pin_length })
    300     }
    301 }
    302 impl EncodeBuffer for CredentialPropertiesOutput {
    303     fn encode_into_buffer(&self, buffer: &mut Vec<u8>) {
    304         self.rk.encode_into_buffer(buffer);
    305     }
    306 }
    307 impl<'a> DecodeBuffer<'a> for CredentialPropertiesOutput {
    308     type Err = EncDecErr;
    309     fn decode_from_buffer(data: &mut &'a [u8]) -> Result<Self, Self::Err> {
    310         Option::decode_from_buffer(data).map(|rk| Self { rk })
    311     }
    312 }
    313 impl EncodeBuffer for AuthenticationExtensionsPrfOutputs {
    314     fn encode_into_buffer(&self, buffer: &mut Vec<u8>) {
    315         self.enabled.encode_into_buffer(buffer);
    316     }
    317 }
    318 impl<'a> DecodeBuffer<'a> for AuthenticationExtensionsPrfOutputs {
    319     type Err = EncDecErr;
    320     fn decode_from_buffer(data: &mut &'a [u8]) -> Result<Self, Self::Err> {
    321         bool::decode_from_buffer(data).map(|enabled| Self { enabled })
    322     }
    323 }
    324 impl EncodeBuffer for ClientExtensionsOutputsMetadata {
    325     fn encode_into_buffer(&self, buffer: &mut Vec<u8>) {
    326         self.cred_props.encode_into_buffer(buffer);
    327     }
    328 }
    329 impl EncodeBuffer for ClientExtensionsOutputsStaticState {
    330     fn encode_into_buffer(&self, buffer: &mut Vec<u8>) {
    331         self.prf.encode_into_buffer(buffer);
    332     }
    333 }
    334 impl<'a> DecodeBuffer<'a> for ClientExtensionsOutputsMetadata {
    335     type Err = EncDecErr;
    336     fn decode_from_buffer(data: &mut &'a [u8]) -> Result<Self, Self::Err> {
    337         Option::decode_from_buffer(data).map(|cred_props| Self { cred_props })
    338     }
    339 }
    340 impl<'a> DecodeBuffer<'a> for ClientExtensionsOutputsStaticState {
    341     type Err = EncDecErr;
    342     fn decode_from_buffer(data: &mut &'a [u8]) -> Result<Self, Self::Err> {
    343         Option::decode_from_buffer(data).map(|prf| Self { prf })
    344     }
    345 }
    346 impl Encode for Metadata<'_> {
    347     type Output<'a>
    348         = Vec<u8>
    349     where
    350         Self: 'a;
    351     type Err = Infallible;
    352     #[inline]
    353     fn encode(&self) -> Result<Self::Output<'_>, Self::Err> {
    354         // Length of the anticipated most common output:
    355         // * 1 for `Attestation`
    356         // * 16 for `Aaguid`.
    357         // * 1 or 2 for `AuthenticatorExtensionOutputMetadata` where we assume 1 is the most common
    358         // * 1–3 for `ClientExtensionsOutputsMetadata` where we assume 1 is the most common
    359         // * 1 for `ResidentKeyRequirement`
    360         let mut buffer = Vec::with_capacity(1 + 16 + 1 + 1 + 1);
    361         self.attestation.encode_into_buffer(&mut buffer);
    362         self.aaguid.encode_into_buffer(&mut buffer);
    363         self.extensions.encode_into_buffer(&mut buffer);
    364         self.client_extension_results
    365             .encode_into_buffer(&mut buffer);
    366         self.resident_key.encode_into_buffer(&mut buffer);
    367         Ok(buffer)
    368     }
    369 }
    370 /// Owned version of [`Metadata`] that exists to [`Self::decode`] the output of [`Metadata::encode`].
    371 #[derive(Clone, Copy, Debug)]
    372 pub struct MetadataOwned {
    373     /// [`Metadata::attestation`].
    374     pub attestation: Attestation,
    375     /// [`Metadata::aaguid`].
    376     pub aaguid: AaguidOwned,
    377     /// [`Metadata::extensions`].
    378     pub extensions: AuthenticatorExtensionOutputMetadata,
    379     /// [`Metadata::client_extension_results`].
    380     pub client_extension_results: ClientExtensionsOutputsMetadata,
    381     /// [`Metadata::resident_key`].
    382     pub resident_key: ResidentKeyRequirement,
    383 }
    384 impl<'a: 'b, 'b> From<&'a MetadataOwned> for Metadata<'b> {
    385     #[inline]
    386     fn from(value: &'a MetadataOwned) -> Self {
    387         Self {
    388             attestation: value.attestation,
    389             aaguid: (&value.aaguid).into(),
    390             extensions: value.extensions,
    391             client_extension_results: value.client_extension_results,
    392             resident_key: value.resident_key,
    393         }
    394     }
    395 }
    396 /// Error returned from [`MetadataOwned::decode`].
    397 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
    398 pub enum DecodeMetadataOwnedErr {
    399     /// Variant returned when [`MetadataOwned::attestation`] could not be decoded.
    400     Attestation,
    401     /// Variant returned when [`MetadataOwned::aaguid`] could not be decoded.
    402     Aaguid,
    403     /// Variant returned when [`MetadataOwned::extensions`] could not be decoded.
    404     Extensions,
    405     /// Variant returned when [`MetadataOwned::client_extension_results`] could not be decoded.
    406     ClientExtensionResults,
    407     /// Variant returned when [`MetadataOwned::resident_key`] could not be decoded.
    408     ResidentKey,
    409     /// Variant returned when [`MetadataOwned`] was decoded with trailing data.
    410     TrailingData,
    411 }
    412 impl Display for DecodeMetadataOwnedErr {
    413     #[inline]
    414     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    415         f.write_str(match *self {
    416             Self::Attestation => "attestation could not be decoded",
    417             Self::Aaguid => "aaguid could not be decoded",
    418             Self::Extensions => "extensions could not be decoded",
    419             Self::ClientExtensionResults => "client_extension_results could not be decoded",
    420             Self::ResidentKey => "resident_key could not be decoded",
    421             Self::TrailingData => "trailing data existed after decoding MetadataOwned",
    422         })
    423     }
    424 }
    425 impl Error for DecodeMetadataOwnedErr {}
    426 impl Decode for MetadataOwned {
    427     type Input<'a> = &'a [u8];
    428     type Err = DecodeMetadataOwnedErr;
    429     #[inline]
    430     fn decode(mut input: Self::Input<'_>) -> Result<Self, Self::Err> {
    431         Attestation::decode_from_buffer(&mut input)
    432             .map_err(|_e| DecodeMetadataOwnedErr::Attestation)
    433             .and_then(|attestation| {
    434                 AaguidOwned::decode_from_buffer(&mut input)
    435                     .map_err(|_e| DecodeMetadataOwnedErr::Aaguid)
    436                     .and_then(|aaguid| {
    437                         AuthenticatorExtensionOutputMetadata::decode_from_buffer(&mut input)
    438                             .map_err(|_e| DecodeMetadataOwnedErr::Extensions)
    439                             .and_then(|extensions| {
    440                                 ClientExtensionsOutputsMetadata::decode_from_buffer(&mut input)
    441                                     .map_err(|_e| DecodeMetadataOwnedErr::ClientExtensionResults)
    442                                     .and_then(|client_extension_results| {
    443                                         ResidentKeyRequirement::decode_from_buffer(&mut input)
    444                                             .map_err(|_e| DecodeMetadataOwnedErr::ResidentKey)
    445                                             .and_then(|resident_key| {
    446                                                 if input.is_empty() {
    447                                                     Ok(Self {
    448                                                         attestation,
    449                                                         aaguid,
    450                                                         extensions,
    451                                                         client_extension_results,
    452                                                         resident_key,
    453                                                     })
    454                                                 } else {
    455                                                     Err(DecodeMetadataOwnedErr::TrailingData)
    456                                                 }
    457                                             })
    458                                     })
    459                             })
    460                     })
    461             })
    462     }
    463 }
    464 impl Encode for StaticState<UncompressedPubKey<'_>> {
    465     type Output<'a>
    466         = Vec<u8>
    467     where
    468         Self: 'a;
    469     type Err = Infallible;
    470     /// Transforms `self` into a `Vec` that can subsequently be [`StaticState::decode`]d into a [`StaticState`] of
    471     /// [`CompressedPubKey`].
    472     #[expect(
    473         clippy::arithmetic_side_effects,
    474         reason = "comment justifies its correctness"
    475     )]
    476     #[inline]
    477     fn encode(&self) -> Result<Self::Output<'_>, Self::Err> {
    478         let mut buffer = Vec::with_capacity(
    479             // The maximum value is 1 + 2 + 2048 + 4 + 1 + 1 + 1 + 1 + 1 = 2060 so overflow cannot happen.
    480             // `key.0.len() <= MAX_RSA_N_BYTES` which is 2048.
    481             match self.credential_public_key {
    482                 UncompressedPubKey::Ed25519(_) => 33,
    483                 UncompressedPubKey::P256(_) => 34,
    484                 UncompressedPubKey::P384(_) => 50,
    485                 UncompressedPubKey::Rsa(key) => 1 + 2 + key.0.len() + 4,
    486             } + 1
    487                 + 1
    488                 + usize::from(self.extensions.hmac_secret.is_some())
    489                 + 1
    490                 + usize::from(self.client_extension_results.prf.is_some()),
    491         );
    492         self.credential_public_key.encode_into_buffer(&mut buffer);
    493         self.extensions.encode_into_buffer(&mut buffer);
    494         self.client_extension_results
    495             .encode_into_buffer(&mut buffer);
    496         Ok(buffer)
    497     }
    498 }
    499 /// Error returned from [`StaticState::decode`].
    500 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
    501 pub enum DecodeStaticStateErr {
    502     /// Variant returned when [`StaticState::credential_public_key`] could not be decoded.
    503     CredentialPublicKey,
    504     /// Variant returned when [`StaticState::extensions`] could not be decoded.
    505     Extensions,
    506     /// Variant returned when [`StaticState::client_extension_results`] could not be decoded.
    507     ClientExtensionResults,
    508     /// Variant returned when there was trailing data after decoding a [`StaticState`].
    509     TrailingData,
    510 }
    511 impl Display for DecodeStaticStateErr {
    512     #[inline]
    513     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    514         f.write_str(match *self {
    515             Self::CredentialPublicKey => "credential_public_key could not be decoded",
    516             Self::Extensions => "extensions could not be decoded",
    517             Self::ClientExtensionResults => "client_extension_results could not be decoded",
    518             Self::TrailingData => "there was trailing data after decoding a StaticState",
    519         })
    520     }
    521 }
    522 impl Error for DecodeStaticStateErr {}
    523 impl Decode
    524     for StaticState<
    525         CompressedPubKey<
    526             [u8; ed25519_dalek::PUBLIC_KEY_LENGTH],
    527             [u8; <NistP256 as Curve>::FieldBytesSize::INT],
    528             [u8; <NistP384 as Curve>::FieldBytesSize::INT],
    529             Vec<u8>,
    530         >,
    531     >
    532 {
    533     type Input<'a> = &'a [u8];
    534     type Err = DecodeStaticStateErr;
    535     /// Interprets `input` as the [`StaticState::Output`] of [`StaticState::encode`].
    536     #[inline]
    537     fn decode(mut input: Self::Input<'_>) -> Result<Self, Self::Err> {
    538         CompressedPubKey::decode_from_buffer(&mut input)
    539             .map_err(|_e| DecodeStaticStateErr::CredentialPublicKey)
    540             .and_then(|credential_public_key| {
    541                 AuthenticatorExtensionOutputStaticState::decode_from_buffer(&mut input)
    542                     .map_err(|_e| DecodeStaticStateErr::Extensions)
    543                     .and_then(|extensions| {
    544                         ClientExtensionsOutputsStaticState::decode_from_buffer(&mut input)
    545                             .map_err(|_e| DecodeStaticStateErr::ClientExtensionResults)
    546                             .and_then(|client_extension_results| {
    547                                 if input.is_empty() {
    548                                     Ok(Self {
    549                                         credential_public_key,
    550                                         extensions,
    551                                         client_extension_results,
    552                                     })
    553                                 } else {
    554                                     Err(DecodeStaticStateErr::TrailingData)
    555                                 }
    556                             })
    557                     })
    558             })
    559     }
    560 }
    561 impl Encode for DynamicState {
    562     type Output<'a>
    563         = [u8; 7]
    564     where
    565         Self: 'a;
    566     type Err = Infallible;
    567     #[expect(
    568         clippy::little_endian_bytes,
    569         reason = "need cross-platform correctness"
    570     )]
    571     #[inline]
    572     fn encode(&self) -> Result<Self::Output<'_>, Self::Err> {
    573         let mut buffer = [
    574             u8::from(self.user_verified),
    575             match self.backup {
    576                 Backup::NotEligible => 0,
    577                 Backup::Eligible => 1,
    578                 Backup::Exists => 2,
    579             },
    580             0,
    581             0,
    582             0,
    583             0,
    584             match self.authenticator_attachment {
    585                 AuthenticatorAttachment::None => 0,
    586                 AuthenticatorAttachment::Platform => 1,
    587                 AuthenticatorAttachment::CrossPlatform => 2,
    588             },
    589         ];
    590         buffer[2..6].copy_from_slice(self.sign_count.to_le_bytes().as_slice());
    591         Ok(buffer)
    592     }
    593 }
    594 /// Error returned from [`DynamicState::decode`].
    595 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
    596 pub enum DecodeDynamicStateErr {
    597     /// Variant returned when [`DynamicState::user_verified`] could not be decoded.
    598     UserVerified,
    599     /// Variant returned when [`DynamicState::backup`] could not be decoded.
    600     Backup,
    601     /// Variant returned when [`DynamicState::sign_count`] could not be decoded.
    602     SignCount,
    603     /// Variant returned when [`DynamicState::authenticator_attachment`] could not be decoded.
    604     AuthenticatorAttachment,
    605 }
    606 impl Display for DecodeDynamicStateErr {
    607     #[inline]
    608     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    609         f.write_str(match *self {
    610             Self::UserVerified => "user_verified could not be decoded",
    611             Self::Backup => "backup could not be decoded",
    612             Self::SignCount => "sign_count could not be decoded",
    613             Self::AuthenticatorAttachment => "authenticator_attachment could not be decoded",
    614         })
    615     }
    616 }
    617 impl Error for DecodeDynamicStateErr {}
    618 impl Decode for DynamicState {
    619     type Input<'a> = [u8; 7];
    620     type Err = DecodeDynamicStateErr;
    621     #[expect(
    622         clippy::panic_in_result_fn,
    623         reason = "want to crash when there is a bug"
    624     )]
    625     #[inline]
    626     fn decode(input: Self::Input<'_>) -> Result<Self, Self::Err> {
    627         let mut buffer = input.as_slice();
    628         bool::decode_from_buffer(&mut buffer)
    629             .map_err(|_e| DecodeDynamicStateErr::UserVerified)
    630             .and_then(|user_verified| {
    631                 Backup::decode_from_buffer(&mut buffer)
    632                     .map_err(|_e| DecodeDynamicStateErr::Backup)
    633                     .and_then(|backup| {
    634                         u32::decode_from_buffer(&mut buffer)
    635                             .map_err(|_e| DecodeDynamicStateErr::SignCount)
    636                             .and_then(|sign_count| {
    637                                 AuthenticatorAttachment::decode_from_buffer(&mut buffer)
    638                                     .map_err(|_e| DecodeDynamicStateErr::AuthenticatorAttachment)
    639                                     .map(|authenticator_attachment| {
    640                                         assert!(
    641                                             buffer.is_empty(),
    642                                             "there is a bug in DynamicState::decode"
    643                                         );
    644                                         Self {
    645                                             user_verified,
    646                                             backup,
    647                                             sign_count,
    648                                             authenticator_attachment,
    649                                         }
    650                                     })
    651                             })
    652                     })
    653             })
    654     }
    655 }