webauthn_rp

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

ser.rs (223952B)


      1 use super::{
      2     super::{
      3         super::request::register::CoseAlgorithmIdentifier,
      4         ser::{
      5             AuthenticationExtensionsPrfOutputsHelper, AuthenticationExtensionsPrfValues,
      6             Base64DecodedVal, ClientExtensions, PublicKeyCredential,
      7         },
      8     },
      9     AttestationObject, AttestedCredentialData, AuthTransports, AuthenticationExtensionsPrfOutputs,
     10     AuthenticatorAttestation, ClientExtensionsOutputs, CredentialPropertiesOutput, FromCbor as _,
     11     Registration, UncompressedPubKey,
     12 };
     13 #[cfg(doc)]
     14 use super::{AuthenticatorAttachment, CredentialId};
     15 use core::{
     16     fmt::{self, Formatter},
     17     marker::PhantomData,
     18     str,
     19 };
     20 use rsa::sha2::{Sha256, digest::OutputSizeUser as _};
     21 use serde::de::{Deserialize, Deserializer, Error, IgnoredAny, MapAccess, Unexpected, Visitor};
     22 /// Functionality for deserializing DER-encoded `SubjectPublicKeyInfo` _without_ making copies of data or
     23 /// verifying the key is valid. This exists purely to ensure that the public key we receive in JSON is the same as
     24 /// the public key in the attestation object.
     25 mod spki {
     26     use super::super::{
     27         Ed25519PubKey, RsaPubKey, RsaPubKeyErr, UncompressedP256PubKey, UncompressedP384PubKey,
     28         UncompressedPubKey,
     29     };
     30     use core::fmt::{self, Display, Formatter};
     31     use p256::{
     32         NistP256,
     33         elliptic_curve::{Curve, generic_array::typenum::type_operators::ToInt as _},
     34     };
     35     use p384::NistP384;
     36     /// Value assigned to the integer type under the universal tag class per
     37     /// [ITU-T X.680](https://www.itu.int/rec/T-REC-X.680-202102-I/en).
     38     const INTEGER: u8 = 2;
     39     /// Value assigned to the bitstring type under the universal tag class per
     40     /// [ITU-T X.680](https://www.itu.int/rec/T-REC-X.680-202102-I/en).
     41     const BITSTRING: u8 = 3;
     42     /// Value assigned to the null type under the universal tag class per
     43     /// [ITU-T X.680](https://www.itu.int/rec/T-REC-X.680-202102-I/en).
     44     const NULL: u8 = 5;
     45     /// Value assigned to the object identifier type under the universal tag class per
     46     /// [ITU-T X.680](https://www.itu.int/rec/T-REC-X.680-202102-I/en).
     47     const OID: u8 = 6;
     48     /// Value assigned to the sequence type under the universal tag class per
     49     /// [ITU-T X.680](https://www.itu.int/rec/T-REC-X.680-202102-I/en).
     50     const SEQUENCE: u8 = 16;
     51     /// Value assigned to a constructed [`SEQUENCE`] per
     52     /// [ITU-T X.690](https://www.itu.int/rec/T-REC-X.690-202102-I/en).
     53     ///
     54     /// All sequences are constructed once encoded, so this will likely always be used instead of
     55     /// `SEQUENCE`.
     56     const CONSTRUCTED_SEQUENCE: u8 = SEQUENCE | 0b0010_0000;
     57     /// Length of the header before the compressed y-coordinate in a DER-encoded ASN.1 `SubjectPublicKeyInfo`
     58     /// for an Ed25519 public key.
     59     const ED25519_HEADER_LEN: usize = 12;
     60     /// Length of a DER-encoded ASN.1 `SubjectPublicKeyInfo` for Ed25519 public key.
     61     const ED25519_LEN: usize = ED25519_HEADER_LEN + ed25519_dalek::PUBLIC_KEY_LENGTH;
     62     /// `ED25519_LEN` as a `u8`.
     63     // `44 as u8` is clearly OK.
     64     #[expect(
     65         clippy::as_conversions,
     66         clippy::cast_possible_truncation,
     67         reason = "comments above justify their correctness"
     68     )]
     69     const ED25519_LEN_U8: u8 = ED25519_LEN as u8;
     70     /// Length of the header before the uncompressed SEC- 1 pubic key in a DER-encoded ASN.1 `SubjectPublicKeyInfo`
     71     /// for an uncompressed ECDSA public key based on secp256r1/P-256.
     72     const P256_HEADER_LEN: usize = 27;
     73     /// Number of bytes the x-coordinate takes in an uncompressed P-256 public key.
     74     const P256_X_LEN: usize = <NistP256 as Curve>::FieldBytesSize::INT;
     75     /// Number of bytes the y-coordinate takes in an uncompressed P-256 public key.
     76     const P256_Y_LEN: usize = <NistP256 as Curve>::FieldBytesSize::INT;
     77     /// Number of bytes the x and y coordinates take in an uncompressed P-256 public key when concatenated together.
     78     const P256_COORD_LEN: usize = P256_X_LEN + P256_Y_LEN;
     79     /// Length of a DER-encoded ASN.1 `SubjectPublicKeyInfo` for an uncompressed SEC-1 ECDSA public key
     80     /// based on secp256r1/P-256.
     81     const P256_LEN: usize = P256_HEADER_LEN + P256_COORD_LEN;
     82     /// `P256_LEN` as a `u8`.
     83     // `91 as u8` is clearly OK.
     84     #[expect(
     85         clippy::as_conversions,
     86         clippy::cast_possible_truncation,
     87         reason = "comments above justify their correctness"
     88     )]
     89     const P256_LEN_U8: u8 = P256_LEN as u8;
     90     /// Length of the header before the uncompressed SEC- 1 pubic key in a DER-encoded ASN.1 `SubjectPublicKeyInfo`
     91     /// for an uncompressed ECDSA public key based on secp384r1/P-384.
     92     const P384_HEADER_LEN: usize = 24;
     93     /// Number of bytes the x-coordinate takes in an uncompressed P-384 public key.
     94     const P384_X_LEN: usize = <NistP384 as Curve>::FieldBytesSize::INT;
     95     /// Number of bytes the y-coordinate takes in an uncompressed P-384 public key.
     96     const P384_Y_LEN: usize = <NistP384 as Curve>::FieldBytesSize::INT;
     97     /// Number of bytes the x and y coordinates take in an uncompressed P-384 public key when concatenated together.
     98     const P384_COORD_LEN: usize = P384_X_LEN + P384_Y_LEN;
     99     /// Length of a DER-encoded ASN.1 `SubjectPublicKeyInfo` for an uncompressed SEC-1 ECDSA public key
    100     /// based on secp384r1/P-384.
    101     const P384_LEN: usize = P384_HEADER_LEN + P384_COORD_LEN;
    102     /// `P384_LEN` as a `u8`.
    103     // `120 as u8` is clearly OK.
    104     #[expect(
    105         clippy::as_conversions,
    106         clippy::cast_possible_truncation,
    107         reason = "comments above justify their correctness"
    108     )]
    109     const P384_LEN_U8: u8 = P384_LEN as u8;
    110     /// Error returned from [`SubjectPublicKeyInfo::from_der`].
    111     pub(super) enum SubjectPublicKeyInfoErr {
    112         /// The DER-encoded `SubjectPublicKeyInfo` had an invalid length.
    113         Len,
    114         /// The length of the DER-encoded Ed25519 key was invalid.
    115         Ed25519Len,
    116         /// The header of the DER-encoded Ed25519 key was invalid.
    117         Ed25519Header,
    118         /// The length of the DER-encoded P-256 key was invalid.
    119         P256Len,
    120         /// The header of the DER-encoded P-256 key was invalid.
    121         P256Header,
    122         /// The length of the DER-encoded P-384 key was invalid.
    123         P384Len,
    124         /// The header of the DER-encoded P-384 key was invalid.
    125         P384Header,
    126         /// The length of the DER-encoded RSA key was invalid.
    127         RsaLen,
    128         /// The DER-encoding of the RSA key was invalid.
    129         RsaEncoding,
    130         /// The exponent of the DER-encoded RSA key was too large.
    131         RsaExponentTooLarge,
    132         /// The DER-encoded RSA key was not a valid [`RsaPubKey`].
    133         RsaPubKey(RsaPubKeyErr),
    134     }
    135     impl Display for SubjectPublicKeyInfoErr {
    136         fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    137             match *self {
    138                 Self::Len => {
    139                     f.write_str("the DER-encoded SubjectPublicKeyInfo had an invalid length")
    140                 }
    141                 Self::Ed25519Len => {
    142                     f.write_str("length of the DER-encoded Ed25519 key was invalid")
    143                 }
    144                 Self::Ed25519Header => {
    145                     f.write_str("header of the DER-encoded Ed25519 key was invalid")
    146                 }
    147                 Self::P256Len => f.write_str("length of the DER-encoded P-256 key was invalid"),
    148                 Self::P256Header => f.write_str("header of the DER-encoded P-256 key was invalid"),
    149                 Self::P384Len => f.write_str("length of the DER-encoded P-384 key was invalid"),
    150                 Self::P384Header => f.write_str("header of the DER-encoded P-384 key was invalid"),
    151                 Self::RsaLen => f.write_str("length of the DER-encoded RSA key was invalid"),
    152                 Self::RsaEncoding => {
    153                     f.write_str("the DER-encoding of the RSA public key was invalid")
    154                 }
    155                 Self::RsaExponentTooLarge => {
    156                     f.write_str("the DER-encoded RSA public key had an exponent that was too large")
    157                 }
    158                 Self::RsaPubKey(err) => {
    159                     write!(f, "the DER-encoded RSA public was not valid: {err}")
    160                 }
    161             }
    162         }
    163     }
    164     /// Types that can be deserialized from the DER-encoded ASN.1 `SubjectPublicKeyInfo` as defined in
    165     /// [RFC 5280](https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1) and other applicable RFCs
    166     /// and documents (e.g., [ITU-T X.690](https://www.itu.int/rec/T-REC-X.690-202102-I/en)).
    167     pub(super) trait SubjectPublicKeyInfo<'a>: Sized {
    168         /// Transforms the DER-encoded ASN.1 `SubjectPublicKeyInfo` into `Self`.
    169         ///
    170         /// # Errors
    171         ///
    172         /// Errors iff `der` does not conform.
    173         #[expect(single_use_lifetimes, reason = "false positive")]
    174         fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr>;
    175     }
    176     impl<'a> SubjectPublicKeyInfo<'a> for Ed25519PubKey<&'a [u8]> {
    177         #[expect(single_use_lifetimes, reason = "false positive")]
    178         fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
    179             /// ```asn
    180             /// SubjectPublicKeyInfo ::= SEQUENCE {
    181             ///     algorithm           AlgorithmIdentifier,
    182             ///     subjectPublicKey    BIT STRING
    183             /// }
    184             ///
    185             /// AlgorithmIdentifier ::= SEQUENCE {
    186             ///     algorithm     OBJECT IDENTIFIER,
    187             ///     parameters    ANY DEFINED BY algorithm OPTIONAL
    188             /// }
    189             /// ```
    190             ///
    191             /// [RFC 8410](https://www.rfc-editor.org/rfc/rfc8410#section-3) requires parameters to not exist
    192             /// in `AlgorithmIdentifier`.
    193             ///
    194             /// RFC 8410 defines the OID as 1.3.101.112 which is encoded as 43.101.112
    195             /// per [X.690](https://www.itu.int/rec/T-REC-X.690-202102-I/en).
    196             ///
    197             /// RFC 8410 defines the bitstring as a reinterpretation of the byte string.
    198             const HEADER: [u8; ED25519_HEADER_LEN] = [
    199                 CONSTRUCTED_SEQUENCE,
    200                 // `ED25519_LEN_U8` is the length of the entire payload; thus we subtract
    201                 // the "consumed" length.
    202                 ED25519_LEN_U8 - 2,
    203                 CONSTRUCTED_SEQUENCE,
    204                 // AlgorithmIdentifier only contains the OID; thus it's length is 5.
    205                 3 + 2,
    206                 OID,
    207                 3,
    208                 43,
    209                 101,
    210                 112,
    211                 BITSTRING,
    212                 // `ED25519_LEN_U8` is the length of the entire payload; thus we subtract
    213                 // the "consumed" length.
    214                 ED25519_LEN_U8 - 11,
    215                 // The number of unused bits.
    216                 0,
    217             ];
    218             der.split_at_checked(HEADER.len())
    219                 .ok_or(SubjectPublicKeyInfoErr::Ed25519Len)
    220                 .and_then(|(header, rem)| {
    221                     if header == HEADER {
    222                         if rem.len() == ed25519_dalek::PUBLIC_KEY_LENGTH {
    223                             Ok(Self(rem))
    224                         } else {
    225                             Err(SubjectPublicKeyInfoErr::Ed25519Len)
    226                         }
    227                     } else {
    228                         Err(SubjectPublicKeyInfoErr::Ed25519Header)
    229                     }
    230                 })
    231         }
    232     }
    233     impl<'a> SubjectPublicKeyInfo<'a> for UncompressedP256PubKey<'a> {
    234         #[expect(single_use_lifetimes, reason = "false positive")]
    235         fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
    236             // ```asn
    237             // SubjectPublicKeyInfo ::= SEQUENCE {
    238             //     algorithm           AlgorithmIdentifier,
    239             //     subjectPublicKey    BIT STRING
    240             // }
    241             //
    242             // AlgorithmIdentifier ::= SEQUENCE {
    243             //     algorithm     OBJECT IDENTIFIER,
    244             //     parameters    ANY DEFINED BY algorithm OPTIONAL
    245             // }
    246             //
    247             // ECParameters ::= CHOICE {
    248             //     namedCurve         OBJECT IDENTIFIER
    249             //     -- implicitCurve   NULL
    250             //     -- specifiedCurve  SpecifiedECDomain
    251             // }
    252             // ```
    253             // [RFC 5480](https://www.rfc-editor.org/rfc/rfc5480#section-2.1.1) requires parameters to exist and
    254             // be of the `ECParameters` form with the requirement that `namedCurve` is chosen.
    255             //
    256             // RFC 5480 defines the OID for id-ecPublicKey as 1.2.840.10045.2.1 and the OID for the namedCurve
    257             // 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
    258             // 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).
    259             //
    260             // [RFC 5480](https://www.rfc-editor.org/rfc/rfc5480#section-5) only requires support for the
    261             // uncompressed form and only states that the compressed form MAY be supported. In practice this means
    262             // DER-encoded payloads almost always are of the uncompressed form for compatibility reasons. This in
    263             // conjunction with the fact the COSE key is required to be in the uncompressed form means we only support
    264             // DER-encoded payloads containing uncompressed keys.
    265             //
    266             // [SEC 1](https://secg.org/sec1-v2.pdf) defines the point as an octet string, and the conversion
    267             // to a bitstring simply requires reinterpreting the octet string as a bitstring.
    268 
    269             /// Header of the DER-encoded payload before the public key.
    270             const HEADER: [u8; P256_HEADER_LEN] = [
    271                 CONSTRUCTED_SEQUENCE,
    272                 // `P256_LEN_U8` is the length of the entire payload; thus we subtract
    273                 // the "consumed" length.
    274                 P256_LEN_U8 - 2,
    275                 CONSTRUCTED_SEQUENCE,
    276                 7 + 2 + 8 + 2,
    277                 OID,
    278                 7,
    279                 42,
    280                 134,
    281                 72,
    282                 206,
    283                 61,
    284                 2,
    285                 1,
    286                 OID,
    287                 8,
    288                 42,
    289                 134,
    290                 72,
    291                 206,
    292                 61,
    293                 3,
    294                 1,
    295                 7,
    296                 BITSTRING,
    297                 // `P256_LEN_U8` is the length of the entire payload; thus we subtract
    298                 // the "consumed" length.
    299                 P256_LEN_U8 - 25,
    300                 // The number of unused bits.
    301                 0,
    302                 // SEC-1 tag for an uncompressed key.
    303                 4,
    304             ];
    305             der.split_at_checked(HEADER.len())
    306                 .ok_or(SubjectPublicKeyInfoErr::P256Len)
    307                 .and_then(|(header, header_rem)| {
    308                     if header == HEADER {
    309                         header_rem
    310                             .split_at_checked(P256_X_LEN)
    311                             .ok_or(SubjectPublicKeyInfoErr::P256Len)
    312                             .and_then(|(x, y)| {
    313                                 if y.len() == P256_Y_LEN {
    314                                     Ok(Self(x, y))
    315                                 } else {
    316                                     Err(SubjectPublicKeyInfoErr::P256Len)
    317                                 }
    318                             })
    319                     } else {
    320                         Err(SubjectPublicKeyInfoErr::P256Header)
    321                     }
    322                 })
    323         }
    324     }
    325     impl<'a> SubjectPublicKeyInfo<'a> for UncompressedP384PubKey<'a> {
    326         #[expect(single_use_lifetimes, reason = "false positive")]
    327         fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
    328             // ```asn
    329             // SubjectPublicKeyInfo ::= SEQUENCE {
    330             //     algorithm           AlgorithmIdentifier,
    331             //     subjectPublicKey    BIT STRING
    332             // }
    333             //
    334             // AlgorithmIdentifier ::= SEQUENCE {
    335             //     algorithm     OBJECT IDENTIFIER,
    336             //     parameters    ANY DEFINED BY algorithm OPTIONAL
    337             // }
    338             //
    339             // ECParameters ::= CHOICE {
    340             //     namedCurve         OBJECT IDENTIFIER
    341             //     -- implicitCurve   NULL
    342             //     -- specifiedCurve  SpecifiedECDomain
    343             // }
    344             // ```
    345             // [RFC 5480](https://www.rfc-editor.org/rfc/rfc5480#section-2.1.1) requires parameters to exist and
    346             // be of the `ECParameters` form with the requirement that `namedCurve` is chosen.
    347             //
    348             // RFC 5480 defines the OID for id-ecPublicKey as 1.2.840.10045.2.1 and the OID for the namedCurve
    349             // secp384r1 as 1.3.132.0.34. The former OID is encoded as 42.134.72.206.61.2.1 and the latter
    350             // is encoded as 43.129.4.0.34 per [X.690](https://www.itu.int/rec/T-REC-X.690-202102-I/en).
    351             //
    352             // [RFC 5480](https://www.rfc-editor.org/rfc/rfc5480#section-5) only requires support for the
    353             // uncompressed form and only states that the compressed form MAY be supported. In practice this means
    354             // DER-encoded payloads almost always are of the uncompressed form for compatibility reasons. This in
    355             // conjunction with the fact the COSE key is required to be in the uncompressed form means we only support
    356             // DER-encoded payloads containing uncompressed keys.
    357             //
    358             // [SEC 1](https://secg.org/sec1-v2.pdf) defines the point as an octet string, and the conversion
    359             // to a bitstring simply requires reinterpreting the octet string as a bitstring.
    360 
    361             /// Header of the DER-encoded payload before the public key.
    362             const HEADER: [u8; P384_HEADER_LEN] = [
    363                 CONSTRUCTED_SEQUENCE,
    364                 // `P384_LEN_U8` is the length of the entire payload; thus we subtract
    365                 // the "consumed" length.
    366                 P384_LEN_U8 - 2,
    367                 CONSTRUCTED_SEQUENCE,
    368                 7 + 2 + 5 + 2,
    369                 OID,
    370                 7,
    371                 42,
    372                 134,
    373                 72,
    374                 206,
    375                 61,
    376                 2,
    377                 1,
    378                 OID,
    379                 5,
    380                 43,
    381                 129,
    382                 4,
    383                 0,
    384                 34,
    385                 BITSTRING,
    386                 // `P384_LEN_U8` is the length of the entire payload; thus we subtract
    387                 // the "consumed" length.
    388                 P384_LEN_U8 - 22,
    389                 // The number of unused bits.
    390                 0,
    391                 // SEC-1 tag for an uncompressed key.
    392                 4,
    393             ];
    394             der.split_at_checked(HEADER.len())
    395                 .ok_or(SubjectPublicKeyInfoErr::P384Len)
    396                 .and_then(|(header, header_rem)| {
    397                     if header == HEADER {
    398                         header_rem
    399                             .split_at_checked(P384_X_LEN)
    400                             .ok_or(SubjectPublicKeyInfoErr::P384Len)
    401                             .and_then(|(x, y)| {
    402                                 if y.len() == P384_Y_LEN {
    403                                     Ok(Self(x, y))
    404                                 } else {
    405                                     Err(SubjectPublicKeyInfoErr::P384Len)
    406                                 }
    407                             })
    408                     } else {
    409                         Err(SubjectPublicKeyInfoErr::P384Header)
    410                     }
    411                 })
    412         }
    413     }
    414     impl<'a> SubjectPublicKeyInfo<'a> for RsaPubKey<&'a [u8]> {
    415         #[expect(single_use_lifetimes, reason = "false positive")]
    416         #[expect(
    417             clippy::arithmetic_side_effects,
    418             clippy::big_endian_bytes,
    419             clippy::indexing_slicing,
    420             clippy::missing_asserts_for_indexing,
    421             reason = "comments justify their correctness"
    422         )]
    423         #[expect(
    424             clippy::too_many_lines,
    425             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."
    426         )]
    427         fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
    428             // ```asn
    429             // SubjectPublicKeyInfo ::= SEQUENCE {
    430             //     algorithm           AlgorithmIdentifier,
    431             //     subjectPublicKey    BIT STRING
    432             // }
    433             //
    434             // AlgorithmIdentifier ::= SEQUENCE {
    435             //     algorithm     OBJECT IDENTIFIER,
    436             //     parameters    ANY DEFINED BY algorithm OPTIONAL
    437             // }
    438             //
    439             // RSAPublicKey ::= SEQUENCE {
    440             //     modulus          INTEGER, -- n
    441             //     publicExponent   INTEGER  --e
    442             // }
    443             //
    444             // pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840)
    445             //     rsadsi(113549) pkcs(1) 1
    446             // }
    447             //
    448             // rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1}
    449             // ```
    450             // [RFC 3279](https://www.rfc-editor.org/rfc/rfc3279#section-2.3.1) requires parameters to exist and
    451             // be null.
    452             //
    453             // RFC 3279 defines the OID for rsaEncryption as 1.2.840.113549.1.1.1 which is encoded as
    454             // 42.134.72.134.247.13.1.1.1 per [X.690](https://www.itu.int/rec/T-REC-X.690-202102-I/en).
    455             //
    456             // Note we only allow moduli that are 256 to 2048 bytes in length inclusively. Additionally
    457             // we only allow `u32` exponents; consequently all lengths that include the modulus will always be
    458             // encoded with two bytes.
    459 
    460             /// `AlgorithmIdentifier` header including the `BITSTRING` and number of bytes the length
    461             /// is encoded in of the `BITSTRING` type of `subjectPublicKey`
    462             /// (130-128 = 2 bytes to encode the length).
    463             const ALG_OID_HEADER: [u8; 17] = [
    464                 CONSTRUCTED_SEQUENCE,
    465                 9 + 2 + 2,
    466                 OID,
    467                 9,
    468                 42,
    469                 134,
    470                 72,
    471                 134,
    472                 247,
    473                 13,
    474                 1,
    475                 1,
    476                 1,
    477                 NULL,
    478                 0,
    479                 BITSTRING,
    480                 130,
    481             ];
    482             /// `CONSTRUCTED_SEQUENCE` whose length is encoded in two bytes.
    483             const SEQ_LONG: [u8; 2] = [CONSTRUCTED_SEQUENCE, 130];
    484             /// `INTEGER` whose length is encoded in two bytes.
    485             const INT_LONG: [u8; 2] = [INTEGER, 130];
    486             der.split_at_checked(SEQ_LONG.len())
    487                 .ok_or(SubjectPublicKeyInfoErr::RsaLen)
    488                 .and_then(|(seq, seq_rem)| {
    489                     if seq == SEQ_LONG {
    490                         seq_rem
    491                             .split_at_checked(2)
    492                             .ok_or(SubjectPublicKeyInfoErr::RsaLen)
    493                             .and_then(|(seq_len, seq_len_rem)| {
    494                                 let mut len = [0; 2];
    495                                 len.copy_from_slice(seq_len);
    496                                 let rem_len = usize::from(u16::from_be_bytes(len));
    497                                 if rem_len == seq_len_rem.len() {
    498                                     if rem_len > 255 {
    499                                         // We can safely split here since we know `seq_len_rem` is at least
    500                                         // 256 which is greater than `ALG_OID_HEADER.len()`.
    501                                         let (a_oid, a_oid_rem) = seq_len_rem.split_at(ALG_OID_HEADER.len());
    502                                         if a_oid == ALG_OID_HEADER {
    503                                             // `a_oid_rem.len()` is at least 239, so splitting is fine.
    504                                             let (bit_str_len_enc, bit_str_val) = a_oid_rem.split_at(2);
    505                                             let mut bit_string_len = [0; 2];
    506                                             bit_string_len.copy_from_slice(bit_str_len_enc);
    507                                             let bit_str_val_len = usize::from(u16::from_be_bytes(bit_string_len));
    508                                             if bit_str_val_len == bit_str_val.len() {
    509                                                 if bit_str_val_len > 255 {
    510                                                     // `bit_str_val.len() > 255`, so splitting is fine.
    511                                                     let (unused_bits, bits_rem) = bit_str_val.split_at(1);
    512                                                     if unused_bits == [0] {
    513                                                         // We can safely split here since we know `bits_rem.len()` is at least
    514                                                         // 255.
    515                                                         let (rsa_seq, rsa_seq_rem) = bits_rem.split_at(SEQ_LONG.len());
    516                                                         if rsa_seq == SEQ_LONG {
    517                                                             // `rsa_seq_rem.len()` is at least 253, so splitting is fine.
    518                                                             let (rsa_seq_len_enc, rsa_seq_len_enc_rem) = rsa_seq_rem.split_at(2);
    519                                                             let mut rsa_seq_len = [0; 2];
    520                                                             rsa_seq_len.copy_from_slice(rsa_seq_len_enc);
    521                                                             let rsa_key_info_len = usize::from(u16::from_be_bytes(rsa_seq_len));
    522                                                             if rsa_key_info_len == rsa_seq_len_enc_rem.len() {
    523                                                                 if rsa_key_info_len > 255 {
    524                                                                     // We can safely split here since we know `rsa_seq_len_enc_rem.len()`
    525                                                                     // is at least 256.
    526                                                                     let (n_meta, n_meta_rem) = rsa_seq_len_enc_rem.split_at(INT_LONG.len());
    527                                                                     if n_meta == INT_LONG {
    528                                                                         // `n_meta_rem.len()` is at least 254, so splitting is fine.
    529                                                                         let (n_len_enc, n_len_enc_rem) = n_meta_rem.split_at(2);
    530                                                                         let mut n_len = [0; 2];
    531                                                                         n_len.copy_from_slice(n_len_enc);
    532                                                                         let mod_len = usize::from(u16::from_be_bytes(n_len));
    533                                                                         if mod_len > 255 {
    534                                                                             n_len_enc_rem.split_at_checked(mod_len).ok_or(SubjectPublicKeyInfoErr::RsaLen).and_then(|(mut n, n_rem)| {
    535                                                                                 // `n.len() > 255`, so indexing is fine.
    536                                                                                 let n_first = n[0];
    537                                                                                 // DER integers are signed; thus the most significant bit must be 0.
    538                                                                                 // DER integers are minimally encoded; thus when a leading 0 exists,
    539                                                                                 // the second byte must be at least 128.
    540                                                                                 // `n.len() > 255`, so indexing is fine.
    541                                                                                 if n_first < 128 && (n_first != 0 || n[1] > 127) {
    542                                                                                     if n_first == 0 {
    543                                                                                         // `n.len() > 255`, so indexing is fine.
    544                                                                                         // We must remove the leading 0.
    545                                                                                         n = &n[1..];
    546                                                                                     }
    547                                                                                     n_rem.split_first().ok_or(SubjectPublicKeyInfoErr::RsaLen).and_then(|(e_type, e_type_rem)| {
    548                                                                                         if *e_type == INTEGER {
    549                                                                                             e_type_rem.split_first().ok_or(SubjectPublicKeyInfoErr::RsaLen).and_then(|(e_len, e_len_rem)| {
    550                                                                                                 let e_len_usize = usize::from(*e_len);
    551                                                                                                 if e_len_usize == e_len_rem.len() {
    552                                                                                                     e_len_rem.first().ok_or(SubjectPublicKeyInfoErr::RsaLen).and_then(|&e_first| {
    553                                                                                                         // DER integers are signed; thus the most significant bit must be 0.
    554                                                                                                         if e_first < 128 {
    555                                                                                                             // `RsaPubKey` only allows `u32` exponents, which means we only care
    556                                                                                                             // about lengths up to 5.
    557                                                                                                             match e_len_usize {
    558                                                                                                                 1 => Ok(u32::from(e_first)),
    559                                                                                                                 2..=5 => if e_first == 0 {
    560                                                                                                                     // DER integers are minimally encoded; thus when a leading
    561                                                                                                                     // 0 exists, the second byte must be at least 128.
    562                                                                                                                     // We know the length is at least 2; thus this won't `panic`.
    563                                                                                                                     if e_len_rem[1] > 127 {
    564                                                                                                                         let mut e = [0; 4];
    565                                                                                                                         if e_len_usize == 5 {
    566                                                                                                                             // We know the length is at least 2; thus this won't `panic`.
    567                                                                                                                             e.copy_from_slice(&e_len_rem[1..]);
    568                                                                                                                         } else {
    569                                                                                                                             // `e.len() == 4` and `e_len_usize` is at most 4; thus underflow
    570                                                                                                                             // won't occur nor will indexing `panic`. `e` is big-endian,
    571                                                                                                                             // so we start from the right.
    572                                                                                                                             e[4 - e_len_usize..].copy_from_slice(e_len_rem);
    573                                                                                                                         }
    574                                                                                                                         Ok(u32::from_be_bytes(e))
    575                                                                                                                     } else {
    576                                                                                                                         Err(SubjectPublicKeyInfoErr::RsaEncoding)
    577                                                                                                                     }
    578                                                                                                                 } else if e_len_usize == 5 {
    579                                                                                                                     // 5 bytes are only possible for `INTEGER`s that
    580                                                                                                                     // are greater than `i32::MAX`, which will be encoded
    581                                                                                                                     // with a leading 0.
    582                                                                                                                     Err(SubjectPublicKeyInfoErr::RsaEncoding)
    583                                                                                                                 } else {
    584                                                                                                                     let mut e = [0; 4];
    585                                                                                                                     // `e.len() == 4` and `e_len_usize` is at most 4; thus underflow
    586                                                                                                                     // won't occur nor will indexing `panic`. `e` is big-endian,
    587                                                                                                                     // so we start from the right.
    588                                                                                                                     e[4 - e_len_usize..].copy_from_slice(e_len_rem);
    589                                                                                                                     Ok(u32::from_be_bytes(e))
    590                                                                                                                 },
    591                                                                                                                 _ => Err(SubjectPublicKeyInfoErr::RsaExponentTooLarge),
    592                                                                                                             }.and_then(|e| Self::try_from((n, e)).map_err(SubjectPublicKeyInfoErr::RsaPubKey))
    593                                                                                                         } else {
    594                                                                                                             Err(SubjectPublicKeyInfoErr::RsaEncoding)
    595                                                                                                         }
    596                                                                                                     })
    597                                                                                                 } else {
    598                                                                                                     Err(SubjectPublicKeyInfoErr::RsaLen)
    599                                                                                                 }
    600                                                                                             })
    601                                                                                         } else {
    602                                                                                             Err(SubjectPublicKeyInfoErr::RsaEncoding)
    603                                                                                         }
    604                                                                                     })
    605                                                                                 } else {
    606                                                                                     Err(SubjectPublicKeyInfoErr::RsaEncoding)
    607                                                                                 }
    608                                                                             })
    609                                                                         } else {
    610                                                                             Err(SubjectPublicKeyInfoErr::RsaEncoding)
    611                                                                         }
    612                                                                     } else {
    613                                                                         Err(SubjectPublicKeyInfoErr::RsaEncoding)
    614                                                                     }
    615                                                                 } else {
    616                                                                     Err(SubjectPublicKeyInfoErr::RsaEncoding)
    617                                                                 }
    618                                                             } else {
    619                                                                 Err(SubjectPublicKeyInfoErr::RsaLen)
    620                                                             }
    621                                                         } else {
    622                                                             Err(SubjectPublicKeyInfoErr::RsaEncoding)
    623                                                         }
    624                                                     } else {
    625                                                         Err(SubjectPublicKeyInfoErr::RsaEncoding)
    626                                                     }
    627                                                 } else {
    628                                                     Err(SubjectPublicKeyInfoErr::RsaEncoding)
    629                                                 }
    630                                             } else {
    631                                                 Err(SubjectPublicKeyInfoErr::RsaLen)
    632                                             }
    633                                         } else {
    634                                             Err(SubjectPublicKeyInfoErr::RsaEncoding)
    635                                         }
    636                                     } else {
    637                                         Err(SubjectPublicKeyInfoErr::RsaEncoding)
    638                                     }
    639                                 } else {
    640                                     Err(SubjectPublicKeyInfoErr::RsaLen)
    641                                 }
    642                             })
    643                     } else {
    644                         Err(SubjectPublicKeyInfoErr::RsaEncoding)
    645                     }
    646                 })
    647         }
    648     }
    649     impl<'a> SubjectPublicKeyInfo<'a> for UncompressedPubKey<'a> {
    650         #[expect(single_use_lifetimes, reason = "false positive")]
    651         fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
    652             // The lengths of the three key types do not overlap.
    653             match der.len() {
    654                 // The minimum modulus we support for RSA is 2048 bits which is 256 bytes;
    655                 // thus clearly its encoding will be at least 256 which is greater than
    656                 // all of the other values.
    657                 ED25519_LEN => Ed25519PubKey::from_der(der).map(Self::Ed25519),
    658                 P256_LEN => UncompressedP256PubKey::from_der(der).map(Self::P256),
    659                 P384_LEN => UncompressedP384PubKey::from_der(der).map(Self::P384),
    660                 256.. => RsaPubKey::from_der(der).map(Self::Rsa),
    661                 _ => Err(SubjectPublicKeyInfoErr::Len),
    662             }
    663         }
    664     }
    665 }
    666 /// Helper type returned from [`AuthenticatorAttestationVisitor::visit_map`].
    667 ///
    668 /// The purpose of this type is to hopefully avoid re-parsing the raw attestation object multiple times. In
    669 /// particular [`Registration`] and [`super::ser_relaxed::RegistrationRelaxed`] will attempt to validate `id` is the
    670 /// same as the [`CredentialId`] within the attestation object.
    671 pub(super) struct AuthAttest {
    672     /// The data we care about.
    673     pub attest: AuthenticatorAttestation,
    674     /// [`CredentialId`] information. This is `None` iff `authenticatorData`, `publicKey`, and
    675     /// `publicKeyAlgorithm` do not exist and we are performing a `RELAXED` parsing. When `Some`, the first
    676     /// `usize` is the starting index of `CredentialId` within the attestation object; and the second `usize` is
    677     /// 1 past the last index of `CredentialId`.
    678     pub cred_info: Option<(usize, usize)>,
    679 }
    680 /// Fields in `AuthenticatorAttestationResponseJSON`.
    681 enum AttestField<const IGNORE_UNKNOWN: bool> {
    682     /// `clientDataJSON`.
    683     ClientDataJson,
    684     /// `attestationObject`.
    685     AttestationObject,
    686     /// `authenticatorData`.
    687     AuthenticatorData,
    688     /// `transports`.
    689     Transports,
    690     /// `publicKey`.
    691     PublicKey,
    692     /// `publicKeyAlgorithm`.
    693     PublicKeyAlgorithm,
    694     /// Unknown fields.
    695     Other,
    696 }
    697 impl<'e, const I: bool> Deserialize<'e> for AttestField<I> {
    698     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    699     where
    700         D: Deserializer<'e>,
    701     {
    702         /// `Visitor` for `AttestField`.
    703         struct AttestFieldVisitor<const IGNORE_UNKNOWN: bool>;
    704         impl<const IG: bool> Visitor<'_> for AttestFieldVisitor<IG> {
    705             type Value = AttestField<IG>;
    706             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    707                 write!(
    708                     formatter,
    709                     "'{CLIENT_DATA_JSON}', '{ATTESTATION_OBJECT}', '{AUTHENTICATOR_DATA}', '{TRANSPORTS}', '{PUBLIC_KEY}', or '{PUBLIC_KEY_ALGORITHM}'"
    710                 )
    711             }
    712             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    713             where
    714                 E: Error,
    715             {
    716                 match v {
    717                     CLIENT_DATA_JSON => Ok(AttestField::ClientDataJson),
    718                     ATTESTATION_OBJECT => Ok(AttestField::AttestationObject),
    719                     AUTHENTICATOR_DATA => Ok(AttestField::AuthenticatorData),
    720                     TRANSPORTS => Ok(AttestField::Transports),
    721                     PUBLIC_KEY => Ok(AttestField::PublicKey),
    722                     PUBLIC_KEY_ALGORITHM => Ok(AttestField::PublicKeyAlgorithm),
    723                     _ => {
    724                         if IG {
    725                             Ok(AttestField::Other)
    726                         } else {
    727                             Err(E::unknown_field(v, AUTH_ATTEST_FIELDS))
    728                         }
    729                     }
    730                 }
    731             }
    732         }
    733         deserializer.deserialize_identifier(AttestFieldVisitor::<I>)
    734     }
    735 }
    736 /// Attestation object. We use this instead of `Base64DecodedVal` since we want to manually
    737 /// allocate the `Vec` in order to avoid re-allocation. Internally `AuthenticatorAttestation::new`
    738 /// appends the SHA-256 hash to the passed attestation object `Vec` to avoid temporarily allocating
    739 /// a `Vec` that contains the attestation object and hash for signature verification. Calling code
    740 /// can avoid any reallocation that would occur when the capacity is not large enough by ensuring the
    741 /// passed `Vec` has at least 32 bytes of available capacity.
    742 pub(super) struct AttObj(pub Vec<u8>);
    743 impl<'e> Deserialize<'e> for AttObj {
    744     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    745     where
    746         D: Deserializer<'e>,
    747     {
    748         /// `Visitor` for `AttObj`.
    749         struct AttObjVisitor;
    750         impl Visitor<'_> for AttObjVisitor {
    751             type Value = AttObj;
    752             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    753                 formatter.write_str("base64url-encoded attestation object")
    754             }
    755             #[expect(
    756                 clippy::arithmetic_side_effects,
    757                 reason = "comment justifies their correctness"
    758             )]
    759             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    760             where
    761                 E: Error,
    762             {
    763                 base64url_nopad::decode_len(v.len())
    764                     .ok_or_else(|| E::invalid_value(Unexpected::Str(v), &"base64url-encoded value"))
    765                     .and_then(|len| {
    766                         // The decoded length is 3/4 of the encoded length, so overflow could only occur
    767                         // if usize::MAX / 4 < 32 => usize::MAX < 128 < u8::MAX; thus overflow is not
    768                         // possible. We add 32 since the SHA-256 hash of `clientDataJSON` will be added to
    769                         // the raw attestation object by `AuthenticatorAttestation::new`.
    770                         let mut att_obj = vec![0; len + Sha256::output_size()];
    771                         att_obj.truncate(len);
    772                         base64url_nopad::decode_buffer_exact(v.as_bytes(), &mut att_obj)
    773                             .map_err(E::custom)
    774                             .map(|()| AttObj(att_obj))
    775                     })
    776             }
    777         }
    778         deserializer.deserialize_str(AttObjVisitor)
    779     }
    780 }
    781 /// `Visitor` for `AuthenticatorAttestation`.
    782 ///
    783 /// Unknown fields are ignored and only `clientDataJSON` and `attestationObject` are required iff `RELAXED`.
    784 pub(super) struct AuthenticatorAttestationVisitor<const RELAXED: bool>;
    785 impl<'d, const R: bool> Visitor<'d> for AuthenticatorAttestationVisitor<R> {
    786     type Value = AuthAttest;
    787     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    788         formatter.write_str("AuthenticatorAttestation")
    789     }
    790     #[expect(clippy::too_many_lines, reason = "find it easier to reason about")]
    791     #[expect(
    792         clippy::arithmetic_side_effects,
    793         clippy::indexing_slicing,
    794         reason = "comments justify their correctness"
    795     )]
    796     fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
    797     where
    798         A: MapAccess<'d>,
    799     {
    800         use spki::SubjectPublicKeyInfo as _;
    801         let mut client_data = None;
    802         let mut attest = None;
    803         let mut auth = None;
    804         let mut pub_key = None;
    805         let mut key_alg = None;
    806         let mut trans = None;
    807         while let Some(key) = map.next_key::<AttestField<R>>()? {
    808             match key {
    809                 AttestField::ClientDataJson => {
    810                     if client_data.is_some() {
    811                         return Err(Error::duplicate_field(CLIENT_DATA_JSON));
    812                     }
    813                     client_data = map
    814                         .next_value::<Base64DecodedVal>()
    815                         .map(|c_data| Some(c_data.0))?;
    816                 }
    817                 AttestField::AttestationObject => {
    818                     if attest.is_some() {
    819                         return Err(Error::duplicate_field(ATTESTATION_OBJECT));
    820                     }
    821                     attest = map.next_value::<AttObj>().map(|att_obj| Some(att_obj.0))?;
    822                 }
    823                 AttestField::AuthenticatorData => {
    824                     if auth.is_some() {
    825                         return Err(Error::duplicate_field(AUTHENTICATOR_DATA));
    826                     }
    827                     auth = map.next_value::<Option<Base64DecodedVal>>().map(Some)?;
    828                 }
    829                 AttestField::Transports => {
    830                     if trans.is_some() {
    831                         return Err(Error::duplicate_field(TRANSPORTS));
    832                     }
    833                     trans = map.next_value::<Option<_>>().map(Some)?;
    834                 }
    835                 AttestField::PublicKey => {
    836                     if pub_key.is_some() {
    837                         return Err(Error::duplicate_field(PUBLIC_KEY));
    838                     }
    839                     pub_key = map.next_value::<Option<Base64DecodedVal>>().map(Some)?;
    840                 }
    841                 AttestField::PublicKeyAlgorithm => {
    842                     if key_alg.is_some() {
    843                         return Err(Error::duplicate_field(PUBLIC_KEY_ALGORITHM));
    844                     }
    845                     key_alg = map
    846                         .next_value::<Option<CoseAlgorithmIdentifier>>()
    847                         .map(Some)?;
    848                 }
    849                 AttestField::Other => map.next_value::<IgnoredAny>().map(|_| ())?,
    850             }
    851         }
    852         // Note the order of this matters from a performance perspective. In particular `auth` must be evaluated
    853         // before `pub_key` which must be evaluated before `key_alg` as this allows us to parse the attestation
    854         // object at most once and allow us to prioritize parsing `authenticatorData` over the attestation object.
    855         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| {
    856             trans.ok_or(false).and_then(|opt_trans| opt_trans.ok_or(true)).or_else(
    857                 |flag| {
    858                     if R {
    859                         Ok(AuthTransports::new())
    860                     } else if flag {
    861                         Err(Error::invalid_type(Unexpected::Other("null"), &format!("{TRANSPORTS} to be a sequence of AuthenticatorTransports").as_str()))
    862                     } else {
    863                         Err(Error::missing_field(TRANSPORTS))
    864                     }
    865                 },
    866             ).and_then(|transports| {
    867                 auth.ok_or(false).and_then(|opt_auth| opt_auth.ok_or(true)).as_ref().map_or_else(
    868                     |flag| {
    869                         if R {
    870                             Ok(None)
    871                         } else if *flag {
    872                             Err(Error::invalid_type(Unexpected::Other("null"), &format!("{AUTHENTICATOR_DATA} to be a base64url-encoded AuthenticatorData").as_str()))
    873                         } else {
    874                             Err(Error::missing_field(AUTHENTICATOR_DATA))
    875                         }
    876                     },
    877                     |a_data| {
    878                         if a_data.0.len() > 37 {
    879                             // The last portion of attestation object is always authenticator data.
    880                             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| {
    881                                 // Indexing is fine; otherwise the above check would have returned `None`.
    882                                 if *a_data.0 == attestation_object[idx..] {
    883                                     // We know `a_data.len() > 37`; thus indexing is fine.
    884                                     // We start at 37 since that is the beginning of `attestedCredentialData`.
    885                                     // Recall the first 32 bytes are `rpIdHash`, then a 1 byte `flags`, then a
    886                                     // 4-byte big-endian integer `signCount`.
    887                                     // The starting index of `credentialId` is 18 within `attestedCredentialData`.
    888                                     // Recall the first 16 bytes are `aaguid`, then a 2-byte big-endian integer
    889                                     // `credentialIdLength`. Consequently the starting index within
    890                                     // `attestation_object` is `idx + 37 + 18` = `idx + 55`. Overflow cannot occur
    891                                     // since we successfully parsed `AttestedCredentialData`.
    892                                     AttestedCredentialData::from_cbor(&a_data.0[37..]).map_err(Error::custom).map(|success| Some((success.value, idx + 55)))
    893                                 } else {
    894                                     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()))
    895                                 }
    896                             })
    897                         } else {
    898                             Err(Error::invalid_value(Unexpected::Bytes(a_data.0.as_slice()), &"authenticator data to be long enough to contain attested credential data"))
    899                         }
    900                     }
    901                 ).and_then(|attested_info| {
    902                     pub_key.ok_or(false).and_then(|opt_key| opt_key.ok_or(true)).map_or_else(
    903                         |flag| {
    904                             if R {
    905                                 attested_info.as_ref().map_or(Ok(None), |&(ref attested_data, cred_id_start)| Ok(Some((match attested_data.credential_public_key {
    906                                     UncompressedPubKey::Ed25519(_) => CoseAlgorithmIdentifier::Eddsa,
    907                                     UncompressedPubKey::P256(_) => CoseAlgorithmIdentifier::Es256,
    908                                     UncompressedPubKey::P384(_) => CoseAlgorithmIdentifier::Es384,
    909                                     UncompressedPubKey::Rsa(_) => CoseAlgorithmIdentifier::Rs256,
    910                                     // Overflow won't occur since this is correct as
    911                                     // `AttestedCredentialData::from_cbor` would have erred if not.
    912                                 }, cred_id_start, cred_id_start + attested_data.credential_id.0.len()))))
    913                             } else {
    914                                 // `publicKey` is only allowed to not exist when `CoseAlgorithmIdentifier::Eddsa`,
    915                                 // `CoseAlgorithmIdentifier::Es256`, or `CoseAlgorithmIdentifier::Rs256` is not
    916                                 // used.
    917                                 attested_info.as_ref().map_or_else(
    918                                     || AttestationObject::parse_data(attestation_object.as_slice()).map_err(Error::custom).and_then(|(att_obj, auth_idx)| {
    919                                         match att_obj.auth_data.attested_credential_data.credential_public_key {
    920                                             UncompressedPubKey::P384(_) => {
    921                                                 // This won't overflow since `AttestationObject::parse_data` succeeded and `auth_idx`
    922                                                 // is the start of the raw authenticator data which itself contains the raw Credential ID.
    923                                                 Ok(Some((CoseAlgorithmIdentifier::Es384, auth_idx,  auth_idx + att_obj.auth_data.attested_credential_data.credential_id.0.len())))
    924                                             }
    925                                             UncompressedPubKey::Ed25519(_) | UncompressedPubKey::P256(_) | UncompressedPubKey::Rsa(_) => Err(Error::missing_field(PUBLIC_KEY)),
    926                                         }
    927                                     }),
    928                                     |&(ref attested_data, cred_id_start)| {
    929                                         match attested_data.credential_public_key {
    930                                             UncompressedPubKey::P384(_) => {
    931                                                 // Overflow won't occur since this is correct. This is correct since we successfully parsed
    932                                                 // `AttestedCredentialData` and calculated `cred_id_start` from it.
    933                                                 Ok(Some((CoseAlgorithmIdentifier::Es384, cred_id_start, cred_id_start + attested_data.credential_id.0.len())))
    934                                             }
    935                                             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)) },
    936                                         }
    937                                     }
    938                                 )
    939                             }
    940                         },
    941                         |der| {
    942                             UncompressedPubKey::from_der(der.0.as_slice()).map_err(Error::custom).and_then(|key| {
    943                                 attested_info.as_ref().map_or_else(
    944                                     || AttestationObject::parse_data(attestation_object.as_slice()).map_err(Error::custom).and_then(|(att_obj, auth_idx)| {
    945                                         if key == att_obj.auth_data.attested_credential_data.credential_public_key {
    946                                             let alg = match att_obj.auth_data.attested_credential_data.credential_public_key {
    947                                                 UncompressedPubKey::Ed25519(_) => CoseAlgorithmIdentifier::Eddsa,
    948                                                 UncompressedPubKey::P256(_) => CoseAlgorithmIdentifier::Es256,
    949                                                 UncompressedPubKey::P384(_) => CoseAlgorithmIdentifier::Es384,
    950                                                 UncompressedPubKey::Rsa(_) => CoseAlgorithmIdentifier::Rs256,
    951                                             };
    952                                             // This won't overflow since `AttestationObject::parse_data` succeeded and `auth_idx`
    953                                             // is the start of the raw authenticator data which itself contains the raw Credential ID.
    954                                             Ok(Some((alg, auth_idx, auth_idx+ att_obj.auth_data.attested_credential_data.credential_id.0.len())))
    955                                         } else {
    956                                             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()))
    957                                         }
    958                                     }),
    959                                     |&(ref attested_data, cred_id_start)| {
    960                                         if key == attested_data.credential_public_key {
    961                                             let alg = match attested_data.credential_public_key {
    962                                                 UncompressedPubKey::Ed25519(_) => CoseAlgorithmIdentifier::Eddsa,
    963                                                 UncompressedPubKey::P256(_) => CoseAlgorithmIdentifier::Es256,
    964                                                 UncompressedPubKey::P384(_) => CoseAlgorithmIdentifier::Es384,
    965                                                 UncompressedPubKey::Rsa(_) => CoseAlgorithmIdentifier::Rs256,
    966                                             };
    967                                             // Overflow won't occur since this is correct. This is correct since we successfully parsed
    968                                             // `AttestedCredentialData` and calculated `cred_id_start` from it.
    969                                             Ok(Some((alg, cred_id_start, cred_id_start + attested_data.credential_id.0.len())))
    970                                         } else {
    971                                             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()))
    972                                         }
    973                                     }
    974                                 )
    975                             })
    976                         }
    977                     ).and_then(|cred_key_alg_cred_info| {
    978                         key_alg.ok_or(false).and_then(|opt_alg| opt_alg.ok_or(true)).map_or_else(
    979                             |flag| {
    980                                 if R {
    981                                     Ok(cred_key_alg_cred_info.map(|info| (info.1, info.2)))
    982                                 } else if flag {
    983                                     Err(Error::invalid_type(Unexpected::Other("null"), &format!("{PUBLIC_KEY_ALGORITHM} to be a base64url-encoded DER-encoded SubjectPublicKeyInfo").as_str()))
    984                                 } else {
    985                                     Err(Error::missing_field(PUBLIC_KEY_ALGORITHM))
    986                                 }
    987                             },
    988                             |alg| {
    989                                 cred_key_alg_cred_info.map_or_else(
    990                                     || AttestationObject::parse_data(attestation_object.as_slice()).map_err(Error::custom).and_then(|(att_obj, auth_idx)| {
    991                                         let att_obj_alg = match att_obj.auth_data.attested_credential_data.credential_public_key {
    992                                             UncompressedPubKey::Ed25519(_) => CoseAlgorithmIdentifier::Eddsa,
    993                                             UncompressedPubKey::P256(_) => CoseAlgorithmIdentifier::Es256,
    994                                             UncompressedPubKey::P384(_) => CoseAlgorithmIdentifier::Es384,
    995                                             UncompressedPubKey::Rsa(_) => CoseAlgorithmIdentifier::Rs256,
    996                                         };
    997                                         if alg == att_obj_alg {
    998                                             // This won't overflow since `AttestationObject::parse_data` succeeded and `auth_idx`
    999                                             // is the start of the raw authenticator data which itself contains the raw Credential ID.
   1000                                             Ok(Some((auth_idx, auth_idx + att_obj.auth_data.attested_credential_data.credential_id.0.len())))
   1001                                         } else {
   1002                                             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()))
   1003                                         }
   1004                                     }),
   1005                                     |(a, start, last)| if alg == a {
   1006                                         Ok(Some((start, last)))
   1007                                     } else {
   1008                                         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()))
   1009                                     },
   1010                                 )
   1011                             }
   1012                         ).map(|cred_info| AuthAttest{ attest: AuthenticatorAttestation::new(client_data_json, attestation_object, transports), cred_info, })
   1013                     })
   1014                 })
   1015             })
   1016         }))
   1017     }
   1018 }
   1019 /// `"clientDataJSON"`
   1020 const CLIENT_DATA_JSON: &str = "clientDataJSON";
   1021 /// `"attestationObject"`
   1022 const ATTESTATION_OBJECT: &str = "attestationObject";
   1023 /// `"authenticatorData"`
   1024 const AUTHENTICATOR_DATA: &str = "authenticatorData";
   1025 /// `"transports"`
   1026 const TRANSPORTS: &str = "transports";
   1027 /// `"publicKey"`
   1028 const PUBLIC_KEY: &str = "publicKey";
   1029 /// `"publicKeyAlgorithm"`
   1030 const PUBLIC_KEY_ALGORITHM: &str = "publicKeyAlgorithm";
   1031 /// Fields in `AuthenticatorAttestationResponseJSON`.
   1032 pub(super) const AUTH_ATTEST_FIELDS: &[&str; 6] = &[
   1033     CLIENT_DATA_JSON,
   1034     ATTESTATION_OBJECT,
   1035     AUTHENTICATOR_DATA,
   1036     TRANSPORTS,
   1037     PUBLIC_KEY,
   1038     PUBLIC_KEY_ALGORITHM,
   1039 ];
   1040 impl<'de> Deserialize<'de> for AuthAttest {
   1041     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1042     where
   1043         D: Deserializer<'de>,
   1044     {
   1045         deserializer.deserialize_struct(
   1046             "AuthenticatorAttestation",
   1047             AUTH_ATTEST_FIELDS,
   1048             AuthenticatorAttestationVisitor::<false>,
   1049         )
   1050     }
   1051 }
   1052 impl<'de> Deserialize<'de> for AuthenticatorAttestation {
   1053     /// Deserializes a `struct` based on
   1054     /// [`AuthenticatorAttestationResponseJSON`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticatorattestationresponsejson).
   1055     ///
   1056     /// Note unknown keys and duplicate keys are forbidden;
   1057     /// [`clientDataJSON`](https://www.w3.org/TR/webauthn-3/#dom-authenticatorattestationresponsejson-clientdatajson),
   1058     /// [`authenticatorData`](https://www.w3.org/TR/webauthn-3/#dom-authenticatorattestationresponsejson-authenticatordata),
   1059     /// [`publicKey`](https://www.w3.org/TR/webauthn-3/#dom-authenticatorattestationresponsejson-publickey)
   1060     /// and
   1061     /// [`attestationObject`](https://www.w3.org/TR/webauthn-3/#dom-authenticatorattestationresponsejson-attestationobject)
   1062     /// are base64url-decoded;
   1063     /// [`transports`](https://www.w3.org/TR/webauthn-3/#dom-authenticatorattestationresponsejson-transports)
   1064     /// is deserialized via [`AuthTransports::deserialize`]; the decoded `publicKey` is parsed according to the
   1065     /// applicable DER-encoded ASN.1 `SubjectPublicKeyInfo` schema;
   1066     /// [`publicKeyAlgorithm`](https://www.w3.org/TR/webauthn-3/#dom-authenticatorattestationresponsejson-publickeyalgorithm)
   1067     /// is deserialized according to
   1068     /// [`CoseAlgorithmIdentifier`](https://www.w3.org/TR/webauthn-3/#typedefdef-cosealgorithmidentifier); all `required`
   1069     /// fields in the `AuthenticatorAttestationResponseJSON` Web IDL `dictionary` exist (and must not be `null`); `publicKey`
   1070     /// exists when Ed25519, P-256 with SHA-256, or RSASSA-PKCS1-v1_5 with SHA-256 is used (and must not be `null`)
   1071     /// [per WebAuthn](https://www.w3.org/TR/webauthn-3/#sctn-public-key-easy); the `publicKeyAlgorithm` aligns
   1072     /// with
   1073     /// [`credentialPublicKey`](https://www.w3.org/TR/webauthn-3/#authdata-attestedcredentialdata-credentialpublickey)
   1074     /// within
   1075     /// [`attestedCredentialData`](https://www.w3.org/TR/webauthn-3/#authdata-attestedcredentialdata) within the
   1076     /// decoded `authenticatorData`; the decoded `publicKey` is the same as `credentialPublicKey` within
   1077     /// `attestedCredentialData` within the decoded `authenticatorData`; and the decoded `authenticatorData` is the
   1078     /// same as [`authData`](https://www.w3.org/TR/webauthn-3/#attestation-object) within the decoded
   1079     /// `attestationObject`.
   1080     #[inline]
   1081     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1082     where
   1083         D: Deserializer<'de>,
   1084     {
   1085         AuthAttest::deserialize(deserializer).map(|val| val.attest)
   1086     }
   1087 }
   1088 /// `Visitor` for `CredentialPropertiesOutput`.
   1089 ///
   1090 /// Unknown fields are ignored iff `RELAXED`.
   1091 pub(super) struct CredentialPropertiesOutputVisitor<const RELAXED: bool>;
   1092 impl<'d, const R: bool> Visitor<'d> for CredentialPropertiesOutputVisitor<R> {
   1093     type Value = CredentialPropertiesOutput;
   1094     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
   1095         formatter.write_str("CredentialPropertiesOutput")
   1096     }
   1097     fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
   1098     where
   1099         A: MapAccess<'d>,
   1100     {
   1101         /// Allowed fields.
   1102         enum Field<const IGNORE_UNKNOWN: bool> {
   1103             /// `rk` field.
   1104             Rk,
   1105             /// Unknown field.
   1106             Other,
   1107         }
   1108         impl<'e, const I: bool> Deserialize<'e> for Field<I> {
   1109             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1110             where
   1111                 D: Deserializer<'e>,
   1112             {
   1113                 /// `Visitor` for `Field`.
   1114                 ///
   1115                 /// Unknown fields are ignored iff `IGNORE_UNKNOWN`.
   1116                 struct FieldVisitor<const IGNORE_UNKNOWN: bool>;
   1117                 impl<const IG: bool> Visitor<'_> for FieldVisitor<IG> {
   1118                     type Value = Field<IG>;
   1119                     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
   1120                         write!(formatter, "'{RK}'")
   1121                     }
   1122                     fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
   1123                     where
   1124                         E: Error,
   1125                     {
   1126                         match v {
   1127                             RK => Ok(Field::Rk),
   1128                             _ => {
   1129                                 if IG {
   1130                                     Ok(Field::Other)
   1131                                 } else {
   1132                                     Err(E::unknown_field(v, PROPS_FIELDS))
   1133                                 }
   1134                             }
   1135                         }
   1136                     }
   1137                 }
   1138                 deserializer.deserialize_identifier(FieldVisitor)
   1139             }
   1140         }
   1141         let mut rk = None;
   1142         while let Some(key) = map.next_key::<Field<R>>()? {
   1143             match key {
   1144                 Field::Rk => {
   1145                     if rk.is_some() {
   1146                         return Err(Error::duplicate_field(RK));
   1147                     }
   1148                     rk = map.next_value().map(Some)?;
   1149                 }
   1150                 Field::Other => map.next_value::<IgnoredAny>().map(|_| ())?,
   1151             }
   1152         }
   1153         Ok(CredentialPropertiesOutput { rk: rk.flatten() })
   1154     }
   1155 }
   1156 /// `"rk"`
   1157 const RK: &str = "rk";
   1158 /// `CredentialPropertiesOutput` fields.
   1159 pub(super) const PROPS_FIELDS: &[&str; 1] = &[RK];
   1160 impl<'de> Deserialize<'de> for CredentialPropertiesOutput {
   1161     /// Deserializes a `struct` based on
   1162     /// [`CredentialPropertiesOutput`](https://www.w3.org/TR/webauthn-3/#dictdef-credentialpropertiesoutput).
   1163     ///
   1164     /// Note unknown and duplicate keys are forbidden.
   1165     #[inline]
   1166     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1167     where
   1168         D: Deserializer<'de>,
   1169     {
   1170         deserializer.deserialize_struct(
   1171             "CredentialPropertiesOutput",
   1172             PROPS_FIELDS,
   1173             CredentialPropertiesOutputVisitor::<false>,
   1174         )
   1175     }
   1176 }
   1177 impl<'de> Deserialize<'de> for AuthenticationExtensionsPrfOutputs {
   1178     /// Deserializes a `struct` based on
   1179     /// [`AuthenticationExtensionsPRFOutputsJSON`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsprfoutputsjson).
   1180     ///
   1181     /// Note unknown and duplicate keys are forbidden;
   1182     /// [`enabled`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfoutputs-enabled)
   1183     /// must exist (and not be `null`); and
   1184     /// [`results`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfoutputs-results) must not exist,
   1185     /// be `null`, or be an
   1186     /// [`AuthenticationExtensionsPRFValues`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsprfvalues)
   1187     /// with no unknown or duplicate keys,
   1188     /// [`first`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfvalues-first) must exist but be
   1189     /// `null`, and
   1190     /// [`second`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfvalues-second) can exist but
   1191     /// must be `null` if so.
   1192     #[inline]
   1193     #[expect(clippy::unreachable, reason = "we want to crash when there is a bug")]
   1194     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1195     where
   1196         D: Deserializer<'de>,
   1197     {
   1198         AuthenticationExtensionsPrfOutputsHelper::<false, true, AuthenticationExtensionsPrfValues>::deserialize(deserializer).map(|val| Self {
   1199             enabled: val.0.unwrap_or_else(|| {
   1200                 unreachable!(
   1201                     "there is a bug in AuthenticationExtensionsPrfOutputsHelper::deserialize"
   1202                 )
   1203             }),
   1204         })
   1205     }
   1206 }
   1207 /// `Visitor` for `ClientExtensionsOutputs`.
   1208 ///
   1209 /// Unknown fields are ignored iff `RELAXED`.
   1210 pub(super) struct ClientExtensionsOutputsVisitor<const RELAXED: bool, PROPS, PRF>(
   1211     pub PhantomData<fn() -> (PROPS, PRF)>,
   1212 );
   1213 impl<'d, const R: bool, C, P> Visitor<'d> for ClientExtensionsOutputsVisitor<R, C, P>
   1214 where
   1215     C: for<'a> Deserialize<'a> + Into<CredentialPropertiesOutput>,
   1216     P: for<'a> Deserialize<'a> + Into<AuthenticationExtensionsPrfOutputs>,
   1217 {
   1218     type Value = ClientExtensionsOutputs;
   1219     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
   1220         formatter.write_str("ClientExtensionsOutputs")
   1221     }
   1222     fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
   1223     where
   1224         A: MapAccess<'d>,
   1225     {
   1226         /// Allowed fields.
   1227         enum Field<const IGNORE_UNKNOWN: bool> {
   1228             /// `credProps` field.
   1229             CredProps,
   1230             /// `prf` field.
   1231             Prf,
   1232             /// Unknown field.
   1233             Other,
   1234         }
   1235         impl<'e, const I: bool> Deserialize<'e> for Field<I> {
   1236             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1237             where
   1238                 D: Deserializer<'e>,
   1239             {
   1240                 /// `Visitor` for `Field`.
   1241                 ///
   1242                 /// Unknown fields are ignored iff `IGNORE_UNKNOWN`.
   1243                 struct FieldVisitor<const IGNORE_UNKNOWN: bool>;
   1244                 impl<const IG: bool> Visitor<'_> for FieldVisitor<IG> {
   1245                     type Value = Field<IG>;
   1246                     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
   1247                         write!(formatter, "'{CRED_PROPS}' or '{PRF}'")
   1248                     }
   1249                     fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
   1250                     where
   1251                         E: Error,
   1252                     {
   1253                         match v {
   1254                             CRED_PROPS => Ok(Field::CredProps),
   1255                             PRF => Ok(Field::Prf),
   1256                             _ => {
   1257                                 if IG {
   1258                                     Ok(Field::Other)
   1259                                 } else {
   1260                                     Err(E::unknown_field(v, EXT_FIELDS))
   1261                                 }
   1262                             }
   1263                         }
   1264                     }
   1265                 }
   1266                 deserializer.deserialize_identifier(FieldVisitor)
   1267             }
   1268         }
   1269         let mut cred_props = None;
   1270         let mut prf = None;
   1271         while let Some(key) = map.next_key::<Field<R>>()? {
   1272             match key {
   1273                 Field::CredProps => {
   1274                     if cred_props.is_some() {
   1275                         return Err(Error::duplicate_field(CRED_PROPS));
   1276                     }
   1277                     cred_props = map.next_value::<Option<C>>().map(Some)?;
   1278                 }
   1279                 Field::Prf => {
   1280                     if prf.is_some() {
   1281                         return Err(Error::duplicate_field(PRF));
   1282                     }
   1283                     prf = map.next_value::<Option<P>>().map(Some)?;
   1284                 }
   1285                 Field::Other => map.next_value::<IgnoredAny>().map(|_| ())?,
   1286             }
   1287         }
   1288         Ok(ClientExtensionsOutputs {
   1289             cred_props: cred_props.flatten().map(Into::into),
   1290             prf: prf.flatten().map(Into::into),
   1291         })
   1292     }
   1293 }
   1294 impl ClientExtensions for ClientExtensionsOutputs {
   1295     fn empty() -> Self {
   1296         Self {
   1297             prf: None,
   1298             cred_props: None,
   1299         }
   1300     }
   1301 }
   1302 /// `"credProps"`
   1303 const CRED_PROPS: &str = "credProps";
   1304 /// `"prf"`
   1305 const PRF: &str = "prf";
   1306 /// `AuthenticationExtensionsClientOutputsJSON` fields.
   1307 pub(super) const EXT_FIELDS: &[&str; 2] = &[CRED_PROPS, PRF];
   1308 impl<'de> Deserialize<'de> for ClientExtensionsOutputs {
   1309     /// Deserializes a `struct` based on
   1310     /// [`AuthenticationExtensionsClientOutputsJSON`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsclientoutputsjson).
   1311     ///
   1312     /// Note that unknown and duplicate keys are forbidden;
   1313     /// [`credProps`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsclientoutputs-credprops) is
   1314     /// `null` or deserialized via [`CredentialPropertiesOutput::deserialize`]; and
   1315     /// [`prf`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsclientoutputs-prf) is `null`
   1316     /// or deserialized via [`AuthenticationExtensionsPrfOutputs::deserialize`].
   1317     #[inline]
   1318     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1319     where
   1320         D: Deserializer<'de>,
   1321     {
   1322         deserializer.deserialize_struct(
   1323             "ClientExtensionsOutputs",
   1324             EXT_FIELDS,
   1325             ClientExtensionsOutputsVisitor::<
   1326                 false,
   1327                 CredentialPropertiesOutput,
   1328                 AuthenticationExtensionsPrfOutputs,
   1329             >(PhantomData),
   1330         )
   1331     }
   1332 }
   1333 impl<'de> Deserialize<'de> for Registration {
   1334     /// Deserializes a `struct` based on
   1335     /// [`RegistrationResponseJSON`](https://www.w3.org/TR/webauthn-3/#dictdef-registrationresponsejson).
   1336     ///
   1337     /// Note that unknown and duplicate keys are forbidden;
   1338     /// [`id`](https://www.w3.org/TR/webauthn-3/#dom-registrationresponsejson-id) and
   1339     /// [`rawId`](https://www.w3.org/TR/webauthn-3/#dom-registrationresponsejson-rawid) are deserialized
   1340     /// via [`CredentialId::deserialize`];
   1341     /// [`response`](https://www.w3.org/TR/webauthn-3/#dom-registrationresponsejson-response) is deserialized
   1342     /// via [`AuthenticatorAttestation::deserialize`];
   1343     /// [`authenticatorAttachment`](https://www.w3.org/TR/webauthn-3/#dom-registrationresponsejson-authenticatorattachment)
   1344     /// is `null` or deserialized via [`AuthenticatorAttachment::deserialize`];
   1345     /// [`clientExtensionResults`](https://www.w3.org/TR/webauthn-3/#dom-registrationresponsejson-clientextensionresults)
   1346     /// is deserialized via [`ClientExtensionsOutputs::deserialize`]; all `required` fields in the
   1347     /// `RegistrationResponseJSON` Web IDL `dictionary` exist (and are not `null`);
   1348     /// [`type`](https://www.w3.org/TR/webauthn-3/#dom-registrationresponsejson-type) is `"public-key"`;
   1349     /// and the decoded `id`, decoded `rawId`, and
   1350     /// [`credentialId`](https://www.w3.org/TR/webauthn-3/#authdata-attestedcredentialdata-credentialid) within
   1351     /// [`attestedCredentialData`](https://www.w3.org/TR/webauthn-3/#authdata-attestedcredentialdata) within
   1352     /// [`authData`](https://www.w3.org/TR/webauthn-3/#attestation-object) within the decoded
   1353     /// [`attestationObject`](https://www.w3.org/TR/webauthn-3/#dom-authenticatorattestationresponsejson-attestationobject)
   1354     /// are all the same.
   1355     #[expect(clippy::unreachable, reason = "when there is a bug, we want to crash")]
   1356     #[expect(clippy::indexing_slicing, reason = "comment justifies its correctness")]
   1357     #[inline]
   1358     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1359     where
   1360         D: Deserializer<'de>,
   1361     {
   1362         PublicKeyCredential::<false, true, AuthAttest, ClientExtensionsOutputs>::deserialize(deserializer).and_then(|cred| {
   1363             let id = cred.id.unwrap_or_else(|| unreachable!("there is a bug in PublicKeyCredential::deserialize"));
   1364             cred.response.cred_info.map_or_else(
   1365                 || AttestationObject::try_from(cred.response.attest.attestation_object()).map_err(Error::custom).and_then(|att_obj| {
   1366                     if id == att_obj.auth_data.attested_credential_data.credential_id {
   1367                         Ok(())
   1368                     } else {
   1369                         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()))
   1370                     }
   1371                 }),
   1372                 // `start` and `last` were calculated based on `cred.response.attest.attestation_object()`
   1373                 // and represent the starting and ending index of the `CredentialId`; therefore this is correct
   1374                 // let alone won't `panic`.
   1375                 |(start, last)| if id.0 == cred.response.attest.attestation_object()[start..last] {
   1376                     Ok(())
   1377                 } else {
   1378                     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()))
   1379                 },
   1380             ).map(|()| Self { response: cred.response.attest, authenticator_attachment: cred.authenticator_attachment, client_extension_results: cred.client_extension_results, })
   1381         })
   1382     }
   1383 }
   1384 #[cfg(test)]
   1385 mod tests {
   1386     use super::{
   1387         super::{
   1388             ALG, AuthenticatorAttachment, EC2, EDDSA, ES256, ES384, Ed25519PubKey, KTY, OKP, RSA,
   1389             Registration, RsaPubKey, UncompressedP256PubKey, UncompressedP384PubKey, cbor,
   1390         },
   1391         CoseAlgorithmIdentifier,
   1392         spki::SubjectPublicKeyInfo,
   1393     };
   1394     use ed25519_dalek::{VerifyingKey, pkcs8::EncodePublicKey};
   1395     use p256::{
   1396         EncodedPoint as P256Pt, PublicKey as P256PubKey, SecretKey as P256Key,
   1397         elliptic_curve::sec1::{FromEncodedPoint as _, ToEncodedPoint as _},
   1398     };
   1399     use p384::{EncodedPoint as P384Pt, PublicKey as P384PubKey, SecretKey as P384Key};
   1400     use rsa::{
   1401         BigUint, RsaPrivateKey,
   1402         sha2::{Digest as _, Sha256},
   1403         traits::PublicKeyParts,
   1404     };
   1405     use serde::de::{Error as _, Unexpected};
   1406     use serde_json::Error;
   1407     #[test]
   1408     fn ed25519_spki() {
   1409         assert!(
   1410             Ed25519PubKey::from_der(
   1411                 VerifyingKey::from_bytes(&[1; 32])
   1412                     .unwrap()
   1413                     .to_public_key_der()
   1414                     .unwrap()
   1415                     .as_bytes()
   1416             )
   1417             .map_or(false, |k| k.0 == [1; 32])
   1418         );
   1419     }
   1420     #[test]
   1421     fn p256_spki() {
   1422         let key = P256Key::from_bytes(
   1423             &[
   1424                 137, 133, 36, 206, 163, 47, 255, 5, 76, 144, 163, 141, 40, 109, 108, 240, 246, 115,
   1425                 178, 237, 169, 68, 6, 129, 92, 21, 238, 127, 55, 158, 207, 95,
   1426             ]
   1427             .into(),
   1428         )
   1429         .unwrap()
   1430         .public_key();
   1431         let enc_key = key.to_encoded_point(false);
   1432         assert!(
   1433             UncompressedP256PubKey::from_der(key.to_public_key_der().unwrap().as_bytes()).map_or(
   1434                 false,
   1435                 |k| k.0 == enc_key.x().unwrap().as_slice()
   1436                     && k.1 == enc_key.y().unwrap().as_slice()
   1437             )
   1438         );
   1439     }
   1440     #[test]
   1441     fn p384_spki() {
   1442         let key = P384Key::from_bytes(
   1443             &[
   1444                 158, 99, 156, 49, 190, 211, 85, 167, 28, 2, 80, 57, 31, 22, 17, 38, 85, 78, 232,
   1445                 42, 45, 199, 154, 243, 136, 251, 84, 34, 5, 120, 208, 91, 61, 248, 64, 144, 87, 1,
   1446                 32, 86, 220, 68, 182, 11, 105, 223, 75, 70,
   1447             ]
   1448             .into(),
   1449         )
   1450         .unwrap()
   1451         .public_key();
   1452         let enc_key = key.to_encoded_point(false);
   1453         assert!(
   1454             UncompressedP384PubKey::from_der(key.to_public_key_der().unwrap().as_bytes()).map_or(
   1455                 false,
   1456                 |k| k.0 == enc_key.x().unwrap().as_slice()
   1457                     && k.1 == enc_key.y().unwrap().as_slice()
   1458             )
   1459         );
   1460     }
   1461     #[test]
   1462     fn rsa_spki() {
   1463         let n = [
   1464             111, 183, 124, 133, 38, 167, 70, 148, 44, 50, 30, 60, 121, 14, 38, 37, 96, 114, 107,
   1465             195, 248, 64, 79, 36, 237, 140, 43, 27, 94, 74, 102, 152, 135, 102, 184, 150, 186, 206,
   1466             185, 19, 165, 209, 48, 98, 98, 9, 3, 205, 208, 82, 250, 105, 132, 201, 73, 62, 60, 165,
   1467             100, 128, 153, 9, 41, 118, 66, 95, 236, 214, 73, 135, 197, 68, 184, 10, 27, 116, 204,
   1468             145, 50, 174, 58, 42, 183, 181, 119, 232, 126, 252, 217, 96, 162, 190, 103, 122, 64,
   1469             87, 145, 45, 32, 207, 17, 239, 223, 3, 35, 14, 112, 119, 124, 141, 123, 208, 239, 105,
   1470             81, 217, 151, 162, 190, 17, 88, 182, 176, 158, 81, 200, 42, 166, 133, 48, 23, 236, 55,
   1471             117, 248, 233, 151, 203, 122, 155, 231, 46, 177, 20, 20, 151, 64, 222, 239, 226, 7, 21,
   1472             254, 81, 202, 64, 232, 161, 235, 22, 51, 246, 207, 213, 0, 229, 138, 46, 222, 205, 157,
   1473             108, 139, 253, 230, 80, 50, 2, 122, 212, 163, 100, 180, 114, 12, 113, 52, 56, 99, 188,
   1474             42, 198, 212, 23, 182, 222, 56, 221, 200, 79, 96, 239, 221, 135, 10, 17, 106, 183, 56,
   1475             104, 68, 94, 198, 196, 35, 200, 83, 204, 26, 185, 204, 212, 31, 183, 19, 111, 233, 13,
   1476             72, 93, 53, 65, 111, 59, 242, 122, 160, 244, 162, 126, 38, 235, 156, 47, 88, 39, 132,
   1477             153, 79, 0, 133, 78, 7, 218, 165, 241,
   1478         ];
   1479         let e = 65537u32;
   1480         let d = [
   1481             145, 79, 21, 97, 233, 3, 192, 194, 177, 68, 181, 80, 120, 197, 23, 44, 185, 74, 144, 0,
   1482             132, 149, 139, 11, 16, 224, 4, 112, 236, 94, 238, 97, 121, 124, 213, 145, 24, 253, 168,
   1483             35, 190, 205, 132, 115, 33, 201, 38, 253, 246, 180, 66, 155, 165, 46, 3, 254, 68, 108,
   1484             154, 247, 246, 45, 187, 0, 204, 96, 185, 157, 249, 174, 158, 38, 62, 244, 183, 76, 102,
   1485             6, 219, 92, 212, 138, 59, 147, 163, 219, 111, 39, 105, 21, 236, 196, 38, 255, 114, 247,
   1486             82, 104, 113, 204, 29, 152, 209, 219, 48, 239, 74, 129, 19, 247, 33, 239, 119, 166,
   1487             216, 152, 94, 138, 238, 164, 242, 129, 50, 150, 57, 20, 53, 224, 56, 241, 138, 97, 111,
   1488             215, 107, 212, 195, 146, 108, 143, 0, 229, 181, 171, 73, 152, 105, 146, 25, 243, 242,
   1489             140, 252, 248, 162, 247, 63, 168, 180, 20, 153, 120, 10, 248, 211, 1, 71, 127, 212,
   1490             249, 237, 203, 202, 48, 26, 216, 226, 228, 186, 13, 204, 70, 255, 240, 89, 255, 59, 83,
   1491             31, 253, 55, 43, 158, 90, 248, 83, 32, 159, 105, 57, 134, 34, 96, 18, 255, 245, 153,
   1492             162, 60, 91, 99, 220, 51, 44, 85, 114, 67, 125, 202, 65, 217, 245, 40, 8, 81, 165, 142,
   1493             24, 245, 127, 122, 247, 152, 212, 75, 45, 59, 90, 184, 234, 31, 147, 36, 8, 212, 45,
   1494             50, 23, 3, 25, 253, 87, 227, 79, 119, 161,
   1495         ];
   1496         let p = BigUint::from_bytes_le(
   1497             [
   1498                 215, 166, 5, 21, 11, 179, 41, 77, 198, 92, 165, 48, 77, 162, 42, 41, 206, 141, 60,
   1499                 69, 47, 164, 19, 92, 46, 72, 100, 238, 100, 53, 214, 197, 163, 185, 6, 140, 229,
   1500                 250, 195, 77, 8, 12, 5, 236, 178, 173, 86, 201, 43, 213, 165, 51, 108, 101, 161,
   1501                 99, 76, 240, 14, 234, 76, 197, 137, 53, 198, 168, 135, 205, 212, 198, 120, 29, 16,
   1502                 82, 98, 233, 236, 177, 12, 171, 141, 100, 107, 146, 33, 176, 125, 202, 172, 79,
   1503                 147, 179, 30, 62, 247, 206, 169, 19, 168, 114, 26, 73, 108, 178, 105, 84, 89, 191,
   1504                 168, 253, 228, 214, 54, 16, 212, 199, 111, 72, 3, 41, 247, 227, 165, 244, 32, 188,
   1505                 24, 247,
   1506             ]
   1507             .as_slice(),
   1508         );
   1509         let p_2 = BigUint::from_bytes_le(
   1510             [
   1511                 41, 25, 198, 240, 134, 206, 121, 57, 11, 5, 134, 192, 212, 77, 229, 197, 14, 78,
   1512                 85, 212, 190, 114, 179, 188, 21, 171, 174, 12, 104, 74, 15, 164, 136, 173, 62, 177,
   1513                 141, 213, 93, 102, 147, 83, 59, 124, 146, 59, 175, 213, 55, 27, 25, 248, 154, 29,
   1514                 39, 85, 50, 235, 134, 60, 203, 106, 186, 195, 190, 185, 71, 169, 142, 236, 92, 11,
   1515                 250, 187, 198, 8, 201, 184, 120, 178, 227, 87, 63, 243, 89, 227, 234, 184, 28, 252,
   1516                 112, 211, 193, 69, 23, 92, 5, 72, 93, 53, 69, 159, 73, 160, 105, 244, 249, 94, 214,
   1517                 173, 9, 236, 4, 255, 129, 11, 224, 140, 252, 168, 57, 143, 176, 241, 60, 219, 90,
   1518                 250,
   1519             ]
   1520             .as_slice(),
   1521         );
   1522         let key = RsaPrivateKey::from_components(
   1523             BigUint::from_bytes_le(n.as_slice()),
   1524             e.into(),
   1525             BigUint::from_bytes_le(d.as_slice()),
   1526             vec![p, p_2],
   1527         )
   1528         .unwrap()
   1529         .to_public_key();
   1530         assert!(
   1531             RsaPubKey::from_der(key.to_public_key_der().unwrap().as_bytes())
   1532                 .map_or(false, |k| k.0 == key.n().to_bytes_be()
   1533                     && BigUint::from(k.1) == *key.e())
   1534         );
   1535     }
   1536     #[test]
   1537     fn eddsa_registration_deserialize_data_mismatch() {
   1538         let c_data_json = serde_json::json!({}).to_string();
   1539         let att_obj = [
   1540             cbor::MAP_3,
   1541             cbor::TEXT_3,
   1542             b'f',
   1543             b'm',
   1544             b't',
   1545             cbor::TEXT_4,
   1546             b'n',
   1547             b'o',
   1548             b'n',
   1549             b'e',
   1550             cbor::TEXT_7,
   1551             b'a',
   1552             b't',
   1553             b't',
   1554             b'S',
   1555             b't',
   1556             b'm',
   1557             b't',
   1558             cbor::MAP_0,
   1559             cbor::TEXT_8,
   1560             b'a',
   1561             b'u',
   1562             b't',
   1563             b'h',
   1564             b'D',
   1565             b'a',
   1566             b't',
   1567             b'a',
   1568             cbor::BYTES_INFO_24,
   1569             115,
   1570             // `rpIdHash`.
   1571             0,
   1572             0,
   1573             0,
   1574             0,
   1575             0,
   1576             0,
   1577             0,
   1578             0,
   1579             0,
   1580             0,
   1581             0,
   1582             0,
   1583             0,
   1584             0,
   1585             0,
   1586             0,
   1587             0,
   1588             0,
   1589             0,
   1590             0,
   1591             0,
   1592             0,
   1593             0,
   1594             0,
   1595             0,
   1596             0,
   1597             0,
   1598             0,
   1599             0,
   1600             0,
   1601             0,
   1602             0,
   1603             // `flags`.
   1604             0b0100_0101,
   1605             // `signCount`.
   1606             0,
   1607             0,
   1608             0,
   1609             0,
   1610             // `aaguid`.
   1611             0,
   1612             0,
   1613             0,
   1614             0,
   1615             0,
   1616             0,
   1617             0,
   1618             0,
   1619             0,
   1620             0,
   1621             0,
   1622             0,
   1623             0,
   1624             0,
   1625             0,
   1626             0,
   1627             // `credentialIdLength`.
   1628             0,
   1629             16,
   1630             // `credentialId`.
   1631             0,
   1632             0,
   1633             0,
   1634             0,
   1635             0,
   1636             0,
   1637             0,
   1638             0,
   1639             0,
   1640             0,
   1641             0,
   1642             0,
   1643             0,
   1644             0,
   1645             0,
   1646             0,
   1647             // Ed25519 COSE key.
   1648             cbor::MAP_4,
   1649             KTY,
   1650             OKP,
   1651             ALG,
   1652             EDDSA,
   1653             // `crv`.
   1654             cbor::NEG_ONE,
   1655             // `Ed25519`.
   1656             cbor::SIX,
   1657             // `x`.
   1658             cbor::NEG_TWO,
   1659             cbor::BYTES_INFO_24,
   1660             32,
   1661             // Compressed y-coordinate.
   1662             1,
   1663             1,
   1664             1,
   1665             1,
   1666             1,
   1667             1,
   1668             1,
   1669             1,
   1670             1,
   1671             1,
   1672             1,
   1673             1,
   1674             1,
   1675             1,
   1676             1,
   1677             1,
   1678             1,
   1679             1,
   1680             1,
   1681             1,
   1682             1,
   1683             1,
   1684             1,
   1685             1,
   1686             1,
   1687             1,
   1688             1,
   1689             1,
   1690             1,
   1691             1,
   1692             1,
   1693             1,
   1694         ];
   1695         let pub_key = VerifyingKey::from_bytes(&[1; 32])
   1696             .unwrap()
   1697             .to_public_key_der()
   1698             .unwrap();
   1699         let b64_cdata = base64url_nopad::encode(c_data_json.as_bytes());
   1700         let b64_adata = base64url_nopad::encode(&att_obj[att_obj.len() - 113..]);
   1701         let b64_key = base64url_nopad::encode(pub_key.as_bytes());
   1702         let b64_aobj = base64url_nopad::encode(att_obj.as_slice());
   1703         // Base case is valid.
   1704         assert!(
   1705             serde_json::from_str::<Registration>(
   1706                 serde_json::json!({
   1707                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   1708                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   1709                     "response": {
   1710                         "clientDataJSON": b64_cdata,
   1711                         "authenticatorData": b64_adata,
   1712                         "transports": ["ble", "usb", "hybrid", "internal", "nfc", "smart-card"],
   1713                         "publicKey": b64_key,
   1714                         "publicKeyAlgorithm": -8,
   1715                         "attestationObject": b64_aobj,
   1716                     },
   1717                     "authenticatorAttachment": "cross-platform",
   1718                     "clientExtensionResults": {},
   1719                     "type": "public-key"
   1720                 })
   1721                 .to_string()
   1722                 .as_str()
   1723             )
   1724             .map_or(false, |reg| reg.response.client_data_json
   1725                 == c_data_json.as_bytes()
   1726                 && reg.response.attestation_object_and_c_data_hash[..att_obj.len()]
   1727                     == att_obj
   1728                 && reg.response.attestation_object_and_c_data_hash[att_obj.len()..]
   1729                     == *Sha256::digest(c_data_json.as_bytes()).as_slice()
   1730                 && reg.response.transports.count() == 6
   1731                 && matches!(
   1732                     reg.authenticator_attachment,
   1733                     AuthenticatorAttachment::CrossPlatform
   1734                 )
   1735                 && reg.client_extension_results.cred_props.is_none()
   1736                 && reg.client_extension_results.prf.is_none())
   1737         );
   1738         // `id` and `rawId` mismatch.
   1739         let mut err = Error::invalid_value(
   1740             Unexpected::Bytes(
   1741                 base64url_nopad::decode("ABABABABABABABABABABAA".as_bytes())
   1742                     .unwrap()
   1743                     .as_slice(),
   1744             ),
   1745             &format!("id and rawId to match: CredentialId({:?})", [0; 16]).as_str(),
   1746         )
   1747         .to_string()
   1748         .into_bytes();
   1749         assert_eq!(
   1750             serde_json::from_str::<Registration>(
   1751                 serde_json::json!({
   1752                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   1753                     "rawId": "ABABABABABABABABABABAA",
   1754                     "response": {
   1755                         "clientDataJSON": b64_cdata,
   1756                         "authenticatorData": b64_adata,
   1757                         "transports": [],
   1758                         "publicKey": b64_key,
   1759                         "publicKeyAlgorithm": -8,
   1760                         "attestationObject": b64_aobj,
   1761                     },
   1762                     "clientExtensionResults": {},
   1763                     "type": "public-key"
   1764                 })
   1765                 .to_string()
   1766                 .as_str()
   1767             )
   1768             .unwrap_err()
   1769             .to_string()
   1770             .into_bytes()[..err.len()],
   1771             err
   1772         );
   1773         // missing `id`.
   1774         err = Error::missing_field("id").to_string().into_bytes();
   1775         assert_eq!(
   1776             serde_json::from_str::<Registration>(
   1777                 serde_json::json!({
   1778                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   1779                     "response": {
   1780                         "clientDataJSON": b64_cdata,
   1781                         "authenticatorData": b64_adata,
   1782                         "transports": [],
   1783                         "publicKey": b64_key,
   1784                         "publicKeyAlgorithm": -8,
   1785                         "attestationObject": b64_aobj,
   1786                     },
   1787                     "clientExtensionResults": {},
   1788                     "type": "public-key"
   1789                 })
   1790                 .to_string()
   1791                 .as_str()
   1792             )
   1793             .unwrap_err()
   1794             .to_string()
   1795             .into_bytes()[..err.len()],
   1796             err
   1797         );
   1798         // `null` `id`.
   1799         err = Error::invalid_type(Unexpected::Other("null"), &"CredentialId")
   1800             .to_string()
   1801             .into_bytes();
   1802         assert_eq!(
   1803             serde_json::from_str::<Registration>(
   1804                 serde_json::json!({
   1805                     "id": null,
   1806                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   1807                     "response": {
   1808                         "clientDataJSON": b64_cdata,
   1809                         "authenticatorData": b64_adata,
   1810                         "transports": [],
   1811                         "publicKey": b64_key,
   1812                         "publicKeyAlgorithm": -8,
   1813                         "attestationObject": b64_aobj,
   1814                     },
   1815                     "clientExtensionResults": {},
   1816                     "type": "public-key"
   1817                 })
   1818                 .to_string()
   1819                 .as_str()
   1820             )
   1821             .unwrap_err()
   1822             .to_string()
   1823             .into_bytes()[..err.len()],
   1824             err
   1825         );
   1826         // missing `rawId`.
   1827         err = Error::missing_field("rawId").to_string().into_bytes();
   1828         assert_eq!(
   1829             serde_json::from_str::<Registration>(
   1830                 serde_json::json!({
   1831                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   1832                     "response": {
   1833                         "clientDataJSON": b64_cdata,
   1834                         "authenticatorData": b64_adata,
   1835                         "transports": [],
   1836                         "publicKey": b64_key,
   1837                         "publicKeyAlgorithm": -8,
   1838                         "attestationObject": b64_aobj,
   1839                     },
   1840                     "clientExtensionResults": {},
   1841                     "type": "public-key"
   1842                 })
   1843                 .to_string()
   1844                 .as_str()
   1845             )
   1846             .unwrap_err()
   1847             .to_string()
   1848             .into_bytes()[..err.len()],
   1849             err
   1850         );
   1851         // `null` `rawId`.
   1852         err = Error::invalid_type(Unexpected::Other("null"), &"CredentialId")
   1853             .to_string()
   1854             .into_bytes();
   1855         assert_eq!(
   1856             serde_json::from_str::<Registration>(
   1857                 serde_json::json!({
   1858                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   1859                     "rawId": null,
   1860                     "response": {
   1861                         "clientDataJSON": b64_cdata,
   1862                         "authenticatorData": b64_adata,
   1863                         "transports": [],
   1864                         "publicKey": b64_key,
   1865                         "publicKeyAlgorithm": -8,
   1866                         "attestationObject": b64_aobj,
   1867                     },
   1868                     "clientExtensionResults": {},
   1869                     "type": "public-key"
   1870                 })
   1871                 .to_string()
   1872                 .as_str()
   1873             )
   1874             .unwrap_err()
   1875             .to_string()
   1876             .into_bytes()[..err.len()],
   1877             err
   1878         );
   1879         // `id` and the credential id in authenticator data mismatch.
   1880         err = Error::invalid_value(
   1881             Unexpected::Bytes(
   1882                 base64url_nopad
   1883                     ::decode("ABABABABABABABABABABAA".as_bytes())
   1884                     .unwrap()
   1885                     .as_slice(),
   1886             ),
   1887             &format!("id, rawId, and the credential id in the attested credential data to all match: {:?}", [0; 16]).as_str(),
   1888         )
   1889         .to_string().into_bytes();
   1890         assert_eq!(
   1891             serde_json::from_str::<Registration>(
   1892                 serde_json::json!({
   1893                     "id": "ABABABABABABABABABABAA",
   1894                     "rawId": "ABABABABABABABABABABAA",
   1895                     "response": {
   1896                         "clientDataJSON": b64_cdata,
   1897                         "authenticatorData": b64_adata,
   1898                         "transports": [],
   1899                         "publicKey": b64_key,
   1900                         "publicKeyAlgorithm": -8,
   1901                         "attestationObject": b64_aobj,
   1902                     },
   1903                     "clientExtensionResults": {},
   1904                     "type": "public-key"
   1905                 })
   1906                 .to_string()
   1907                 .as_str()
   1908             )
   1909             .unwrap_err()
   1910             .to_string()
   1911             .into_bytes()[..err.len()],
   1912             err
   1913         );
   1914         // `authenticatorData` mismatches `authData` in attestation object.
   1915         let mut bad_auth = [0; 113];
   1916         bad_auth.copy_from_slice(&att_obj[att_obj.len() - 113..]);
   1917         bad_auth[113 - 32..].copy_from_slice([0; 32].as_slice());
   1918         err = Error::invalid_value(
   1919             Unexpected::Bytes(bad_auth.as_slice()),
   1920             &format!("authenticator data to match the authenticator data portion of attestation object: {:?}", &att_obj[att_obj.len() - bad_auth.len()..]).as_str(),
   1921         )
   1922         .to_string().into_bytes();
   1923         assert_eq!(
   1924             serde_json::from_str::<Registration>(
   1925                 serde_json::json!({
   1926                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   1927                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   1928                     "response": {
   1929                         "clientDataJSON": b64_cdata,
   1930                         "authenticatorData": base64url_nopad::encode(bad_auth.as_slice()),
   1931                         "transports": [],
   1932                         "publicKey": b64_key,
   1933                         "publicKeyAlgorithm": -8,
   1934                         "attestationObject": b64_aobj,
   1935                     },
   1936                     "clientExtensionResults": {},
   1937                     "type": "public-key"
   1938                 })
   1939                 .to_string()
   1940                 .as_str()
   1941             )
   1942             .unwrap_err()
   1943             .to_string()
   1944             .into_bytes()[..err.len()],
   1945             err
   1946         );
   1947         // Missing `authenticatorData`.
   1948         err = Error::missing_field("authenticatorData")
   1949             .to_string()
   1950             .into_bytes();
   1951         assert_eq!(
   1952             serde_json::from_str::<Registration>(
   1953                 serde_json::json!({
   1954                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   1955                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   1956                     "response": {
   1957                         "clientDataJSON": b64_cdata,
   1958                         "transports": [],
   1959                         "publicKey": b64_key,
   1960                         "publicKeyAlgorithm": -8,
   1961                         "attestationObject": b64_aobj,
   1962                     },
   1963                     "clientExtensionResults": {},
   1964                     "type": "public-key"
   1965                 })
   1966                 .to_string()
   1967                 .as_str()
   1968             )
   1969             .unwrap_err()
   1970             .to_string()
   1971             .into_bytes()[..err.len()],
   1972             err
   1973         );
   1974         // `null` `authenticatorData`.
   1975         err = Error::invalid_type(Unexpected::Other("null"), &"authenticatorData")
   1976             .to_string()
   1977             .into_bytes();
   1978         assert_eq!(
   1979             serde_json::from_str::<Registration>(
   1980                 serde_json::json!({
   1981                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   1982                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   1983                     "response": {
   1984                         "clientDataJSON": b64_cdata,
   1985                         "transports": [],
   1986                         "authenticatorData": null,
   1987                         "publicKey": b64_key,
   1988                         "publicKeyAlgorithm": -8,
   1989                         "attestationObject": b64_aobj,
   1990                     },
   1991                     "clientExtensionResults": {},
   1992                     "type": "public-key"
   1993                 })
   1994                 .to_string()
   1995                 .as_str()
   1996             )
   1997             .unwrap_err()
   1998             .to_string()
   1999             .into_bytes()[..err.len()],
   2000             err
   2001         );
   2002         // `publicKeyAlgorithm` mismatch.
   2003         err = Error::invalid_value(
   2004             Unexpected::Other(&format!("{:?}", CoseAlgorithmIdentifier::Es256).as_str()),
   2005             &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Eddsa).as_str()
   2006         )
   2007         .to_string().into_bytes();
   2008         assert_eq!(
   2009             serde_json::from_str::<Registration>(
   2010                 serde_json::json!({
   2011                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2012                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2013                     "response": {
   2014                         "clientDataJSON": b64_cdata,
   2015                         "authenticatorData": b64_adata,
   2016                         "transports": [],
   2017                         "publicKey": b64_key,
   2018                         "publicKeyAlgorithm": -7,
   2019                         "attestationObject": b64_aobj,
   2020                     },
   2021                     "clientExtensionResults": {},
   2022                     "type": "public-key"
   2023                 })
   2024                 .to_string()
   2025                 .as_str()
   2026             )
   2027             .unwrap_err()
   2028             .to_string()
   2029             .into_bytes()[..err.len()],
   2030             err
   2031         );
   2032         // Missing `publicKeyAlgorithm`.
   2033         err = Error::missing_field("publicKeyAlgorithm")
   2034             .to_string()
   2035             .into_bytes();
   2036         assert_eq!(
   2037             serde_json::from_str::<Registration>(
   2038                 serde_json::json!({
   2039                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2040                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2041                     "response": {
   2042                         "clientDataJSON": b64_cdata,
   2043                         "authenticatorData": b64_adata,
   2044                         "transports": [],
   2045                         "publicKey": b64_key,
   2046                         "attestationObject": b64_aobj,
   2047                     },
   2048                     "clientExtensionResults": {},
   2049                     "type": "public-key"
   2050                 })
   2051                 .to_string()
   2052                 .as_str()
   2053             )
   2054             .unwrap_err()
   2055             .to_string()
   2056             .into_bytes()[..err.len()],
   2057             err
   2058         );
   2059         // `null` `publicKeyAlgorithm`.
   2060         err = Error::invalid_type(Unexpected::Other("null"), &"publicKeyAlgorithm")
   2061             .to_string()
   2062             .into_bytes();
   2063         assert_eq!(
   2064             serde_json::from_str::<Registration>(
   2065                 serde_json::json!({
   2066                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2067                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2068                     "response": {
   2069                         "clientDataJSON": b64_cdata,
   2070                         "authenticatorData": b64_adata,
   2071                         "transports": [],
   2072                         "publicKey": b64_key,
   2073                         "publicKeyAlgorithm": null,
   2074                         "attestationObject": b64_aobj,
   2075                     },
   2076                     "clientExtensionResults": {},
   2077                     "type": "public-key"
   2078                 })
   2079                 .to_string()
   2080                 .as_str()
   2081             )
   2082             .unwrap_err()
   2083             .to_string()
   2084             .into_bytes()[..err.len()],
   2085             err
   2086         );
   2087         // `publicKey` mismatch.
   2088         err = Error::invalid_value(
   2089             Unexpected::Bytes([0; 32].as_slice()),
   2090             &format!(
   2091                 "DER-encoded public key to match the public key within the attestation object: Ed25519(Ed25519PubKey({:?}))",
   2092                 &att_obj[att_obj.len() - 32..],
   2093             )
   2094             .as_str(),
   2095         )
   2096         .to_string().into_bytes();
   2097         assert_eq!(serde_json::from_str::<Registration>(
   2098             serde_json::json!({
   2099                 "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2100                 "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2101                 "response": {
   2102                     "clientDataJSON": b64_cdata,
   2103                     "authenticatorData": b64_adata,
   2104                     "transports": [],
   2105                     "publicKey": base64url_nopad::encode(VerifyingKey::from_bytes(&[0; 32]).unwrap().to_public_key_der().unwrap().as_bytes()),
   2106                     "publicKeyAlgorithm": -8,
   2107                     "attestationObject": b64_aobj,
   2108                 },
   2109                 "clientExtensionResults": {},
   2110                 "type": "public-key"
   2111             })
   2112             .to_string()
   2113             .as_str()
   2114             )
   2115             .unwrap_err().to_string().into_bytes()[..err.len()],
   2116             err
   2117         );
   2118         // Missing `publicKey` when using EdDSA, ES256, or RS256.
   2119         err = Error::missing_field("publicKey").to_string().into_bytes();
   2120         assert_eq!(
   2121             serde_json::from_str::<Registration>(
   2122                 serde_json::json!({
   2123                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2124                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2125                     "response": {
   2126                         "clientDataJSON": b64_cdata,
   2127                         "authenticatorData": b64_adata,
   2128                         "transports": [],
   2129                         "publicKeyAlgorithm": -8,
   2130                         "attestationObject": b64_aobj,
   2131                     },
   2132                     "clientExtensionResults": {},
   2133                     "type": "public-key"
   2134                 })
   2135                 .to_string()
   2136                 .as_str()
   2137             )
   2138             .unwrap_err()
   2139             .to_string()
   2140             .into_bytes()[..err.len()],
   2141             err
   2142         );
   2143         // `null` `publicKey` when using EdDSA, ES256, or RS256.
   2144         err = Error::invalid_type(Unexpected::Other("null"), &"publicKey")
   2145             .to_string()
   2146             .into_bytes();
   2147         assert_eq!(
   2148             serde_json::from_str::<Registration>(
   2149                 serde_json::json!({
   2150                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2151                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2152                     "response": {
   2153                         "clientDataJSON": b64_cdata,
   2154                         "authenticatorData": b64_adata,
   2155                         "transports": [],
   2156                         "publicKey": null,
   2157                         "publicKeyAlgorithm": -8,
   2158                         "attestationObject": b64_aobj,
   2159                     },
   2160                     "clientExtensionResults": {},
   2161                     "type": "public-key"
   2162                 })
   2163                 .to_string()
   2164                 .as_str()
   2165             )
   2166             .unwrap_err()
   2167             .to_string()
   2168             .into_bytes()[..err.len()],
   2169             err
   2170         );
   2171         // Missing `transports`.
   2172         err = Error::missing_field("transports").to_string().into_bytes();
   2173         assert_eq!(
   2174             serde_json::from_str::<Registration>(
   2175                 serde_json::json!({
   2176                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2177                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2178                     "response": {
   2179                         "clientDataJSON": b64_cdata,
   2180                         "authenticatorData": b64_adata,
   2181                         "publicKey": b64_key,
   2182                         "publicKeyAlgorithm": -8,
   2183                         "attestationObject": b64_aobj,
   2184                     },
   2185                     "clientExtensionResults": {},
   2186                     "type": "public-key"
   2187                 })
   2188                 .to_string()
   2189                 .as_str()
   2190             )
   2191             .unwrap_err()
   2192             .to_string()
   2193             .into_bytes()[..err.len()],
   2194             err
   2195         );
   2196         // Duplicate `transports` are allowed.
   2197         assert!(
   2198             serde_json::from_str::<Registration>(
   2199                 serde_json::json!({
   2200                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2201                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2202                     "response": {
   2203                         "clientDataJSON": b64_cdata,
   2204                         "authenticatorData": b64_adata,
   2205                         "transports": ["usb", "usb"],
   2206                         "publicKey": b64_key,
   2207                         "publicKeyAlgorithm": -8,
   2208                         "attestationObject": b64_aobj,
   2209                     },
   2210                     "clientExtensionResults": {},
   2211                     "type": "public-key"
   2212                 })
   2213                 .to_string()
   2214                 .as_str()
   2215             )
   2216             .map_or(false, |reg| reg.response.transports.count() == 1)
   2217         );
   2218         // `null` `transports`.
   2219         err = Error::invalid_type(Unexpected::Other("null"), &"transports")
   2220             .to_string()
   2221             .into_bytes();
   2222         assert_eq!(
   2223             serde_json::from_str::<Registration>(
   2224                 serde_json::json!({
   2225                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2226                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2227                     "response": {
   2228                         "clientDataJSON": b64_cdata,
   2229                         "authenticatorData": b64_adata,
   2230                         "transports": null,
   2231                         "publicKey": b64_key,
   2232                         "publicKeyAlgorithm": -8,
   2233                         "attestationObject": b64_aobj,
   2234                     },
   2235                     "clientExtensionResults": {},
   2236                     "type": "public-key"
   2237                 })
   2238                 .to_string()
   2239                 .as_str()
   2240             )
   2241             .unwrap_err()
   2242             .to_string()
   2243             .into_bytes()[..err.len()],
   2244             err
   2245         );
   2246         // Unknown `transports`.
   2247         err = Error::invalid_value(
   2248             Unexpected::Str("Usb"),
   2249             &"'ble', 'cable', 'hybrid', 'internal', 'nfc', 'smart-card', or 'usb'",
   2250         )
   2251         .to_string()
   2252         .into_bytes();
   2253         assert_eq!(
   2254             serde_json::from_str::<Registration>(
   2255                 serde_json::json!({
   2256                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2257                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2258                     "response": {
   2259                         "clientDataJSON": b64_cdata,
   2260                         "authenticatorData": b64_adata,
   2261                         "transports": ["Usb"],
   2262                         "publicKey": b64_key,
   2263                         "publicKeyAlgorithm": -8,
   2264                         "attestationObject": b64_aobj,
   2265                     },
   2266                     "clientExtensionResults": {},
   2267                     "type": "public-key"
   2268                 })
   2269                 .to_string()
   2270                 .as_str()
   2271             )
   2272             .unwrap_err()
   2273             .to_string()
   2274             .into_bytes()[..err.len()],
   2275             err
   2276         );
   2277         // `null` `authenticatorAttachment`.
   2278         assert!(
   2279             serde_json::from_str::<Registration>(
   2280                 serde_json::json!({
   2281                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2282                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2283                     "response": {
   2284                         "clientDataJSON": b64_cdata,
   2285                         "authenticatorData": b64_adata,
   2286                         "transports": [],
   2287                         "publicKey": b64_key,
   2288                         "publicKeyAlgorithm": -8,
   2289                         "attestationObject": b64_aobj,
   2290                     },
   2291                     "authenticatorAttachment": null,
   2292                     "clientExtensionResults": {},
   2293                     "type": "public-key"
   2294                 })
   2295                 .to_string()
   2296                 .as_str()
   2297             )
   2298             .map_or(false, |reg| matches!(
   2299                 reg.authenticator_attachment,
   2300                 AuthenticatorAttachment::None
   2301             ))
   2302         );
   2303         // Unknown `authenticatorAttachment`.
   2304         err = Error::invalid_value(
   2305             Unexpected::Str("Platform"),
   2306             &"'platform' or 'cross-platform'",
   2307         )
   2308         .to_string()
   2309         .into_bytes();
   2310         assert_eq!(
   2311             serde_json::from_str::<Registration>(
   2312                 serde_json::json!({
   2313                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2314                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2315                     "response": {
   2316                         "clientDataJSON": b64_cdata,
   2317                         "authenticatorData": b64_adata,
   2318                         "transports": [],
   2319                         "publicKey": b64_key,
   2320                         "publicKeyAlgorithm": -8,
   2321                         "attestationObject": b64_aobj,
   2322                     },
   2323                     "authenticatorAttachment": "Platform",
   2324                     "clientExtensionResults": {},
   2325                     "type": "public-key"
   2326                 })
   2327                 .to_string()
   2328                 .as_str()
   2329             )
   2330             .unwrap_err()
   2331             .to_string()
   2332             .into_bytes()[..err.len()],
   2333             err
   2334         );
   2335         // Missing `clientDataJSON`.
   2336         err = Error::missing_field("clientDataJSON")
   2337             .to_string()
   2338             .into_bytes();
   2339         assert_eq!(
   2340             serde_json::from_str::<Registration>(
   2341                 serde_json::json!({
   2342                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2343                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2344                     "response": {
   2345                         "authenticatorData": b64_adata,
   2346                         "transports": [],
   2347                         "publicKey": b64_key,
   2348                         "publicKeyAlgorithm": -8,
   2349                         "attestationObject": b64_aobj,
   2350                     },
   2351                     "clientExtensionResults": {},
   2352                     "type": "public-key"
   2353                 })
   2354                 .to_string()
   2355                 .as_str()
   2356             )
   2357             .unwrap_err()
   2358             .to_string()
   2359             .into_bytes()[..err.len()],
   2360             err
   2361         );
   2362         // `null` `clientDataJSON`.
   2363         err = Error::invalid_type(Unexpected::Other("null"), &"base64url-encoded data")
   2364             .to_string()
   2365             .into_bytes();
   2366         assert_eq!(
   2367             serde_json::from_str::<Registration>(
   2368                 serde_json::json!({
   2369                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2370                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2371                     "response": {
   2372                         "clientDataJSON": null,
   2373                         "authenticatorData": b64_adata,
   2374                         "transports": [],
   2375                         "publicKey": b64_key,
   2376                         "publicKeyAlgorithm": -8,
   2377                         "attestationObject": b64_aobj,
   2378                     },
   2379                     "clientExtensionResults": {},
   2380                     "type": "public-key"
   2381                 })
   2382                 .to_string()
   2383                 .as_str()
   2384             )
   2385             .unwrap_err()
   2386             .to_string()
   2387             .into_bytes()[..err.len()],
   2388             err
   2389         );
   2390         // Missing `attestationObject`.
   2391         err = Error::missing_field("attestationObject")
   2392             .to_string()
   2393             .into_bytes();
   2394         assert_eq!(
   2395             serde_json::from_str::<Registration>(
   2396                 serde_json::json!({
   2397                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2398                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2399                     "response": {
   2400                         "clientDataJSON": b64_cdata,
   2401                         "authenticatorData": b64_adata,
   2402                         "transports": [],
   2403                         "publicKey": b64_key,
   2404                         "publicKeyAlgorithm": -8,
   2405                     },
   2406                     "clientExtensionResults": {},
   2407                     "type": "public-key"
   2408                 })
   2409                 .to_string()
   2410                 .as_str()
   2411             )
   2412             .unwrap_err()
   2413             .to_string()
   2414             .into_bytes()[..err.len()],
   2415             err
   2416         );
   2417         // `null` `attestationObject`.
   2418         err = Error::invalid_type(
   2419             Unexpected::Other("null"),
   2420             &"base64url-encoded attestation object",
   2421         )
   2422         .to_string()
   2423         .into_bytes();
   2424         assert_eq!(
   2425             serde_json::from_str::<Registration>(
   2426                 serde_json::json!({
   2427                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2428                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2429                     "response": {
   2430                         "clientDataJSON": b64_cdata,
   2431                         "authenticatorData": b64_adata,
   2432                         "transports": [],
   2433                         "publicKey": b64_key,
   2434                         "publicKeyAlgorithm": -8,
   2435                         "attestationObject": null,
   2436                     },
   2437                     "clientExtensionResults": {},
   2438                     "type": "public-key"
   2439                 })
   2440                 .to_string()
   2441                 .as_str()
   2442             )
   2443             .unwrap_err()
   2444             .to_string()
   2445             .into_bytes()[..err.len()],
   2446             err
   2447         );
   2448         // Missing `response`.
   2449         err = Error::missing_field("response").to_string().into_bytes();
   2450         assert_eq!(
   2451             serde_json::from_str::<Registration>(
   2452                 serde_json::json!({
   2453                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2454                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2455                     "clientExtensionResults": {},
   2456                     "type": "public-key"
   2457                 })
   2458                 .to_string()
   2459                 .as_str()
   2460             )
   2461             .unwrap_err()
   2462             .to_string()
   2463             .into_bytes()[..err.len()],
   2464             err
   2465         );
   2466         // `null` `response`.
   2467         err = Error::invalid_type(Unexpected::Other("null"), &"AuthenticatorAttestation")
   2468             .to_string()
   2469             .into_bytes();
   2470         assert_eq!(
   2471             serde_json::from_str::<Registration>(
   2472                 serde_json::json!({
   2473                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2474                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2475                     "response": null,
   2476                     "clientExtensionResults": {},
   2477                     "type": "public-key"
   2478                 })
   2479                 .to_string()
   2480                 .as_str()
   2481             )
   2482             .unwrap_err()
   2483             .to_string()
   2484             .into_bytes()[..err.len()],
   2485             err
   2486         );
   2487         // Empty `response`.
   2488         err = Error::missing_field("clientDataJSON")
   2489             .to_string()
   2490             .into_bytes();
   2491         assert_eq!(
   2492             serde_json::from_str::<Registration>(
   2493                 serde_json::json!({
   2494                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2495                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2496                     "response": {},
   2497                     "clientExtensionResults": {},
   2498                     "type": "public-key"
   2499                 })
   2500                 .to_string()
   2501                 .as_str()
   2502             )
   2503             .unwrap_err()
   2504             .to_string()
   2505             .into_bytes()[..err.len()],
   2506             err
   2507         );
   2508         // Missing `clientExtensionResults`.
   2509         err = Error::missing_field("clientExtensionResults")
   2510             .to_string()
   2511             .into_bytes();
   2512         assert_eq!(
   2513             serde_json::from_str::<Registration>(
   2514                 serde_json::json!({
   2515                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2516                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2517                     "response": {
   2518                         "clientDataJSON": b64_cdata,
   2519                         "authenticatorData": b64_adata,
   2520                         "transports": [],
   2521                         "publicKey": b64_key,
   2522                         "publicKeyAlgorithm": -8,
   2523                         "attestationObject": b64_aobj,
   2524                     },
   2525                     "type": "public-key"
   2526                 })
   2527                 .to_string()
   2528                 .as_str()
   2529             )
   2530             .unwrap_err()
   2531             .to_string()
   2532             .into_bytes()[..err.len()],
   2533             err
   2534         );
   2535         // `null` `clientExtensionResults`.
   2536         err = Error::invalid_type(
   2537             Unexpected::Other("null"),
   2538             &"clientExtensionResults to be a map of allowed client extensions",
   2539         )
   2540         .to_string()
   2541         .into_bytes();
   2542         assert_eq!(
   2543             serde_json::from_str::<Registration>(
   2544                 serde_json::json!({
   2545                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2546                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2547                     "response": {
   2548                         "clientDataJSON": b64_cdata,
   2549                         "authenticatorData": b64_adata,
   2550                         "transports": [],
   2551                         "publicKey": b64_key,
   2552                         "publicKeyAlgorithm": -8,
   2553                         "attestationObject": b64_aobj,
   2554                     },
   2555                     "clientExtensionResults": null,
   2556                     "type": "public-key"
   2557                 })
   2558                 .to_string()
   2559                 .as_str()
   2560             )
   2561             .unwrap_err()
   2562             .to_string()
   2563             .into_bytes()[..err.len()],
   2564             err
   2565         );
   2566         // Missing `type`.
   2567         err = Error::missing_field("type").to_string().into_bytes();
   2568         assert_eq!(
   2569             serde_json::from_str::<Registration>(
   2570                 serde_json::json!({
   2571                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2572                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2573                     "response": {
   2574                         "clientDataJSON": b64_cdata,
   2575                         "authenticatorData": b64_adata,
   2576                         "transports": [],
   2577                         "publicKey": b64_key,
   2578                         "publicKeyAlgorithm": -8,
   2579                         "attestationObject": b64_aobj,
   2580                     },
   2581                     "clientExtensionResults": {},
   2582                 })
   2583                 .to_string()
   2584                 .as_str()
   2585             )
   2586             .unwrap_err()
   2587             .to_string()
   2588             .into_bytes()[..err.len()],
   2589             err
   2590         );
   2591         // `null` `type`.
   2592         err = Error::invalid_type(Unexpected::Other("null"), &"public-key")
   2593             .to_string()
   2594             .into_bytes();
   2595         assert_eq!(
   2596             serde_json::from_str::<Registration>(
   2597                 serde_json::json!({
   2598                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2599                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2600                     "response": {
   2601                         "clientDataJSON": b64_cdata,
   2602                         "authenticatorData": b64_adata,
   2603                         "transports": [],
   2604                         "publicKey": b64_key,
   2605                         "publicKeyAlgorithm": -8,
   2606                         "attestationObject": b64_aobj,
   2607                     },
   2608                     "clientExtensionResults": {},
   2609                     "type": null
   2610                 })
   2611                 .to_string()
   2612                 .as_str()
   2613             )
   2614             .unwrap_err()
   2615             .to_string()
   2616             .into_bytes()[..err.len()],
   2617             err
   2618         );
   2619         // Not exactly `public-type` `type`.
   2620         err = Error::invalid_value(Unexpected::Str("Public-key"), &"public-key")
   2621             .to_string()
   2622             .into_bytes();
   2623         assert_eq!(
   2624             serde_json::from_str::<Registration>(
   2625                 serde_json::json!({
   2626                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2627                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2628                     "response": {
   2629                         "clientDataJSON": b64_cdata,
   2630                         "authenticatorData": b64_adata,
   2631                         "transports": [],
   2632                         "publicKey": b64_key,
   2633                         "publicKeyAlgorithm": -8,
   2634                         "attestationObject": b64_aobj,
   2635                     },
   2636                     "clientExtensionResults": {},
   2637                     "type": "Public-key"
   2638                 })
   2639                 .to_string()
   2640                 .as_str()
   2641             )
   2642             .unwrap_err()
   2643             .to_string()
   2644             .into_bytes()[..err.len()],
   2645             err
   2646         );
   2647         // `null`.
   2648         err = Error::invalid_type(Unexpected::Other("null"), &"PublicKeyCredential")
   2649             .to_string()
   2650             .into_bytes();
   2651         assert_eq!(
   2652             serde_json::from_str::<Registration>(serde_json::json!(null).to_string().as_str())
   2653                 .unwrap_err()
   2654                 .to_string()
   2655                 .into_bytes()[..err.len()],
   2656             err
   2657         );
   2658         // Empty.
   2659         err = Error::missing_field("response").to_string().into_bytes();
   2660         assert_eq!(
   2661             serde_json::from_str::<Registration>(serde_json::json!({}).to_string().as_str())
   2662                 .unwrap_err()
   2663                 .to_string()
   2664                 .into_bytes()[..err.len()],
   2665             err
   2666         );
   2667         // Unknown field in `response`.
   2668         err = Error::unknown_field(
   2669             "foo",
   2670             [
   2671                 "clientDataJSON",
   2672                 "attestationObject",
   2673                 "authenticatorData",
   2674                 "transports",
   2675                 "publicKey",
   2676                 "publicKeyAlgorithm",
   2677             ]
   2678             .as_slice(),
   2679         )
   2680         .to_string()
   2681         .into_bytes();
   2682         assert_eq!(
   2683             serde_json::from_str::<Registration>(
   2684                 serde_json::json!({
   2685                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2686                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2687                     "response": {
   2688                         "clientDataJSON": b64_cdata,
   2689                         "authenticatorData": b64_adata,
   2690                         "transports": [],
   2691                         "publicKey": b64_key,
   2692                         "publicKeyAlgorithm": -8,
   2693                         "attestationObject": b64_aobj,
   2694                         "foo": true,
   2695                     },
   2696                     "clientExtensionResults": {},
   2697                     "type": "public-key"
   2698                 })
   2699                 .to_string()
   2700                 .as_str()
   2701             )
   2702             .unwrap_err()
   2703             .to_string()
   2704             .into_bytes()[..err.len()],
   2705             err
   2706         );
   2707         // Duplicate field in `response`.
   2708         err = Error::duplicate_field("transports")
   2709             .to_string()
   2710             .into_bytes();
   2711         assert_eq!(
   2712             serde_json::from_str::<Registration>(
   2713                 format!(
   2714                     "{{
   2715                        \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\",
   2716                        \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\",
   2717                        \"response\": {{
   2718                            \"clientDataJSON\": \"{b64_cdata}\",
   2719                            \"authenticatorData\": \"{b64_adata}\",
   2720                            \"transports\": [],
   2721                            \"publicKey\": \"{b64_key}\",
   2722                            \"publicKeyAlgorithm\": -8,
   2723                            \"attestationObject\": \"{b64_aobj}\",
   2724                            \"transports\": []
   2725                        }},
   2726                        \"clientExtensionResults\": {{}},
   2727                        \"type\": \"public-key\"
   2728                             
   2729                      }}"
   2730                 )
   2731                 .as_str()
   2732             )
   2733             .unwrap_err()
   2734             .to_string()
   2735             .into_bytes()[..err.len()],
   2736             err
   2737         );
   2738         // Unknown field in `PublicKeyCredential`.
   2739         err = Error::unknown_field(
   2740             "foo",
   2741             [
   2742                 "id",
   2743                 "type",
   2744                 "rawId",
   2745                 "response",
   2746                 "authenticatorAttachment",
   2747                 "clientExtensionResults",
   2748             ]
   2749             .as_slice(),
   2750         )
   2751         .to_string()
   2752         .into_bytes();
   2753         assert_eq!(
   2754             serde_json::from_str::<Registration>(
   2755                 serde_json::json!({
   2756                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2757                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2758                     "response": {
   2759                         "clientDataJSON": b64_cdata,
   2760                         "authenticatorData": b64_adata,
   2761                         "transports": [],
   2762                         "publicKey": b64_key,
   2763                         "publicKeyAlgorithm": -8,
   2764                         "attestationObject": b64_aobj
   2765                     },
   2766                     "clientExtensionResults": {},
   2767                     "type": "public-key",
   2768                     "foo": true,
   2769                 })
   2770                 .to_string()
   2771                 .as_str()
   2772             )
   2773             .unwrap_err()
   2774             .to_string()
   2775             .into_bytes()[..err.len()],
   2776             err
   2777         );
   2778         // Duplicate field in `PublicKeyCredential`.
   2779         err = Error::duplicate_field("id").to_string().into_bytes();
   2780         assert_eq!(
   2781             serde_json::from_str::<Registration>(
   2782                 format!(
   2783                     "{{
   2784                        \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\",
   2785                        \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\",
   2786                        \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\",
   2787                        \"response\": {{
   2788                            \"clientDataJSON\": \"{b64_cdata}\",
   2789                            \"authenticatorData\": \"{b64_adata}\",
   2790                            \"transports\": [],
   2791                            \"publicKey\": \"{b64_key}\",
   2792                            \"publicKeyAlgorithm\": -8,
   2793                            \"attestationObject\": \"{b64_aobj}\"
   2794                        }},
   2795                        \"clientExtensionResults\": {{}},
   2796                        \"type\": \"public-key\"
   2797                             
   2798                      }}"
   2799                 )
   2800                 .as_str()
   2801             )
   2802             .unwrap_err()
   2803             .to_string()
   2804             .into_bytes()[..err.len()],
   2805             err
   2806         );
   2807     }
   2808     #[test]
   2809     fn client_extensions() {
   2810         let c_data_json = serde_json::json!({}).to_string();
   2811         let att_obj = [
   2812             cbor::MAP_3,
   2813             cbor::TEXT_3,
   2814             b'f',
   2815             b'm',
   2816             b't',
   2817             cbor::TEXT_4,
   2818             b'n',
   2819             b'o',
   2820             b'n',
   2821             b'e',
   2822             cbor::TEXT_7,
   2823             b'a',
   2824             b't',
   2825             b't',
   2826             b'S',
   2827             b't',
   2828             b'm',
   2829             b't',
   2830             cbor::MAP_0,
   2831             cbor::TEXT_8,
   2832             b'a',
   2833             b'u',
   2834             b't',
   2835             b'h',
   2836             b'D',
   2837             b'a',
   2838             b't',
   2839             b'a',
   2840             cbor::BYTES_INFO_24,
   2841             113,
   2842             // `rpIdHash`.
   2843             0,
   2844             0,
   2845             0,
   2846             0,
   2847             0,
   2848             0,
   2849             0,
   2850             0,
   2851             0,
   2852             0,
   2853             0,
   2854             0,
   2855             0,
   2856             0,
   2857             0,
   2858             0,
   2859             0,
   2860             0,
   2861             0,
   2862             0,
   2863             0,
   2864             0,
   2865             0,
   2866             0,
   2867             0,
   2868             0,
   2869             0,
   2870             0,
   2871             0,
   2872             0,
   2873             0,
   2874             0,
   2875             // `flags`.
   2876             0b0100_0101,
   2877             // `signCount`.
   2878             0,
   2879             0,
   2880             0,
   2881             0,
   2882             // `aaguid`.
   2883             0,
   2884             0,
   2885             0,
   2886             0,
   2887             0,
   2888             0,
   2889             0,
   2890             0,
   2891             0,
   2892             0,
   2893             0,
   2894             0,
   2895             0,
   2896             0,
   2897             0,
   2898             0,
   2899             // `credentialIdLength`.
   2900             0,
   2901             16,
   2902             // `credentialId`.
   2903             0,
   2904             0,
   2905             0,
   2906             0,
   2907             0,
   2908             0,
   2909             0,
   2910             0,
   2911             0,
   2912             0,
   2913             0,
   2914             0,
   2915             0,
   2916             0,
   2917             0,
   2918             0,
   2919             // Ed25519 COSE key.
   2920             cbor::MAP_4,
   2921             KTY,
   2922             OKP,
   2923             ALG,
   2924             EDDSA,
   2925             // `crv`.
   2926             cbor::NEG_ONE,
   2927             // `Ed25519`.
   2928             cbor::SIX,
   2929             // `x`.
   2930             cbor::NEG_TWO,
   2931             cbor::BYTES_INFO_24,
   2932             32,
   2933             // Compressed y-coordinate.
   2934             1,
   2935             1,
   2936             1,
   2937             1,
   2938             1,
   2939             1,
   2940             1,
   2941             1,
   2942             1,
   2943             1,
   2944             1,
   2945             1,
   2946             1,
   2947             1,
   2948             1,
   2949             1,
   2950             1,
   2951             1,
   2952             1,
   2953             1,
   2954             1,
   2955             1,
   2956             1,
   2957             1,
   2958             1,
   2959             1,
   2960             1,
   2961             1,
   2962             1,
   2963             1,
   2964             1,
   2965             1,
   2966         ];
   2967         let pub_key = VerifyingKey::from_bytes(&[1; 32])
   2968             .unwrap()
   2969             .to_public_key_der()
   2970             .unwrap();
   2971         let b64_cdata = base64url_nopad::encode(c_data_json.as_bytes());
   2972         let b64_adata = base64url_nopad::encode(&att_obj[att_obj.len() - 113..]);
   2973         let b64_key = base64url_nopad::encode(pub_key.as_bytes());
   2974         let b64_aobj = base64url_nopad::encode(att_obj.as_slice());
   2975         // Base case is valid.
   2976         assert!(
   2977             serde_json::from_str::<Registration>(
   2978                 serde_json::json!({
   2979                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   2980                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   2981                     "response": {
   2982                         "clientDataJSON": b64_cdata,
   2983                         "authenticatorData": b64_adata,
   2984                         "transports": [],
   2985                         "publicKey": b64_key,
   2986                         "publicKeyAlgorithm": -8,
   2987                         "attestationObject": b64_aobj,
   2988                     },
   2989                     "clientExtensionResults": {},
   2990                     "type": "public-key"
   2991                 })
   2992                 .to_string()
   2993                 .as_str()
   2994             )
   2995             .map_or(false, |reg| reg.response.client_data_json
   2996                 == c_data_json.as_bytes()
   2997                 && reg.response.attestation_object_and_c_data_hash[..att_obj.len()]
   2998                     == att_obj
   2999                 && reg.response.attestation_object_and_c_data_hash[att_obj.len()..]
   3000                     == *Sha256::digest(c_data_json.as_bytes()).as_slice()
   3001                 && reg.response.transports.is_empty()
   3002                 && matches!(reg.authenticator_attachment, AuthenticatorAttachment::None)
   3003                 && reg.client_extension_results.cred_props.is_none()
   3004                 && reg.client_extension_results.prf.is_none())
   3005         );
   3006         // `null` `credProps`.
   3007         assert!(
   3008             serde_json::from_str::<Registration>(
   3009                 serde_json::json!({
   3010                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3011                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3012                     "response": {
   3013                         "clientDataJSON": b64_cdata,
   3014                         "authenticatorData": b64_adata,
   3015                         "transports": [],
   3016                         "publicKey": b64_key,
   3017                         "publicKeyAlgorithm": -8,
   3018                         "attestationObject": b64_aobj,
   3019                     },
   3020                     "clientExtensionResults": {
   3021                         "credProps": null
   3022                     },
   3023                     "type": "public-key"
   3024                 })
   3025                 .to_string()
   3026                 .as_str()
   3027             )
   3028             .map_or(false, |reg| reg
   3029                 .client_extension_results
   3030                 .cred_props
   3031                 .is_none()
   3032                 && reg.client_extension_results.prf.is_none())
   3033         );
   3034         // `null` `prf`.
   3035         assert!(
   3036             serde_json::from_str::<Registration>(
   3037                 serde_json::json!({
   3038                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3039                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3040                     "response": {
   3041                         "clientDataJSON": b64_cdata,
   3042                         "authenticatorData": b64_adata,
   3043                         "transports": [],
   3044                         "publicKey": b64_key,
   3045                         "publicKeyAlgorithm": -8,
   3046                         "attestationObject": b64_aobj,
   3047                     },
   3048                     "clientExtensionResults": {
   3049                         "prf": null
   3050                     },
   3051                     "type": "public-key"
   3052                 })
   3053                 .to_string()
   3054                 .as_str()
   3055             )
   3056             .map_or(false, |reg| reg
   3057                 .client_extension_results
   3058                 .cred_props
   3059                 .is_none()
   3060                 && reg.client_extension_results.prf.is_none())
   3061         );
   3062         // Unknown `clientExtensionResults`.
   3063         let mut err = Error::unknown_field("CredProps", ["credProps", "prf"].as_slice())
   3064             .to_string()
   3065             .into_bytes();
   3066         assert_eq!(
   3067             serde_json::from_str::<Registration>(
   3068                 serde_json::json!({
   3069                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3070                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3071                     "response": {
   3072                         "clientDataJSON": b64_cdata,
   3073                         "authenticatorData": b64_adata,
   3074                         "transports": [],
   3075                         "publicKey": b64_key,
   3076                         "publicKeyAlgorithm": -8,
   3077                         "attestationObject": b64_aobj,
   3078                     },
   3079                     "clientExtensionResults": {
   3080                         "CredProps": {
   3081                             "rk": true
   3082                         }
   3083                     },
   3084                     "type": "public-key"
   3085                 })
   3086                 .to_string()
   3087                 .as_str()
   3088             )
   3089             .unwrap_err()
   3090             .to_string()
   3091             .into_bytes()[..err.len()],
   3092             err
   3093         );
   3094         // Duplicate field.
   3095         err = Error::duplicate_field("credProps").to_string().into_bytes();
   3096         assert_eq!(
   3097             serde_json::from_str::<Registration>(
   3098                 format!(
   3099                     "{{
   3100                        \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\",
   3101                        \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\",
   3102                        \"response\": {{
   3103                            \"clientDataJSON\": \"{b64_cdata}\",
   3104                            \"authenticatorData\": \"{b64_adata}\",
   3105                            \"transports\": [],
   3106                            \"publicKey\": \"{b64_key}\",
   3107                            \"publicKeyAlgorithm\": -8,
   3108                            \"attestationObject\": \"{b64_aobj}\"
   3109                        }},
   3110                        \"clientExtensionResults\": {{
   3111                            \"credProps\": null,
   3112                            \"credProps\": null
   3113                        }},
   3114                        \"type\": \"public-key\"
   3115                      }}"
   3116                 )
   3117                 .as_str()
   3118             )
   3119             .unwrap_err()
   3120             .to_string()
   3121             .into_bytes()[..err.len()],
   3122             err
   3123         );
   3124         // `null` `rk`.
   3125         assert!(
   3126             serde_json::from_str::<Registration>(
   3127                 serde_json::json!({
   3128                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3129                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3130                     "response": {
   3131                         "clientDataJSON": b64_cdata,
   3132                         "authenticatorData": b64_adata,
   3133                         "transports": [],
   3134                         "publicKey": b64_key,
   3135                         "publicKeyAlgorithm": -8,
   3136                         "attestationObject": b64_aobj,
   3137                     },
   3138                     "clientExtensionResults": {
   3139                         "credProps": {
   3140                             "rk": null
   3141                         }
   3142                     },
   3143                     "type": "public-key"
   3144                 })
   3145                 .to_string()
   3146                 .as_str()
   3147             )
   3148             .map_or(false, |reg| reg
   3149                 .client_extension_results
   3150                 .cred_props
   3151                 .map_or(false, |props| props.rk.is_none())
   3152                 && reg.client_extension_results.prf.is_none())
   3153         );
   3154         // Missing `rk`.
   3155         assert!(
   3156             serde_json::from_str::<Registration>(
   3157                 serde_json::json!({
   3158                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3159                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3160                     "response": {
   3161                         "clientDataJSON": b64_cdata,
   3162                         "authenticatorData": b64_adata,
   3163                         "transports": [],
   3164                         "publicKey": b64_key,
   3165                         "publicKeyAlgorithm": -8,
   3166                         "attestationObject": b64_aobj,
   3167                     },
   3168                     "clientExtensionResults": {
   3169                         "credProps": {}
   3170                     },
   3171                     "type": "public-key"
   3172                 })
   3173                 .to_string()
   3174                 .as_str()
   3175             )
   3176             .map_or(false, |reg| reg
   3177                 .client_extension_results
   3178                 .cred_props
   3179                 .map_or(false, |props| props.rk.is_none())
   3180                 && reg.client_extension_results.prf.is_none())
   3181         );
   3182         // `true` rk`.
   3183         assert!(
   3184             serde_json::from_str::<Registration>(
   3185                 serde_json::json!({
   3186                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3187                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3188                     "response": {
   3189                         "clientDataJSON": b64_cdata,
   3190                         "authenticatorData": b64_adata,
   3191                         "transports": [],
   3192                         "publicKey": b64_key,
   3193                         "publicKeyAlgorithm": -8,
   3194                         "attestationObject": b64_aobj,
   3195                     },
   3196                     "clientExtensionResults": {
   3197                         "credProps": {
   3198                             "rk": true
   3199                         }
   3200                     },
   3201                     "type": "public-key"
   3202                 })
   3203                 .to_string()
   3204                 .as_str()
   3205             )
   3206             .map_or(false, |reg| reg
   3207                 .client_extension_results
   3208                 .cred_props
   3209                 .map_or(false, |props| props.rk.unwrap_or_default())
   3210                 && reg.client_extension_results.prf.is_none())
   3211         );
   3212         // `false` rk`.
   3213         assert!(
   3214             serde_json::from_str::<Registration>(
   3215                 serde_json::json!({
   3216                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3217                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3218                     "response": {
   3219                         "clientDataJSON": b64_cdata,
   3220                         "authenticatorData": b64_adata,
   3221                         "transports": [],
   3222                         "publicKey": b64_key,
   3223                         "publicKeyAlgorithm": -8,
   3224                         "attestationObject": b64_aobj,
   3225                     },
   3226                     "clientExtensionResults": {
   3227                         "credProps": {
   3228                             "rk": false
   3229                         }
   3230                     },
   3231                     "type": "public-key"
   3232                 })
   3233                 .to_string()
   3234                 .as_str()
   3235             )
   3236             .map_or(false, |reg| reg
   3237                 .client_extension_results
   3238                 .cred_props
   3239                 .map_or(false, |props| props.rk.map_or(false, |rk| !rk))
   3240                 && reg.client_extension_results.prf.is_none())
   3241         );
   3242         // Invalid `rk`.
   3243         err = Error::invalid_type(Unexpected::Unsigned(3), &"a boolean")
   3244             .to_string()
   3245             .into_bytes();
   3246         assert_eq!(
   3247             serde_json::from_str::<Registration>(
   3248                 serde_json::json!({
   3249                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3250                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3251                     "response": {
   3252                         "clientDataJSON": b64_cdata,
   3253                         "authenticatorData": b64_adata,
   3254                         "transports": [],
   3255                         "publicKey": b64_key,
   3256                         "publicKeyAlgorithm": -8,
   3257                         "attestationObject": b64_aobj,
   3258                     },
   3259                     "clientExtensionResults": {
   3260                         "credProps": {
   3261                             "rk": 3
   3262                         }
   3263                     },
   3264                     "type": "public-key"
   3265                 })
   3266                 .to_string()
   3267                 .as_str()
   3268             )
   3269             .unwrap_err()
   3270             .to_string()
   3271             .into_bytes()[..err.len()],
   3272             err
   3273         );
   3274         // Unknown `credProps` field.
   3275         err = Error::unknown_field("Rk", ["rk"].as_slice())
   3276             .to_string()
   3277             .into_bytes();
   3278         assert_eq!(
   3279             serde_json::from_str::<Registration>(
   3280                 serde_json::json!({
   3281                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3282                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3283                     "response": {
   3284                         "clientDataJSON": b64_cdata,
   3285                         "authenticatorData": b64_adata,
   3286                         "transports": [],
   3287                         "publicKey": b64_key,
   3288                         "publicKeyAlgorithm": -8,
   3289                         "attestationObject": b64_aobj,
   3290                     },
   3291                     "clientExtensionResults": {
   3292                         "credProps": {
   3293                             "Rk": true,
   3294                         }
   3295                     },
   3296                     "type": "public-key"
   3297                 })
   3298                 .to_string()
   3299                 .as_str()
   3300             )
   3301             .unwrap_err()
   3302             .to_string()
   3303             .into_bytes()[..err.len()],
   3304             err
   3305         );
   3306         // Duplicate field in `credProps`.
   3307         err = Error::duplicate_field("rk").to_string().into_bytes();
   3308         assert_eq!(
   3309             serde_json::from_str::<Registration>(
   3310                 format!(
   3311                     "{{
   3312                        \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\",
   3313                        \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\",
   3314                        \"response\": {{
   3315                            \"clientDataJSON\": \"{b64_cdata}\",
   3316                            \"authenticatorData\": \"{b64_adata}\",
   3317                            \"transports\": [],
   3318                            \"publicKey\": \"{b64_key}\",
   3319                            \"publicKeyAlgorithm\": -8,
   3320                            \"attestationObject\": \"{b64_aobj}\"
   3321                        }},
   3322                        \"clientExtensionResults\": {{
   3323                            \"credProps\": {{
   3324                                \"rk\": true,
   3325                                \"rk\": true
   3326                            }}
   3327                        }},
   3328                        \"type\": \"public-key\"
   3329                      }}"
   3330                 )
   3331                 .as_str()
   3332             )
   3333             .unwrap_err()
   3334             .to_string()
   3335             .into_bytes()[..err.len()],
   3336             err
   3337         );
   3338         // `null` `enabled`.
   3339         err = Error::invalid_type(Unexpected::Other("null"), &"a boolean")
   3340             .to_string()
   3341             .into_bytes();
   3342         assert_eq!(
   3343             serde_json::from_str::<Registration>(
   3344                 serde_json::json!({
   3345                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3346                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3347                     "response": {
   3348                         "clientDataJSON": b64_cdata,
   3349                         "authenticatorData": b64_adata,
   3350                         "transports": [],
   3351                         "publicKey": b64_key,
   3352                         "publicKeyAlgorithm": -8,
   3353                         "attestationObject": b64_aobj,
   3354                     },
   3355                     "clientExtensionResults": {
   3356                         "prf": {
   3357                             "enabled": null
   3358                         }
   3359                     },
   3360                     "type": "public-key"
   3361                 })
   3362                 .to_string()
   3363                 .as_str()
   3364             )
   3365             .unwrap_err()
   3366             .to_string()
   3367             .into_bytes()[..err.len()],
   3368             err
   3369         );
   3370         // Missing `enabled`.
   3371         err = Error::missing_field("enabled").to_string().into_bytes();
   3372         assert_eq!(
   3373             serde_json::from_str::<Registration>(
   3374                 serde_json::json!({
   3375                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3376                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3377                     "response": {
   3378                         "clientDataJSON": b64_cdata,
   3379                         "authenticatorData": b64_adata,
   3380                         "transports": [],
   3381                         "publicKey": b64_key,
   3382                         "publicKeyAlgorithm": -8,
   3383                         "attestationObject": b64_aobj,
   3384                     },
   3385                     "clientExtensionResults": {
   3386                         "prf": {}
   3387                     },
   3388                     "type": "public-key"
   3389                 })
   3390                 .to_string()
   3391                 .as_str()
   3392             )
   3393             .unwrap_err()
   3394             .to_string()
   3395             .into_bytes()[..err.len()],
   3396             err
   3397         );
   3398         // `true` `enabled`.
   3399         assert!(
   3400             serde_json::from_str::<Registration>(
   3401                 serde_json::json!({
   3402                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3403                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3404                     "response": {
   3405                         "clientDataJSON": b64_cdata,
   3406                         "authenticatorData": b64_adata,
   3407                         "transports": [],
   3408                         "publicKey": b64_key,
   3409                         "publicKeyAlgorithm": -8,
   3410                         "attestationObject": b64_aobj,
   3411                     },
   3412                     "clientExtensionResults": {
   3413                         "prf": {
   3414                             "enabled": true
   3415                         }
   3416                     },
   3417                     "type": "public-key"
   3418                 })
   3419                 .to_string()
   3420                 .as_str()
   3421             )
   3422             .map_or(false, |reg| reg
   3423                 .client_extension_results
   3424                 .cred_props
   3425                 .is_none()
   3426                 && reg
   3427                     .client_extension_results
   3428                     .prf
   3429                     .map_or(false, |prf| prf.enabled))
   3430         );
   3431         // `false` `enabled`.
   3432         assert!(
   3433             serde_json::from_str::<Registration>(
   3434                 serde_json::json!({
   3435                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3436                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3437                     "response": {
   3438                         "clientDataJSON": b64_cdata,
   3439                         "authenticatorData": b64_adata,
   3440                         "transports": [],
   3441                         "publicKey": b64_key,
   3442                         "publicKeyAlgorithm": -8,
   3443                         "attestationObject": b64_aobj,
   3444                     },
   3445                     "clientExtensionResults": {
   3446                         "prf": {
   3447                             "enabled": false,
   3448                         }
   3449                     },
   3450                     "type": "public-key"
   3451                 })
   3452                 .to_string()
   3453                 .as_str()
   3454             )
   3455             .map_or(false, |reg| reg
   3456                 .client_extension_results
   3457                 .cred_props
   3458                 .is_none()
   3459                 && reg
   3460                     .client_extension_results
   3461                     .prf
   3462                     .map_or(false, |prf| !prf.enabled))
   3463         );
   3464         // Invalid `enabled`.
   3465         err = Error::invalid_type(Unexpected::Unsigned(3), &"a boolean")
   3466             .to_string()
   3467             .into_bytes();
   3468         assert_eq!(
   3469             serde_json::from_str::<Registration>(
   3470                 serde_json::json!({
   3471                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3472                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3473                     "response": {
   3474                         "clientDataJSON": b64_cdata,
   3475                         "authenticatorData": b64_adata,
   3476                         "transports": [],
   3477                         "publicKey": b64_key,
   3478                         "publicKeyAlgorithm": -8,
   3479                         "attestationObject": b64_aobj,
   3480                     },
   3481                     "clientExtensionResults": {
   3482                         "prf": {
   3483                             "enabled": 3
   3484                         }
   3485                     },
   3486                     "type": "public-key"
   3487                 })
   3488                 .to_string()
   3489                 .as_str()
   3490             )
   3491             .unwrap_err()
   3492             .to_string()
   3493             .into_bytes()[..err.len()],
   3494             err
   3495         );
   3496         // `null` `results` with `enabled` `true`.
   3497         assert!(
   3498             serde_json::from_str::<Registration>(
   3499                 serde_json::json!({
   3500                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3501                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3502                     "response": {
   3503                         "clientDataJSON": b64_cdata,
   3504                         "authenticatorData": b64_adata,
   3505                         "transports": [],
   3506                         "publicKey": b64_key,
   3507                         "publicKeyAlgorithm": -8,
   3508                         "attestationObject": b64_aobj,
   3509                     },
   3510                     "clientExtensionResults": {
   3511                         "prf": {
   3512                             "enabled": true,
   3513                             "results": null,
   3514                         }
   3515                     },
   3516                     "type": "public-key"
   3517                 })
   3518                 .to_string()
   3519                 .as_str()
   3520             )
   3521             .map_or(false, |reg| reg
   3522                 .client_extension_results
   3523                 .cred_props
   3524                 .is_none()
   3525                 && reg
   3526                     .client_extension_results
   3527                     .prf
   3528                     .map_or(false, |prf| prf.enabled))
   3529         );
   3530         // `null` `results` with `enabled` `false`.
   3531         err = Error::custom(
   3532             "prf must not have 'results', including a null 'results', if 'enabled' is false",
   3533         )
   3534         .to_string()
   3535         .into_bytes();
   3536         assert_eq!(
   3537             serde_json::from_str::<Registration>(
   3538                 serde_json::json!({
   3539                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3540                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3541                     "response": {
   3542                         "clientDataJSON": b64_cdata,
   3543                         "authenticatorData": b64_adata,
   3544                         "transports": [],
   3545                         "publicKey": b64_key,
   3546                         "publicKeyAlgorithm": -8,
   3547                         "attestationObject": b64_aobj,
   3548                     },
   3549                     "clientExtensionResults": {
   3550                         "prf": {
   3551                             "enabled": false,
   3552                             "results": null
   3553                         }
   3554                     },
   3555                     "type": "public-key"
   3556                 })
   3557                 .to_string()
   3558                 .as_str()
   3559             )
   3560             .unwrap_err()
   3561             .to_string()
   3562             .into_bytes()[..err.len()],
   3563             err
   3564         );
   3565         // Duplicate field in `prf`.
   3566         err = Error::duplicate_field("enabled").to_string().into_bytes();
   3567         assert_eq!(
   3568             serde_json::from_str::<Registration>(
   3569                 format!(
   3570                     "{{
   3571                        \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\",
   3572                        \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\",
   3573                        \"response\": {{
   3574                            \"clientDataJSON\": \"{b64_cdata}\",
   3575                            \"authenticatorData\": \"{b64_adata}\",
   3576                            \"transports\": [],
   3577                            \"publicKey\": \"{b64_key}\",
   3578                            \"publicKeyAlgorithm\": -8,
   3579                            \"attestationObject\": \"{b64_aobj}\"
   3580                        }},
   3581                        \"clientExtensionResults\": {{
   3582                            \"prf\": {{
   3583                                \"enabled\": true,
   3584                                \"enabled\": true
   3585                            }}
   3586                        }},
   3587                        \"type\": \"public-key\"
   3588                      }}"
   3589                 )
   3590                 .as_str()
   3591             )
   3592             .unwrap_err()
   3593             .to_string()
   3594             .into_bytes()[..err.len()],
   3595             err
   3596         );
   3597         // Missing `first`.
   3598         err = Error::missing_field("first").to_string().into_bytes();
   3599         assert_eq!(
   3600             serde_json::from_str::<Registration>(
   3601                 serde_json::json!({
   3602                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3603                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3604                     "response": {
   3605                         "clientDataJSON": b64_cdata,
   3606                         "authenticatorData": b64_adata,
   3607                         "transports": [],
   3608                         "publicKey": b64_key,
   3609                         "publicKeyAlgorithm": -8,
   3610                         "attestationObject": b64_aobj,
   3611                     },
   3612                     "clientExtensionResults": {
   3613                         "prf": {
   3614                             "enabled": true,
   3615                             "results": {},
   3616                         }
   3617                     },
   3618                     "type": "public-key"
   3619                 })
   3620                 .to_string()
   3621                 .as_str()
   3622             )
   3623             .unwrap_err()
   3624             .to_string()
   3625             .into_bytes()[..err.len()],
   3626             err
   3627         );
   3628         // `null` `first`.
   3629         assert!(
   3630             serde_json::from_str::<Registration>(
   3631                 serde_json::json!({
   3632                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3633                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3634                     "response": {
   3635                         "clientDataJSON": b64_cdata,
   3636                         "authenticatorData": b64_adata,
   3637                         "transports": [],
   3638                         "publicKey": b64_key,
   3639                         "publicKeyAlgorithm": -8,
   3640                         "attestationObject": b64_aobj,
   3641                     },
   3642                     "clientExtensionResults": {
   3643                         "prf": {
   3644                             "enabled": true,
   3645                             "results": {
   3646                                 "first": null
   3647                             },
   3648                         }
   3649                     },
   3650                     "type": "public-key"
   3651                 })
   3652                 .to_string()
   3653                 .as_str()
   3654             )
   3655             .map_or(false, |reg| reg
   3656                 .client_extension_results
   3657                 .cred_props
   3658                 .is_none()
   3659                 && reg
   3660                     .client_extension_results
   3661                     .prf
   3662                     .map_or(false, |prf| prf.enabled))
   3663         );
   3664         // `null` `second`.
   3665         assert!(
   3666             serde_json::from_str::<Registration>(
   3667                 serde_json::json!({
   3668                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3669                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3670                     "response": {
   3671                         "clientDataJSON": b64_cdata,
   3672                         "authenticatorData": b64_adata,
   3673                         "transports": [],
   3674                         "publicKey": b64_key,
   3675                         "publicKeyAlgorithm": -8,
   3676                         "attestationObject": b64_aobj,
   3677                     },
   3678                     "clientExtensionResults": {
   3679                         "prf": {
   3680                             "enabled": true,
   3681                             "results": {
   3682                                 "first": null,
   3683                                 "second": null
   3684                             },
   3685                         }
   3686                     },
   3687                     "type": "public-key"
   3688                 })
   3689                 .to_string()
   3690                 .as_str()
   3691             )
   3692             .map_or(false, |reg| reg
   3693                 .client_extension_results
   3694                 .cred_props
   3695                 .is_none()
   3696                 && reg
   3697                     .client_extension_results
   3698                     .prf
   3699                     .map_or(false, |prf| prf.enabled))
   3700         );
   3701         // Non-`null` `first`.
   3702         err = Error::invalid_type(Unexpected::Option, &"null")
   3703             .to_string()
   3704             .into_bytes();
   3705         assert_eq!(
   3706             serde_json::from_str::<Registration>(
   3707                 serde_json::json!({
   3708                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3709                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3710                     "response": {
   3711                         "clientDataJSON": b64_cdata,
   3712                         "authenticatorData": b64_adata,
   3713                         "transports": [],
   3714                         "publicKey": b64_key,
   3715                         "publicKeyAlgorithm": -8,
   3716                         "attestationObject": b64_aobj,
   3717                     },
   3718                     "clientExtensionResults": {
   3719                         "prf": {
   3720                             "enabled": true,
   3721                             "results": {
   3722                                 "first": ""
   3723                             },
   3724                         }
   3725                     },
   3726                     "type": "public-key"
   3727                 })
   3728                 .to_string()
   3729                 .as_str()
   3730             )
   3731             .unwrap_err()
   3732             .to_string()
   3733             .into_bytes()[..err.len()],
   3734             err
   3735         );
   3736         // Non-`null` `second`.
   3737         err = Error::invalid_type(Unexpected::Option, &"null")
   3738             .to_string()
   3739             .into_bytes();
   3740         assert_eq!(
   3741             serde_json::from_str::<Registration>(
   3742                 serde_json::json!({
   3743                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3744                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3745                     "response": {
   3746                         "clientDataJSON": b64_cdata,
   3747                         "authenticatorData": b64_adata,
   3748                         "transports": [],
   3749                         "publicKey": b64_key,
   3750                         "publicKeyAlgorithm": -8,
   3751                         "attestationObject": b64_aobj,
   3752                     },
   3753                     "clientExtensionResults": {
   3754                         "prf": {
   3755                             "enabled": true,
   3756                             "results": {
   3757                                 "first": null,
   3758                                 "second": ""
   3759                             },
   3760                         }
   3761                     },
   3762                     "type": "public-key"
   3763                 })
   3764                 .to_string()
   3765                 .as_str()
   3766             )
   3767             .unwrap_err()
   3768             .to_string()
   3769             .into_bytes()[..err.len()],
   3770             err
   3771         );
   3772         // Unknown `prf` field.
   3773         err = Error::unknown_field("Results", ["enabled", "results"].as_slice())
   3774             .to_string()
   3775             .into_bytes();
   3776         assert_eq!(
   3777             serde_json::from_str::<Registration>(
   3778                 serde_json::json!({
   3779                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3780                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3781                     "response": {
   3782                         "clientDataJSON": b64_cdata,
   3783                         "authenticatorData": b64_adata,
   3784                         "transports": [],
   3785                         "publicKey": b64_key,
   3786                         "publicKeyAlgorithm": -8,
   3787                         "attestationObject": b64_aobj,
   3788                     },
   3789                     "clientExtensionResults": {
   3790                         "prf": {
   3791                             "enabled": true,
   3792                             "Results": null
   3793                         }
   3794                     },
   3795                     "type": "public-key"
   3796                 })
   3797                 .to_string()
   3798                 .as_str()
   3799             )
   3800             .unwrap_err()
   3801             .to_string()
   3802             .into_bytes()[..err.len()],
   3803             err
   3804         );
   3805         // Unknown `results` field.
   3806         err = Error::unknown_field("Second", ["first", "second"].as_slice())
   3807             .to_string()
   3808             .into_bytes();
   3809         assert_eq!(
   3810             serde_json::from_str::<Registration>(
   3811                 serde_json::json!({
   3812                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   3813                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   3814                     "response": {
   3815                         "clientDataJSON": b64_cdata,
   3816                         "authenticatorData": b64_adata,
   3817                         "transports": [],
   3818                         "publicKey": b64_key,
   3819                         "publicKeyAlgorithm": -8,
   3820                         "attestationObject": b64_aobj,
   3821                     },
   3822                     "clientExtensionResults": {
   3823                         "prf": {
   3824                             "enabled": true,
   3825                             "results": {
   3826                                 "first": null,
   3827                                 "Second": null
   3828                             }
   3829                         }
   3830                     },
   3831                     "type": "public-key"
   3832                 })
   3833                 .to_string()
   3834                 .as_str()
   3835             )
   3836             .unwrap_err()
   3837             .to_string()
   3838             .into_bytes()[..err.len()],
   3839             err
   3840         );
   3841         // Duplicate field in `results`.
   3842         err = Error::duplicate_field("first").to_string().into_bytes();
   3843         assert_eq!(
   3844             serde_json::from_str::<Registration>(
   3845                 format!(
   3846                     "{{
   3847                        \"id\": \"AAAAAAAAAAAAAAAAAAAAAA\",
   3848                        \"rawId\": \"AAAAAAAAAAAAAAAAAAAAAA\",
   3849                        \"response\": {{
   3850                            \"clientDataJSON\": \"{b64_cdata}\",
   3851                            \"authenticatorData\": \"{b64_adata}\",
   3852                            \"transports\": [],
   3853                            \"publicKey\": \"{b64_key}\",
   3854                            \"publicKeyAlgorithm\": -8,
   3855                            \"attestationObject\": \"{b64_aobj}\"
   3856                        }},
   3857                        \"clientExtensionResults\": {{
   3858                            \"prf\": {{
   3859                                \"enabled\": true,
   3860                                \"results\": {{
   3861                                    \"first\": null,
   3862                                    \"first\": null
   3863                                }}
   3864                            }}
   3865                        }},
   3866                        \"type\": \"public-key\"
   3867                      }}"
   3868                 )
   3869                 .as_str()
   3870             )
   3871             .unwrap_err()
   3872             .to_string()
   3873             .into_bytes()[..err.len()],
   3874             err
   3875         );
   3876     }
   3877     #[test]
   3878     fn es256_registration_deserialize_data_mismatch() {
   3879         let c_data_json = serde_json::json!({}).to_string();
   3880         let mut att_obj = [
   3881             cbor::MAP_3,
   3882             cbor::TEXT_3,
   3883             b'f',
   3884             b'm',
   3885             b't',
   3886             cbor::TEXT_4,
   3887             b'n',
   3888             b'o',
   3889             b'n',
   3890             b'e',
   3891             cbor::TEXT_7,
   3892             b'a',
   3893             b't',
   3894             b't',
   3895             b'S',
   3896             b't',
   3897             b'm',
   3898             b't',
   3899             cbor::MAP_0,
   3900             cbor::TEXT_8,
   3901             b'a',
   3902             b'u',
   3903             b't',
   3904             b'h',
   3905             b'D',
   3906             b'a',
   3907             b't',
   3908             b'a',
   3909             cbor::BYTES_INFO_24,
   3910             148,
   3911             // `rpIdHash`.
   3912             0,
   3913             0,
   3914             0,
   3915             0,
   3916             0,
   3917             0,
   3918             0,
   3919             0,
   3920             0,
   3921             0,
   3922             0,
   3923             0,
   3924             0,
   3925             0,
   3926             0,
   3927             0,
   3928             0,
   3929             0,
   3930             0,
   3931             0,
   3932             0,
   3933             0,
   3934             0,
   3935             0,
   3936             0,
   3937             0,
   3938             0,
   3939             0,
   3940             0,
   3941             0,
   3942             0,
   3943             0,
   3944             // `flags`.
   3945             0b0100_0101,
   3946             // `signCount`.
   3947             0,
   3948             0,
   3949             0,
   3950             0,
   3951             // `aaguid`.
   3952             0,
   3953             0,
   3954             0,
   3955             0,
   3956             0,
   3957             0,
   3958             0,
   3959             0,
   3960             0,
   3961             0,
   3962             0,
   3963             0,
   3964             0,
   3965             0,
   3966             0,
   3967             0,
   3968             // `credentialIdLength`.
   3969             0,
   3970             16,
   3971             // `credentialId`.
   3972             0,
   3973             0,
   3974             0,
   3975             0,
   3976             0,
   3977             0,
   3978             0,
   3979             0,
   3980             0,
   3981             0,
   3982             0,
   3983             0,
   3984             0,
   3985             0,
   3986             0,
   3987             0,
   3988             // P-256 COSE key.
   3989             cbor::MAP_5,
   3990             KTY,
   3991             EC2,
   3992             ALG,
   3993             ES256,
   3994             // `crv`.
   3995             cbor::NEG_ONE,
   3996             // `P-256`.
   3997             cbor::ONE,
   3998             // `x`.
   3999             cbor::NEG_TWO,
   4000             cbor::BYTES_INFO_24,
   4001             32,
   4002             // x-coordinate. This will be overwritten later.
   4003             0,
   4004             0,
   4005             0,
   4006             0,
   4007             0,
   4008             0,
   4009             0,
   4010             0,
   4011             0,
   4012             0,
   4013             0,
   4014             0,
   4015             0,
   4016             0,
   4017             0,
   4018             0,
   4019             0,
   4020             0,
   4021             0,
   4022             0,
   4023             0,
   4024             0,
   4025             0,
   4026             0,
   4027             0,
   4028             0,
   4029             0,
   4030             0,
   4031             0,
   4032             0,
   4033             0,
   4034             0,
   4035             // `y`.
   4036             cbor::NEG_THREE,
   4037             cbor::BYTES_INFO_24,
   4038             32,
   4039             // y-coordinate. This will be overwritten later.
   4040             0,
   4041             0,
   4042             0,
   4043             0,
   4044             0,
   4045             0,
   4046             0,
   4047             0,
   4048             0,
   4049             0,
   4050             0,
   4051             0,
   4052             0,
   4053             0,
   4054             0,
   4055             0,
   4056             0,
   4057             0,
   4058             0,
   4059             0,
   4060             0,
   4061             0,
   4062             0,
   4063             0,
   4064             0,
   4065             0,
   4066             0,
   4067             0,
   4068             0,
   4069             0,
   4070             0,
   4071             0,
   4072         ];
   4073         let key = P256Key::from_bytes(
   4074             &[
   4075                 137, 133, 36, 206, 163, 47, 255, 5, 76, 144, 163, 141, 40, 109, 108, 240, 246, 115,
   4076                 178, 237, 169, 68, 6, 129, 92, 21, 238, 127, 55, 158, 207, 95,
   4077             ]
   4078             .into(),
   4079         )
   4080         .unwrap()
   4081         .public_key();
   4082         let enc_key = key.to_encoded_point(false);
   4083         let pub_key = key.to_public_key_der().unwrap();
   4084         let att_obj_len = att_obj.len();
   4085         att_obj[att_obj_len - 67..att_obj_len - 35]
   4086             .copy_from_slice(enc_key.x().unwrap().as_slice());
   4087         att_obj[att_obj_len - 32..].copy_from_slice(enc_key.y().unwrap().as_slice());
   4088         let b64_cdata = base64url_nopad::encode(c_data_json.as_bytes());
   4089         let b64_adata = base64url_nopad::encode(&att_obj[att_obj.len() - 148..]);
   4090         let b64_key = base64url_nopad::encode(pub_key.as_bytes());
   4091         let b64_aobj = base64url_nopad::encode(att_obj.as_slice());
   4092         // Base case is valid.
   4093         assert!(
   4094             serde_json::from_str::<Registration>(
   4095                 serde_json::json!({
   4096                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   4097                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   4098                     "response": {
   4099                         "clientDataJSON": b64_cdata,
   4100                         "authenticatorData": b64_adata,
   4101                         "transports": [],
   4102                         "publicKey": b64_key,
   4103                         "publicKeyAlgorithm": -7,
   4104                         "attestationObject": b64_aobj,
   4105                     },
   4106                     "clientExtensionResults": {},
   4107                     "type": "public-key"
   4108                 })
   4109                 .to_string()
   4110                 .as_str()
   4111             )
   4112             .map_or(false, |reg| reg.response.client_data_json
   4113                 == c_data_json.as_bytes()
   4114                 && reg.response.attestation_object_and_c_data_hash[..att_obj.len()]
   4115                     == att_obj
   4116                 && reg.response.attestation_object_and_c_data_hash[att_obj.len()..]
   4117                     == *Sha256::digest(c_data_json.as_bytes()).as_slice()
   4118                 && reg.response.transports.is_empty()
   4119                 && matches!(reg.authenticator_attachment, AuthenticatorAttachment::None)
   4120                 && reg.client_extension_results.cred_props.is_none()
   4121                 && reg.client_extension_results.prf.is_none())
   4122         );
   4123         // `publicKeyAlgorithm` mismatch.
   4124         let mut err = Error::invalid_value(
   4125             Unexpected::Other(&format!("{:?}", CoseAlgorithmIdentifier::Eddsa).as_str()),
   4126             &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Es256).as_str()
   4127         )
   4128         .to_string().into_bytes();
   4129         assert_eq!(
   4130             serde_json::from_str::<Registration>(
   4131                 serde_json::json!({
   4132                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   4133                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   4134                     "response": {
   4135                         "clientDataJSON": b64_cdata,
   4136                         "authenticatorData": b64_adata,
   4137                         "transports": [],
   4138                         "publicKey": b64_key,
   4139                         "publicKeyAlgorithm": -8,
   4140                         "attestationObject": b64_aobj,
   4141                     },
   4142                     "clientExtensionResults": {},
   4143                     "type": "public-key"
   4144                 })
   4145                 .to_string()
   4146                 .as_str()
   4147             )
   4148             .unwrap_err()
   4149             .to_string()
   4150             .into_bytes()[..err.len()],
   4151             err
   4152         );
   4153         // Missing `publicKeyAlgorithm`.
   4154         err = Error::missing_field("publicKeyAlgorithm")
   4155             .to_string()
   4156             .into_bytes();
   4157         assert_eq!(
   4158             serde_json::from_str::<Registration>(
   4159                 serde_json::json!({
   4160                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   4161                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   4162                     "response": {
   4163                         "clientDataJSON": b64_cdata,
   4164                         "authenticatorData": b64_adata,
   4165                         "transports": [],
   4166                         "publicKey": b64_key,
   4167                         "attestationObject": b64_aobj,
   4168                     },
   4169                     "clientExtensionResults": {},
   4170                     "type": "public-key"
   4171                 })
   4172                 .to_string()
   4173                 .as_str()
   4174             )
   4175             .unwrap_err()
   4176             .to_string()
   4177             .into_bytes()[..err.len()],
   4178             err
   4179         );
   4180         // `null` `publicKeyAlgorithm`.
   4181         err = Error::invalid_type(Unexpected::Other("null"), &"publicKeyAlgorithm")
   4182             .to_string()
   4183             .into_bytes();
   4184         assert_eq!(
   4185             serde_json::from_str::<Registration>(
   4186                 serde_json::json!({
   4187                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   4188                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   4189                     "response": {
   4190                         "clientDataJSON": b64_cdata,
   4191                         "authenticatorData": b64_adata,
   4192                         "transports": [],
   4193                         "publicKey": b64_key,
   4194                         "publicKeyAlgorithm": null,
   4195                         "attestationObject": b64_aobj,
   4196                     },
   4197                     "clientExtensionResults": {},
   4198                     "type": "public-key"
   4199                 })
   4200                 .to_string()
   4201                 .as_str()
   4202             )
   4203             .unwrap_err()
   4204             .to_string()
   4205             .into_bytes()[..err.len()],
   4206             err
   4207         );
   4208         // `publicKey` mismatch.
   4209         let bad_pub_key = P256PubKey::from_encoded_point(&P256Pt::from_affine_coordinates(
   4210             &[
   4211                 66, 71, 188, 41, 125, 2, 226, 44, 148, 62, 63, 190, 172, 64, 33, 214, 6, 37, 148,
   4212                 23, 240, 235, 203, 84, 112, 219, 232, 197, 54, 182, 17, 235,
   4213             ]
   4214             .into(),
   4215             &[
   4216                 22, 172, 123, 13, 170, 242, 217, 248, 193, 209, 206, 163, 92, 4, 162, 168, 113, 63,
   4217                 2, 117, 16, 223, 239, 196, 109, 179, 10, 130, 43, 213, 205, 92,
   4218             ]
   4219             .into(),
   4220             false,
   4221         ))
   4222         .unwrap();
   4223         err = Error::invalid_value(
   4224             Unexpected::Bytes([0; 32].as_slice()),
   4225             &format!(
   4226                 "DER-encoded public key to match the public key within the attestation object: P256(UncompressedP256PubKey({:?}, {:?}))",
   4227                 &att_obj[att_obj.len() - 67..att_obj.len() - 35],
   4228                 &att_obj[att_obj.len() - 32..],
   4229             )
   4230             .as_str(),
   4231         )
   4232         .to_string().into_bytes();
   4233         assert_eq!(serde_json::from_str::<Registration>(
   4234             serde_json::json!({
   4235                 "id": "AAAAAAAAAAAAAAAAAAAAAA",
   4236                 "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   4237                 "response": {
   4238                     "clientDataJSON": b64_cdata,
   4239                     "authenticatorData": b64_adata,
   4240                     "transports": [],
   4241                     "publicKey": base64url_nopad::encode(bad_pub_key.to_public_key_der().unwrap().as_bytes()),
   4242                     "publicKeyAlgorithm": -7,
   4243                     "attestationObject": b64_aobj,
   4244                 },
   4245                 "clientExtensionResults": {},
   4246                 "type": "public-key"
   4247             })
   4248             .to_string()
   4249             .as_str()
   4250             )
   4251             .unwrap_err().to_string().into_bytes()[..err.len()],
   4252             err
   4253         );
   4254         // Missing `publicKey` when using EdDSA, ES256, or RS256.
   4255         err = Error::missing_field("publicKey").to_string().into_bytes();
   4256         assert_eq!(
   4257             serde_json::from_str::<Registration>(
   4258                 serde_json::json!({
   4259                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   4260                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   4261                     "response": {
   4262                         "clientDataJSON": b64_cdata,
   4263                         "authenticatorData": b64_adata,
   4264                         "transports": [],
   4265                         "publicKeyAlgorithm": -7,
   4266                         "attestationObject": b64_aobj,
   4267                     },
   4268                     "clientExtensionResults": {},
   4269                     "type": "public-key"
   4270                 })
   4271                 .to_string()
   4272                 .as_str()
   4273             )
   4274             .unwrap_err()
   4275             .to_string()
   4276             .into_bytes()[..err.len()],
   4277             err
   4278         );
   4279         // `null` `publicKey` when using EdDSA, ES256, or RS256.
   4280         err = Error::invalid_type(Unexpected::Other("null"), &"publicKey")
   4281             .to_string()
   4282             .into_bytes();
   4283         assert_eq!(
   4284             serde_json::from_str::<Registration>(
   4285                 serde_json::json!({
   4286                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   4287                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   4288                     "response": {
   4289                         "clientDataJSON": b64_cdata,
   4290                         "authenticatorData": b64_adata,
   4291                         "transports": [],
   4292                         "publicKey": null,
   4293                         "publicKeyAlgorithm": -7,
   4294                         "attestationObject": b64_aobj,
   4295                     },
   4296                     "clientExtensionResults": {},
   4297                     "type": "public-key"
   4298                 })
   4299                 .to_string()
   4300                 .as_str()
   4301             )
   4302             .unwrap_err()
   4303             .to_string()
   4304             .into_bytes()[..err.len()],
   4305             err
   4306         );
   4307     }
   4308     #[test]
   4309     fn es384_registration_deserialize_data_mismatch() {
   4310         let c_data_json = serde_json::json!({}).to_string();
   4311         let mut att_obj = [
   4312             cbor::MAP_3,
   4313             cbor::TEXT_3,
   4314             b'f',
   4315             b'm',
   4316             b't',
   4317             cbor::TEXT_4,
   4318             b'n',
   4319             b'o',
   4320             b'n',
   4321             b'e',
   4322             cbor::TEXT_7,
   4323             b'a',
   4324             b't',
   4325             b't',
   4326             b'S',
   4327             b't',
   4328             b'm',
   4329             b't',
   4330             cbor::MAP_0,
   4331             cbor::TEXT_8,
   4332             b'a',
   4333             b'u',
   4334             b't',
   4335             b'h',
   4336             b'D',
   4337             b'a',
   4338             b't',
   4339             b'a',
   4340             cbor::BYTES_INFO_24,
   4341             181,
   4342             // `rpIdHash`.
   4343             0,
   4344             0,
   4345             0,
   4346             0,
   4347             0,
   4348             0,
   4349             0,
   4350             0,
   4351             0,
   4352             0,
   4353             0,
   4354             0,
   4355             0,
   4356             0,
   4357             0,
   4358             0,
   4359             0,
   4360             0,
   4361             0,
   4362             0,
   4363             0,
   4364             0,
   4365             0,
   4366             0,
   4367             0,
   4368             0,
   4369             0,
   4370             0,
   4371             0,
   4372             0,
   4373             0,
   4374             0,
   4375             // `flags`.
   4376             0b0100_0101,
   4377             // `signCount`.
   4378             0,
   4379             0,
   4380             0,
   4381             0,
   4382             // `aaguid`.
   4383             0,
   4384             0,
   4385             0,
   4386             0,
   4387             0,
   4388             0,
   4389             0,
   4390             0,
   4391             0,
   4392             0,
   4393             0,
   4394             0,
   4395             0,
   4396             0,
   4397             0,
   4398             0,
   4399             // `credentialIdLength`.
   4400             0,
   4401             16,
   4402             // `credentialId`.
   4403             0,
   4404             0,
   4405             0,
   4406             0,
   4407             0,
   4408             0,
   4409             0,
   4410             0,
   4411             0,
   4412             0,
   4413             0,
   4414             0,
   4415             0,
   4416             0,
   4417             0,
   4418             0,
   4419             // P-384 COSE key.
   4420             cbor::MAP_5,
   4421             KTY,
   4422             EC2,
   4423             ALG,
   4424             cbor::NEG_INFO_24,
   4425             ES384,
   4426             // `crv`.
   4427             cbor::NEG_ONE,
   4428             // `P-384`.
   4429             cbor::TWO,
   4430             // `x`.
   4431             cbor::NEG_TWO,
   4432             cbor::BYTES_INFO_24,
   4433             48,
   4434             // x-coordinate. This will be overwritten later.
   4435             0,
   4436             0,
   4437             0,
   4438             0,
   4439             0,
   4440             0,
   4441             0,
   4442             0,
   4443             0,
   4444             0,
   4445             0,
   4446             0,
   4447             0,
   4448             0,
   4449             0,
   4450             0,
   4451             0,
   4452             0,
   4453             0,
   4454             0,
   4455             0,
   4456             0,
   4457             0,
   4458             0,
   4459             0,
   4460             0,
   4461             0,
   4462             0,
   4463             0,
   4464             0,
   4465             0,
   4466             0,
   4467             0,
   4468             0,
   4469             0,
   4470             0,
   4471             0,
   4472             0,
   4473             0,
   4474             0,
   4475             0,
   4476             0,
   4477             0,
   4478             0,
   4479             0,
   4480             0,
   4481             0,
   4482             0,
   4483             // `y`.
   4484             cbor::NEG_THREE,
   4485             cbor::BYTES_INFO_24,
   4486             48,
   4487             // y-coordinate. This will be overwritten later.
   4488             0,
   4489             0,
   4490             0,
   4491             0,
   4492             0,
   4493             0,
   4494             0,
   4495             0,
   4496             0,
   4497             0,
   4498             0,
   4499             0,
   4500             0,
   4501             0,
   4502             0,
   4503             0,
   4504             0,
   4505             0,
   4506             0,
   4507             0,
   4508             0,
   4509             0,
   4510             0,
   4511             0,
   4512             0,
   4513             0,
   4514             0,
   4515             0,
   4516             0,
   4517             0,
   4518             0,
   4519             0,
   4520             0,
   4521             0,
   4522             0,
   4523             0,
   4524             0,
   4525             0,
   4526             0,
   4527             0,
   4528             0,
   4529             0,
   4530             0,
   4531             0,
   4532             0,
   4533             0,
   4534             0,
   4535             0,
   4536         ];
   4537         let key = P384Key::from_bytes(
   4538             &[
   4539                 158, 99, 156, 49, 190, 211, 85, 167, 28, 2, 80, 57, 31, 22, 17, 38, 85, 78, 232,
   4540                 42, 45, 199, 154, 243, 136, 251, 84, 34, 5, 120, 208, 91, 61, 248, 64, 144, 87, 1,
   4541                 32, 86, 220, 68, 182, 11, 105, 223, 75, 70,
   4542             ]
   4543             .into(),
   4544         )
   4545         .unwrap()
   4546         .public_key();
   4547         let enc_key = key.to_encoded_point(false);
   4548         let pub_key = key.to_public_key_der().unwrap();
   4549         let att_obj_len = att_obj.len();
   4550         att_obj[att_obj_len - 99..att_obj_len - 51]
   4551             .copy_from_slice(enc_key.x().unwrap().as_slice());
   4552         att_obj[att_obj_len - 48..].copy_from_slice(enc_key.y().unwrap().as_slice());
   4553         let b64_cdata = base64url_nopad::encode(c_data_json.as_bytes());
   4554         let b64_adata = base64url_nopad::encode(&att_obj[att_obj.len() - 181..]);
   4555         let b64_key = base64url_nopad::encode(pub_key.as_bytes());
   4556         let b64_aobj = base64url_nopad::encode(att_obj.as_slice());
   4557         // Base case is valid.
   4558         assert!(
   4559             serde_json::from_str::<Registration>(
   4560                 serde_json::json!({
   4561                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   4562                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   4563                     "response": {
   4564                         "clientDataJSON": b64_cdata,
   4565                         "authenticatorData": b64_adata,
   4566                         "transports": [],
   4567                         "publicKey": b64_key,
   4568                         "publicKeyAlgorithm": -35,
   4569                         "attestationObject": b64_aobj,
   4570                     },
   4571                     "clientExtensionResults": {},
   4572                     "type": "public-key"
   4573                 })
   4574                 .to_string()
   4575                 .as_str()
   4576             )
   4577             .map_or(false, |reg| reg.response.client_data_json
   4578                 == c_data_json.as_bytes()
   4579                 && reg.response.attestation_object_and_c_data_hash[..att_obj.len()]
   4580                     == att_obj
   4581                 && reg.response.attestation_object_and_c_data_hash[att_obj.len()..]
   4582                     == *Sha256::digest(c_data_json.as_bytes()).as_slice()
   4583                 && reg.response.transports.is_empty()
   4584                 && matches!(reg.authenticator_attachment, AuthenticatorAttachment::None)
   4585                 && reg.client_extension_results.cred_props.is_none()
   4586                 && reg.client_extension_results.prf.is_none())
   4587         );
   4588         // `publicKeyAlgorithm` mismatch.
   4589         let mut err = Error::invalid_value(
   4590             Unexpected::Other(&format!("{:?}", CoseAlgorithmIdentifier::Es256).as_str()),
   4591             &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Es384).as_str()
   4592         )
   4593         .to_string().into_bytes();
   4594         assert_eq!(
   4595             serde_json::from_str::<Registration>(
   4596                 serde_json::json!({
   4597                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   4598                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   4599                     "response": {
   4600                         "clientDataJSON": b64_cdata,
   4601                         "authenticatorData": b64_adata,
   4602                         "transports": [],
   4603                         "publicKey": b64_key,
   4604                         "publicKeyAlgorithm": -7,
   4605                         "attestationObject": b64_aobj,
   4606                     },
   4607                     "clientExtensionResults": {},
   4608                     "type": "public-key"
   4609                 })
   4610                 .to_string()
   4611                 .as_str()
   4612             )
   4613             .unwrap_err()
   4614             .to_string()
   4615             .into_bytes()[..err.len()],
   4616             err
   4617         );
   4618         // Missing `publicKeyAlgorithm`.
   4619         err = Error::missing_field("publicKeyAlgorithm")
   4620             .to_string()
   4621             .into_bytes();
   4622         assert_eq!(
   4623             serde_json::from_str::<Registration>(
   4624                 serde_json::json!({
   4625                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   4626                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   4627                     "response": {
   4628                         "clientDataJSON": b64_cdata,
   4629                         "authenticatorData": b64_adata,
   4630                         "transports": [],
   4631                         "publicKey": b64_key,
   4632                         "attestationObject": b64_aobj,
   4633                     },
   4634                     "clientExtensionResults": {},
   4635                     "type": "public-key"
   4636                 })
   4637                 .to_string()
   4638                 .as_str()
   4639             )
   4640             .unwrap_err()
   4641             .to_string()
   4642             .into_bytes()[..err.len()],
   4643             err
   4644         );
   4645         // `null` `publicKeyAlgorithm`.
   4646         err = Error::invalid_type(Unexpected::Other("null"), &"publicKeyAlgorithm")
   4647             .to_string()
   4648             .into_bytes();
   4649         assert_eq!(
   4650             serde_json::from_str::<Registration>(
   4651                 serde_json::json!({
   4652                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   4653                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   4654                     "response": {
   4655                         "clientDataJSON": b64_cdata,
   4656                         "authenticatorData": b64_adata,
   4657                         "transports": [],
   4658                         "publicKey": b64_key,
   4659                         "publicKeyAlgorithm": null,
   4660                         "attestationObject": b64_aobj,
   4661                     },
   4662                     "clientExtensionResults": {},
   4663                     "type": "public-key"
   4664                 })
   4665                 .to_string()
   4666                 .as_str()
   4667             )
   4668             .unwrap_err()
   4669             .to_string()
   4670             .into_bytes()[..err.len()],
   4671             err
   4672         );
   4673         // `publicKey` mismatch.
   4674         let bad_pub_key = P384PubKey::from_encoded_point(&P384Pt::from_affine_coordinates(
   4675             &[
   4676                 192, 10, 27, 46, 66, 67, 80, 98, 33, 230, 156, 95, 1, 135, 150, 110, 64, 243, 22,
   4677                 118, 5, 255, 107, 44, 234, 111, 217, 105, 125, 114, 39, 7, 126, 2, 191, 111, 48,
   4678                 93, 234, 175, 18, 172, 59, 28, 97, 106, 178, 152,
   4679             ]
   4680             .into(),
   4681             &[
   4682                 57, 36, 196, 12, 109, 129, 253, 115, 88, 154, 6, 43, 195, 85, 169, 5, 230, 51, 28,
   4683                 205, 142, 28, 150, 35, 24, 222, 170, 253, 14, 248, 84, 151, 109, 191, 152, 111,
   4684                 222, 70, 134, 247, 109, 171, 211, 33, 214, 217, 200, 111,
   4685             ]
   4686             .into(),
   4687             false,
   4688         ))
   4689         .unwrap();
   4690         err = Error::invalid_value(
   4691             Unexpected::Bytes([0; 32].as_slice()),
   4692             &format!(
   4693                 "DER-encoded public key to match the public key within the attestation object: P384(UncompressedP384PubKey({:?}, {:?}))",
   4694                 &att_obj[att_obj.len() - 99..att_obj.len() - 51],
   4695                 &att_obj[att_obj.len() - 48..],
   4696             )
   4697             .as_str(),
   4698         )
   4699         .to_string().into_bytes();
   4700         assert_eq!(serde_json::from_str::<Registration>(
   4701             serde_json::json!({
   4702                 "id": "AAAAAAAAAAAAAAAAAAAAAA",
   4703                 "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   4704                 "response": {
   4705                     "clientDataJSON": b64_cdata,
   4706                     "authenticatorData": b64_adata,
   4707                     "transports": [],
   4708                     "publicKey": base64url_nopad::encode(bad_pub_key.to_public_key_der().unwrap().as_bytes()),
   4709                     "publicKeyAlgorithm": -35,
   4710                     "attestationObject": b64_aobj,
   4711                 },
   4712                 "clientExtensionResults": {},
   4713                 "type": "public-key"
   4714             })
   4715             .to_string()
   4716             .as_str()
   4717             )
   4718             .unwrap_err().to_string().into_bytes()[..err.len()],
   4719             err
   4720         );
   4721         // Missing `publicKey` is allowed when not using EdDSA, ES256, or RS256.
   4722         assert!(
   4723             serde_json::from_str::<Registration>(
   4724                 serde_json::json!({
   4725                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   4726                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   4727                     "response": {
   4728                         "clientDataJSON": b64_cdata,
   4729                         "authenticatorData": b64_adata,
   4730                         "transports": [],
   4731                         "publicKeyAlgorithm": -35,
   4732                         "attestationObject": b64_aobj,
   4733                     },
   4734                     "clientExtensionResults": {},
   4735                     "type": "public-key"
   4736                 })
   4737                 .to_string()
   4738                 .as_str()
   4739             )
   4740             .is_ok()
   4741         );
   4742         // `publicKeyAlgorithm` mismatch when `publicKey` does not exist.
   4743         err = Error::invalid_value(
   4744             Unexpected::Other(&format!("{:?}", CoseAlgorithmIdentifier::Es256).as_str()),
   4745             &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Es384).as_str()
   4746         )
   4747         .to_string().into_bytes();
   4748         assert_eq!(
   4749             serde_json::from_str::<Registration>(
   4750                 serde_json::json!({
   4751                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   4752                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   4753                     "response": {
   4754                         "clientDataJSON": b64_cdata,
   4755                         "authenticatorData": b64_adata,
   4756                         "transports": [],
   4757                         "publicKeyAlgorithm": -7,
   4758                         "attestationObject": b64_aobj,
   4759                     },
   4760                     "clientExtensionResults": {},
   4761                     "type": "public-key"
   4762                 })
   4763                 .to_string()
   4764                 .as_str()
   4765             )
   4766             .unwrap_err()
   4767             .to_string()
   4768             .into_bytes()[..err.len()],
   4769             err
   4770         );
   4771         // `null` `publicKey` is allowed when not using EdDSA, ES256, or RS256.
   4772         assert!(
   4773             serde_json::from_str::<Registration>(
   4774                 serde_json::json!({
   4775                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   4776                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   4777                     "response": {
   4778                         "clientDataJSON": b64_cdata,
   4779                         "authenticatorData": b64_adata,
   4780                         "transports": [],
   4781                         "publicKey": null,
   4782                         "publicKeyAlgorithm": -35,
   4783                         "attestationObject": b64_aobj,
   4784                     },
   4785                     "clientExtensionResults": {},
   4786                     "type": "public-key"
   4787                 })
   4788                 .to_string()
   4789                 .as_str()
   4790             )
   4791             .is_ok()
   4792         );
   4793         // `publicKeyAlgorithm` mismatch when `publicKey` is null.
   4794         err = Error::invalid_value(
   4795             Unexpected::Other(&format!("{:?}", CoseAlgorithmIdentifier::Es256).as_str()),
   4796             &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Es384).as_str()
   4797         )
   4798         .to_string().into_bytes();
   4799         assert_eq!(
   4800             serde_json::from_str::<Registration>(
   4801                 serde_json::json!({
   4802                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   4803                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   4804                     "response": {
   4805                         "clientDataJSON": b64_cdata,
   4806                         "authenticatorData": b64_adata,
   4807                         "transports": [],
   4808                         "publicKey": null,
   4809                         "publicKeyAlgorithm": -7,
   4810                         "attestationObject": b64_aobj,
   4811                     },
   4812                     "clientExtensionResults": {},
   4813                     "type": "public-key"
   4814                 })
   4815                 .to_string()
   4816                 .as_str()
   4817             )
   4818             .unwrap_err()
   4819             .to_string()
   4820             .into_bytes()[..err.len()],
   4821             err
   4822         );
   4823     }
   4824     #[test]
   4825     fn rs256_registration_deserialize_data_mismatch() {
   4826         let c_data_json = serde_json::json!({}).to_string();
   4827         let mut att_obj = [
   4828             cbor::MAP_3,
   4829             cbor::TEXT_3,
   4830             b'f',
   4831             b'm',
   4832             b't',
   4833             cbor::TEXT_4,
   4834             b'n',
   4835             b'o',
   4836             b'n',
   4837             b'e',
   4838             cbor::TEXT_7,
   4839             b'a',
   4840             b't',
   4841             b't',
   4842             b'S',
   4843             b't',
   4844             b'm',
   4845             b't',
   4846             cbor::MAP_0,
   4847             cbor::TEXT_8,
   4848             b'a',
   4849             b'u',
   4850             b't',
   4851             b'h',
   4852             b'D',
   4853             b'a',
   4854             b't',
   4855             b'a',
   4856             cbor::BYTES_INFO_25,
   4857             1,
   4858             87,
   4859             // `rpIdHash`.
   4860             0,
   4861             0,
   4862             0,
   4863             0,
   4864             0,
   4865             0,
   4866             0,
   4867             0,
   4868             0,
   4869             0,
   4870             0,
   4871             0,
   4872             0,
   4873             0,
   4874             0,
   4875             0,
   4876             0,
   4877             0,
   4878             0,
   4879             0,
   4880             0,
   4881             0,
   4882             0,
   4883             0,
   4884             0,
   4885             0,
   4886             0,
   4887             0,
   4888             0,
   4889             0,
   4890             0,
   4891             0,
   4892             // `flags`.
   4893             0b0100_0101,
   4894             // `signCount`.
   4895             0,
   4896             0,
   4897             0,
   4898             0,
   4899             // `aaguid`.
   4900             0,
   4901             0,
   4902             0,
   4903             0,
   4904             0,
   4905             0,
   4906             0,
   4907             0,
   4908             0,
   4909             0,
   4910             0,
   4911             0,
   4912             0,
   4913             0,
   4914             0,
   4915             0,
   4916             // `credentialIdLength`.
   4917             0,
   4918             16,
   4919             // `credentialId`.
   4920             0,
   4921             0,
   4922             0,
   4923             0,
   4924             0,
   4925             0,
   4926             0,
   4927             0,
   4928             0,
   4929             0,
   4930             0,
   4931             0,
   4932             0,
   4933             0,
   4934             0,
   4935             0,
   4936             // RSA COSE key.
   4937             cbor::MAP_4,
   4938             KTY,
   4939             RSA,
   4940             ALG,
   4941             cbor::NEG_INFO_25,
   4942             // RS256.
   4943             1,
   4944             0,
   4945             // `n`.
   4946             cbor::NEG_ONE,
   4947             cbor::BYTES_INFO_25,
   4948             1,
   4949             0,
   4950             // n. This will be overwritten later.
   4951             0,
   4952             0,
   4953             0,
   4954             0,
   4955             0,
   4956             0,
   4957             0,
   4958             0,
   4959             0,
   4960             0,
   4961             0,
   4962             0,
   4963             0,
   4964             0,
   4965             0,
   4966             0,
   4967             0,
   4968             0,
   4969             0,
   4970             0,
   4971             0,
   4972             0,
   4973             0,
   4974             0,
   4975             0,
   4976             0,
   4977             0,
   4978             0,
   4979             0,
   4980             0,
   4981             0,
   4982             0,
   4983             0,
   4984             0,
   4985             0,
   4986             0,
   4987             0,
   4988             0,
   4989             0,
   4990             0,
   4991             0,
   4992             0,
   4993             0,
   4994             0,
   4995             0,
   4996             0,
   4997             0,
   4998             0,
   4999             0,
   5000             0,
   5001             0,
   5002             0,
   5003             0,
   5004             0,
   5005             0,
   5006             0,
   5007             0,
   5008             0,
   5009             0,
   5010             0,
   5011             0,
   5012             0,
   5013             0,
   5014             0,
   5015             0,
   5016             0,
   5017             0,
   5018             0,
   5019             0,
   5020             0,
   5021             0,
   5022             0,
   5023             0,
   5024             0,
   5025             0,
   5026             0,
   5027             0,
   5028             0,
   5029             0,
   5030             0,
   5031             0,
   5032             0,
   5033             0,
   5034             0,
   5035             0,
   5036             0,
   5037             0,
   5038             0,
   5039             0,
   5040             0,
   5041             0,
   5042             0,
   5043             0,
   5044             0,
   5045             0,
   5046             0,
   5047             0,
   5048             0,
   5049             0,
   5050             0,
   5051             0,
   5052             0,
   5053             0,
   5054             0,
   5055             0,
   5056             0,
   5057             0,
   5058             0,
   5059             0,
   5060             0,
   5061             0,
   5062             0,
   5063             0,
   5064             0,
   5065             0,
   5066             0,
   5067             0,
   5068             0,
   5069             0,
   5070             0,
   5071             0,
   5072             0,
   5073             0,
   5074             0,
   5075             0,
   5076             0,
   5077             0,
   5078             0,
   5079             0,
   5080             0,
   5081             0,
   5082             0,
   5083             0,
   5084             0,
   5085             0,
   5086             0,
   5087             0,
   5088             0,
   5089             0,
   5090             0,
   5091             0,
   5092             0,
   5093             0,
   5094             0,
   5095             0,
   5096             0,
   5097             0,
   5098             0,
   5099             0,
   5100             0,
   5101             0,
   5102             0,
   5103             0,
   5104             0,
   5105             0,
   5106             0,
   5107             0,
   5108             0,
   5109             0,
   5110             0,
   5111             0,
   5112             0,
   5113             0,
   5114             0,
   5115             0,
   5116             0,
   5117             0,
   5118             0,
   5119             0,
   5120             0,
   5121             0,
   5122             0,
   5123             0,
   5124             0,
   5125             0,
   5126             0,
   5127             0,
   5128             0,
   5129             0,
   5130             0,
   5131             0,
   5132             0,
   5133             0,
   5134             0,
   5135             0,
   5136             0,
   5137             0,
   5138             0,
   5139             0,
   5140             0,
   5141             0,
   5142             0,
   5143             0,
   5144             0,
   5145             0,
   5146             0,
   5147             0,
   5148             0,
   5149             0,
   5150             0,
   5151             0,
   5152             0,
   5153             0,
   5154             0,
   5155             0,
   5156             0,
   5157             0,
   5158             0,
   5159             0,
   5160             0,
   5161             0,
   5162             0,
   5163             0,
   5164             0,
   5165             0,
   5166             0,
   5167             0,
   5168             0,
   5169             0,
   5170             0,
   5171             0,
   5172             0,
   5173             0,
   5174             0,
   5175             0,
   5176             0,
   5177             0,
   5178             0,
   5179             0,
   5180             0,
   5181             0,
   5182             0,
   5183             0,
   5184             0,
   5185             0,
   5186             0,
   5187             0,
   5188             0,
   5189             0,
   5190             0,
   5191             0,
   5192             0,
   5193             0,
   5194             0,
   5195             0,
   5196             0,
   5197             0,
   5198             0,
   5199             0,
   5200             0,
   5201             0,
   5202             0,
   5203             0,
   5204             0,
   5205             0,
   5206             0,
   5207             // `e`.
   5208             cbor::NEG_TWO,
   5209             cbor::BYTES | 3,
   5210             // e.
   5211             1,
   5212             0,
   5213             1,
   5214         ];
   5215         let n = [
   5216             111, 183, 124, 133, 38, 167, 70, 148, 44, 50, 30, 60, 121, 14, 38, 37, 96, 114, 107,
   5217             195, 248, 64, 79, 36, 237, 140, 43, 27, 94, 74, 102, 152, 135, 102, 184, 150, 186, 206,
   5218             185, 19, 165, 209, 48, 98, 98, 9, 3, 205, 208, 82, 250, 105, 132, 201, 73, 62, 60, 165,
   5219             100, 128, 153, 9, 41, 118, 66, 95, 236, 214, 73, 135, 197, 68, 184, 10, 27, 116, 204,
   5220             145, 50, 174, 58, 42, 183, 181, 119, 232, 126, 252, 217, 96, 162, 190, 103, 122, 64,
   5221             87, 145, 45, 32, 207, 17, 239, 223, 3, 35, 14, 112, 119, 124, 141, 123, 208, 239, 105,
   5222             81, 217, 151, 162, 190, 17, 88, 182, 176, 158, 81, 200, 42, 166, 133, 48, 23, 236, 55,
   5223             117, 248, 233, 151, 203, 122, 155, 231, 46, 177, 20, 20, 151, 64, 222, 239, 226, 7, 21,
   5224             254, 81, 202, 64, 232, 161, 235, 22, 51, 246, 207, 213, 0, 229, 138, 46, 222, 205, 157,
   5225             108, 139, 253, 230, 80, 50, 2, 122, 212, 163, 100, 180, 114, 12, 113, 52, 56, 99, 188,
   5226             42, 198, 212, 23, 182, 222, 56, 221, 200, 79, 96, 239, 221, 135, 10, 17, 106, 183, 56,
   5227             104, 68, 94, 198, 196, 35, 200, 83, 204, 26, 185, 204, 212, 31, 183, 19, 111, 233, 13,
   5228             72, 93, 53, 65, 111, 59, 242, 122, 160, 244, 162, 126, 38, 235, 156, 47, 88, 39, 132,
   5229             153, 79, 0, 133, 78, 7, 218, 165, 241,
   5230         ];
   5231         let e = 65537u32;
   5232         let d = [
   5233             145, 79, 21, 97, 233, 3, 192, 194, 177, 68, 181, 80, 120, 197, 23, 44, 185, 74, 144, 0,
   5234             132, 149, 139, 11, 16, 224, 4, 112, 236, 94, 238, 97, 121, 124, 213, 145, 24, 253, 168,
   5235             35, 190, 205, 132, 115, 33, 201, 38, 253, 246, 180, 66, 155, 165, 46, 3, 254, 68, 108,
   5236             154, 247, 246, 45, 187, 0, 204, 96, 185, 157, 249, 174, 158, 38, 62, 244, 183, 76, 102,
   5237             6, 219, 92, 212, 138, 59, 147, 163, 219, 111, 39, 105, 21, 236, 196, 38, 255, 114, 247,
   5238             82, 104, 113, 204, 29, 152, 209, 219, 48, 239, 74, 129, 19, 247, 33, 239, 119, 166,
   5239             216, 152, 94, 138, 238, 164, 242, 129, 50, 150, 57, 20, 53, 224, 56, 241, 138, 97, 111,
   5240             215, 107, 212, 195, 146, 108, 143, 0, 229, 181, 171, 73, 152, 105, 146, 25, 243, 242,
   5241             140, 252, 248, 162, 247, 63, 168, 180, 20, 153, 120, 10, 248, 211, 1, 71, 127, 212,
   5242             249, 237, 203, 202, 48, 26, 216, 226, 228, 186, 13, 204, 70, 255, 240, 89, 255, 59, 83,
   5243             31, 253, 55, 43, 158, 90, 248, 83, 32, 159, 105, 57, 134, 34, 96, 18, 255, 245, 153,
   5244             162, 60, 91, 99, 220, 51, 44, 85, 114, 67, 125, 202, 65, 217, 245, 40, 8, 81, 165, 142,
   5245             24, 245, 127, 122, 247, 152, 212, 75, 45, 59, 90, 184, 234, 31, 147, 36, 8, 212, 45,
   5246             50, 23, 3, 25, 253, 87, 227, 79, 119, 161,
   5247         ];
   5248         let p = BigUint::from_bytes_le(
   5249             [
   5250                 215, 166, 5, 21, 11, 179, 41, 77, 198, 92, 165, 48, 77, 162, 42, 41, 206, 141, 60,
   5251                 69, 47, 164, 19, 92, 46, 72, 100, 238, 100, 53, 214, 197, 163, 185, 6, 140, 229,
   5252                 250, 195, 77, 8, 12, 5, 236, 178, 173, 86, 201, 43, 213, 165, 51, 108, 101, 161,
   5253                 99, 76, 240, 14, 234, 76, 197, 137, 53, 198, 168, 135, 205, 212, 198, 120, 29, 16,
   5254                 82, 98, 233, 236, 177, 12, 171, 141, 100, 107, 146, 33, 176, 125, 202, 172, 79,
   5255                 147, 179, 30, 62, 247, 206, 169, 19, 168, 114, 26, 73, 108, 178, 105, 84, 89, 191,
   5256                 168, 253, 228, 214, 54, 16, 212, 199, 111, 72, 3, 41, 247, 227, 165, 244, 32, 188,
   5257                 24, 247,
   5258             ]
   5259             .as_slice(),
   5260         );
   5261         let p_2 = BigUint::from_bytes_le(
   5262             [
   5263                 41, 25, 198, 240, 134, 206, 121, 57, 11, 5, 134, 192, 212, 77, 229, 197, 14, 78,
   5264                 85, 212, 190, 114, 179, 188, 21, 171, 174, 12, 104, 74, 15, 164, 136, 173, 62, 177,
   5265                 141, 213, 93, 102, 147, 83, 59, 124, 146, 59, 175, 213, 55, 27, 25, 248, 154, 29,
   5266                 39, 85, 50, 235, 134, 60, 203, 106, 186, 195, 190, 185, 71, 169, 142, 236, 92, 11,
   5267                 250, 187, 198, 8, 201, 184, 120, 178, 227, 87, 63, 243, 89, 227, 234, 184, 28, 252,
   5268                 112, 211, 193, 69, 23, 92, 5, 72, 93, 53, 69, 159, 73, 160, 105, 244, 249, 94, 214,
   5269                 173, 9, 236, 4, 255, 129, 11, 224, 140, 252, 168, 57, 143, 176, 241, 60, 219, 90,
   5270                 250,
   5271             ]
   5272             .as_slice(),
   5273         );
   5274         let key = RsaPrivateKey::from_components(
   5275             BigUint::from_bytes_le(n.as_slice()),
   5276             e.into(),
   5277             BigUint::from_bytes_le(d.as_slice()),
   5278             vec![p, p_2],
   5279         )
   5280         .unwrap()
   5281         .to_public_key();
   5282         let pub_key = key.to_public_key_der().unwrap();
   5283         let att_obj_len = att_obj.len();
   5284         att_obj[att_obj_len - 261..att_obj_len - 5]
   5285             .copy_from_slice(key.n().to_bytes_be().as_slice());
   5286         let b64_cdata = base64url_nopad::encode(c_data_json.as_bytes());
   5287         let b64_adata = base64url_nopad::encode(&att_obj[att_obj.len() - 343..]);
   5288         let b64_key = base64url_nopad::encode(pub_key.as_bytes());
   5289         let b64_aobj = base64url_nopad::encode(att_obj.as_slice());
   5290         // Base case is valid.
   5291         assert!(
   5292             serde_json::from_str::<Registration>(
   5293                 serde_json::json!({
   5294                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   5295                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   5296                     "response": {
   5297                         "clientDataJSON": b64_cdata,
   5298                         "authenticatorData": b64_adata,
   5299                         "transports": [],
   5300                         "publicKey": b64_key,
   5301                         "publicKeyAlgorithm": -257,
   5302                         "attestationObject": b64_aobj,
   5303                     },
   5304                     "clientExtensionResults": {},
   5305                     "type": "public-key"
   5306                 })
   5307                 .to_string()
   5308                 .as_str()
   5309             )
   5310             .map_or(false, |reg| reg.response.client_data_json
   5311                 == c_data_json.as_bytes()
   5312                 && reg.response.attestation_object_and_c_data_hash[..att_obj.len()]
   5313                     == att_obj
   5314                 && reg.response.attestation_object_and_c_data_hash[att_obj.len()..]
   5315                     == *Sha256::digest(c_data_json.as_bytes()).as_slice()
   5316                 && reg.response.transports.is_empty()
   5317                 && matches!(reg.authenticator_attachment, AuthenticatorAttachment::None)
   5318                 && reg.client_extension_results.cred_props.is_none()
   5319                 && reg.client_extension_results.prf.is_none())
   5320         );
   5321         // `publicKeyAlgorithm` mismatch.
   5322         let mut err = Error::invalid_value(
   5323             Unexpected::Other(&format!("{:?}", CoseAlgorithmIdentifier::Eddsa).as_str()),
   5324             &format!("public key algorithm to match the algorithm associated with the public key within the attestation object: {:?}", CoseAlgorithmIdentifier::Rs256).as_str()
   5325         )
   5326         .to_string().into_bytes();
   5327         assert_eq!(
   5328             serde_json::from_str::<Registration>(
   5329                 serde_json::json!({
   5330                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   5331                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   5332                     "response": {
   5333                         "clientDataJSON": b64_cdata,
   5334                         "authenticatorData": b64_adata,
   5335                         "transports": [],
   5336                         "publicKey": b64_key,
   5337                         "publicKeyAlgorithm": -8,
   5338                         "attestationObject": b64_aobj,
   5339                     },
   5340                     "clientExtensionResults": {},
   5341                     "type": "public-key"
   5342                 })
   5343                 .to_string()
   5344                 .as_str()
   5345             )
   5346             .unwrap_err()
   5347             .to_string()
   5348             .into_bytes()[..err.len()],
   5349             err
   5350         );
   5351         // Missing `publicKeyAlgorithm`.
   5352         err = Error::missing_field("publicKeyAlgorithm")
   5353             .to_string()
   5354             .into_bytes();
   5355         assert_eq!(
   5356             serde_json::from_str::<Registration>(
   5357                 serde_json::json!({
   5358                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   5359                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   5360                     "response": {
   5361                         "clientDataJSON": b64_cdata,
   5362                         "authenticatorData": b64_adata,
   5363                         "transports": [],
   5364                         "publicKey": b64_key,
   5365                         "attestationObject": b64_aobj,
   5366                     },
   5367                     "clientExtensionResults": {},
   5368                     "type": "public-key"
   5369                 })
   5370                 .to_string()
   5371                 .as_str()
   5372             )
   5373             .unwrap_err()
   5374             .to_string()
   5375             .into_bytes()[..err.len()],
   5376             err
   5377         );
   5378         // `null` `publicKeyAlgorithm`.
   5379         err = Error::invalid_type(Unexpected::Other("null"), &"publicKeyAlgorithm")
   5380             .to_string()
   5381             .into_bytes();
   5382         assert_eq!(
   5383             serde_json::from_str::<Registration>(
   5384                 serde_json::json!({
   5385                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   5386                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   5387                     "response": {
   5388                         "clientDataJSON": b64_cdata,
   5389                         "authenticatorData": b64_adata,
   5390                         "transports": [],
   5391                         "publicKey": b64_key,
   5392                         "publicKeyAlgorithm": null,
   5393                         "attestationObject": b64_aobj,
   5394                     },
   5395                     "clientExtensionResults": {},
   5396                     "type": "public-key"
   5397                 })
   5398                 .to_string()
   5399                 .as_str()
   5400             )
   5401             .unwrap_err()
   5402             .to_string()
   5403             .into_bytes()[..err.len()],
   5404             err
   5405         );
   5406         // `publicKey` mismatch.
   5407         let bad_pub_key = RsaPrivateKey::from_components(
   5408             BigUint::from_bytes_le(
   5409                 [
   5410                     175, 161, 161, 75, 52, 244, 72, 168, 29, 119, 33, 120, 3, 222, 231, 152, 222,
   5411                     119, 112, 83, 221, 237, 74, 174, 79, 216, 147, 251, 245, 94, 234, 114, 254, 21,
   5412                     17, 254, 8, 115, 75, 127, 150, 87, 59, 109, 230, 116, 85, 90, 11, 160, 63, 217,
   5413                     9, 38, 187, 250, 226, 183, 38, 164, 182, 218, 22, 19, 58, 189, 83, 219, 11,
   5414                     144, 15, 99, 151, 166, 46, 57, 17, 111, 189, 131, 142, 113, 85, 122, 188, 238,
   5415                     52, 21, 116, 125, 102, 195, 182, 165, 29, 156, 213, 182, 125, 156, 88, 56, 221,
   5416                     2, 98, 43, 210, 115, 32, 4, 105, 88, 181, 158, 207, 236, 162, 250, 253, 240,
   5417                     72, 8, 253, 50, 220, 247, 76, 170, 143, 68, 225, 231, 113, 64, 244, 17, 138,
   5418                     162, 233, 33, 2, 67, 11, 223, 188, 232, 152, 193, 20, 32, 243, 52, 64, 43, 2,
   5419                     243, 8, 77, 150, 232, 109, 148, 95, 127, 55, 71, 162, 34, 54, 83, 135, 52, 172,
   5420                     191, 32, 42, 106, 43, 211, 206, 100, 104, 110, 232, 5, 43, 120, 180, 166, 40,
   5421                     144, 233, 239, 103, 134, 103, 255, 224, 138, 184, 208, 137, 127, 36, 189, 143,
   5422                     248, 201, 2, 218, 51, 232, 96, 30, 83, 124, 109, 241, 23, 179, 247, 151, 238,
   5423                     212, 204, 44, 43, 223, 148, 241, 172, 10, 235, 155, 94, 68, 116, 24, 116, 191,
   5424                     86, 53, 127, 35, 133, 198, 204, 59, 76, 110, 16, 1, 15, 148, 135, 157,
   5425                 ]
   5426                 .as_slice(),
   5427             ),
   5428             65537u32.into(),
   5429             BigUint::from_bytes_le(
   5430                 [
   5431                     129, 93, 123, 251, 104, 29, 84, 203, 116, 100, 75, 237, 111, 160, 12, 100, 172,
   5432                     76, 57, 178, 144, 235, 81, 61, 115, 243, 28, 40, 183, 22, 56, 150, 68, 38, 220,
   5433                     62, 233, 110, 48, 174, 35, 197, 244, 109, 148, 109, 36, 69, 69, 82, 225, 113,
   5434                     175, 6, 239, 27, 193, 101, 50, 239, 122, 102, 7, 46, 98, 79, 195, 116, 155,
   5435                     158, 138, 147, 51, 93, 24, 237, 246, 82, 14, 109, 144, 250, 239, 93, 63, 214,
   5436                     96, 130, 226, 134, 198, 145, 161, 11, 231, 97, 214, 180, 255, 95, 158, 88, 108,
   5437                     254, 243, 177, 133, 184, 92, 95, 148, 88, 55, 124, 245, 244, 84, 86, 4, 121,
   5438                     44, 231, 97, 176, 190, 29, 155, 40, 57, 69, 165, 80, 168, 9, 56, 43, 233, 6,
   5439                     14, 157, 112, 223, 64, 88, 141, 7, 65, 23, 64, 208, 6, 83, 61, 8, 182, 248,
   5440                     126, 84, 179, 163, 80, 238, 90, 133, 4, 14, 71, 177, 175, 27, 29, 151, 211,
   5441                     108, 162, 195, 7, 157, 167, 86, 169, 3, 87, 235, 89, 158, 237, 216, 31, 243,
   5442                     197, 62, 5, 84, 131, 230, 186, 248, 49, 12, 93, 244, 61, 135, 180, 17, 162,
   5443                     241, 13, 115, 241, 138, 219, 98, 155, 166, 191, 63, 12, 37, 1, 165, 178, 84,
   5444                     200, 72, 80, 41, 77, 136, 217, 141, 246, 209, 31, 243, 159, 71, 43, 246, 159,
   5445                     182, 171, 116, 12, 3, 142, 235, 218, 164, 70, 90, 147, 238, 42, 75,
   5446                 ]
   5447                 .as_slice(),
   5448             ),
   5449             vec![
   5450                 BigUint::from_bytes_le(
   5451                     [
   5452                         215, 199, 110, 28, 64, 16, 16, 109, 106, 152, 150, 124, 52, 166, 121, 92,
   5453                         242, 13, 0, 69, 7, 152, 72, 172, 118, 63, 156, 180, 140, 39, 53, 29, 197,
   5454                         224, 177, 48, 41, 221, 102, 65, 17, 185, 55, 62, 219, 152, 227, 7, 78, 219,
   5455                         14, 139, 71, 204, 144, 152, 14, 39, 247, 244, 165, 224, 234, 60, 213, 74,
   5456                         237, 30, 102, 177, 242, 138, 168, 31, 122, 47, 206, 155, 225, 113, 103,
   5457                         175, 152, 244, 27, 233, 112, 223, 248, 38, 215, 178, 20, 244, 8, 121, 26,
   5458                         11, 70, 122, 16, 85, 167, 87, 64, 216, 228, 227, 173, 57, 250, 8, 221, 38,
   5459                         12, 203, 212, 1, 112, 43, 72, 91, 225, 97, 228, 57, 154, 193,
   5460                     ]
   5461                     .as_slice(),
   5462                 ),
   5463                 BigUint::from_bytes_le(
   5464                     [
   5465                         233, 89, 204, 152, 31, 242, 8, 110, 38, 190, 111, 159, 105, 105, 45, 85,
   5466                         15, 244, 30, 250, 174, 226, 219, 111, 107, 191, 196, 135, 17, 123, 186,
   5467                         167, 85, 13, 120, 197, 159, 129, 78, 237, 152, 31, 230, 26, 229, 253, 197,
   5468                         211, 105, 204, 126, 142, 250, 55, 26, 172, 65, 160, 45, 6, 99, 86, 66, 238,
   5469                         107, 6, 98, 171, 93, 224, 201, 160, 31, 204, 82, 120, 228, 158, 238, 6,
   5470                         190, 12, 150, 153, 239, 95, 57, 71, 100, 239, 235, 155, 73, 200, 5, 225,
   5471                         127, 185, 46, 48, 243, 84, 33, 142, 17, 19, 20, 23, 215, 16, 114, 58, 211,
   5472                         14, 73, 148, 168, 252, 159, 252, 125, 57, 101, 211, 188, 12, 77, 208,
   5473                     ]
   5474                     .as_slice(),
   5475                 ),
   5476             ],
   5477         )
   5478         .unwrap()
   5479         .to_public_key();
   5480         err = Error::invalid_value(
   5481             Unexpected::Bytes([0; 32].as_slice()),
   5482             &format!(
   5483                 "DER-encoded public key to match the public key within the attestation object: Rsa(RsaPubKey({:?}, 65537))",
   5484                 &att_obj[att_obj.len() - 261..att_obj.len() - 5],
   5485             )
   5486             .as_str(),
   5487         )
   5488         .to_string().into_bytes();
   5489         assert_eq!(serde_json::from_str::<Registration>(
   5490             serde_json::json!({
   5491                 "id": "AAAAAAAAAAAAAAAAAAAAAA",
   5492                 "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   5493                 "response": {
   5494                     "clientDataJSON": b64_cdata,
   5495                     "authenticatorData": b64_adata,
   5496                     "transports": [],
   5497                     "publicKey": base64url_nopad::encode(bad_pub_key.to_public_key_der().unwrap().as_bytes()),
   5498                     "publicKeyAlgorithm": -257,
   5499                     "attestationObject": b64_aobj,
   5500                 },
   5501                 "clientExtensionResults": {},
   5502                 "type": "public-key"
   5503             })
   5504             .to_string()
   5505             .as_str()
   5506             )
   5507             .unwrap_err().to_string().into_bytes()[..err.len()],
   5508             err
   5509         );
   5510         // Missing `publicKey` when using EdDSA, ES256, or RS256.
   5511         err = Error::missing_field("publicKey").to_string().into_bytes();
   5512         assert_eq!(
   5513             serde_json::from_str::<Registration>(
   5514                 serde_json::json!({
   5515                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   5516                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   5517                     "response": {
   5518                         "clientDataJSON": b64_cdata,
   5519                         "authenticatorData": b64_adata,
   5520                         "transports": [],
   5521                         "publicKeyAlgorithm": -257,
   5522                         "attestationObject": b64_aobj,
   5523                     },
   5524                     "clientExtensionResults": {},
   5525                     "type": "public-key"
   5526                 })
   5527                 .to_string()
   5528                 .as_str()
   5529             )
   5530             .unwrap_err()
   5531             .to_string()
   5532             .into_bytes()[..err.len()],
   5533             err
   5534         );
   5535         // `null` `publicKey` when using EdDSA, ES256, or RS256.
   5536         err = Error::invalid_type(Unexpected::Other("null"), &"publicKey")
   5537             .to_string()
   5538             .into_bytes();
   5539         assert_eq!(
   5540             serde_json::from_str::<Registration>(
   5541                 serde_json::json!({
   5542                     "id": "AAAAAAAAAAAAAAAAAAAAAA",
   5543                     "rawId": "AAAAAAAAAAAAAAAAAAAAAA",
   5544                     "response": {
   5545                         "clientDataJSON": b64_cdata,
   5546                         "authenticatorData": b64_adata,
   5547                         "transports": [],
   5548                         "publicKey": null,
   5549                         "publicKeyAlgorithm": -257,
   5550                         "attestationObject": b64_aobj,
   5551                     },
   5552                     "clientExtensionResults": {},
   5553                     "type": "public-key"
   5554                 })
   5555                 .to_string()
   5556                 .as_str()
   5557             )
   5558             .unwrap_err()
   5559             .to_string()
   5560             .into_bytes()[..err.len()],
   5561             err
   5562         );
   5563     }
   5564 }