1use crate::core::Capability;
4use thiserror::Error;
5
6pub use auths_crypto::AuthsErrorInfo;
7
8#[derive(Error, Debug)]
10pub enum AttestationError {
11 #[error("Issuer signature verification failed: {0}")]
13 IssuerSignatureFailed(String),
14
15 #[error("Device signature verification failed: {0}")]
17 DeviceSignatureFailed(String),
18
19 #[error("Attestation expired on {at}")]
21 AttestationExpired {
22 at: String,
24 },
25
26 #[error("Attestation revoked")]
28 AttestationRevoked,
29
30 #[error("Attestation timestamp {at} is in the future")]
32 TimestampInFuture {
33 at: String,
35 },
36
37 #[error("Missing required capability: required {required:?}, available {available:?}")]
39 MissingCapability {
40 required: Capability,
42 available: Vec<Capability>,
44 },
45
46 #[error("Signing failed: {0}")]
48 SigningError(String),
49
50 #[error("DID resolution failed: {0}")]
52 DidResolutionError(String),
53
54 #[error("Serialization error: {0}")]
56 SerializationError(String),
57
58 #[error("Invalid input: {0}")]
60 InvalidInput(String),
61
62 #[error("Crypto error: {0}")]
64 CryptoError(String),
65
66 #[error("Input too large: {0}")]
68 InputTooLarge(String),
69
70 #[error("Internal error: {0}")]
72 InternalError(String),
73
74 #[error("Organizational Attestation verification failed: {0}")]
76 OrgVerificationFailed(String),
77
78 #[error("Organizational Attestation expired")]
80 OrgAttestationExpired,
81
82 #[error("Organizational DID resolution failed: {0}")]
84 OrgDidResolutionFailed(String),
85
86 #[error("Bundle is {age_secs}s old (max {max_secs}s). Refresh with: auths id export-bundle")]
88 BundleExpired {
89 age_secs: u64,
91 max_secs: u64,
93 },
94
95 #[error("Attestation is {age_secs}s old (max {max_secs}s)")]
97 AttestationTooOld {
98 age_secs: u64,
100 max_secs: u64,
102 },
103
104 #[error("Delegated attestation escalates capability beyond its delegator")]
106 CapabilityEscalation,
107
108 #[error("Delegated attestation outlives its delegator")]
110 DelegationOutlivesParent,
111
112 #[error("Delegator attestation is revoked")]
114 DelegatorRevoked,
115
116 #[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 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}