webauthn_rp

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

error.rs (17015B)


      1 #[cfg(feature = "serde_relaxed")]
      2 use super::super::SerdeJsonErr;
      3 use super::super::{
      4     super::CredentialId, AuthRespErr, AuthenticatorDataErr as AuthDataErr, CeremonyErr,
      5     CollectedClientDataErr, PubKeyErr, RpId,
      6 };
      7 #[cfg(doc)]
      8 use super::{
      9     super::{
     10         super::{
     11             AuthenticatedCredential, DynamicState, StaticState,
     12             request::{
     13                 UserVerificationRequirement,
     14                 auth::{
     15                     AllowedCredential, AllowedCredentials, AuthenticationVerificationOptions,
     16                     BackupStateReq, CredentialSpecificExtension,
     17                     DiscoverableAuthenticationServerState, DiscoverableCredentialRequestOptions,
     18                     Extension, NonDiscoverableAuthenticationServerState,
     19                     PublicKeyCredentialRequestOptions,
     20                 },
     21             },
     22         },
     23         Backup,
     24         register::CredentialProtectionPolicy,
     25     },
     26     Authentication, AuthenticatorAssertion, AuthenticatorAttachment, AuthenticatorData,
     27     AuthenticatorExtensionOutput, CollectedClientData, CompressedPubKeyBorrowed, Flag, HmacSecret,
     28     Signature, UserHandle,
     29 };
     30 use core::{
     31     convert::Infallible,
     32     error::Error,
     33     fmt::{self, Display, Formatter},
     34 };
     35 /// Error returned in [`AuthenticatorDataErr::AuthenticatorExtension`].
     36 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
     37 pub enum AuthenticatorExtensionOutputErr {
     38     /// The `slice` had an invalid length.
     39     Len,
     40     /// The first byte did not represent a map of one key pair.
     41     CborHeader,
     42     /// `hmac-secret` was not a byte string with additional info 24.
     43     HmacSecretType,
     44     /// `hmac-secret` was not a byte string of length 48 or 80.
     45     HmacSecretValue,
     46     /// An unsupported extension existed.
     47     Unsupported,
     48     /// Fewer extensions existed than expected.
     49     Missing,
     50 }
     51 impl Display for AuthenticatorExtensionOutputErr {
     52     #[inline]
     53     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
     54         f.write_str(match *self {
     55             Self::Len => "CBOR authenticator extensions had an invalid length",
     56             Self::CborHeader => {
     57                 "CBOR authenticator extensions did not represent a map of one key pair"
     58             }
     59             Self::HmacSecretType => "CBOR authenticator extension 'hmac-secret' was not a byte string with additional info 24",
     60             Self::HmacSecretValue => "CBOR authenticator extension 'hmac-secret' was not a byte string of length 48 or 80",
     61             Self::Unsupported => "CBOR authenticator extension had an unsupported extension",
     62             Self::Missing => "CBOR authenticator extensions had fewer extensions than expected",
     63         })
     64     }
     65 }
     66 impl Error for AuthenticatorExtensionOutputErr {}
     67 /// Error returned from [`AuthenticatorData::try_from`].
     68 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
     69 pub enum AuthenticatorDataErr {
     70     /// The `slice` had an invalid length.
     71     Len,
     72     /// [`Flag::user_present`] was `false`.
     73     UserNotPresent,
     74     /// Bit 1 in [`flags`](https://www.w3.org/TR/webauthn-3/#authdata-flags) is not 0.
     75     FlagsBit1Not0,
     76     /// Bit 5 in [`flags`](https://www.w3.org/TR/webauthn-3/#authdata-flags) is not 0.
     77     FlagsBit5Not0,
     78     /// [AT](https://www.w3.org/TR/webauthn-3/#authdata-flags-at) was 1.
     79     AttestedCredentialDataIncluded,
     80     /// [BE](https://www.w3.org/TR/webauthn-3/#authdata-flags-be) and
     81     /// [BS](https://www.w3.org/TR/webauthn-3/#authdata-flags-bs) bits were 0 and 1 respectively.
     82     BackupWithoutEligibility,
     83     /// Error returned when [`AuthenticatorExtensionOutput`] is malformed.
     84     AuthenticatorExtension(AuthenticatorExtensionOutputErr),
     85     /// [ED](https://www.w3.org/TR/webauthn-3/#authdata-flags-ed) bit was 0, but
     86     /// [`extensions`](https://www.w3.org/TR/webauthn-3/#authdata-extensions) existed.
     87     NoExtensionBitWithData,
     88     /// [ED](https://www.w3.org/TR/webauthn-3/#authdata-flags-ed) bit was 1, but
     89     /// [`extensions`](https://www.w3.org/TR/webauthn-3/#authdata-extensions) did not exist.
     90     ExtensionBitWithoutData,
     91     /// There was data remaining that could not be deserialized.
     92     TrailingData,
     93 }
     94 impl Display for AuthenticatorDataErr {
     95     #[inline]
     96     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
     97         match *self {
     98             Self::Len => AuthDataErr::<(), Infallible, AuthenticatorExtensionOutputErr>::Len.fmt(f),
     99             Self::UserNotPresent => f.write_str("the user was not present"),
    100             Self::FlagsBit1Not0 => {
    101                 AuthDataErr::<(), Infallible, AuthenticatorExtensionOutputErr>::FlagsBit1Not0.fmt(f)
    102             }
    103             Self::FlagsBit5Not0 => {
    104                 AuthDataErr::<(), Infallible, AuthenticatorExtensionOutputErr>::FlagsBit5Not0.fmt(f)
    105             }
    106             Self::AttestedCredentialDataIncluded => {
    107                 f.write_str("attested credential data was included")
    108             }
    109             Self::BackupWithoutEligibility => AuthDataErr::<
    110                 (),
    111                 Infallible,
    112                 AuthenticatorExtensionOutputErr,
    113             >::BackupWithoutEligibility
    114                 .fmt(f),
    115             Self::AuthenticatorExtension(err) => err.fmt(f),
    116             Self::NoExtensionBitWithData => AuthDataErr::<
    117                 (),
    118                 Infallible,
    119                 AuthenticatorExtensionOutputErr,
    120             >::NoExtensionBitWithData
    121                 .fmt(f),
    122             Self::ExtensionBitWithoutData => AuthDataErr::<
    123                 (),
    124                 Infallible,
    125                 AuthenticatorExtensionOutputErr,
    126             >::ExtensionBitWithoutData
    127                 .fmt(f),
    128             Self::TrailingData => {
    129                 AuthDataErr::<(), Infallible, AuthenticatorExtensionOutputErr>::TrailingData.fmt(f)
    130             }
    131         }
    132     }
    133 }
    134 impl Error for AuthenticatorDataErr {}
    135 /// One or two.
    136 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
    137 pub enum OneOrTwo {
    138     /// One.
    139     One,
    140     /// Two.
    141     Two,
    142 }
    143 impl Display for OneOrTwo {
    144     #[inline]
    145     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    146         f.write_str(match *self {
    147             Self::One => "one",
    148             Self::Two => "two",
    149         })
    150     }
    151 }
    152 /// Error in [`AuthCeremonyErr::Extension`].
    153 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
    154 pub enum ExtensionErr {
    155     /// [`AuthenticatorExtensionOutput::hmac_secret`] was sent from the client, but [`Flag::user_verified`]
    156     /// was `false`.
    157     ///
    158     /// Note this is only possible iff [`PublicKeyCredentialRequestOptions::user_verification`] is not
    159     /// [`UserVerificationRequirement::Required`], [`Extension::prf`] is `None`,
    160     /// [`CredentialSpecificExtension::prf`] is `None`, and
    161     /// [`AuthenticationVerificationOptions::error_on_unsolicited_extensions`] is `false`.
    162     UserNotVerifiedHmacSecret,
    163     /// [`AuthenticatorExtensionOutput::hmac_secret`] was sent from the client but was not supposed to be.
    164     ForbiddenHmacSecret,
    165     /// [`hmac-secret`](https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html#sctn-hmac-secret-extension)
    166     /// was received for a credential that does not support it.
    167     HmacSecretForNonHmacSecretCredential,
    168     /// [`Extension::prf`] was requested for a PRF-capable credential that is based on the
    169     /// [`hmac-secret`](https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html#sctn-hmac-secret-extension)
    170     /// extension, but the required response was not sent back.
    171     MissingHmacSecret,
    172     /// [`Extension::prf`] was requested with the first number of PRF inputs, but the second number of
    173     /// [`hmac-secret`](https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html#sctn-hmac-secret-extension)
    174     /// outputs were sent for a PRF-capable credential that is based on the `hmac-secret` extension.
    175     InvalidHmacSecretValue(OneOrTwo, OneOrTwo),
    176 }
    177 impl Display for ExtensionErr {
    178     #[inline]
    179     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    180         match *self {
    181             Self::UserNotVerifiedHmacSecret => {
    182                 f.write_str("user was not verified but hmac-secret info was sent from the client")
    183             }
    184             Self::ForbiddenHmacSecret => {
    185                 f.write_str("hmac-secret info was sent from the client, but it is not allowed")
    186             }
    187             Self::HmacSecretForNonHmacSecretCredential => f.write_str(
    188                 "hmac-secret info was sent from the client, but the credential does not support it",
    189             ),
    190             Self::MissingHmacSecret => f.write_str("hmac-secret was not sent from the client"),
    191             Self::InvalidHmacSecretValue(sent, recv) => write!(
    192                 f,
    193                 "{sent} PRF input(s) were sent, but {recv} hmac-secret output(s) were received"
    194             ),
    195         }
    196     }
    197 }
    198 impl Error for ExtensionErr {}
    199 /// Error returned by [`DiscoverableAuthenticationServerState::verify`] and
    200 /// [`NonDiscoverableAuthenticationServerState::verify`].
    201 #[derive(Debug)]
    202 pub enum AuthCeremonyErr {
    203     /// [`PublicKeyCredentialRequestOptions::timeout`] was exceeded.
    204     Timeout,
    205     /// [`AuthenticatorAssertion::client_data_json`] could not be parsed by
    206     /// [`CollectedClientData::from_client_data_json`].
    207     CollectedClientData(CollectedClientDataErr),
    208     /// [`AuthenticatorAssertion::client_data_json`] could not be parsed by
    209     /// [`CollectedClientData::from_client_data_json_relaxed`].
    210     #[cfg(feature = "serde_relaxed")]
    211     CollectedClientDataRelaxed(SerdeJsonErr),
    212     /// [`AuthenticatorAssertion::authenticator_data`] could not be parsed into an
    213     /// [`AuthenticatorData`].
    214     AuthenticatorData(AuthenticatorDataErr),
    215     /// [`CompressedPubKeyBorrowed`] was not valid.
    216     PubKey(PubKeyErr),
    217     /// [`CompressedPubKeyBorrowed`] was not able to verify [`AuthenticatorAssertion::signature`].
    218     AssertionSignature,
    219     /// [`CollectedClientData::origin`] does not match one of the values in
    220     /// [`AuthenticationVerificationOptions::allowed_origins`].
    221     OriginMismatch,
    222     /// [`CollectedClientData::cross_origin`] was `true`, but
    223     /// [`AuthenticationVerificationOptions::allowed_top_origins`] was `None`.
    224     CrossOrigin,
    225     /// [`CollectedClientData::top_origin`] does not match one of the values in
    226     /// [`AuthenticationVerificationOptions::allowed_top_origins`].
    227     TopOriginMismatch,
    228     /// [`PublicKeyCredentialRequestOptions::challenge`] and [`CollectedClientData::challenge`] don't match.
    229     ChallengeMismatch,
    230     /// The SHA-256 hash of the [`RpId`] does not match [`AuthenticatorData::rp_id_hash`].
    231     RpIdHashMismatch,
    232     /// [`PublicKeyCredentialRequestOptions::user_verification`] was set to
    233     /// [`UserVerificationRequirement::Required`], but [`Flag::user_verified`] was `false`.
    234     UserNotVerified,
    235     /// [`Backup::Eligible`] was sent back despite the credential not being eligible to be backed up.
    236     BackupEligible,
    237     /// [`Backup::NotEligible`] was sent back despite the credential being eligible to be backed up.
    238     BackupNotEligible,
    239     /// [`Backup::Exists`] was sent back despite [`BackupStateReq::DoesntExist`].
    240     BackupExists,
    241     /// [`Backup::Eligible`] was sent back despite [`BackupStateReq::Exists`].
    242     BackupDoesNotExist,
    243     /// [`AuthenticatorAttachment`] was not sent back despite being required.
    244     MissingAuthenticatorAttachment,
    245     /// [`AuthenticatorAttachment`] modality changed despite it being forbidden to do so.
    246     AuthenticatorAttachmentMismatch,
    247     /// Variant returned when there is an issue with [`Extension`]s.
    248     Extension(ExtensionErr),
    249     /// [`AuthenticatorData::sign_count`] was not strictly greater than [`DynamicState::sign_count`].
    250     SignatureCounter,
    251     /// [`AuthenticatorAssertion::user_handle`] did not match [`AuthenticatedCredential::user_id`].
    252     UserHandleMismatch,
    253     /// [`Authentication::raw_id`] did not match [`AuthenticatedCredential::id`].
    254     CredentialIdMismatch,
    255     /// [`AllowedCredentials`] did not have a matching [`CredentialId`] as
    256     /// [`Authentication::raw_id`].
    257     NoMatchingAllowedCredential,
    258     /// [`AllowedCredentials`] is empty (i.e., a discoverable request was issued), but
    259     /// [`AuthenticatorAssertion::user_handle`] was [`None`].
    260     MissingUserHandle,
    261     /// [`Flag::user_verified`] was `false`, but the credential has
    262     /// [`CredentialProtectionPolicy::UserVerificationRequired`].
    263     UserNotVerifiedCredProtectRequired,
    264     /// [`DiscoverableCredentialRequestOptions`] was sent but the credential has
    265     /// [`CredentialProtectionPolicy::UserVerificationOptionalWithCredentialIdList`].
    266     DiscoverableCredProtectCredentialIdList,
    267 }
    268 impl Display for AuthCeremonyErr {
    269     #[inline]
    270     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    271         match *self {
    272             Self::Timeout => CeremonyErr::<AuthenticatorDataErr>::Timeout.fmt(f),
    273             Self::CollectedClientData(ref err) => write!(f, "clientDataJSON could not be parsed: {err}"),
    274             #[cfg(feature = "serde_relaxed")]
    275             Self::CollectedClientDataRelaxed(ref err) => write!(f, "clientDataJSON could not be parsed: {err}"),
    276             Self::AuthenticatorData(err) => err.fmt(f),
    277             Self::PubKey(err) => err.fmt(f),
    278             Self::AssertionSignature => AuthRespErr::<AuthenticatorDataErr>::Signature.fmt(f),
    279             Self::OriginMismatch => CeremonyErr::<AuthenticatorDataErr>::OriginMismatch.fmt(f),
    280             Self::CrossOrigin => CeremonyErr::<AuthenticatorDataErr>::CrossOrigin.fmt(f),
    281             Self::TopOriginMismatch => CeremonyErr::<AuthenticatorDataErr>::TopOriginMismatch.fmt(f),
    282             Self::BackupEligible => CeremonyErr::<AuthenticatorDataErr>::BackupEligible.fmt(f),
    283             Self::BackupNotEligible => CeremonyErr::<AuthenticatorDataErr>::BackupNotEligible.fmt(f),
    284             Self::BackupExists => CeremonyErr::<AuthenticatorDataErr>::BackupExists.fmt(f),
    285             Self::BackupDoesNotExist => CeremonyErr::<AuthenticatorDataErr>::BackupDoesNotExist.fmt(f),
    286             Self::ChallengeMismatch => CeremonyErr::<AuthenticatorDataErr>::ChallengeMismatch.fmt(f),
    287             Self::RpIdHashMismatch => CeremonyErr::<AuthenticatorDataErr>::RpIdHashMismatch.fmt(f),
    288             Self::UserNotVerified => CeremonyErr::<AuthenticatorDataErr>::UserNotVerified.fmt(f),
    289             Self::MissingAuthenticatorAttachment=> f.write_str(
    290                 "authenticator attachment was not sent back despite being required",
    291             ),
    292             Self::AuthenticatorAttachmentMismatch => f.write_str(
    293                 "authenticator attachment modality changed despite not being allowed to",
    294             ),
    295             Self::Extension(err) => err.fmt(f),
    296             Self::SignatureCounter => f.write_str(
    297                 "the signature counter sent back is not strictly greater than the previous counter",
    298             ),
    299             Self::UserHandleMismatch => f.write_str("the user handle does not match"),
    300             Self::CredentialIdMismatch => f.write_str("the credential ID does not match"),
    301             Self::NoMatchingAllowedCredential => f.write_str("none of the credentials used to start the non-discoverable request have the same Credential ID as the credential used to finish the ceremony"),
    302             Self::MissingUserHandle => f.write_str("the credential used to finish the ceremony did not have a user handle despite a discoverable request being issued"),
    303             Self::UserNotVerifiedCredProtectRequired => f.write_str("the credential requires user verification, but the user was not verified"),
    304             Self::DiscoverableCredProtectCredentialIdList => f.write_str("the credential requires user verification or to be used for non-discoverable requests, but a discoverable request was used and the user was not verified"),
    305         }
    306     }
    307 }
    308 impl Error for AuthCeremonyErr {}
    309 /// [`UnknownCredentialOptions`](https://www.w3.org/TR/webauthn-3/#dictdef-unknowncredentialoptions).
    310 ///
    311 /// This can be sent to the client when an authentication ceremony fails due to an unknown [`CredentialId`]. This
    312 /// can be due to the user deleting a credential on the RP's side but not deleting it on the authenticator. This
    313 /// response can be forwarded to the authenticator which can subsequently delete the credential.
    314 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
    315 pub struct UnknownCredentialOptions<'rp, 'cred> {
    316     /// [`rpId`](https://www.w3.org/TR/webauthn-3/#dictdef-unknowncredentialoptions-rpid).
    317     pub rp_id: &'rp RpId,
    318     /// [`credentialId`](https://www.w3.org/TR/webauthn-3/#dictdef-unknowncredentialoptions-credentialid).
    319     pub credential_id: CredentialId<&'cred [u8]>,
    320 }
    321 /// Error when a [`UserHandle`] does not exist that is required to.
    322 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
    323 pub struct MissingUserHandleErr;
    324 impl Display for MissingUserHandleErr {
    325     #[inline]
    326     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    327         f.write_str("user handle does not exist")
    328     }
    329 }
    330 impl Error for MissingUserHandleErr {}