use crate::core::Capability;
use thiserror::Error;
pub use auths_crypto::AuthsErrorInfo;
#[derive(Error, Debug)]
pub enum AttestationError {
#[error("Issuer signature verification failed: {0}")]
IssuerSignatureFailed(String),
#[error("Device signature verification failed: {0}")]
DeviceSignatureFailed(String),
#[error("Attestation expired on {at}")]
AttestationExpired {
at: String,
},
#[error("Attestation revoked")]
AttestationRevoked,
#[error("Attestation timestamp {at} is in the future")]
TimestampInFuture {
at: String,
},
#[error("Missing required capability: required {required:?}, available {available:?}")]
MissingCapability {
required: Capability,
available: Vec<Capability>,
},
#[error("Signing failed: {0}")]
SigningError(String),
#[error("DID resolution failed: {0}")]
DidResolutionError(String),
#[error("Serialization error: {0}")]
SerializationError(String),
#[error("Invalid input: {0}")]
InvalidInput(String),
#[error("Crypto error: {0}")]
CryptoError(String),
#[error("Input too large: {0}")]
InputTooLarge(String),
#[error("Internal error: {0}")]
InternalError(String),
#[error("Organizational Attestation verification failed: {0}")]
OrgVerificationFailed(String),
#[error("Organizational Attestation expired")]
OrgAttestationExpired,
#[error("Organizational DID resolution failed: {0}")]
OrgDidResolutionFailed(String),
#[error("Bundle is {age_secs}s old (max {max_secs}s). Refresh with: auths id export-bundle")]
BundleExpired {
age_secs: u64,
max_secs: u64,
},
#[error("Attestation is {age_secs}s old (max {max_secs}s)")]
AttestationTooOld {
age_secs: u64,
max_secs: u64,
},
#[error("Delegated attestation escalates capability beyond its delegator")]
CapabilityEscalation,
#[error("Delegated attestation outlives its delegator")]
DelegationOutlivesParent,
#[error("Delegator attestation is revoked")]
DelegatorRevoked,
#[error("Delegator attestation could not be resolved")]
DelegatorUnresolved,
}
impl AuthsErrorInfo for AttestationError {
fn error_code(&self) -> &'static str {
match self {
Self::IssuerSignatureFailed(_) => "AUTHS-E2001",
Self::DeviceSignatureFailed(_) => "AUTHS-E2002",
Self::AttestationExpired { .. } => "AUTHS-E2003",
Self::AttestationRevoked => "AUTHS-E2004",
Self::TimestampInFuture { .. } => "AUTHS-E2005",
Self::MissingCapability { .. } => "AUTHS-E2006",
Self::SigningError(_) => "AUTHS-E2007",
Self::DidResolutionError(_) => "AUTHS-E2008",
Self::SerializationError(_) => "AUTHS-E2009",
Self::InputTooLarge(_) => "AUTHS-E2010",
Self::InvalidInput(_) => "AUTHS-E2011",
Self::CryptoError(_) => "AUTHS-E2012",
Self::InternalError(_) => "AUTHS-E2013",
Self::OrgVerificationFailed(_) => "AUTHS-E2014",
Self::OrgAttestationExpired => "AUTHS-E2015",
Self::OrgDidResolutionFailed(_) => "AUTHS-E2016",
Self::BundleExpired { .. } => "AUTHS-E2017",
Self::AttestationTooOld { .. } => "AUTHS-E2018",
Self::CapabilityEscalation => "AUTHS-E2019",
Self::DelegationOutlivesParent => "AUTHS-E2020",
Self::DelegatorRevoked => "AUTHS-E2021",
Self::DelegatorUnresolved => "AUTHS-E2022",
}
}
fn suggestion(&self) -> Option<&'static str> {
match self {
Self::IssuerSignatureFailed(_) => {
Some("Verify the attestation was signed with the correct issuer key")
}
Self::DeviceSignatureFailed(_) => Some("Verify the device key matches the attestation"),
Self::AttestationExpired { .. } => Some("Request a new attestation from the issuer"),
Self::AttestationRevoked => {
Some("This device has been revoked; contact the identity admin")
}
Self::TimestampInFuture { .. } => Some("Check system clock synchronization"),
Self::MissingCapability { .. } => {
Some("Request an attestation with the required capability")
}
Self::DidResolutionError(_) => Some("Check that the DID is valid and resolvable"),
Self::OrgVerificationFailed(_) => {
Some("Verify organizational identity is properly configured")
}
Self::OrgAttestationExpired => {
Some("Request a new organizational attestation from the admin")
}
Self::OrgDidResolutionFailed(_) => {
Some("Check that the organization's DID is correctly configured")
}
Self::InputTooLarge(_) => {
Some("Reduce the size of the JSON input or split into smaller batches")
}
Self::BundleExpired { .. } => Some(
"Re-export the bundle: auths id export-bundle --alias <ALIAS> --output bundle.json --max-age-secs <SECS>",
),
Self::AttestationTooOld { .. } => {
Some("Request a fresh attestation or increase the max_age threshold")
}
Self::SigningError(_) => {
Some("The cryptographic signing operation failed; verify key material is valid")
}
Self::SerializationError(_) => {
Some("Failed to serialize/deserialize attestation data; check JSON format")
}
Self::InvalidInput(_) => {
Some("Check the input parameters and ensure they match the expected format")
}
Self::CryptoError(_) => {
Some("A cryptographic operation failed; verify key material is valid")
}
Self::InternalError(_) => {
Some("An unexpected internal error occurred; please report this issue")
}
Self::CapabilityEscalation
| Self::DelegationOutlivesParent
| Self::DelegatorRevoked
| Self::DelegatorUnresolved => Some(
"Re-issue the delegated attestation within the delegator's capability and validity scope",
),
}
}
}