webauthn_rp

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

error.rs (16993B)


      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                 BackupReq, UserVerificationRequirement,
     14                 auth::{
     15                     AllowedCredential, AllowedCredentials, AuthenticationVerificationOptions,
     16                     CredentialSpecificExtension, DiscoverableAuthenticationServerState,
     17                     DiscoverableCredentialRequestOptions, Extension,
     18                     NonDiscoverableAuthenticationServerState, PublicKeyCredentialRequestOptions,
     19                 },
     20             },
     21         },
     22         Backup,
     23         register::CredentialProtectionPolicy,
     24     },
     25     Authentication, AuthenticatorAssertion, AuthenticatorAttachment, AuthenticatorData,
     26     AuthenticatorExtensionOutput, CollectedClientData, CompressedPubKey, Flag, HmacSecret,
     27     Signature, UserHandle,
     28 };
     29 use core::{
     30     convert::Infallible,
     31     error::Error,
     32     fmt::{self, Display, Formatter},
     33 };
     34 /// Error returned in [`AuthenticatorDataErr::AuthenticatorExtension`].
     35 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
     36 pub enum AuthenticatorExtensionOutputErr {
     37     /// The `slice` had an invalid length.
     38     Len,
     39     /// The first byte did not represent a map of one key pair.
     40     CborHeader,
     41     /// `hmac-secret` was not a byte string with additional info 24.
     42     HmacSecretType,
     43     /// `hmac-secret` was not a byte string of length 48 or 80.
     44     HmacSecretValue,
     45     /// An unsupported extension existed.
     46     Unsupported,
     47     /// Fewer extensions existed than expected.
     48     Missing,
     49 }
     50 impl Display for AuthenticatorExtensionOutputErr {
     51     #[inline]
     52     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
     53         f.write_str(match *self {
     54             Self::Len => "CBOR authenticator extensions had an invalid length",
     55             Self::CborHeader => {
     56                 "CBOR authenticator extensions did not represent a map of one key pair"
     57             }
     58             Self::HmacSecretType => "CBOR authenticator extension 'hmac-secret' was not a byte string with additional info 24",
     59             Self::HmacSecretValue => "CBOR authenticator extension 'hmac-secret' was not a byte string of length 48 or 80",
     60             Self::Unsupported => "CBOR authenticator extension had an unsupported extension",
     61             Self::Missing => "CBOR authenticator extensions had fewer extensions than expected",
     62         })
     63     }
     64 }
     65 impl Error for AuthenticatorExtensionOutputErr {}
     66 /// Error returned from [`AuthenticatorData::try_from`].
     67 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
     68 pub enum AuthenticatorDataErr {
     69     /// The `slice` had an invalid length.
     70     Len,
     71     /// [`Flag::user_present`] was `false`.
     72     UserNotPresent,
     73     /// Bit 1 in [`flags`](https://www.w3.org/TR/webauthn-3/#authdata-flags) is not 0.
     74     FlagsBit1Not0,
     75     /// Bit 5 in [`flags`](https://www.w3.org/TR/webauthn-3/#authdata-flags) is not 0.
     76     FlagsBit5Not0,
     77     /// [AT](https://www.w3.org/TR/webauthn-3/#authdata-flags-at) was 1.
     78     AttestedCredentialDataIncluded,
     79     /// [BE](https://www.w3.org/TR/webauthn-3/#authdata-flags-be) and
     80     /// [BS](https://www.w3.org/TR/webauthn-3/#authdata-flags-bs) bits were 0 and 1 respectively.
     81     BackupWithoutEligibility,
     82     /// Error returned when [`AuthenticatorExtensionOutput`] is malformed.
     83     AuthenticatorExtension(AuthenticatorExtensionOutputErr),
     84     /// [ED](https://www.w3.org/TR/webauthn-3/#authdata-flags-ed) bit was 0, but
     85     /// [`extensions`](https://www.w3.org/TR/webauthn-3/#authdata-extensions) existed.
     86     NoExtensionBitWithData,
     87     /// [ED](https://www.w3.org/TR/webauthn-3/#authdata-flags-ed) bit was 1, but
     88     /// [`extensions`](https://www.w3.org/TR/webauthn-3/#authdata-extensions) did not exist.
     89     ExtensionBitWithoutData,
     90     /// There was data remaining that could not be deserialized.
     91     TrailingData,
     92 }
     93 impl Display for AuthenticatorDataErr {
     94     #[inline]
     95     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
     96         match *self {
     97             Self::Len => AuthDataErr::<(), Infallible, AuthenticatorExtensionOutputErr>::Len.fmt(f),
     98             Self::UserNotPresent => f.write_str("the user was not present"),
     99             Self::FlagsBit1Not0 => {
    100                 AuthDataErr::<(), Infallible, AuthenticatorExtensionOutputErr>::FlagsBit1Not0.fmt(f)
    101             }
    102             Self::FlagsBit5Not0 => {
    103                 AuthDataErr::<(), Infallible, AuthenticatorExtensionOutputErr>::FlagsBit5Not0.fmt(f)
    104             }
    105             Self::AttestedCredentialDataIncluded => {
    106                 f.write_str("attested credential data was included")
    107             }
    108             Self::BackupWithoutEligibility => AuthDataErr::<
    109                 (),
    110                 Infallible,
    111                 AuthenticatorExtensionOutputErr,
    112             >::BackupWithoutEligibility
    113                 .fmt(f),
    114             Self::AuthenticatorExtension(err) => err.fmt(f),
    115             Self::NoExtensionBitWithData => AuthDataErr::<
    116                 (),
    117                 Infallible,
    118                 AuthenticatorExtensionOutputErr,
    119             >::NoExtensionBitWithData
    120                 .fmt(f),
    121             Self::ExtensionBitWithoutData => AuthDataErr::<
    122                 (),
    123                 Infallible,
    124                 AuthenticatorExtensionOutputErr,
    125             >::ExtensionBitWithoutData
    126                 .fmt(f),
    127             Self::TrailingData => {
    128                 AuthDataErr::<(), Infallible, AuthenticatorExtensionOutputErr>::TrailingData.fmt(f)
    129             }
    130         }
    131     }
    132 }
    133 impl Error for AuthenticatorDataErr {}
    134 /// One or two.
    135 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
    136 pub enum OneOrTwo {
    137     /// One.
    138     One,
    139     /// Two.
    140     Two,
    141 }
    142 impl Display for OneOrTwo {
    143     #[inline]
    144     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    145         f.write_str(match *self {
    146             Self::One => "one",
    147             Self::Two => "two",
    148         })
    149     }
    150 }
    151 /// Error in [`AuthCeremonyErr::Extension`].
    152 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
    153 pub enum ExtensionErr {
    154     /// [`AuthenticatorExtensionOutput::hmac_secret`] was sent from the client, but [`Flag::user_verified`]
    155     /// was `false`.
    156     ///
    157     /// Note this is only possible iff [`PublicKeyCredentialRequestOptions::user_verification`] is not
    158     /// [`UserVerificationRequirement::Required`], [`Extension::prf`] is `None`,
    159     /// [`CredentialSpecificExtension::prf`] is `None`, and
    160     /// [`AuthenticationVerificationOptions::error_on_unsolicited_extensions`] is `false`.
    161     UserNotVerifiedHmacSecret,
    162     /// [`AuthenticatorExtensionOutput::hmac_secret`] was sent from the client but was not supposed to be.
    163     ForbiddenHmacSecret,
    164     /// [`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)
    165     /// was received for a credential that does not support it.
    166     HmacSecretForNonHmacSecretCredential,
    167     /// [`Extension::prf`] was requested for a PRF-capable credential that is based on the
    168     /// [`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)
    169     /// extension, but the required response was not sent back.
    170     MissingHmacSecret,
    171     /// [`Extension::prf`] was requested with the first number of PRF inputs, but the second number of
    172     /// [`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)
    173     /// outputs were sent for a PRF-capable credential that is based on the `hmac-secret` extension.
    174     InvalidHmacSecretValue(OneOrTwo, OneOrTwo),
    175 }
    176 impl Display for ExtensionErr {
    177     #[inline]
    178     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    179         match *self {
    180             Self::UserNotVerifiedHmacSecret => {
    181                 f.write_str("user was not verified but hmac-secret info was sent from the client")
    182             }
    183             Self::ForbiddenHmacSecret => {
    184                 f.write_str("hmac-secret info was sent from the client, but it is not allowed")
    185             }
    186             Self::HmacSecretForNonHmacSecretCredential => f.write_str(
    187                 "hmac-secret info was sent from the client, but the credential does not support it",
    188             ),
    189             Self::MissingHmacSecret => f.write_str("hmac-secret was not sent from the client"),
    190             Self::InvalidHmacSecretValue(sent, recv) => write!(
    191                 f,
    192                 "{sent} PRF input(s) were sent, but {recv} hmac-secret output(s) were received"
    193             ),
    194         }
    195     }
    196 }
    197 impl Error for ExtensionErr {}
    198 /// Error returned by [`DiscoverableAuthenticationServerState::verify`] and
    199 /// [`NonDiscoverableAuthenticationServerState::verify`].
    200 #[derive(Debug)]
    201 pub enum AuthCeremonyErr {
    202     /// [`PublicKeyCredentialRequestOptions::timeout`] was exceeded.
    203     Timeout,
    204     /// [`AuthenticatorAssertion::client_data_json`] could not be parsed by
    205     /// [`CollectedClientData::from_client_data_json`].
    206     CollectedClientData(CollectedClientDataErr),
    207     /// [`AuthenticatorAssertion::client_data_json`] could not be parsed by
    208     /// [`CollectedClientData::from_client_data_json_relaxed`].
    209     #[cfg_attr(docsrs, doc(cfg(feature = "serde_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     /// [`CompressedPubKey`] was not valid.
    216     PubKey(PubKeyErr),
    217     /// [`CompressedPubKey`] 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::NotEligible`] was not sent back despite [`BackupReq::NotEligible`].
    236     BackupEligible,
    237     /// [`Backup::NotEligible`] was sent back despite [`BackupReq::Eligible`].
    238     BackupNotEligible,
    239     /// [`Backup::Eligible`] was not sent back despite [`BackupReq::EligibleNotExists`].
    240     BackupExists,
    241     /// [`Backup::Exists`] was not sent back despite [`BackupReq::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 {}