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