use thiserror::Error;
use crate::{nsm::error::NsmError as InnerNsm, time};
pub type AttestResult<T> = Result<T, AttestError>;
pub type AttestationResult<T> = Result<T, AttestationError>;
pub type CertResult<T> = Result<T, CertError>;
#[allow(clippy::module_name_repetitions)]
#[derive(Error, Debug)]
pub enum AttestError
where
Self: Send + Sync,
{
#[error("An error occurred while attesting the connection received: {0}")]
AttestationError(#[from] AttestationError),
#[error("An error occurred while validating the TLS Certificate received: {0}")]
CertError(#[from] CertError),
#[error("An error occurred interfacing with the Nitro Security Module: {0}")]
NsmError(#[from] InnerNsm),
#[error("An error occured decoding the public key from the attestation doc's userdata")]
DecodeError(#[from] base64::DecodeError),
#[error("An error occured parsing the expiry date from the attestation doc's userdata")]
DateParseError(#[from] chrono::ParseError),
}
#[allow(clippy::module_name_repetitions)]
#[derive(Error, Debug)]
pub enum AttestationError
where
Self: Send + Sync,
{
#[error("COSE error: `{0}`")]
InvalidCose(String),
#[error(transparent)]
InvalidCbor(#[from] serde_cbor::error::Error),
#[error("A part of the attestation doc structure was deemed invalid")]
DocStructureInvalid,
#[error("The COSE signature does not match the public key provided in the attestation doc")]
InvalidCoseSignature,
#[error(
"The PCRs found were different to the expected values.\n\nExpected:\n{0}\n\nReceived:\n{1}"
)]
UnexpectedPCRs(String, String),
#[error("PCR{0} was missing in the attestation doc")]
MissingPCR(usize),
#[error("User data was not set in the attestation doc")]
MissingUserData,
#[error("User data in attestation doc did not contain the certificate public key")]
UserDataMismatch,
#[error("Nonce in the attestation doc did not match the nonce provided,\n\nExpected: {expected}\nReceived: {received:?}")]
NonceMismatch {
expected: String,
received: Option<String>,
},
#[error("The module id was missing from the attestation doc")]
MissingModuleId,
#[error("The digest in the attestation was not SHA384")]
DigestAlgorithmInvalid,
#[error("The PCRs in the attestation doc were invalid")]
InvalidPCRs,
#[error("The CA bundle length in the attestation doc was invalid")]
InvalidCABundle,
#[error("The public key length in the attestation doc was invalid")]
InvalidPublicKey,
#[error("The nonce length in the attestation doc was invalid")]
InvalidNonce,
#[error("The user data length in the attestation doc was invalid")]
InvalidUserData,
#[error("The supplied attestation doc has expired")]
ExpiredDocument,
}
#[allow(clippy::module_name_repetitions)]
#[derive(Error, Debug)]
pub enum CertError
where
Self: Send + Sync,
{
#[error("Failed to validate the trust chain for the provided cert — {0}")]
InvalidTrustChain(String),
#[error("The certificate in the attestation doc was detected as not having the NSM as root")]
UntrustedCert,
#[error("The received certificate had no Subject Alt Name extension")]
NoSubjectAltNames,
#[error("Attempts to parse certificate from PEM and DER encoding failed")]
DecodeError,
#[error("Unable to parse attestation doc bytes from Subject Alt Name extension")]
ParseError,
#[error(transparent)]
HexError(#[from] hex::FromHexError),
#[error(transparent)]
TimeError(#[from] time::Error),
#[error("Failed to parse cert from pem encoding")]
PemError(#[from] x509_parser::error::PEMError),
#[error("Failed to parse x509 cert from pem encoding")]
X509Error,
#[error("No cert given")]
NoCertGiven,
}
impl std::convert::From<webpki::Error> for CertError {
fn from(value: webpki::Error) -> Self {
Self::InvalidTrustChain(value.to_string())
}
}