Skip to main content

auths_verifier/
error.rs

1//! Error types for attestation and verification operations.
2
3use crate::core::Capability;
4use thiserror::Error;
5
6pub use auths_crypto::AuthsErrorInfo;
7
8/// Errors returned by attestation signing, verification, and related operations.
9#[derive(Error, Debug)]
10pub enum AttestationError {
11    /// Issuer's Ed25519 signature did not verify.
12    #[error("Issuer signature verification failed: {0}")]
13    IssuerSignatureFailed(String),
14
15    /// Device's Ed25519 signature did not verify.
16    #[error("Device signature verification failed: {0}")]
17    DeviceSignatureFailed(String),
18
19    /// Attestation has passed its expiry timestamp.
20    #[error("Attestation expired on {at}")]
21    AttestationExpired {
22        /// RFC 3339 formatted expiry timestamp.
23        at: String,
24    },
25
26    /// Attestation was explicitly revoked.
27    #[error("Attestation revoked")]
28    AttestationRevoked,
29
30    /// Attestation timestamp is in the future (clock skew).
31    #[error("Attestation timestamp {at} is in the future")]
32    TimestampInFuture {
33        /// RFC 3339 formatted timestamp.
34        at: String,
35    },
36
37    /// The attestation does not grant the required capability.
38    #[error("Missing required capability: required {required:?}, available {available:?}")]
39    MissingCapability {
40        /// The capability that was required.
41        required: Capability,
42        /// The capabilities present in the attestation.
43        available: Vec<Capability>,
44    },
45
46    /// Signing the attestation data failed.
47    #[error("Signing failed: {0}")]
48    SigningError(String),
49
50    /// DID resolution failed.
51    #[error("DID resolution failed: {0}")]
52    DidResolutionError(String),
53
54    /// JSON serialization or deserialization failed.
55    #[error("Serialization error: {0}")]
56    SerializationError(String),
57
58    /// Caller provided invalid input data.
59    #[error("Invalid input: {0}")]
60    InvalidInput(String),
61
62    /// A cryptographic primitive (key parsing, hashing) failed.
63    #[error("Crypto error: {0}")]
64    CryptoError(String),
65
66    /// The JSON input exceeds the allowed size limit.
67    #[error("Input too large: {0}")]
68    InputTooLarge(String),
69
70    /// An unexpected internal error occurred.
71    #[error("Internal error: {0}")]
72    InternalError(String),
73
74    /// Organizational attestation signature verification failed.
75    #[error("Organizational Attestation verification failed: {0}")]
76    OrgVerificationFailed(String),
77
78    /// The organizational attestation has expired.
79    #[error("Organizational Attestation expired")]
80    OrgAttestationExpired,
81
82    /// DID resolution for the organization failed.
83    #[error("Organizational DID resolution failed: {0}")]
84    OrgDidResolutionFailed(String),
85
86    /// The identity bundle is older than its declared maximum age.
87    #[error("Bundle is {age_secs}s old (max {max_secs}s). Refresh with: auths id export-bundle")]
88    BundleExpired {
89        /// Actual bundle age in seconds.
90        age_secs: u64,
91        /// Maximum permitted age in seconds.
92        max_secs: u64,
93    },
94
95    /// The attestation timestamp is older than the caller-specified maximum age.
96    #[error("Attestation is {age_secs}s old (max {max_secs}s)")]
97    AttestationTooOld {
98        /// Actual attestation age in seconds.
99        age_secs: u64,
100        /// Maximum permitted age in seconds.
101        max_secs: u64,
102    },
103
104    /// A delegated attestation claims a capability its delegator does not hold.
105    #[error("Delegated attestation escalates capability beyond its delegator")]
106    CapabilityEscalation,
107
108    /// A delegated attestation expires after (outlives) its delegator.
109    #[error("Delegated attestation outlives its delegator")]
110    DelegationOutlivesParent,
111
112    /// The resolved delegator attestation has been revoked.
113    #[error("Delegator attestation is revoked")]
114    DelegatorRevoked,
115
116    /// A delegated attestation was verified standalone but its delegator could
117    /// not be resolved — fail closed rather than grant unscoped authority.
118    #[error("Delegator attestation could not be resolved")]
119    DelegatorUnresolved,
120}
121
122impl AuthsErrorInfo for AttestationError {
123    fn error_code(&self) -> &'static str {
124        match self {
125            Self::IssuerSignatureFailed(_) => "AUTHS-E2001",
126            Self::DeviceSignatureFailed(_) => "AUTHS-E2002",
127            Self::AttestationExpired { .. } => "AUTHS-E2003",
128            Self::AttestationRevoked => "AUTHS-E2004",
129            Self::TimestampInFuture { .. } => "AUTHS-E2005",
130            Self::MissingCapability { .. } => "AUTHS-E2006",
131            Self::SigningError(_) => "AUTHS-E2007",
132            Self::DidResolutionError(_) => "AUTHS-E2008",
133            Self::SerializationError(_) => "AUTHS-E2009",
134            Self::InputTooLarge(_) => "AUTHS-E2010",
135            Self::InvalidInput(_) => "AUTHS-E2011",
136            Self::CryptoError(_) => "AUTHS-E2012",
137            Self::InternalError(_) => "AUTHS-E2013",
138            Self::OrgVerificationFailed(_) => "AUTHS-E2014",
139            Self::OrgAttestationExpired => "AUTHS-E2015",
140            Self::OrgDidResolutionFailed(_) => "AUTHS-E2016",
141            Self::BundleExpired { .. } => "AUTHS-E2017",
142            Self::AttestationTooOld { .. } => "AUTHS-E2018",
143            Self::CapabilityEscalation => "AUTHS-E2019",
144            Self::DelegationOutlivesParent => "AUTHS-E2020",
145            Self::DelegatorRevoked => "AUTHS-E2021",
146            Self::DelegatorUnresolved => "AUTHS-E2022",
147        }
148    }
149
150    fn suggestion(&self) -> Option<&'static str> {
151        match self {
152            Self::IssuerSignatureFailed(_) => {
153                Some("Verify the attestation was signed with the correct issuer key")
154            }
155            Self::DeviceSignatureFailed(_) => Some("Verify the device key matches the attestation"),
156            Self::AttestationExpired { .. } => Some("Request a new attestation from the issuer"),
157            Self::AttestationRevoked => {
158                Some("This device has been revoked; contact the identity admin")
159            }
160            Self::TimestampInFuture { .. } => Some("Check system clock synchronization"),
161            Self::MissingCapability { .. } => {
162                Some("Request an attestation with the required capability")
163            }
164            Self::DidResolutionError(_) => Some("Check that the DID is valid and resolvable"),
165            Self::OrgVerificationFailed(_) => {
166                Some("Verify organizational identity is properly configured")
167            }
168            Self::OrgAttestationExpired => {
169                Some("Request a new organizational attestation from the admin")
170            }
171            Self::OrgDidResolutionFailed(_) => {
172                Some("Check that the organization's DID is correctly configured")
173            }
174            // These typically don't have actionable suggestions
175            Self::InputTooLarge(_) => {
176                Some("Reduce the size of the JSON input or split into smaller batches")
177            }
178            Self::BundleExpired { .. } => Some(
179                "Re-export the bundle: auths id export-bundle --alias <ALIAS> --output bundle.json --max-age-secs <SECS>",
180            ),
181            Self::AttestationTooOld { .. } => {
182                Some("Request a fresh attestation or increase the max_age threshold")
183            }
184            Self::SigningError(_) => {
185                Some("The cryptographic signing operation failed; verify key material is valid")
186            }
187            Self::SerializationError(_) => {
188                Some("Failed to serialize/deserialize attestation data; check JSON format")
189            }
190            Self::InvalidInput(_) => {
191                Some("Check the input parameters and ensure they match the expected format")
192            }
193            Self::CryptoError(_) => {
194                Some("A cryptographic operation failed; verify key material is valid")
195            }
196            Self::InternalError(_) => {
197                Some("An unexpected internal error occurred; please report this issue")
198            }
199            Self::CapabilityEscalation
200            | Self::DelegationOutlivesParent
201            | Self::DelegatorRevoked
202            | Self::DelegatorUnresolved => Some(
203                "Re-issue the delegated attestation within the delegator's capability and validity scope",
204            ),
205        }
206    }
207}