webauthn_rp

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

error.rs (16735B)


      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)]
     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)]
     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)]
    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)]
    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     /// [`Extension::prf`] was requested for a credential that does not support it.
    165     PrfRequestedForPrfIncapableCred,
    166     /// [`Extension::prf`] was requested for a PRF-capable credential that is based on the
    167     /// [`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)
    168     /// extension, but the required response was not sent back.
    169     MissingHmacSecret,
    170     /// [`Extension::prf`] was requested with the first number of PRF inputs, but the second number of
    171     /// [`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)
    172     /// outputs were sent for a PRF-capable credential that is based on the `hmac-secret` extension.
    173     InvalidHmacSecretValue(OneOrTwo, OneOrTwo),
    174 }
    175 impl Display for ExtensionErr {
    176     #[inline]
    177     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    178         match *self {
    179             Self::UserNotVerifiedHmacSecret => {
    180                 f.write_str("user was not verified but hmac-secret info was sent from the client")
    181             }
    182             Self::ForbiddenHmacSecret => {
    183                 f.write_str("hmac-secret info was sent from the client, but it is not allowed")
    184             }
    185             Self::PrfRequestedForPrfIncapableCred => {
    186                 f.write_str("prf extension was requested for a credential that is not PRF-capable")
    187             }
    188             Self::MissingHmacSecret => f.write_str("hmac-secret was not sent from the client"),
    189             Self::InvalidHmacSecretValue(sent, recv) => write!(
    190                 f,
    191                 "{sent} PRF input(s) were sent, but {recv} hmac-secret output(s) were received"
    192             ),
    193         }
    194     }
    195 }
    196 impl Error for ExtensionErr {}
    197 /// Error returned by [`DiscoverableAuthenticationServerState::verify`] and
    198 /// [`NonDiscoverableAuthenticationServerState::verify`].
    199 #[derive(Debug)]
    200 pub enum AuthCeremonyErr {
    201     /// [`PublicKeyCredentialRequestOptions::timeout`] was exceeded.
    202     Timeout,
    203     /// [`AuthenticatorAssertion::client_data_json`] could not be parsed by
    204     /// [`CollectedClientData::from_client_data_json`].
    205     CollectedClientData(CollectedClientDataErr),
    206     /// [`AuthenticatorAssertion::client_data_json`] could not be parsed by
    207     /// [`CollectedClientData::from_client_data_json_relaxed`].
    208     #[cfg_attr(docsrs, doc(cfg(feature = "serde_relaxed")))]
    209     #[cfg(feature = "serde_relaxed")]
    210     CollectedClientDataRelaxed(SerdeJsonErr),
    211     /// [`AuthenticatorAssertion::authenticator_data`] could not be parsed into an
    212     /// [`AuthenticatorData`].
    213     AuthenticatorData(AuthenticatorDataErr),
    214     /// [`CompressedPubKey`] was not valid.
    215     PubKey(PubKeyErr),
    216     /// [`CompressedPubKey`] was not able to verify [`AuthenticatorAssertion::signature`].
    217     AssertionSignature,
    218     /// [`CollectedClientData::origin`] does not match one of the values in
    219     /// [`AuthenticationVerificationOptions::allowed_origins`].
    220     OriginMismatch,
    221     /// [`CollectedClientData::cross_origin`] was `true`, but
    222     /// [`AuthenticationVerificationOptions::allowed_top_origins`] was `None`.
    223     CrossOrigin,
    224     /// [`CollectedClientData::top_origin`] does not match one of the values in
    225     /// [`AuthenticationVerificationOptions::allowed_top_origins`].
    226     TopOriginMismatch,
    227     /// [`PublicKeyCredentialRequestOptions::challenge`] and [`CollectedClientData::challenge`] don't match.
    228     ChallengeMismatch,
    229     /// The SHA-256 hash of the [`RpId`] does not match [`AuthenticatorData::rp_id_hash`].
    230     RpIdHashMismatch,
    231     /// [`PublicKeyCredentialRequestOptions::user_verification`] was set to
    232     /// [`UserVerificationRequirement::Required`], but [`Flag::user_verified`] was `false`.
    233     UserNotVerified,
    234     /// [`Backup::NotEligible`] was not sent back despite [`BackupReq::NotEligible`].
    235     BackupEligible,
    236     /// [`Backup::NotEligible`] was sent back despite [`BackupReq::Eligible`].
    237     BackupNotEligible,
    238     /// [`Backup::Eligible`] was not sent back despite [`BackupReq::EligibleNotExists`].
    239     BackupExists,
    240     /// [`Backup::Exists`] was not sent back despite [`BackupReq::Exists`].
    241     BackupDoesNotExist,
    242     /// [`AuthenticatorAttachment`] was not sent back despite being required.
    243     MissingAuthenticatorAttachment,
    244     /// [`AuthenticatorAttachment`] modality changed despite it being forbidden to do so.
    245     AuthenticatorAttachmentMismatch,
    246     /// Variant returned when there is an issue with [`Extension`]s.
    247     Extension(ExtensionErr),
    248     /// [`AuthenticatorData::sign_count`] was not strictly greater than [`DynamicState::sign_count`].
    249     SignatureCounter,
    250     /// [`AuthenticatorAssertion::user_handle`] did not match [`AuthenticatedCredential::user_id`].
    251     UserHandleMismatch,
    252     /// [`Authentication::raw_id`] did not match [`AuthenticatedCredential::id`].
    253     CredentialIdMismatch,
    254     /// [`AllowedCredentials`] did not have a matching [`CredentialId`] as
    255     /// [`Authentication::raw_id`].
    256     NoMatchingAllowedCredential,
    257     /// [`AllowedCredentials`] is empty (i.e., a discoverable request was issued), but
    258     /// [`AuthenticatorAssertion::user_handle`] was [`None`].
    259     MissingUserHandle,
    260     /// [`Flag::user_verified`] was `false`, but the credential has
    261     /// [`CredentialProtectionPolicy::UserVerificationRequired`].
    262     UserNotVerifiedCredProtectRequired,
    263     /// [`DiscoverableCredentialRequestOptions`] was sent but the credential has
    264     /// [`CredentialProtectionPolicy::UserVerificationOptionalWithCredentialIdList`].
    265     DiscoverableCredProtectCredentialIdList,
    266 }
    267 impl Display for AuthCeremonyErr {
    268     #[inline]
    269     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    270         match *self {
    271             Self::Timeout => CeremonyErr::<AuthenticatorDataErr>::Timeout.fmt(f),
    272             Self::CollectedClientData(ref err) => write!(f, "clientDataJSON could not be parsed: {err}"),
    273             #[cfg(feature = "serde_relaxed")]
    274             Self::CollectedClientDataRelaxed(ref err) => write!(f, "clientDataJSON could not be parsed: {err}"),
    275             Self::AuthenticatorData(err) => err.fmt(f),
    276             Self::PubKey(err) => err.fmt(f),
    277             Self::AssertionSignature => AuthRespErr::<AuthenticatorDataErr>::Signature.fmt(f),
    278             Self::OriginMismatch => CeremonyErr::<AuthenticatorDataErr>::OriginMismatch.fmt(f),
    279             Self::CrossOrigin => CeremonyErr::<AuthenticatorDataErr>::CrossOrigin.fmt(f),
    280             Self::TopOriginMismatch => CeremonyErr::<AuthenticatorDataErr>::TopOriginMismatch.fmt(f),
    281             Self::BackupEligible => CeremonyErr::<AuthenticatorDataErr>::BackupEligible.fmt(f),
    282             Self::BackupNotEligible => CeremonyErr::<AuthenticatorDataErr>::BackupNotEligible.fmt(f),
    283             Self::BackupExists => CeremonyErr::<AuthenticatorDataErr>::BackupExists.fmt(f),
    284             Self::BackupDoesNotExist => CeremonyErr::<AuthenticatorDataErr>::BackupDoesNotExist.fmt(f),
    285             Self::ChallengeMismatch => CeremonyErr::<AuthenticatorDataErr>::ChallengeMismatch.fmt(f),
    286             Self::RpIdHashMismatch => CeremonyErr::<AuthenticatorDataErr>::RpIdHashMismatch.fmt(f),
    287             Self::UserNotVerified => CeremonyErr::<AuthenticatorDataErr>::UserNotVerified.fmt(f),
    288             Self::MissingAuthenticatorAttachment=> f.write_str(
    289                 "authenticator attachment was not sent back despite being required",
    290             ),
    291             Self::AuthenticatorAttachmentMismatch => f.write_str(
    292                 "authenticator attachment modality changed despite not being allowed to",
    293             ),
    294             Self::Extension(err) => err.fmt(f),
    295             Self::SignatureCounter => f.write_str(
    296                 "the signature counter sent back is not strictly greater than the previous counter",
    297             ),
    298             Self::UserHandleMismatch => f.write_str("the user handle does not match"),
    299             Self::CredentialIdMismatch => f.write_str("the credential ID does not match"),
    300             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"),
    301             Self::MissingUserHandle => f.write_str("the credential used to finish the ceremony did not have a user handle despite a discoverable request being issued"),
    302             Self::UserNotVerifiedCredProtectRequired => f.write_str("the credential requires user verification, but the user was not verified"),
    303             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"),
    304         }
    305     }
    306 }
    307 impl Error for AuthCeremonyErr {}
    308 /// [`UnknownCredentialOptions`](https://www.w3.org/TR/webauthn-3/#dictdef-unknowncredentialoptions).
    309 ///
    310 /// This can be sent to the client when an authentication ceremony fails due to an unknown [`CredentialId`]. This
    311 /// can be due to the user deleting a credential on the RP's side but not deleting it on the authenticator. This
    312 /// response can be forwarded to the authenticator which can subsequently delete the credential.
    313 #[derive(Clone, Copy, Debug)]
    314 pub struct UnknownCredentialOptions<'rp, 'cred> {
    315     /// [`rpId`](https://www.w3.org/TR/webauthn-3/#dictdef-unknowncredentialoptions-rpid).
    316     pub rp_id: &'rp RpId,
    317     /// [`credentialId`](https://www.w3.org/TR/webauthn-3/#dictdef-unknowncredentialoptions-credentialid).
    318     pub credential_id: CredentialId<&'cred [u8]>,
    319 }
    320 /// Error when a [`UserHandle`] does not exist that is required to.
    321 #[derive(Clone, Copy, Debug)]
    322 pub struct MissingUserHandleErr;
    323 impl Display for MissingUserHandleErr {
    324     #[inline]
    325     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    326         f.write_str("user handle does not exist")
    327     }
    328 }
    329 impl Error for MissingUserHandleErr {}