webauthn_rp

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

ser.rs (96781B)


      1 #[cfg(test)]
      2 mod tests;
      3 use super::{
      4     super::{
      5         super::request::register::CoseAlgorithmIdentifier,
      6         ser::{
      7             AuthenticationExtensionsPrfOutputsHelper, AuthenticationExtensionsPrfValues,
      8             Base64DecodedVal, ClientExtensions, PublicKeyCredential,
      9         },
     10     },
     11     AttestationObject, AttestedCredentialData, AuthTransports, AuthenticationExtensionsPrfOutputs,
     12     AuthenticatorAttestation, ClientExtensionsOutputs, CredentialPropertiesOutput, FromCbor as _,
     13     Registration, UncompressedPubKey,
     14 };
     15 #[cfg(doc)]
     16 use super::{AuthenticatorAttachment, CredentialId};
     17 use core::{
     18     fmt::{self, Formatter},
     19     marker::PhantomData,
     20     str,
     21 };
     22 use rsa::sha2::{Sha256, digest::OutputSizeUser as _};
     23 use serde::de::{Deserialize, Deserializer, Error, IgnoredAny, MapAccess, Unexpected, Visitor};
     24 /// Functionality for deserializing DER-encoded `SubjectPublicKeyInfo` _without_ making copies of data or
     25 /// verifying the key is valid. This exists purely to ensure that the public key we receive in JSON is the same as
     26 /// the public key in the attestation object.
     27 mod spki {
     28     use super::super::{
     29         Ed25519PubKey, MlDsa44PubKey, MlDsa65PubKey, MlDsa87PubKey, RsaPubKey, RsaPubKeyErr,
     30         UncompressedP256PubKey, UncompressedP384PubKey, UncompressedPubKey,
     31     };
     32     use core::fmt::{self, Display, Formatter};
     33     use p256::{
     34         NistP256,
     35         elliptic_curve::{Curve, common::typenum::type_operators::ToInt as _},
     36     };
     37     use p384::NistP384;
     38     /// Value assigned to the integer type under the universal tag class per
     39     /// [ITU-T X.680](https://www.itu.int/rec/T-REC-X.680-202102-I/en).
     40     const INTEGER: u8 = 2;
     41     /// Value assigned to the bitstring type under the universal tag class per
     42     /// [ITU-T X.680](https://www.itu.int/rec/T-REC-X.680-202102-I/en).
     43     const BITSTRING: u8 = 3;
     44     /// Value assigned to the null type under the universal tag class per
     45     /// [ITU-T X.680](https://www.itu.int/rec/T-REC-X.680-202102-I/en).
     46     const NULL: u8 = 5;
     47     /// Value assigned to the object identifier type under the universal tag class per
     48     /// [ITU-T X.680](https://www.itu.int/rec/T-REC-X.680-202102-I/en).
     49     const OID: u8 = 6;
     50     /// Value assigned to the sequence type under the universal tag class per
     51     /// [ITU-T X.680](https://www.itu.int/rec/T-REC-X.680-202102-I/en).
     52     const SEQUENCE: u8 = 16;
     53     /// Value assigned to a constructed [`SEQUENCE`] per
     54     /// [ITU-T X.690](https://www.itu.int/rec/T-REC-X.690-202102-I/en).
     55     ///
     56     /// All sequences are constructed once encoded, so this will likely always be used instead of
     57     /// `SEQUENCE`.
     58     const CONSTRUCTED_SEQUENCE: u8 = SEQUENCE | 0b0010_0000;
     59     /// Length of the header before the encoded key in a DER-encoded ASN.1 `SubjectPublicKeyInfo`
     60     /// for an ML-DSA-87 public key.
     61     const MLDSA87_HEADER_LEN: usize = 22;
     62     /// Length of a DER-encoded ASN.1 `SubjectPublicKeyInfo` for ML-DSA-87 public key.
     63     const MLDSA87_LEN: usize = MLDSA87_HEADER_LEN + 2592;
     64     /// Length of the header before the encoded key in a DER-encoded ASN.1 `SubjectPublicKeyInfo`
     65     /// for an ML-DSA-65 public key.
     66     const MLDSA65_HEADER_LEN: usize = 22;
     67     /// Length of a DER-encoded ASN.1 `SubjectPublicKeyInfo` for ML-DSA-65 public key.
     68     const MLDSA65_LEN: usize = MLDSA65_HEADER_LEN + 1952;
     69     /// Length of the header before the encoded key in a DER-encoded ASN.1 `SubjectPublicKeyInfo`
     70     /// for an ML-DSA-44 public key.
     71     const MLDSA44_HEADER_LEN: usize = 22;
     72     /// Length of a DER-encoded ASN.1 `SubjectPublicKeyInfo` for ML-DSA-44 public key.
     73     const MLDSA44_LEN: usize = MLDSA44_HEADER_LEN + 1312;
     74     /// Length of the header before the compressed y-coordinate in a DER-encoded ASN.1 `SubjectPublicKeyInfo`
     75     /// for an Ed25519 public key.
     76     const ED25519_HEADER_LEN: usize = 12;
     77     /// Length of a DER-encoded ASN.1 `SubjectPublicKeyInfo` for Ed25519 public key.
     78     const ED25519_LEN: usize = ED25519_HEADER_LEN + ed25519_dalek::PUBLIC_KEY_LENGTH;
     79     /// `ED25519_LEN` as a `u8`.
     80     // `44 as u8` is clearly OK.
     81     #[expect(
     82         clippy::as_conversions,
     83         clippy::cast_possible_truncation,
     84         reason = "comments above justify their correctness"
     85     )]
     86     const ED25519_LEN_U8: u8 = ED25519_LEN as u8;
     87     /// Length of the header before the uncompressed SEC- 1 pubic key in a DER-encoded ASN.1 `SubjectPublicKeyInfo`
     88     /// for an uncompressed ECDSA public key based on secp256r1/P-256.
     89     const P256_HEADER_LEN: usize = 27;
     90     /// Number of bytes the x-coordinate takes in an uncompressed P-256 public key.
     91     const P256_X_LEN: usize = <NistP256 as Curve>::FieldBytesSize::INT;
     92     /// Number of bytes the y-coordinate takes in an uncompressed P-256 public key.
     93     const P256_Y_LEN: usize = <NistP256 as Curve>::FieldBytesSize::INT;
     94     /// Number of bytes the x and y coordinates take in an uncompressed P-256 public key when concatenated together.
     95     const P256_COORD_LEN: usize = P256_X_LEN + P256_Y_LEN;
     96     /// Length of a DER-encoded ASN.1 `SubjectPublicKeyInfo` for an uncompressed SEC-1 ECDSA public key
     97     /// based on secp256r1/P-256.
     98     const P256_LEN: usize = P256_HEADER_LEN + P256_COORD_LEN;
     99     /// `P256_LEN` as a `u8`.
    100     // `91 as u8` is clearly OK.
    101     #[expect(
    102         clippy::as_conversions,
    103         clippy::cast_possible_truncation,
    104         reason = "comments above justify their correctness"
    105     )]
    106     const P256_LEN_U8: u8 = P256_LEN as u8;
    107     /// Length of the header before the uncompressed SEC- 1 pubic key in a DER-encoded ASN.1 `SubjectPublicKeyInfo`
    108     /// for an uncompressed ECDSA public key based on secp384r1/P-384.
    109     const P384_HEADER_LEN: usize = 24;
    110     /// Number of bytes the x-coordinate takes in an uncompressed P-384 public key.
    111     const P384_X_LEN: usize = <NistP384 as Curve>::FieldBytesSize::INT;
    112     /// Number of bytes the y-coordinate takes in an uncompressed P-384 public key.
    113     const P384_Y_LEN: usize = <NistP384 as Curve>::FieldBytesSize::INT;
    114     /// Number of bytes the x and y coordinates take in an uncompressed P-384 public key when concatenated together.
    115     const P384_COORD_LEN: usize = P384_X_LEN + P384_Y_LEN;
    116     /// Length of a DER-encoded ASN.1 `SubjectPublicKeyInfo` for an uncompressed SEC-1 ECDSA public key
    117     /// based on secp384r1/P-384.
    118     const P384_LEN: usize = P384_HEADER_LEN + P384_COORD_LEN;
    119     /// `P384_LEN` as a `u8`.
    120     // `120 as u8` is clearly OK.
    121     #[expect(
    122         clippy::as_conversions,
    123         clippy::cast_possible_truncation,
    124         reason = "comments above justify their correctness"
    125     )]
    126     const P384_LEN_U8: u8 = P384_LEN as u8;
    127     /// Error returned from [`SubjectPublicKeyInfo::from_der`].
    128     pub(super) enum SubjectPublicKeyInfoErr {
    129         /// The length of the DER-encoded ML-DSA-87 key was invalid.
    130         MlDsa87Len,
    131         /// The header of the DER-encoded ML-DSA-87 key was invalid.
    132         MlDsa87Header,
    133         /// The length of the DER-encoded ML-DSA-65 key was invalid.
    134         MlDsa65Len,
    135         /// The header of the DER-encoded ML-DSA-65 key was invalid.
    136         MlDsa65Header,
    137         /// The length of the DER-encoded ML-DSA-44 key was invalid.
    138         MlDsa44Len,
    139         /// The header of the DER-encoded ML-DSA-44 key was invalid.
    140         MlDsa44Header,
    141         /// The length of the DER-encoded Ed25519 key was invalid.
    142         Ed25519Len,
    143         /// The header of the DER-encoded Ed25519 key was invalid.
    144         Ed25519Header,
    145         /// The length of the DER-encoded P-256 key was invalid.
    146         P256Len,
    147         /// The header of the DER-encoded P-256 key was invalid.
    148         P256Header,
    149         /// The length of the DER-encoded P-384 key was invalid.
    150         P384Len,
    151         /// The header of the DER-encoded P-384 key was invalid.
    152         P384Header,
    153         /// The length of the DER-encoded RSA key was invalid.
    154         RsaLen,
    155         /// The DER-encoding of the RSA key was invalid.
    156         RsaEncoding,
    157         /// The exponent of the DER-encoded RSA key was too large.
    158         RsaExponentTooLarge,
    159         /// The DER-encoded RSA key was not a valid [`RsaPubKey`].
    160         RsaPubKey(RsaPubKeyErr),
    161     }
    162     impl Display for SubjectPublicKeyInfoErr {
    163         fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    164             match *self {
    165                 Self::MlDsa87Len => {
    166                     f.write_str("length of the DER-encoded ML-DSA-87 key was invalid")
    167                 }
    168                 Self::MlDsa87Header => {
    169                     f.write_str("header of the DER-encoded ML-DSA-87 key was invalid")
    170                 }
    171                 Self::MlDsa65Len => {
    172                     f.write_str("length of the DER-encoded ML-DSA-65 key was invalid")
    173                 }
    174                 Self::MlDsa65Header => {
    175                     f.write_str("header of the DER-encoded ML-DSA-65 key was invalid")
    176                 }
    177                 Self::MlDsa44Len => {
    178                     f.write_str("length of the DER-encoded ML-DSA-44 key was invalid")
    179                 }
    180                 Self::MlDsa44Header => {
    181                     f.write_str("header of the DER-encoded ML-DSA-44 key was invalid")
    182                 }
    183                 Self::Ed25519Len => {
    184                     f.write_str("length of the DER-encoded Ed25519 key was invalid")
    185                 }
    186                 Self::Ed25519Header => {
    187                     f.write_str("header of the DER-encoded Ed25519 key was invalid")
    188                 }
    189                 Self::P256Len => f.write_str("length of the DER-encoded P-256 key was invalid"),
    190                 Self::P256Header => f.write_str("header of the DER-encoded P-256 key was invalid"),
    191                 Self::P384Len => f.write_str("length of the DER-encoded P-384 key was invalid"),
    192                 Self::P384Header => f.write_str("header of the DER-encoded P-384 key was invalid"),
    193                 Self::RsaLen => f.write_str("length of the DER-encoded RSA key was invalid"),
    194                 Self::RsaEncoding => {
    195                     f.write_str("the DER-encoding of the RSA public key was invalid")
    196                 }
    197                 Self::RsaExponentTooLarge => {
    198                     f.write_str("the DER-encoded RSA public key had an exponent that was too large")
    199                 }
    200                 Self::RsaPubKey(err) => {
    201                     write!(f, "the DER-encoded RSA public was not valid: {err}")
    202                 }
    203             }
    204         }
    205     }
    206     /// Types that can be deserialized from the DER-encoded ASN.1 `SubjectPublicKeyInfo` as defined in
    207     /// [RFC 5280](https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1) and other applicable RFCs
    208     /// and documents (e.g., [ITU-T X.690](https://www.itu.int/rec/T-REC-X.690-202102-I/en)).
    209     pub(super) trait SubjectPublicKeyInfo<'a>: Sized {
    210         /// Transforms the DER-encoded ASN.1 `SubjectPublicKeyInfo` into `Self`.
    211         ///
    212         /// # Errors
    213         ///
    214         /// Errors iff `der` does not conform.
    215         #[expect(single_use_lifetimes, reason = "false positive")]
    216         fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr>;
    217     }
    218     impl<'a> SubjectPublicKeyInfo<'a> for MlDsa87PubKey<&'a [u8]> {
    219         #[expect(single_use_lifetimes, reason = "false positive")]
    220         fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
    221             /// ```asn
    222             /// SubjectPublicKeyInfo ::= SEQUENCE {
    223             ///     algorithm           AlgorithmIdentifier,
    224             ///     subjectPublicKey    BIT STRING
    225             /// }
    226             ///
    227             /// AlgorithmIdentifier ::= SEQUENCE {
    228             ///     algorithm     OBJECT IDENTIFIER,
    229             ///     parameters    ANY DEFINED BY algorithm OPTIONAL
    230             /// }
    231             /// ```
    232             ///
    233             /// [RFC 9882](https://www.rfc-editor.org/rfc/rfc9882.html) requires parameters to not exist
    234             /// in `AlgorithmIdentifier`.
    235             ///
    236             /// RFC 9882 defines the OID as 2.16.840.1.101.3.4.3.19 which is encoded as 96.134.72.1.101.3.4.3.19
    237             /// per [X.690](https://www.itu.int/rec/T-REC-X.690-202102-I/en).
    238             ///
    239             /// [FIPS 204](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf) defines the bitstring as a reinterpretation of the byte string.
    240             const HEADER: [u8; MLDSA87_HEADER_LEN] = [
    241                 CONSTRUCTED_SEQUENCE,
    242                 130,
    243                 10,
    244                 50,
    245                 CONSTRUCTED_SEQUENCE,
    246                 9 + 2,
    247                 OID,
    248                 9,
    249                 96,
    250                 134,
    251                 72,
    252                 1,
    253                 101,
    254                 3,
    255                 4,
    256                 3,
    257                 19,
    258                 BITSTRING,
    259                 130,
    260                 10,
    261                 33,
    262                 // The number of unused bits.
    263                 0,
    264             ];
    265             der.split_at_checked(HEADER.len())
    266                 .ok_or(SubjectPublicKeyInfoErr::MlDsa87Len)
    267                 .and_then(|(header, rem)| {
    268                     if header == HEADER {
    269                         if rem.len() == 2592 {
    270                             Ok(Self(rem))
    271                         } else {
    272                             Err(SubjectPublicKeyInfoErr::MlDsa87Len)
    273                         }
    274                     } else {
    275                         Err(SubjectPublicKeyInfoErr::MlDsa87Header)
    276                     }
    277                 })
    278         }
    279     }
    280     impl<'a> SubjectPublicKeyInfo<'a> for MlDsa65PubKey<&'a [u8]> {
    281         #[expect(single_use_lifetimes, reason = "false positive")]
    282         fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
    283             /// ```asn
    284             /// SubjectPublicKeyInfo ::= SEQUENCE {
    285             ///     algorithm           AlgorithmIdentifier,
    286             ///     subjectPublicKey    BIT STRING
    287             /// }
    288             ///
    289             /// AlgorithmIdentifier ::= SEQUENCE {
    290             ///     algorithm     OBJECT IDENTIFIER,
    291             ///     parameters    ANY DEFINED BY algorithm OPTIONAL
    292             /// }
    293             /// ```
    294             ///
    295             /// [RFC 9882](https://www.rfc-editor.org/rfc/rfc9882.html) requires parameters to not exist
    296             /// in `AlgorithmIdentifier`.
    297             ///
    298             /// RFC 9882 defines the OID as 2.16.840.1.101.3.4.3.18 which is encoded as 96.134.72.1.101.3.4.3.18
    299             /// per [X.690](https://www.itu.int/rec/T-REC-X.690-202102-I/en).
    300             ///
    301             /// [FIPS 204](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf) defines the bitstring as a reinterpretation of the byte string.
    302             const HEADER: [u8; MLDSA65_HEADER_LEN] = [
    303                 CONSTRUCTED_SEQUENCE,
    304                 130,
    305                 7,
    306                 178,
    307                 CONSTRUCTED_SEQUENCE,
    308                 9 + 2,
    309                 OID,
    310                 9,
    311                 96,
    312                 134,
    313                 72,
    314                 1,
    315                 101,
    316                 3,
    317                 4,
    318                 3,
    319                 18,
    320                 BITSTRING,
    321                 130,
    322                 7,
    323                 161,
    324                 // The number of unused bits.
    325                 0,
    326             ];
    327             der.split_at_checked(HEADER.len())
    328                 .ok_or(SubjectPublicKeyInfoErr::MlDsa65Len)
    329                 .and_then(|(header, rem)| {
    330                     if header == HEADER {
    331                         if rem.len() == 1952 {
    332                             Ok(Self(rem))
    333                         } else {
    334                             Err(SubjectPublicKeyInfoErr::MlDsa65Len)
    335                         }
    336                     } else {
    337                         Err(SubjectPublicKeyInfoErr::MlDsa65Header)
    338                     }
    339                 })
    340         }
    341     }
    342     impl<'a> SubjectPublicKeyInfo<'a> for MlDsa44PubKey<&'a [u8]> {
    343         #[expect(single_use_lifetimes, reason = "false positive")]
    344         fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
    345             /// ```asn
    346             /// SubjectPublicKeyInfo ::= SEQUENCE {
    347             ///     algorithm           AlgorithmIdentifier,
    348             ///     subjectPublicKey    BIT STRING
    349             /// }
    350             ///
    351             /// AlgorithmIdentifier ::= SEQUENCE {
    352             ///     algorithm     OBJECT IDENTIFIER,
    353             ///     parameters    ANY DEFINED BY algorithm OPTIONAL
    354             /// }
    355             /// ```
    356             ///
    357             /// [RFC 9882](https://www.rfc-editor.org/rfc/rfc9882.html) requires parameters to not exist
    358             /// in `AlgorithmIdentifier`.
    359             ///
    360             /// RFC 9882 defines the OID as 2.16.840.1.101.3.4.3.17 which is encoded as 96.134.72.1.101.3.4.3.17
    361             /// per [X.690](https://www.itu.int/rec/T-REC-X.690-202102-I/en).
    362             ///
    363             /// [FIPS 204](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf) defines the bitstring as a reinterpretation of the byte string.
    364             const HEADER: [u8; MLDSA44_HEADER_LEN] = [
    365                 CONSTRUCTED_SEQUENCE,
    366                 130,
    367                 5,
    368                 50,
    369                 CONSTRUCTED_SEQUENCE,
    370                 9 + 2,
    371                 OID,
    372                 9,
    373                 96,
    374                 134,
    375                 72,
    376                 1,
    377                 101,
    378                 3,
    379                 4,
    380                 3,
    381                 17,
    382                 BITSTRING,
    383                 130,
    384                 5,
    385                 33,
    386                 // The number of unused bits.
    387                 0,
    388             ];
    389             der.split_at_checked(HEADER.len())
    390                 .ok_or(SubjectPublicKeyInfoErr::MlDsa44Len)
    391                 .and_then(|(header, rem)| {
    392                     if header == HEADER {
    393                         if rem.len() == 1312 {
    394                             Ok(Self(rem))
    395                         } else {
    396                             Err(SubjectPublicKeyInfoErr::MlDsa44Len)
    397                         }
    398                     } else {
    399                         Err(SubjectPublicKeyInfoErr::MlDsa44Header)
    400                     }
    401                 })
    402         }
    403     }
    404     impl<'a> SubjectPublicKeyInfo<'a> for Ed25519PubKey<&'a [u8]> {
    405         #[expect(single_use_lifetimes, reason = "false positive")]
    406         fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
    407             /// ```asn
    408             /// SubjectPublicKeyInfo ::= SEQUENCE {
    409             ///     algorithm           AlgorithmIdentifier,
    410             ///     subjectPublicKey    BIT STRING
    411             /// }
    412             ///
    413             /// AlgorithmIdentifier ::= SEQUENCE {
    414             ///     algorithm     OBJECT IDENTIFIER,
    415             ///     parameters    ANY DEFINED BY algorithm OPTIONAL
    416             /// }
    417             /// ```
    418             ///
    419             /// [RFC 8410](https://www.rfc-editor.org/rfc/rfc8410#section-3) requires parameters to not exist
    420             /// in `AlgorithmIdentifier`.
    421             ///
    422             /// RFC 8410 defines the OID as 1.3.101.112 which is encoded as 43.101.112
    423             /// per [X.690](https://www.itu.int/rec/T-REC-X.690-202102-I/en).
    424             ///
    425             /// RFC 8410 defines the bitstring as a reinterpretation of the byte string.
    426             const HEADER: [u8; ED25519_HEADER_LEN] = [
    427                 CONSTRUCTED_SEQUENCE,
    428                 // `ED25519_LEN_U8` is the length of the entire payload; thus we subtract
    429                 // the "consumed" length.
    430                 ED25519_LEN_U8 - 2,
    431                 CONSTRUCTED_SEQUENCE,
    432                 // AlgorithmIdentifier only contains the OID; thus it's length is 5.
    433                 3 + 2,
    434                 OID,
    435                 3,
    436                 43,
    437                 101,
    438                 112,
    439                 BITSTRING,
    440                 // `ED25519_LEN_U8` is the length of the entire payload; thus we subtract
    441                 // the "consumed" length.
    442                 ED25519_LEN_U8 - 11,
    443                 // The number of unused bits.
    444                 0,
    445             ];
    446             der.split_at_checked(HEADER.len())
    447                 .ok_or(SubjectPublicKeyInfoErr::Ed25519Len)
    448                 .and_then(|(header, rem)| {
    449                     if header == HEADER {
    450                         if rem.len() == ed25519_dalek::PUBLIC_KEY_LENGTH {
    451                             Ok(Self(rem))
    452                         } else {
    453                             Err(SubjectPublicKeyInfoErr::Ed25519Len)
    454                         }
    455                     } else {
    456                         Err(SubjectPublicKeyInfoErr::Ed25519Header)
    457                     }
    458                 })
    459         }
    460     }
    461     impl<'a> SubjectPublicKeyInfo<'a> for UncompressedP256PubKey<'a> {
    462         #[expect(single_use_lifetimes, reason = "false positive")]
    463         fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
    464             // ```asn
    465             // SubjectPublicKeyInfo ::= SEQUENCE {
    466             //     algorithm           AlgorithmIdentifier,
    467             //     subjectPublicKey    BIT STRING
    468             // }
    469             //
    470             // AlgorithmIdentifier ::= SEQUENCE {
    471             //     algorithm     OBJECT IDENTIFIER,
    472             //     parameters    ANY DEFINED BY algorithm OPTIONAL
    473             // }
    474             //
    475             // ECParameters ::= CHOICE {
    476             //     namedCurve         OBJECT IDENTIFIER
    477             //     -- implicitCurve   NULL
    478             //     -- specifiedCurve  SpecifiedECDomain
    479             // }
    480             // ```
    481             // [RFC 5480](https://www.rfc-editor.org/rfc/rfc5480#section-2.1.1) requires parameters to exist and
    482             // be of the `ECParameters` form with the requirement that `namedCurve` is chosen.
    483             //
    484             // RFC 5480 defines the OID for id-ecPublicKey as 1.2.840.10045.2.1 and the OID for the namedCurve
    485             // secp256r1 as 1.2.840.10045.3.1.7. The former OID is encoded as 42.134.72.206.61.2.1 and the latter
    486             // is encoded as 42.134.72.206.61.3.1.7 per [X.690](https://www.itu.int/rec/T-REC-X.690-202102-I/en).
    487             //
    488             // [RFC 5480](https://www.rfc-editor.org/rfc/rfc5480#section-5) only requires support for the
    489             // uncompressed form and only states that the compressed form MAY be supported. In practice this means
    490             // DER-encoded payloads almost always are of the uncompressed form for compatibility reasons. This in
    491             // conjunction with the fact the COSE key is required to be in the uncompressed form means we only support
    492             // DER-encoded payloads containing uncompressed keys.
    493             //
    494             // [SEC 1](https://secg.org/sec1-v2.pdf) defines the point as an octet string, and the conversion
    495             // to a bitstring simply requires reinterpreting the octet string as a bitstring.
    496 
    497             /// Header of the DER-encoded payload before the public key.
    498             const HEADER: [u8; P256_HEADER_LEN] = [
    499                 CONSTRUCTED_SEQUENCE,
    500                 // `P256_LEN_U8` is the length of the entire payload; thus we subtract
    501                 // the "consumed" length.
    502                 P256_LEN_U8 - 2,
    503                 CONSTRUCTED_SEQUENCE,
    504                 7 + 2 + 8 + 2,
    505                 OID,
    506                 7,
    507                 42,
    508                 134,
    509                 72,
    510                 206,
    511                 61,
    512                 2,
    513                 1,
    514                 OID,
    515                 8,
    516                 42,
    517                 134,
    518                 72,
    519                 206,
    520                 61,
    521                 3,
    522                 1,
    523                 7,
    524                 BITSTRING,
    525                 // `P256_LEN_U8` is the length of the entire payload; thus we subtract
    526                 // the "consumed" length.
    527                 P256_LEN_U8 - 25,
    528                 // The number of unused bits.
    529                 0,
    530                 // SEC-1 tag for an uncompressed key.
    531                 4,
    532             ];
    533             der.split_at_checked(HEADER.len())
    534                 .ok_or(SubjectPublicKeyInfoErr::P256Len)
    535                 .and_then(|(header, header_rem)| {
    536                     if header == HEADER {
    537                         header_rem
    538                             .split_at_checked(P256_X_LEN)
    539                             .ok_or(SubjectPublicKeyInfoErr::P256Len)
    540                             .and_then(|(x, y)| {
    541                                 if y.len() == P256_Y_LEN {
    542                                     Ok(Self(x, y))
    543                                 } else {
    544                                     Err(SubjectPublicKeyInfoErr::P256Len)
    545                                 }
    546                             })
    547                     } else {
    548                         Err(SubjectPublicKeyInfoErr::P256Header)
    549                     }
    550                 })
    551         }
    552     }
    553     impl<'a> SubjectPublicKeyInfo<'a> for UncompressedP384PubKey<'a> {
    554         #[expect(single_use_lifetimes, reason = "false positive")]
    555         fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
    556             // ```asn
    557             // SubjectPublicKeyInfo ::= SEQUENCE {
    558             //     algorithm           AlgorithmIdentifier,
    559             //     subjectPublicKey    BIT STRING
    560             // }
    561             //
    562             // AlgorithmIdentifier ::= SEQUENCE {
    563             //     algorithm     OBJECT IDENTIFIER,
    564             //     parameters    ANY DEFINED BY algorithm OPTIONAL
    565             // }
    566             //
    567             // ECParameters ::= CHOICE {
    568             //     namedCurve         OBJECT IDENTIFIER
    569             //     -- implicitCurve   NULL
    570             //     -- specifiedCurve  SpecifiedECDomain
    571             // }
    572             // ```
    573             // [RFC 5480](https://www.rfc-editor.org/rfc/rfc5480#section-2.1.1) requires parameters to exist and
    574             // be of the `ECParameters` form with the requirement that `namedCurve` is chosen.
    575             //
    576             // RFC 5480 defines the OID for id-ecPublicKey as 1.2.840.10045.2.1 and the OID for the namedCurve
    577             // secp384r1 as 1.3.132.0.34. The former OID is encoded as 42.134.72.206.61.2.1 and the latter
    578             // is encoded as 43.129.4.0.34 per [X.690](https://www.itu.int/rec/T-REC-X.690-202102-I/en).
    579             //
    580             // [RFC 5480](https://www.rfc-editor.org/rfc/rfc5480#section-5) only requires support for the
    581             // uncompressed form and only states that the compressed form MAY be supported. In practice this means
    582             // DER-encoded payloads almost always are of the uncompressed form for compatibility reasons. This in
    583             // conjunction with the fact the COSE key is required to be in the uncompressed form means we only support
    584             // DER-encoded payloads containing uncompressed keys.
    585             //
    586             // [SEC 1](https://secg.org/sec1-v2.pdf) defines the point as an octet string, and the conversion
    587             // to a bitstring simply requires reinterpreting the octet string as a bitstring.
    588 
    589             /// Header of the DER-encoded payload before the public key.
    590             const HEADER: [u8; P384_HEADER_LEN] = [
    591                 CONSTRUCTED_SEQUENCE,
    592                 // `P384_LEN_U8` is the length of the entire payload; thus we subtract
    593                 // the "consumed" length.
    594                 P384_LEN_U8 - 2,
    595                 CONSTRUCTED_SEQUENCE,
    596                 7 + 2 + 5 + 2,
    597                 OID,
    598                 7,
    599                 42,
    600                 134,
    601                 72,
    602                 206,
    603                 61,
    604                 2,
    605                 1,
    606                 OID,
    607                 5,
    608                 43,
    609                 129,
    610                 4,
    611                 0,
    612                 34,
    613                 BITSTRING,
    614                 // `P384_LEN_U8` is the length of the entire payload; thus we subtract
    615                 // the "consumed" length.
    616                 P384_LEN_U8 - 22,
    617                 // The number of unused bits.
    618                 0,
    619                 // SEC-1 tag for an uncompressed key.
    620                 4,
    621             ];
    622             der.split_at_checked(HEADER.len())
    623                 .ok_or(SubjectPublicKeyInfoErr::P384Len)
    624                 .and_then(|(header, header_rem)| {
    625                     if header == HEADER {
    626                         header_rem
    627                             .split_at_checked(P384_X_LEN)
    628                             .ok_or(SubjectPublicKeyInfoErr::P384Len)
    629                             .and_then(|(x, y)| {
    630                                 if y.len() == P384_Y_LEN {
    631                                     Ok(Self(x, y))
    632                                 } else {
    633                                     Err(SubjectPublicKeyInfoErr::P384Len)
    634                                 }
    635                             })
    636                     } else {
    637                         Err(SubjectPublicKeyInfoErr::P384Header)
    638                     }
    639                 })
    640         }
    641     }
    642     impl<'a> SubjectPublicKeyInfo<'a> for RsaPubKey<&'a [u8]> {
    643         #[expect(single_use_lifetimes, reason = "false positive")]
    644         #[expect(
    645             clippy::arithmetic_side_effects,
    646             clippy::big_endian_bytes,
    647             clippy::indexing_slicing,
    648             clippy::missing_asserts_for_indexing,
    649             reason = "comments justify their correctness"
    650         )]
    651         #[expect(
    652             clippy::too_many_lines,
    653             reason = "rsa keys are the only type that would benefit from a modular SubjectPublicKeyInfo (similar to FromCbor). if more types benefit in the future, then this will be done."
    654         )]
    655         fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
    656             // ```asn
    657             // SubjectPublicKeyInfo ::= SEQUENCE {
    658             //     algorithm           AlgorithmIdentifier,
    659             //     subjectPublicKey    BIT STRING
    660             // }
    661             //
    662             // AlgorithmIdentifier ::= SEQUENCE {
    663             //     algorithm     OBJECT IDENTIFIER,
    664             //     parameters    ANY DEFINED BY algorithm OPTIONAL
    665             // }
    666             //
    667             // RSAPublicKey ::= SEQUENCE {
    668             //     modulus          INTEGER, -- n
    669             //     publicExponent   INTEGER  --e
    670             // }
    671             //
    672             // pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840)
    673             //     rsadsi(113549) pkcs(1) 1
    674             // }
    675             //
    676             // rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1}
    677             // ```
    678             // [RFC 3279](https://www.rfc-editor.org/rfc/rfc3279#section-2.3.1) requires parameters to exist and
    679             // be null.
    680             //
    681             // RFC 3279 defines the OID for rsaEncryption as 1.2.840.113549.1.1.1 which is encoded as
    682             // 42.134.72.134.247.13.1.1.1 per [X.690](https://www.itu.int/rec/T-REC-X.690-202102-I/en).
    683             //
    684             // Note we only allow moduli that are 256 to 2048 bytes in length inclusively. Additionally
    685             // we only allow `u32` exponents; consequently all lengths that include the modulus will always be
    686             // encoded with two bytes.
    687 
    688             /// `AlgorithmIdentifier` header including the `BITSTRING` and number of bytes the length
    689             /// is encoded in of the `BITSTRING` type of `subjectPublicKey`
    690             /// (130-128 = 2 bytes to encode the length).
    691             const ALG_OID_HEADER: [u8; 17] = [
    692                 CONSTRUCTED_SEQUENCE,
    693                 9 + 2 + 2,
    694                 OID,
    695                 9,
    696                 42,
    697                 134,
    698                 72,
    699                 134,
    700                 247,
    701                 13,
    702                 1,
    703                 1,
    704                 1,
    705                 NULL,
    706                 0,
    707                 BITSTRING,
    708                 130,
    709             ];
    710             /// `CONSTRUCTED_SEQUENCE` whose length is encoded in two bytes.
    711             const SEQ_LONG: [u8; 2] = [CONSTRUCTED_SEQUENCE, 130];
    712             /// `INTEGER` whose length is encoded in two bytes.
    713             const INT_LONG: [u8; 2] = [INTEGER, 130];
    714             der.split_at_checked(SEQ_LONG.len())
    715                 .ok_or(SubjectPublicKeyInfoErr::RsaLen)
    716                 .and_then(|(seq, seq_rem)| {
    717                     if seq == SEQ_LONG {
    718                         seq_rem
    719                             .split_at_checked(2)
    720                             .ok_or(SubjectPublicKeyInfoErr::RsaLen)
    721                             .and_then(|(seq_len, seq_len_rem)| {
    722                                 let mut len = [0; 2];
    723                                 len.copy_from_slice(seq_len);
    724                                 let rem_len = usize::from(u16::from_be_bytes(len));
    725                                 if rem_len == seq_len_rem.len() {
    726                                     if rem_len > 255 {
    727                                         // We can safely split here since we know `seq_len_rem` is at least
    728                                         // 256 which is greater than `ALG_OID_HEADER.len()`.
    729                                         let (a_oid, a_oid_rem) = seq_len_rem.split_at(ALG_OID_HEADER.len());
    730                                         if a_oid == ALG_OID_HEADER {
    731                                             // `a_oid_rem.len()` is at least 239, so splitting is fine.
    732                                             let (bit_str_len_enc, bit_str_val) = a_oid_rem.split_at(2);
    733                                             let mut bit_string_len = [0; 2];
    734                                             bit_string_len.copy_from_slice(bit_str_len_enc);
    735                                             let bit_str_val_len = usize::from(u16::from_be_bytes(bit_string_len));
    736                                             if bit_str_val_len == bit_str_val.len() {
    737                                                 if bit_str_val_len > 255 {
    738                                                     // `bit_str_val.len() > 255`, so splitting is fine.
    739                                                     let (unused_bits, bits_rem) = bit_str_val.split_at(1);
    740                                                     if unused_bits == [0] {
    741                                                         // We can safely split here since we know `bits_rem.len()` is at least
    742                                                         // 255.
    743                                                         let (rsa_seq, rsa_seq_rem) = bits_rem.split_at(SEQ_LONG.len());
    744                                                         if rsa_seq == SEQ_LONG {
    745                                                             // `rsa_seq_rem.len()` is at least 253, so splitting is fine.
    746                                                             let (rsa_seq_len_enc, rsa_seq_len_enc_rem) = rsa_seq_rem.split_at(2);
    747                                                             let mut rsa_seq_len = [0; 2];
    748                                                             rsa_seq_len.copy_from_slice(rsa_seq_len_enc);
    749                                                             let rsa_key_info_len = usize::from(u16::from_be_bytes(rsa_seq_len));
    750                                                             if rsa_key_info_len == rsa_seq_len_enc_rem.len() {
    751                                                                 if rsa_key_info_len > 255 {
    752                                                                     // We can safely split here since we know `rsa_seq_len_enc_rem.len()`
    753                                                                     // is at least 256.
    754                                                                     let (n_meta, n_meta_rem) = rsa_seq_len_enc_rem.split_at(INT_LONG.len());
    755                                                                     if n_meta == INT_LONG {
    756                                                                         // `n_meta_rem.len()` is at least 254, so splitting is fine.
    757                                                                         let (n_len_enc, n_len_enc_rem) = n_meta_rem.split_at(2);
    758                                                                         let mut n_len = [0; 2];
    759                                                                         n_len.copy_from_slice(n_len_enc);
    760                                                                         let mod_len = usize::from(u16::from_be_bytes(n_len));
    761                                                                         if mod_len > 255 {
    762                                                                             n_len_enc_rem.split_at_checked(mod_len).ok_or(SubjectPublicKeyInfoErr::RsaLen).and_then(|(mut n, n_rem)| {
    763                                                                                 // `n.len() > 255`, so indexing is fine.
    764                                                                                 let n_first = n[0];
    765                                                                                 // DER integers are signed; thus the most significant bit must be 0.
    766                                                                                 // DER integers are minimally encoded; thus when a leading 0 exists,
    767                                                                                 // the second byte must be at least 128.
    768                                                                                 // `n.len() > 255`, so indexing is fine.
    769                                                                                 if n_first < 128 && (n_first != 0 || n[1] > 127) {
    770                                                                                     if n_first == 0 {
    771                                                                                         // `n.len() > 255`, so indexing is fine.
    772                                                                                         // We must remove the leading 0.
    773                                                                                         n = &n[1..];
    774                                                                                     }
    775                                                                                     n_rem.split_first().ok_or(SubjectPublicKeyInfoErr::RsaLen).and_then(|(e_type, e_type_rem)| {
    776                                                                                         if *e_type == INTEGER {
    777                                                                                             e_type_rem.split_first().ok_or(SubjectPublicKeyInfoErr::RsaLen).and_then(|(e_len, e_len_rem)| {
    778                                                                                                 let e_len_usize = usize::from(*e_len);
    779                                                                                                 if e_len_usize == e_len_rem.len() {
    780                                                                                                     e_len_rem.first().ok_or(SubjectPublicKeyInfoErr::RsaLen).and_then(|&e_first| {
    781                                                                                                         // DER integers are signed; thus the most significant bit must be 0.
    782                                                                                                         if e_first < 128 {
    783                                                                                                             // `RsaPubKey` only allows `u32` exponents, which means we only care
    784                                                                                                             // about lengths up to 5.
    785                                                                                                             match e_len_usize {
    786                                                                                                                 1 => Ok(u32::from(e_first)),
    787                                                                                                                 2..=5 => if e_first == 0 {
    788                                                                                                                     // DER integers are minimally encoded; thus when a leading
    789                                                                                                                     // 0 exists, the second byte must be at least 128.
    790                                                                                                                     // We know the length is at least 2; thus this won't `panic`.
    791                                                                                                                     if e_len_rem[1] > 127 {
    792                                                                                                                         let mut e = [0; 4];
    793                                                                                                                         if e_len_usize == 5 {
    794                                                                                                                             // We know the length is at least 2; thus this won't `panic`.
    795                                                                                                                             e.copy_from_slice(&e_len_rem[1..]);
    796                                                                                                                         } else {
    797                                                                                                                             // `e.len() == 4` and `e_len_usize` is at most 4; thus underflow
    798                                                                                                                             // won't occur nor will indexing `panic`. `e` is big-endian,
    799                                                                                                                             // so we start from the right.
    800                                                                                                                             e[4 - e_len_usize..].copy_from_slice(e_len_rem);
    801                                                                                                                         }
    802                                                                                                                         Ok(u32::from_be_bytes(e))
    803                                                                                                                     } else {
    804                                                                                                                         Err(SubjectPublicKeyInfoErr::RsaEncoding)
    805                                                                                                                     }
    806                                                                                                                 } else if e_len_usize == 5 {
    807                                                                                                                     // 5 bytes are only possible for `INTEGER`s that
    808                                                                                                                     // are greater than `i32::MAX`, which will be encoded
    809                                                                                                                     // with a leading 0.
    810                                                                                                                     Err(SubjectPublicKeyInfoErr::RsaEncoding)
    811                                                                                                                 } else {
    812                                                                                                                     let mut e = [0; 4];
    813                                                                                                                     // `e.len() == 4` and `e_len_usize` is at most 4; thus underflow
    814                                                                                                                     // won't occur nor will indexing `panic`. `e` is big-endian,
    815                                                                                                                     // so we start from the right.
    816                                                                                                                     e[4 - e_len_usize..].copy_from_slice(e_len_rem);
    817                                                                                                                     Ok(u32::from_be_bytes(e))
    818                                                                                                                 },
    819                                                                                                                 _ => Err(SubjectPublicKeyInfoErr::RsaExponentTooLarge),
    820                                                                                                             }.and_then(|e| Self::try_from((n, e)).map_err(SubjectPublicKeyInfoErr::RsaPubKey))
    821                                                                                                         } else {
    822                                                                                                             Err(SubjectPublicKeyInfoErr::RsaEncoding)
    823                                                                                                         }
    824                                                                                                     })
    825                                                                                                 } else {
    826                                                                                                     Err(SubjectPublicKeyInfoErr::RsaLen)
    827                                                                                                 }
    828                                                                                             })
    829                                                                                         } else {
    830                                                                                             Err(SubjectPublicKeyInfoErr::RsaEncoding)
    831                                                                                         }
    832                                                                                     })
    833                                                                                 } else {
    834                                                                                     Err(SubjectPublicKeyInfoErr::RsaEncoding)
    835                                                                                 }
    836                                                                             })
    837                                                                         } else {
    838                                                                             Err(SubjectPublicKeyInfoErr::RsaEncoding)
    839                                                                         }
    840                                                                     } else {
    841                                                                         Err(SubjectPublicKeyInfoErr::RsaEncoding)
    842                                                                     }
    843                                                                 } else {
    844                                                                     Err(SubjectPublicKeyInfoErr::RsaEncoding)
    845                                                                 }
    846                                                             } else {
    847                                                                 Err(SubjectPublicKeyInfoErr::RsaLen)
    848                                                             }
    849                                                         } else {
    850                                                             Err(SubjectPublicKeyInfoErr::RsaEncoding)
    851                                                         }
    852                                                     } else {
    853                                                         Err(SubjectPublicKeyInfoErr::RsaEncoding)
    854                                                     }
    855                                                 } else {
    856                                                     Err(SubjectPublicKeyInfoErr::RsaEncoding)
    857                                                 }
    858                                             } else {
    859                                                 Err(SubjectPublicKeyInfoErr::RsaLen)
    860                                             }
    861                                         } else {
    862                                             Err(SubjectPublicKeyInfoErr::RsaEncoding)
    863                                         }
    864                                     } else {
    865                                         Err(SubjectPublicKeyInfoErr::RsaEncoding)
    866                                     }
    867                                 } else {
    868                                     Err(SubjectPublicKeyInfoErr::RsaLen)
    869                                 }
    870                             })
    871                     } else {
    872                         Err(SubjectPublicKeyInfoErr::RsaEncoding)
    873                     }
    874                 })
    875         }
    876     }
    877     impl<'a> SubjectPublicKeyInfo<'a> for UncompressedPubKey<'a> {
    878         #[expect(clippy::indexing_slicing, reason = "comments justify correctness")]
    879         #[expect(single_use_lifetimes, reason = "false positive")]
    880         fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
    881             /// Index in a DER-encoded payload of the ML-DSA-* public key that corresponds
    882             /// to the OID length.
    883             const ML_DSA_OID_LEN_IDX: usize = 5;
    884             /// Length of the OID for the DER-encoded ML-DSA-* public keys.
    885             ///
    886             /// Note this is _not_ the same as the OID length for an RSA public key (i.e., 13).
    887             const ML_DSA_OID_LEN: u8 = 11;
    888             // The only lengths that overlap is RSA with ML-DSA-44 and ML-DSA-65.
    889             match der.len() {
    890                 // The minimum modulus we support for RSA is 2048 bits which is 256 bytes;
    891                 // thus clearly its encoding will be at least 256 which is greater than
    892                 // all of the non-ML-DSA-* values and less than the ML-DSA-* values.
    893                 // The maximum modulus we support for RSA is 16K bits which is 2048 bytes and the maximum
    894                 // exponent we support for RSA is 4 bytes which is hundreds of bytes less than 2614
    895                 // (i.e., the length of a DER-encoded ML-DSAS-87 public key).
    896                 ED25519_LEN => Ed25519PubKey::from_der(der).map(Self::Ed25519),
    897                 P256_LEN => UncompressedP256PubKey::from_der(der).map(Self::P256),
    898                 P384_LEN => UncompressedP384PubKey::from_der(der).map(Self::P384),
    899                 MLDSA44_LEN => {
    900                     // `ML_DSA_OID_LEN_IDX < MLDSA44_LEN = der.len()` so indexing
    901                     // won't `panic`.
    902                     if der[ML_DSA_OID_LEN_IDX] == ML_DSA_OID_LEN {
    903                         MlDsa44PubKey::from_der(der).map(Self::MlDsa44)
    904                     } else {
    905                         RsaPubKey::from_der(der).map(Self::Rsa)
    906                     }
    907                 }
    908                 MLDSA65_LEN => {
    909                     // `ML_DSA_OID_LEN_IDX < MLDSA65_LEN = der.len()` so indexing
    910                     // won't `panic`.
    911                     if der[ML_DSA_OID_LEN_IDX] == ML_DSA_OID_LEN {
    912                         MlDsa65PubKey::from_der(der).map(Self::MlDsa65)
    913                     } else {
    914                         RsaPubKey::from_der(der).map(Self::Rsa)
    915                     }
    916                 }
    917                 MLDSA87_LEN => MlDsa87PubKey::from_der(der).map(Self::MlDsa87),
    918                 _ => RsaPubKey::from_der(der).map(Self::Rsa),
    919             }
    920         }
    921     }
    922 }
    923 /// Helper type returned from [`AuthenticatorAttestationVisitor::visit_map`].
    924 ///
    925 /// The purpose of this type is to hopefully avoid re-parsing the raw attestation object multiple times. In
    926 /// particular [`Registration`] and [`super::ser_relaxed::RegistrationRelaxed`] will attempt to validate `id` is the
    927 /// same as the [`CredentialId`] within the attestation object.
    928 pub(super) struct AuthAttest {
    929     /// The data we care about.
    930     pub attest: AuthenticatorAttestation,
    931     /// [`CredentialId`] information. This is `None` iff `authenticatorData`, `publicKey`, and
    932     /// `publicKeyAlgorithm` do not exist and we are performing a `RELAXED` parsing. When `Some`, the first
    933     /// `usize` is the starting index of `CredentialId` within the attestation object; and the second `usize` is
    934     /// 1 past the last index of `CredentialId`.
    935     pub cred_info: Option<(usize, usize)>,
    936 }
    937 /// Fields in `AuthenticatorAttestationResponseJSON`.
    938 enum AttestField<const IGNORE_UNKNOWN: bool> {
    939     /// `clientDataJSON`.
    940     ClientDataJson,
    941     /// `attestationObject`.
    942     AttestationObject,
    943     /// `authenticatorData`.
    944     AuthenticatorData,
    945     /// `transports`.
    946     Transports,
    947     /// `publicKey`.
    948     PublicKey,
    949     /// `publicKeyAlgorithm`.
    950     PublicKeyAlgorithm,
    951     /// Unknown fields.
    952     Other,
    953 }
    954 impl<'e, const I: bool> Deserialize<'e> for AttestField<I> {
    955     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    956     where
    957         D: Deserializer<'e>,
    958     {
    959         /// `Visitor` for `AttestField`.
    960         struct AttestFieldVisitor<const IGNORE_UNKNOWN: bool>;
    961         impl<const IG: bool> Visitor<'_> for AttestFieldVisitor<IG> {
    962             type Value = AttestField<IG>;
    963             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    964                 write!(
    965                     formatter,
    966                     "'{CLIENT_DATA_JSON}', '{ATTESTATION_OBJECT}', '{AUTHENTICATOR_DATA}', '{TRANSPORTS}', '{PUBLIC_KEY}', or '{PUBLIC_KEY_ALGORITHM}'"
    967                 )
    968             }
    969             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    970             where
    971                 E: Error,
    972             {
    973                 match v {
    974                     CLIENT_DATA_JSON => Ok(AttestField::ClientDataJson),
    975                     ATTESTATION_OBJECT => Ok(AttestField::AttestationObject),
    976                     AUTHENTICATOR_DATA => Ok(AttestField::AuthenticatorData),
    977                     TRANSPORTS => Ok(AttestField::Transports),
    978                     PUBLIC_KEY => Ok(AttestField::PublicKey),
    979                     PUBLIC_KEY_ALGORITHM => Ok(AttestField::PublicKeyAlgorithm),
    980                     _ => {
    981                         if IG {
    982                             Ok(AttestField::Other)
    983                         } else {
    984                             Err(E::unknown_field(v, AUTH_ATTEST_FIELDS))
    985                         }
    986                     }
    987                 }
    988             }
    989         }
    990         deserializer.deserialize_identifier(AttestFieldVisitor::<I>)
    991     }
    992 }
    993 /// Attestation object. We use this instead of `Base64DecodedVal` since we want to manually
    994 /// allocate the `Vec` in order to avoid re-allocation. Internally `AuthenticatorAttestation::new`
    995 /// appends the SHA-256 hash to the passed attestation object `Vec` to avoid temporarily allocating
    996 /// a `Vec` that contains the attestation object and hash for signature verification. Calling code
    997 /// can avoid any reallocation that would occur when the capacity is not large enough by ensuring the
    998 /// passed `Vec` has at least 32 bytes of available capacity.
    999 pub(super) struct AttObj(pub Vec<u8>);
   1000 impl<'e> Deserialize<'e> for AttObj {
   1001     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1002     where
   1003         D: Deserializer<'e>,
   1004     {
   1005         /// `Visitor` for `AttObj`.
   1006         struct AttObjVisitor;
   1007         impl Visitor<'_> for AttObjVisitor {
   1008             type Value = AttObj;
   1009             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
   1010                 formatter.write_str("base64url-encoded attestation object")
   1011             }
   1012             #[expect(
   1013                 clippy::arithmetic_side_effects,
   1014                 reason = "comment justifies their correctness"
   1015             )]
   1016             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
   1017             where
   1018                 E: Error,
   1019             {
   1020                 base64url_nopad::decode_len(v.len())
   1021                     .ok_or_else(|| E::invalid_value(Unexpected::Str(v), &"base64url-encoded value"))
   1022                     .and_then(|len| {
   1023                         // The decoded length is 3/4 of the encoded length, so overflow could only occur
   1024                         // if usize::MAX / 4 < 32 => usize::MAX < 128 < u8::MAX; thus overflow is not
   1025                         // possible. We add 32 since the SHA-256 hash of `clientDataJSON` will be added to
   1026                         // the raw attestation object by `AuthenticatorAttestation::new`.
   1027                         let mut att_obj = vec![0; len + Sha256::output_size()];
   1028                         att_obj.truncate(len);
   1029                         base64url_nopad::decode_buffer_exact(v.as_bytes(), &mut att_obj)
   1030                             .map_err(E::custom)
   1031                             .map(|()| AttObj(att_obj))
   1032                     })
   1033             }
   1034         }
   1035         deserializer.deserialize_str(AttObjVisitor)
   1036     }
   1037 }
   1038 /// `Visitor` for `AuthenticatorAttestation`.
   1039 ///
   1040 /// Unknown fields are ignored and only `clientDataJSON` and `attestationObject` are required iff `RELAXED`.
   1041 pub(super) struct AuthenticatorAttestationVisitor<const RELAXED: bool>;
   1042 impl<'d, const R: bool> Visitor<'d> for AuthenticatorAttestationVisitor<R> {
   1043     type Value = AuthAttest;
   1044     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
   1045         formatter.write_str("AuthenticatorAttestation")
   1046     }
   1047     #[expect(clippy::too_many_lines, reason = "find it easier to reason about")]
   1048     #[expect(
   1049         clippy::arithmetic_side_effects,
   1050         clippy::indexing_slicing,
   1051         reason = "comments justify their correctness"
   1052     )]
   1053     fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
   1054     where
   1055         A: MapAccess<'d>,
   1056     {
   1057         use spki::SubjectPublicKeyInfo as _;
   1058         let mut client_data = None;
   1059         let mut attest = None;
   1060         let mut auth = None;
   1061         let mut pub_key = None;
   1062         let mut key_alg = None;
   1063         let mut trans = None;
   1064         while let Some(key) = map.next_key::<AttestField<R>>()? {
   1065             match key {
   1066                 AttestField::ClientDataJson => {
   1067                     if client_data.is_some() {
   1068                         return Err(Error::duplicate_field(CLIENT_DATA_JSON));
   1069                     }
   1070                     client_data = map
   1071                         .next_value::<Base64DecodedVal>()
   1072                         .map(|c_data| Some(c_data.0))?;
   1073                 }
   1074                 AttestField::AttestationObject => {
   1075                     if attest.is_some() {
   1076                         return Err(Error::duplicate_field(ATTESTATION_OBJECT));
   1077                     }
   1078                     attest = map.next_value::<AttObj>().map(|att_obj| Some(att_obj.0))?;
   1079                 }
   1080                 AttestField::AuthenticatorData => {
   1081                     if auth.is_some() {
   1082                         return Err(Error::duplicate_field(AUTHENTICATOR_DATA));
   1083                     }
   1084                     auth = map.next_value::<Option<Base64DecodedVal>>().map(Some)?;
   1085                 }
   1086                 AttestField::Transports => {
   1087                     if trans.is_some() {
   1088                         return Err(Error::duplicate_field(TRANSPORTS));
   1089                     }
   1090                     trans = map.next_value::<Option<_>>().map(Some)?;
   1091                 }
   1092                 AttestField::PublicKey => {
   1093                     if pub_key.is_some() {
   1094                         return Err(Error::duplicate_field(PUBLIC_KEY));
   1095                     }
   1096                     pub_key = map.next_value::<Option<Base64DecodedVal>>().map(Some)?;
   1097                 }
   1098                 AttestField::PublicKeyAlgorithm => {
   1099                     if key_alg.is_some() {
   1100                         return Err(Error::duplicate_field(PUBLIC_KEY_ALGORITHM));
   1101                     }
   1102                     key_alg = map
   1103                         .next_value::<Option<CoseAlgorithmIdentifier>>()
   1104                         .map(Some)?;
   1105                 }
   1106                 AttestField::Other => map.next_value::<IgnoredAny>().map(|_| ())?,
   1107             }
   1108         }
   1109         // Note the order of this matters from a performance perspective. In particular `auth` must be evaluated
   1110         // before `pub_key` which must be evaluated before `key_alg` as this allows us to parse the attestation
   1111         // object at most once and allow us to prioritize parsing `authenticatorData` over the attestation object.
   1112         client_data.ok_or_else(|| Error::missing_field(CLIENT_DATA_JSON)).and_then(|client_data_json| attest.ok_or_else(|| Error::missing_field(ATTESTATION_OBJECT)).and_then(|attestation_object| {
   1113             trans.ok_or(false).and_then(|opt_trans| opt_trans.ok_or(true)).or_else(
   1114                 |flag| {
   1115                     if R {
   1116                         Ok(AuthTransports::new())
   1117                     } else if flag {
   1118                         Err(Error::invalid_type(Unexpected::Other("null"), &format!("{TRANSPORTS} to be a sequence of AuthenticatorTransports").as_str()))
   1119                     } else {
   1120                         Err(Error::missing_field(TRANSPORTS))
   1121                     }
   1122                 },
   1123             ).and_then(|transports| {
   1124                 auth.ok_or(false).and_then(|opt_auth| opt_auth.ok_or(true)).as_ref().map_or_else(
   1125                     |flag| {
   1126                         if R {
   1127                             Ok(None)
   1128                         } else if *flag {
   1129                             Err(Error::invalid_type(Unexpected::Other("null"), &format!("{AUTHENTICATOR_DATA} to be a base64url-encoded AuthenticatorData").as_str()))
   1130                         } else {
   1131                             Err(Error::missing_field(AUTHENTICATOR_DATA))
   1132                         }
   1133                     },
   1134                     |a_data| {
   1135                         if a_data.0.len() > 37 {
   1136                             // The last portion of attestation object is always authenticator data.
   1137                             attestation_object.len().checked_sub(a_data.0.len()).ok_or_else(|| Error::invalid_value(Unexpected::Bytes(a_data.0.as_slice()), &format!("authenticator data to match the authenticator data portion of attestation object: {attestation_object:?}").as_str())).and_then(|idx| {
   1138                                 // Indexing is fine; otherwise the above check would have returned `None`.
   1139                                 if *a_data.0 == attestation_object[idx..] {
   1140                                     // We know `a_data.len() > 37`; thus indexing is fine.
   1141                                     // We start at 37 since that is the beginning of `attestedCredentialData`.
   1142                                     // Recall the first 32 bytes are `rpIdHash`, then a 1 byte `flags`, then a
   1143                                     // 4-byte big-endian integer `signCount`.
   1144                                     // The starting index of `credentialId` is 18 within `attestedCredentialData`.
   1145                                     // Recall the first 16 bytes are `aaguid`, then a 2-byte big-endian integer
   1146                                     // `credentialIdLength`. Consequently the starting index within
   1147                                     // `attestation_object` is `idx + 37 + 18` = `idx + 55`. Overflow cannot occur
   1148                                     // since we successfully parsed `AttestedCredentialData`.
   1149                                     AttestedCredentialData::from_cbor(&a_data.0[37..]).map_err(Error::custom).map(|success| Some((success.value, idx + 55)))
   1150                                 } else {
   1151                                     Err(Error::invalid_value(Unexpected::Bytes(a_data.0.as_slice()), &format!("authenticator data to match the authenticator data portion of attestation object: {:?}", &attestation_object[idx..]).as_str()))
   1152                                 }
   1153                             })
   1154                         } else {
   1155                             Err(Error::invalid_value(Unexpected::Bytes(a_data.0.as_slice()), &"authenticator data to be long enough to contain attested credential data"))
   1156                         }
   1157                     }
   1158                 ).and_then(|attested_info| {
   1159                     pub_key.ok_or(false).and_then(|opt_key| opt_key.ok_or(true)).map_or_else(
   1160                         |flag| {
   1161                             if R {
   1162                                 attested_info.as_ref().map_or(Ok(None), |&(ref attested_data, cred_id_start)| Ok(Some((match attested_data.credential_public_key {
   1163                                     UncompressedPubKey::MlDsa87(_) => CoseAlgorithmIdentifier::Mldsa87,
   1164                                     UncompressedPubKey::MlDsa65(_) => CoseAlgorithmIdentifier::Mldsa65,
   1165                                     UncompressedPubKey::MlDsa44(_) => CoseAlgorithmIdentifier::Mldsa44,
   1166                                     UncompressedPubKey::Ed25519(_) => CoseAlgorithmIdentifier::Eddsa,
   1167                                     UncompressedPubKey::P256(_) => CoseAlgorithmIdentifier::Es256,
   1168                                     UncompressedPubKey::P384(_) => CoseAlgorithmIdentifier::Es384,
   1169                                     UncompressedPubKey::Rsa(_) => CoseAlgorithmIdentifier::Rs256,
   1170                                     // Overflow won't occur since this is correct as
   1171                                     // `AttestedCredentialData::from_cbor` would have erred if not.
   1172                                 }, cred_id_start, cred_id_start + attested_data.credential_id.0.len()))))
   1173                             } else {
   1174                                 // `publicKey` is only allowed to not exist when `CoseAlgorithmIdentifier::Eddsa`,
   1175                                 // `CoseAlgorithmIdentifier::Es256`, or `CoseAlgorithmIdentifier::Rs256` is not
   1176                                 // used.
   1177                                 attested_info.as_ref().map_or_else(
   1178                                     || AttestationObject::parse_data(attestation_object.as_slice()).map_err(Error::custom).and_then(|(att_obj, auth_idx)| {
   1179                                         match att_obj.auth_data.attested_credential_data.credential_public_key {
   1180                                             UncompressedPubKey::MlDsa87(_) => {
   1181                                                 // This won't overflow since `AttestationObject::parse_data` succeeded and `auth_idx`
   1182                                                 // is the start of the raw authenticator data which itself contains the raw Credential ID.
   1183                                                 Ok(Some((CoseAlgorithmIdentifier::Mldsa87, auth_idx,  auth_idx + att_obj.auth_data.attested_credential_data.credential_id.0.len())))
   1184                                             }
   1185                                             UncompressedPubKey::MlDsa65(_) => {
   1186                                                 // This won't overflow since `AttestationObject::parse_data` succeeded and `auth_idx`
   1187                                                 // is the start of the raw authenticator data which itself contains the raw Credential ID.
   1188                                                 Ok(Some((CoseAlgorithmIdentifier::Mldsa65, auth_idx,  auth_idx + att_obj.auth_data.attested_credential_data.credential_id.0.len())))
   1189                                             }
   1190                                             UncompressedPubKey::MlDsa44(_) => {
   1191                                                 // This won't overflow since `AttestationObject::parse_data` succeeded and `auth_idx`
   1192                                                 // is the start of the raw authenticator data which itself contains the raw Credential ID.
   1193                                                 Ok(Some((CoseAlgorithmIdentifier::Mldsa44, auth_idx,  auth_idx + att_obj.auth_data.attested_credential_data.credential_id.0.len())))
   1194                                             }
   1195                                             UncompressedPubKey::P384(_) => {
   1196                                                 // This won't overflow since `AttestationObject::parse_data` succeeded and `auth_idx`
   1197                                                 // is the start of the raw authenticator data which itself contains the raw Credential ID.
   1198                                                 Ok(Some((CoseAlgorithmIdentifier::Es384, auth_idx,  auth_idx + att_obj.auth_data.attested_credential_data.credential_id.0.len())))
   1199                                             }
   1200                                             UncompressedPubKey::Ed25519(_) | UncompressedPubKey::P256(_) | UncompressedPubKey::Rsa(_) => Err(Error::missing_field(PUBLIC_KEY)),
   1201                                         }
   1202                                     }),
   1203                                     |&(ref attested_data, cred_id_start)| {
   1204                                         match attested_data.credential_public_key {
   1205                                             UncompressedPubKey::MlDsa87(_) => {
   1206                                                 // Overflow won't occur since this is correct. This is correct since we successfully parsed
   1207                                                 // `AttestedCredentialData` and calculated `cred_id_start` from it.
   1208                                                 Ok(Some((CoseAlgorithmIdentifier::Mldsa87, cred_id_start, cred_id_start + attested_data.credential_id.0.len())))
   1209                                             }
   1210                                             UncompressedPubKey::MlDsa65(_) => {
   1211                                                 // Overflow won't occur since this is correct. This is correct since we successfully parsed
   1212                                                 // `AttestedCredentialData` and calculated `cred_id_start` from it.
   1213                                                 Ok(Some((CoseAlgorithmIdentifier::Mldsa65, cred_id_start, cred_id_start + attested_data.credential_id.0.len())))
   1214                                             }
   1215                                             UncompressedPubKey::MlDsa44(_) => {
   1216                                                 // Overflow won't occur since this is correct. This is correct since we successfully parsed
   1217                                                 // `AttestedCredentialData` and calculated `cred_id_start` from it.
   1218                                                 Ok(Some((CoseAlgorithmIdentifier::Mldsa44, cred_id_start, cred_id_start + attested_data.credential_id.0.len())))
   1219                                             }
   1220                                             UncompressedPubKey::P384(_) => {
   1221                                                 // Overflow won't occur since this is correct. This is correct since we successfully parsed
   1222                                                 // `AttestedCredentialData` and calculated `cred_id_start` from it.
   1223                                                 Ok(Some((CoseAlgorithmIdentifier::Es384, cred_id_start, cred_id_start + attested_data.credential_id.0.len())))
   1224                                             }
   1225                                             UncompressedPubKey::Ed25519(_) | UncompressedPubKey::P256(_) | UncompressedPubKey::Rsa(_) => if flag { Err(Error::invalid_type(Unexpected::Other("null"), &format!("{PUBLIC_KEY} to be a base64url-encoded DER-encoded SubjectPublicKeyInfo").as_str())) } else { Err(Error::missing_field(PUBLIC_KEY)) },
   1226                                         }
   1227                                     }
   1228                                 )
   1229                             }
   1230                         },
   1231                         |der| {
   1232                             UncompressedPubKey::from_der(der.0.as_slice()).map_err(Error::custom).and_then(|key| {
   1233                                 attested_info.as_ref().map_or_else(
   1234                                     || AttestationObject::parse_data(attestation_object.as_slice()).map_err(Error::custom).and_then(|(att_obj, auth_idx)| {
   1235                                         if key == att_obj.auth_data.attested_credential_data.credential_public_key {
   1236                                             let alg = match att_obj.auth_data.attested_credential_data.credential_public_key {
   1237                                                 UncompressedPubKey::MlDsa87(_) => CoseAlgorithmIdentifier::Mldsa87,
   1238                                                 UncompressedPubKey::MlDsa65(_) => CoseAlgorithmIdentifier::Mldsa65,
   1239                                                 UncompressedPubKey::MlDsa44(_) => CoseAlgorithmIdentifier::Mldsa44,
   1240                                                 UncompressedPubKey::Ed25519(_) => CoseAlgorithmIdentifier::Eddsa,
   1241                                                 UncompressedPubKey::P256(_) => CoseAlgorithmIdentifier::Es256,
   1242                                                 UncompressedPubKey::P384(_) => CoseAlgorithmIdentifier::Es384,
   1243                                                 UncompressedPubKey::Rsa(_) => CoseAlgorithmIdentifier::Rs256,
   1244                                             };
   1245                                             // This won't overflow since `AttestationObject::parse_data` succeeded and `auth_idx`
   1246                                             // is the start of the raw authenticator data which itself contains the raw Credential ID.
   1247                                             Ok(Some((alg, auth_idx, auth_idx+ att_obj.auth_data.attested_credential_data.credential_id.0.len())))
   1248                                         } else {
   1249                                             Err(Error::invalid_value(Unexpected::Bytes(der.0.as_slice()), &format!("DER-encoded public key to match the public key within the attestation object: {:?}", att_obj.auth_data.attested_credential_data.credential_public_key).as_str()))
   1250                                         }
   1251                                     }),
   1252                                     |&(ref attested_data, cred_id_start)| {
   1253                                         if key == attested_data.credential_public_key {
   1254                                             let alg = match attested_data.credential_public_key {
   1255                                                 UncompressedPubKey::MlDsa87(_) => CoseAlgorithmIdentifier::Mldsa87,
   1256                                                 UncompressedPubKey::MlDsa65(_) => CoseAlgorithmIdentifier::Mldsa65,
   1257                                                 UncompressedPubKey::MlDsa44(_) => CoseAlgorithmIdentifier::Mldsa44,
   1258                                                 UncompressedPubKey::Ed25519(_) => CoseAlgorithmIdentifier::Eddsa,
   1259                                                 UncompressedPubKey::P256(_) => CoseAlgorithmIdentifier::Es256,
   1260                                                 UncompressedPubKey::P384(_) => CoseAlgorithmIdentifier::Es384,
   1261                                                 UncompressedPubKey::Rsa(_) => CoseAlgorithmIdentifier::Rs256,
   1262                                             };
   1263                                             // Overflow won't occur since this is correct. This is correct since we successfully parsed
   1264                                             // `AttestedCredentialData` and calculated `cred_id_start` from it.
   1265                                             Ok(Some((alg, cred_id_start, cred_id_start + attested_data.credential_id.0.len())))
   1266                                         } else {
   1267                                             Err(Error::invalid_value(Unexpected::Bytes(der.0.as_slice()), &format!("DER-encoded public key to match the public key within the attestation object: {:?}", attested_data.credential_public_key).as_str()))
   1268                                         }
   1269                                     }
   1270                                 )
   1271                             })
   1272                         }
   1273                     ).and_then(|cred_key_alg_cred_info| {
   1274                         key_alg.ok_or(false).and_then(|opt_alg| opt_alg.ok_or(true)).map_or_else(
   1275                             |flag| {
   1276                                 if R {
   1277                                     Ok(cred_key_alg_cred_info.map(|info| (info.1, info.2)))
   1278                                 } else if flag {
   1279                                     Err(Error::invalid_type(Unexpected::Other("null"), &format!("{PUBLIC_KEY_ALGORITHM} to be a base64url-encoded DER-encoded SubjectPublicKeyInfo").as_str()))
   1280                                 } else {
   1281                                     Err(Error::missing_field(PUBLIC_KEY_ALGORITHM))
   1282                                 }
   1283                             },
   1284                             |alg| {
   1285                                 cred_key_alg_cred_info.map_or_else(
   1286                                     || AttestationObject::parse_data(attestation_object.as_slice()).map_err(Error::custom).and_then(|(att_obj, auth_idx)| {
   1287                                         let att_obj_alg = match att_obj.auth_data.attested_credential_data.credential_public_key {
   1288                                             UncompressedPubKey::MlDsa87(_) => CoseAlgorithmIdentifier::Mldsa87,
   1289                                             UncompressedPubKey::MlDsa65(_) => CoseAlgorithmIdentifier::Mldsa65,
   1290                                             UncompressedPubKey::MlDsa44(_) => CoseAlgorithmIdentifier::Mldsa44,
   1291                                             UncompressedPubKey::Ed25519(_) => CoseAlgorithmIdentifier::Eddsa,
   1292                                             UncompressedPubKey::P256(_) => CoseAlgorithmIdentifier::Es256,
   1293                                             UncompressedPubKey::P384(_) => CoseAlgorithmIdentifier::Es384,
   1294                                             UncompressedPubKey::Rsa(_) => CoseAlgorithmIdentifier::Rs256,
   1295                                         };
   1296                                         if alg == att_obj_alg {
   1297                                             // This won't overflow since `AttestationObject::parse_data` succeeded and `auth_idx`
   1298                                             // is the start of the raw authenticator data which itself contains the raw Credential ID.
   1299                                             Ok(Some((auth_idx, auth_idx + att_obj.auth_data.attested_credential_data.credential_id.0.len())))
   1300                                         } else {
   1301                                             Err(Error::invalid_value(Unexpected::Other(format!("{alg:?}").as_str()), &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {att_obj_alg:?}").as_str()))
   1302                                         }
   1303                                     }),
   1304                                     |(a, start, last)| if alg == a {
   1305                                         Ok(Some((start, last)))
   1306                                     } else {
   1307                                         Err(Error::invalid_value(Unexpected::Other(format!("{alg:?}").as_str()), &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {a:?}").as_str()))
   1308                                     },
   1309                                 )
   1310                             }
   1311                         ).map(|cred_info| AuthAttest{ attest: AuthenticatorAttestation::new(client_data_json, attestation_object, transports), cred_info, })
   1312                     })
   1313                 })
   1314             })
   1315         }))
   1316     }
   1317 }
   1318 /// `"clientDataJSON"`
   1319 const CLIENT_DATA_JSON: &str = "clientDataJSON";
   1320 /// `"attestationObject"`
   1321 const ATTESTATION_OBJECT: &str = "attestationObject";
   1322 /// `"authenticatorData"`
   1323 const AUTHENTICATOR_DATA: &str = "authenticatorData";
   1324 /// `"transports"`
   1325 const TRANSPORTS: &str = "transports";
   1326 /// `"publicKey"`
   1327 const PUBLIC_KEY: &str = "publicKey";
   1328 /// `"publicKeyAlgorithm"`
   1329 const PUBLIC_KEY_ALGORITHM: &str = "publicKeyAlgorithm";
   1330 /// Fields in `AuthenticatorAttestationResponseJSON`.
   1331 pub(super) const AUTH_ATTEST_FIELDS: &[&str; 6] = &[
   1332     CLIENT_DATA_JSON,
   1333     ATTESTATION_OBJECT,
   1334     AUTHENTICATOR_DATA,
   1335     TRANSPORTS,
   1336     PUBLIC_KEY,
   1337     PUBLIC_KEY_ALGORITHM,
   1338 ];
   1339 impl<'de> Deserialize<'de> for AuthAttest {
   1340     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1341     where
   1342         D: Deserializer<'de>,
   1343     {
   1344         deserializer.deserialize_struct(
   1345             "AuthenticatorAttestation",
   1346             AUTH_ATTEST_FIELDS,
   1347             AuthenticatorAttestationVisitor::<false>,
   1348         )
   1349     }
   1350 }
   1351 impl<'de> Deserialize<'de> for AuthenticatorAttestation {
   1352     /// Deserializes a `struct` based on
   1353     /// [`AuthenticatorAttestationResponseJSON`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticatorattestationresponsejson).
   1354     ///
   1355     /// Note unknown keys and duplicate keys are forbidden;
   1356     /// [`clientDataJSON`](https://www.w3.org/TR/webauthn-3/#dom-authenticatorattestationresponsejson-clientdatajson),
   1357     /// [`authenticatorData`](https://www.w3.org/TR/webauthn-3/#dom-authenticatorattestationresponsejson-authenticatordata),
   1358     /// [`publicKey`](https://www.w3.org/TR/webauthn-3/#dom-authenticatorattestationresponsejson-publickey)
   1359     /// and
   1360     /// [`attestationObject`](https://www.w3.org/TR/webauthn-3/#dom-authenticatorattestationresponsejson-attestationobject)
   1361     /// are base64url-decoded;
   1362     /// [`transports`](https://www.w3.org/TR/webauthn-3/#dom-authenticatorattestationresponsejson-transports)
   1363     /// is deserialized via [`AuthTransports::deserialize`]; the decoded `publicKey` is parsed according to the
   1364     /// applicable DER-encoded ASN.1 `SubjectPublicKeyInfo` schema;
   1365     /// [`publicKeyAlgorithm`](https://www.w3.org/TR/webauthn-3/#dom-authenticatorattestationresponsejson-publickeyalgorithm)
   1366     /// is deserialized according to
   1367     /// [`CoseAlgorithmIdentifier`](https://www.w3.org/TR/webauthn-3/#typedefdef-cosealgorithmidentifier); all `required`
   1368     /// fields in the `AuthenticatorAttestationResponseJSON` Web IDL `dictionary` exist (and must not be `null`); `publicKey`
   1369     /// exists when Ed25519, P-256 with SHA-256, or RSASSA-PKCS1-v1_5 with SHA-256 is used (and must not be `null`)
   1370     /// [per WebAuthn](https://www.w3.org/TR/webauthn-3/#sctn-public-key-easy); the `publicKeyAlgorithm` aligns
   1371     /// with
   1372     /// [`credentialPublicKey`](https://www.w3.org/TR/webauthn-3/#authdata-attestedcredentialdata-credentialpublickey)
   1373     /// within
   1374     /// [`attestedCredentialData`](https://www.w3.org/TR/webauthn-3/#authdata-attestedcredentialdata) within the
   1375     /// decoded `authenticatorData`; the decoded `publicKey` is the same as `credentialPublicKey` within
   1376     /// `attestedCredentialData` within the decoded `authenticatorData`; and the decoded `authenticatorData` is the
   1377     /// same as [`authData`](https://www.w3.org/TR/webauthn-3/#attestation-object) within the decoded
   1378     /// `attestationObject`.
   1379     #[inline]
   1380     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1381     where
   1382         D: Deserializer<'de>,
   1383     {
   1384         AuthAttest::deserialize(deserializer).map(|val| val.attest)
   1385     }
   1386 }
   1387 /// `Visitor` for `CredentialPropertiesOutput`.
   1388 ///
   1389 /// Unknown fields are ignored iff `RELAXED`.
   1390 pub(super) struct CredentialPropertiesOutputVisitor<const RELAXED: bool>;
   1391 impl<'d, const R: bool> Visitor<'d> for CredentialPropertiesOutputVisitor<R> {
   1392     type Value = CredentialPropertiesOutput;
   1393     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
   1394         formatter.write_str("CredentialPropertiesOutput")
   1395     }
   1396     fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
   1397     where
   1398         A: MapAccess<'d>,
   1399     {
   1400         /// Allowed fields.
   1401         enum Field<const IGNORE_UNKNOWN: bool> {
   1402             /// `rk` field.
   1403             Rk,
   1404             /// Unknown field.
   1405             Other,
   1406         }
   1407         impl<'e, const I: bool> Deserialize<'e> for Field<I> {
   1408             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1409             where
   1410                 D: Deserializer<'e>,
   1411             {
   1412                 /// `Visitor` for `Field`.
   1413                 ///
   1414                 /// Unknown fields are ignored iff `IGNORE_UNKNOWN`.
   1415                 struct FieldVisitor<const IGNORE_UNKNOWN: bool>;
   1416                 impl<const IG: bool> Visitor<'_> for FieldVisitor<IG> {
   1417                     type Value = Field<IG>;
   1418                     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
   1419                         write!(formatter, "'{RK}'")
   1420                     }
   1421                     fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
   1422                     where
   1423                         E: Error,
   1424                     {
   1425                         match v {
   1426                             RK => Ok(Field::Rk),
   1427                             _ => {
   1428                                 if IG {
   1429                                     Ok(Field::Other)
   1430                                 } else {
   1431                                     Err(E::unknown_field(v, PROPS_FIELDS))
   1432                                 }
   1433                             }
   1434                         }
   1435                     }
   1436                 }
   1437                 deserializer.deserialize_identifier(FieldVisitor)
   1438             }
   1439         }
   1440         let mut rk = None;
   1441         while let Some(key) = map.next_key::<Field<R>>()? {
   1442             match key {
   1443                 Field::Rk => {
   1444                     if rk.is_some() {
   1445                         return Err(Error::duplicate_field(RK));
   1446                     }
   1447                     rk = map.next_value().map(Some)?;
   1448                 }
   1449                 Field::Other => map.next_value::<IgnoredAny>().map(|_| ())?,
   1450             }
   1451         }
   1452         Ok(CredentialPropertiesOutput { rk: rk.flatten() })
   1453     }
   1454 }
   1455 /// `"rk"`
   1456 const RK: &str = "rk";
   1457 /// `CredentialPropertiesOutput` fields.
   1458 pub(super) const PROPS_FIELDS: &[&str; 1] = &[RK];
   1459 impl<'de> Deserialize<'de> for CredentialPropertiesOutput {
   1460     /// Deserializes a `struct` based on
   1461     /// [`CredentialPropertiesOutput`](https://www.w3.org/TR/webauthn-3/#dictdef-credentialpropertiesoutput).
   1462     ///
   1463     /// Note unknown and duplicate keys are forbidden.
   1464     #[inline]
   1465     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1466     where
   1467         D: Deserializer<'de>,
   1468     {
   1469         deserializer.deserialize_struct(
   1470             "CredentialPropertiesOutput",
   1471             PROPS_FIELDS,
   1472             CredentialPropertiesOutputVisitor::<false>,
   1473         )
   1474     }
   1475 }
   1476 impl<'de> Deserialize<'de> for AuthenticationExtensionsPrfOutputs {
   1477     /// Deserializes a `struct` based on
   1478     /// [`AuthenticationExtensionsPRFOutputsJSON`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsprfoutputsjson).
   1479     ///
   1480     /// Note unknown and duplicate keys are forbidden;
   1481     /// [`enabled`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfoutputs-enabled)
   1482     /// must exist (and not be `null`); and
   1483     /// [`results`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfoutputs-results) must not exist,
   1484     /// be `null`, or be an
   1485     /// [`AuthenticationExtensionsPRFValues`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsprfvalues)
   1486     /// with no unknown or duplicate keys,
   1487     /// [`first`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfvalues-first) must exist but be
   1488     /// `null`, and
   1489     /// [`second`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfvalues-second) can exist but
   1490     /// must be `null` if so.
   1491     #[inline]
   1492     #[expect(clippy::unreachable, reason = "we want to crash when there is a bug")]
   1493     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1494     where
   1495         D: Deserializer<'de>,
   1496     {
   1497         AuthenticationExtensionsPrfOutputsHelper::<false, true, AuthenticationExtensionsPrfValues>::deserialize(deserializer).map(|val| Self {
   1498             enabled: val.0.unwrap_or_else(|| {
   1499                 unreachable!(
   1500                     "there is a bug in AuthenticationExtensionsPrfOutputsHelper::deserialize"
   1501                 )
   1502             }),
   1503         })
   1504     }
   1505 }
   1506 /// `Visitor` for `ClientExtensionsOutputs`.
   1507 ///
   1508 /// Unknown fields are ignored iff `RELAXED`.
   1509 pub(super) struct ClientExtensionsOutputsVisitor<const RELAXED: bool, PROPS, PRF>(
   1510     pub PhantomData<fn() -> (PROPS, PRF)>,
   1511 );
   1512 impl<'d, const R: bool, C, P> Visitor<'d> for ClientExtensionsOutputsVisitor<R, C, P>
   1513 where
   1514     C: for<'a> Deserialize<'a> + Into<CredentialPropertiesOutput>,
   1515     P: for<'a> Deserialize<'a> + Into<AuthenticationExtensionsPrfOutputs>,
   1516 {
   1517     type Value = ClientExtensionsOutputs;
   1518     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
   1519         formatter.write_str("ClientExtensionsOutputs")
   1520     }
   1521     fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
   1522     where
   1523         A: MapAccess<'d>,
   1524     {
   1525         /// Allowed fields.
   1526         enum Field<const IGNORE_UNKNOWN: bool> {
   1527             /// `credProps` field.
   1528             CredProps,
   1529             /// `prf` field.
   1530             Prf,
   1531             /// Unknown field.
   1532             Other,
   1533         }
   1534         impl<'e, const I: bool> Deserialize<'e> for Field<I> {
   1535             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1536             where
   1537                 D: Deserializer<'e>,
   1538             {
   1539                 /// `Visitor` for `Field`.
   1540                 ///
   1541                 /// Unknown fields are ignored iff `IGNORE_UNKNOWN`.
   1542                 struct FieldVisitor<const IGNORE_UNKNOWN: bool>;
   1543                 impl<const IG: bool> Visitor<'_> for FieldVisitor<IG> {
   1544                     type Value = Field<IG>;
   1545                     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
   1546                         write!(formatter, "'{CRED_PROPS}' or '{PRF}'")
   1547                     }
   1548                     fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
   1549                     where
   1550                         E: Error,
   1551                     {
   1552                         match v {
   1553                             CRED_PROPS => Ok(Field::CredProps),
   1554                             PRF => Ok(Field::Prf),
   1555                             _ => {
   1556                                 if IG {
   1557                                     Ok(Field::Other)
   1558                                 } else {
   1559                                     Err(E::unknown_field(v, EXT_FIELDS))
   1560                                 }
   1561                             }
   1562                         }
   1563                     }
   1564                 }
   1565                 deserializer.deserialize_identifier(FieldVisitor)
   1566             }
   1567         }
   1568         let mut cred_props = None;
   1569         let mut prf = None;
   1570         while let Some(key) = map.next_key::<Field<R>>()? {
   1571             match key {
   1572                 Field::CredProps => {
   1573                     if cred_props.is_some() {
   1574                         return Err(Error::duplicate_field(CRED_PROPS));
   1575                     }
   1576                     cred_props = map.next_value::<Option<C>>().map(Some)?;
   1577                 }
   1578                 Field::Prf => {
   1579                     if prf.is_some() {
   1580                         return Err(Error::duplicate_field(PRF));
   1581                     }
   1582                     prf = map.next_value::<Option<P>>().map(Some)?;
   1583                 }
   1584                 Field::Other => map.next_value::<IgnoredAny>().map(|_| ())?,
   1585             }
   1586         }
   1587         Ok(ClientExtensionsOutputs {
   1588             cred_props: cred_props.flatten().map(Into::into),
   1589             prf: prf.flatten().map(Into::into),
   1590         })
   1591     }
   1592 }
   1593 impl ClientExtensions for ClientExtensionsOutputs {
   1594     fn empty() -> Self {
   1595         Self {
   1596             prf: None,
   1597             cred_props: None,
   1598         }
   1599     }
   1600 }
   1601 /// `"credProps"`
   1602 const CRED_PROPS: &str = "credProps";
   1603 /// `"prf"`
   1604 const PRF: &str = "prf";
   1605 /// `AuthenticationExtensionsClientOutputsJSON` fields.
   1606 pub(super) const EXT_FIELDS: &[&str; 2] = &[CRED_PROPS, PRF];
   1607 impl<'de> Deserialize<'de> for ClientExtensionsOutputs {
   1608     /// Deserializes a `struct` based on
   1609     /// [`AuthenticationExtensionsClientOutputsJSON`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsclientoutputsjson).
   1610     ///
   1611     /// Note that unknown and duplicate keys are forbidden;
   1612     /// [`credProps`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsclientoutputs-credprops) is
   1613     /// `null` or deserialized via [`CredentialPropertiesOutput::deserialize`]; and
   1614     /// [`prf`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsclientoutputs-prf) is `null`
   1615     /// or deserialized via [`AuthenticationExtensionsPrfOutputs::deserialize`].
   1616     #[inline]
   1617     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1618     where
   1619         D: Deserializer<'de>,
   1620     {
   1621         deserializer.deserialize_struct(
   1622             "ClientExtensionsOutputs",
   1623             EXT_FIELDS,
   1624             ClientExtensionsOutputsVisitor::<
   1625                 false,
   1626                 CredentialPropertiesOutput,
   1627                 AuthenticationExtensionsPrfOutputs,
   1628             >(PhantomData),
   1629         )
   1630     }
   1631 }
   1632 impl<'de> Deserialize<'de> for Registration {
   1633     /// Deserializes a `struct` based on
   1634     /// [`RegistrationResponseJSON`](https://www.w3.org/TR/webauthn-3/#dictdef-registrationresponsejson).
   1635     ///
   1636     /// Note that unknown and duplicate keys are forbidden;
   1637     /// [`id`](https://www.w3.org/TR/webauthn-3/#dom-registrationresponsejson-id) and
   1638     /// [`rawId`](https://www.w3.org/TR/webauthn-3/#dom-registrationresponsejson-rawid) are deserialized
   1639     /// via [`CredentialId::deserialize`];
   1640     /// [`response`](https://www.w3.org/TR/webauthn-3/#dom-registrationresponsejson-response) is deserialized
   1641     /// via [`AuthenticatorAttestation::deserialize`];
   1642     /// [`authenticatorAttachment`](https://www.w3.org/TR/webauthn-3/#dom-registrationresponsejson-authenticatorattachment)
   1643     /// is `null` or deserialized via [`AuthenticatorAttachment::deserialize`];
   1644     /// [`clientExtensionResults`](https://www.w3.org/TR/webauthn-3/#dom-registrationresponsejson-clientextensionresults)
   1645     /// is deserialized via [`ClientExtensionsOutputs::deserialize`]; all `required` fields in the
   1646     /// `RegistrationResponseJSON` Web IDL `dictionary` exist (and are not `null`);
   1647     /// [`type`](https://www.w3.org/TR/webauthn-3/#dom-registrationresponsejson-type) is `"public-key"`;
   1648     /// and the decoded `id`, decoded `rawId`, and
   1649     /// [`credentialId`](https://www.w3.org/TR/webauthn-3/#authdata-attestedcredentialdata-credentialid) within
   1650     /// [`attestedCredentialData`](https://www.w3.org/TR/webauthn-3/#authdata-attestedcredentialdata) within
   1651     /// [`authData`](https://www.w3.org/TR/webauthn-3/#attestation-object) within the decoded
   1652     /// [`attestationObject`](https://www.w3.org/TR/webauthn-3/#dom-authenticatorattestationresponsejson-attestationobject)
   1653     /// are all the same.
   1654     #[expect(clippy::unreachable, reason = "when there is a bug, we want to crash")]
   1655     #[expect(clippy::indexing_slicing, reason = "comment justifies its correctness")]
   1656     #[inline]
   1657     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1658     where
   1659         D: Deserializer<'de>,
   1660     {
   1661         PublicKeyCredential::<false, true, AuthAttest, ClientExtensionsOutputs>::deserialize(deserializer).and_then(|cred| {
   1662             let id = cred.id.unwrap_or_else(|| unreachable!("there is a bug in PublicKeyCredential::deserialize"));
   1663             cred.response.cred_info.map_or_else(
   1664                 || AttestationObject::try_from(cred.response.attest.attestation_object()).map_err(Error::custom).and_then(|att_obj| {
   1665                     if id.as_ref() == att_obj.auth_data.attested_credential_data.credential_id.as_ref() {
   1666                         Ok(())
   1667                     } else {
   1668                         Err(Error::invalid_value(Unexpected::Bytes(id.as_ref()), &format!("id, rawId, and the credential id in the attested credential data to all match: {:?}", att_obj.auth_data.attested_credential_data.credential_id.0).as_str()))
   1669                     }
   1670                 }),
   1671                 // `start` and `last` were calculated based on `cred.response.attest.attestation_object()`
   1672                 // and represent the starting and ending index of the `CredentialId`; therefore this is correct
   1673                 // let alone won't `panic`.
   1674                 |(start, last)| if *id.0 == cred.response.attest.attestation_object()[start..last] {
   1675                     Ok(())
   1676                 } else {
   1677                     Err(Error::invalid_value(Unexpected::Bytes(id.as_ref()), &format!("id, rawId, and the credential id in the attested credential data to all match: {:?}", &cred.response.attest.attestation_object()[start..last]).as_str()))
   1678                 },
   1679             ).map(|()| Self { response: cred.response.attest, authenticator_attachment: cred.authenticator_attachment, client_extension_results: cred.client_extension_results, })
   1680         })
   1681     }
   1682 }