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 {}