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
105impl AuthsErrorInfo for AttestationError {
106    fn error_code(&self) -> &'static str {
107        match self {
108            Self::IssuerSignatureFailed(_) => "AUTHS-E2001",
109            Self::DeviceSignatureFailed(_) => "AUTHS-E2002",
110            Self::AttestationExpired { .. } => "AUTHS-E2003",
111            Self::AttestationRevoked => "AUTHS-E2004",
112            Self::TimestampInFuture { .. } => "AUTHS-E2005",
113            Self::MissingCapability { .. } => "AUTHS-E2006",
114            Self::SigningError(_) => "AUTHS-E2007",
115            Self::DidResolutionError(_) => "AUTHS-E2008",
116            Self::SerializationError(_) => "AUTHS-E2009",
117            Self::InputTooLarge(_) => "AUTHS-E2010",
118            Self::InvalidInput(_) => "AUTHS-E2011",
119            Self::CryptoError(_) => "AUTHS-E2012",
120            Self::InternalError(_) => "AUTHS-E2013",
121            Self::OrgVerificationFailed(_) => "AUTHS-E2014",
122            Self::OrgAttestationExpired => "AUTHS-E2015",
123            Self::OrgDidResolutionFailed(_) => "AUTHS-E2016",
124            Self::BundleExpired { .. } => "AUTHS-E2017",
125            Self::AttestationTooOld { .. } => "AUTHS-E2018",
126        }
127    }
128
129    fn suggestion(&self) -> Option<&'static str> {
130        match self {
131            Self::IssuerSignatureFailed(_) => {
132                Some("Verify the attestation was signed with the correct issuer key")
133            }
134            Self::DeviceSignatureFailed(_) => Some("Verify the device key matches the attestation"),
135            Self::AttestationExpired { .. } => Some("Request a new attestation from the issuer"),
136            Self::AttestationRevoked => {
137                Some("This device has been revoked; contact the identity admin")
138            }
139            Self::TimestampInFuture { .. } => Some("Check system clock synchronization"),
140            Self::MissingCapability { .. } => {
141                Some("Request an attestation with the required capability")
142            }
143            Self::DidResolutionError(_) => Some("Check that the DID is valid and resolvable"),
144            Self::OrgVerificationFailed(_) => {
145                Some("Verify organizational identity is properly configured")
146            }
147            Self::OrgAttestationExpired => {
148                Some("Request a new organizational attestation from the admin")
149            }
150            Self::OrgDidResolutionFailed(_) => {
151                Some("Check that the organization's DID is correctly configured")
152            }
153            // These typically don't have actionable suggestions
154            Self::InputTooLarge(_) => {
155                Some("Reduce the size of the JSON input or split into smaller batches")
156            }
157            Self::BundleExpired { .. } => Some(
158                "Re-export the bundle: auths id export-bundle --alias <ALIAS> --output bundle.json --max-age-secs <SECS>",
159            ),
160            Self::AttestationTooOld { .. } => {
161                Some("Request a fresh attestation or increase the max_age threshold")
162            }
163            Self::SigningError(_) => {
164                Some("The cryptographic signing operation failed; verify key material is valid")
165            }
166            Self::SerializationError(_) => {
167                Some("Failed to serialize/deserialize attestation data; check JSON format")
168            }
169            Self::InvalidInput(_) => {
170                Some("Check the input parameters and ensure they match the expected format")
171            }
172            Self::CryptoError(_) => {
173                Some("A cryptographic operation failed; verify key material is valid")
174            }
175            Self::InternalError(_) => {
176                Some("An unexpected internal error occurred; please report this issue")
177            }
178        }
179    }
180}