use sigstore_crypto::SubjectAltName;
use thiserror::Error;
use crate::IdentityMatcher;
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum Error {
#[error("identity mismatch: expected {expected}, got {}", display_opt(actual))]
IdentityMismatch {
expected: IdentityMatcher,
actual: Option<SubjectAltName>,
},
#[error("issuer mismatch: expected {expected}, got {}", display_opt(actual))]
IssuerMismatch {
expected: String,
actual: Option<String>,
},
#[error("invalid signature: {0}")]
SignatureInvalid(String),
#[error("artifact mismatch: {0}")]
ArtifactMismatch(String),
#[error("unsupported artifact input: {0}")]
UnsupportedArtifact(String),
#[error(transparent)]
Certificate(#[from] CertificateError),
#[error(transparent)]
TransparencyLog(#[from] TransparencyLogError),
#[error(transparent)]
Timestamp(#[from] TimestampError),
#[error("invalid bundle: {0}")]
InvalidBundle(String),
#[error("unsupported bundle: {0}")]
UnsupportedBundle(String),
#[error("invalid trusted root: {0}")]
InvalidTrustRoot(String),
#[error("Types error: {0}")]
Types(#[from] sigstore_types::Error),
#[error("Crypto error: {0}")]
Crypto(#[from] sigstore_crypto::Error),
#[error("Bundle error: {0}")]
Bundle(#[from] sigstore_bundle::Error),
#[error("Trust root error: {0}")]
TrustRoot(#[from] sigstore_trust_root::Error),
#[error("invalid trusted certificate: {0}")]
TrustedCertificate(#[source] Box<dyn std::error::Error + Send + Sync>),
#[error("failed to read artifact: {0}")]
ArtifactRead(#[source] std::io::Error),
}
#[derive(Error, Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum CertificateError {
#[error("malformed certificate: {0}")]
Malformed(String),
#[error("certificate chain is invalid: {0}")]
ChainInvalid(String),
#[error("no trusted certificate authority is valid at {time}")]
NoValidAuthority {
time: jiff::Timestamp,
},
#[error("certificate is not yet valid at {time} (not before {not_before})")]
NotYetValid {
time: jiff::Timestamp,
not_before: jiff::Timestamp,
},
#[error("certificate had expired at {time} (not after {not_after})")]
Expired {
time: jiff::Timestamp,
not_after: jiff::Timestamp,
},
#[error("invalid signed certificate timestamp: {0}")]
Sct(String),
}
#[derive(Error, Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum TransparencyLogError {
#[error("unknown transparency log {log_id}")]
UnknownLog {
log_id: String,
},
#[error("invalid inclusion proof: {0}")]
InclusionProof(String),
#[error("invalid checkpoint: {0}")]
Checkpoint(String),
#[error("invalid inclusion promise: {0}")]
InclusionPromise(String),
#[error("log entry does not match the bundle: {0}")]
EntryMismatch(String),
#[error("invalid integrated time: {0}")]
IntegratedTime(String),
#[error("malformed log entry: {0}")]
MalformedEntry(String),
}
#[derive(Error, Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum TimestampError {
#[error("invalid RFC 3161 timestamp: {0}")]
Invalid(String),
#[error(
"RFC 3161 timestamp {time} is outside the validity period of the authority that signed it"
)]
OutsideAuthorityValidity {
time: jiff::Timestamp,
},
#[error("no verified timestamp: {0}")]
NoVerifiedTimestamp(String),
}
impl Error {
pub(crate) fn cert_malformed(detail: String) -> Self {
CertificateError::Malformed(detail).into()
}
pub(crate) fn cert_chain_invalid(detail: String) -> Self {
CertificateError::ChainInvalid(detail).into()
}
pub(crate) fn sct(detail: String) -> Self {
CertificateError::Sct(detail).into()
}
pub(crate) fn unknown_log(log_id: String) -> Self {
TransparencyLogError::UnknownLog { log_id }.into()
}
pub(crate) fn inclusion_proof(detail: String) -> Self {
TransparencyLogError::InclusionProof(detail).into()
}
pub(crate) fn checkpoint(detail: String) -> Self {
TransparencyLogError::Checkpoint(detail).into()
}
pub(crate) fn inclusion_promise(detail: String) -> Self {
TransparencyLogError::InclusionPromise(detail).into()
}
pub(crate) fn entry_mismatch(detail: String) -> Self {
TransparencyLogError::EntryMismatch(detail).into()
}
pub(crate) fn integrated_time(detail: String) -> Self {
TransparencyLogError::IntegratedTime(detail).into()
}
pub(crate) fn malformed_entry(detail: String) -> Self {
TransparencyLogError::MalformedEntry(detail).into()
}
pub(crate) fn timestamp_invalid(detail: String) -> Self {
TimestampError::Invalid(detail).into()
}
pub(crate) fn no_verified_timestamp(detail: String) -> Self {
TimestampError::NoVerifiedTimestamp(detail).into()
}
}
fn display_opt(value: &Option<impl std::fmt::Display>) -> String {
value
.as_ref()
.map_or_else(|| "none".to_string(), ToString::to_string)
}
pub type Result<T> = std::result::Result<T, Error>;