#[cfg(feature = "openssl")]
use openssl::error::ErrorStack;
use std::{
array::TryFromSliceError,
convert::From,
error,
fmt::{Debug, Display},
io,
};
#[cfg(feature = "openssl")]
use rdrand::ErrorCode;
use std::os::raw::c_int;
#[cfg(feature = "openssl")]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CertFormatError {
UnknownFormat,
}
#[cfg(feature = "openssl")]
impl std::error::Error for CertFormatError {}
#[cfg(feature = "openssl")]
impl std::fmt::Display for CertFormatError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::UnknownFormat => write!(f, "Unknown Certificate Format Encountered."),
}
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum VmmError {
InvalidCertificatePageLength = 0x1,
RateLimitRetryRequest = 0x2,
Unknown,
}
impl error::Error for VmmError {}
impl From<u32> for VmmError {
fn from(value: u32) -> Self {
match value {
0x1 => VmmError::InvalidCertificatePageLength,
0x2 => VmmError::RateLimitRetryRequest,
_ => VmmError::Unknown,
}
}
}
impl From<u64> for VmmError {
fn from(value: u64) -> Self {
((value >> 0x20) as u32).into()
}
}
impl Display for VmmError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
VmmError::InvalidCertificatePageLength => write!(f, "An invalid number of pages was provided to copy the certificate table and certificate data to userspace."),
VmmError::RateLimitRetryRequest => write!(f, "The AMD Secure Processor detected a possible denial-of-service. Please retry your request."),
VmmError::Unknown => write!(f, "An unknown VMM error was encountered!"),
}
}
}
#[derive(Debug)]
pub(crate) struct RawFwError(pub(crate) u64);
impl std::error::Error for RawFwError {}
impl From<u64> for RawFwError {
fn from(value: u64) -> Self {
Self(value)
}
}
impl PartialEq for RawFwError {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl From<RawFwError> for (u32, u32) {
fn from(value: RawFwError) -> Self {
((value.0 >> 0x20) as u32, value.0 as u32)
}
}
impl From<RawFwError> for (VmmError, SevError) {
fn from(value: RawFwError) -> Self {
(((value.0 >> 0x20) as u32).into(), (value.0 as u32).into())
}
}
impl Display for RawFwError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "RawFwError: {}", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(u32)]
pub enum SevError {
InvalidPlatformState = 0x0001,
InvalidGuestState = 0x0002,
InvalidConfig = 0x0003,
InvalidLen = 0x0004,
AlreadyOwned = 0x0005,
InvalidCertificate = 0x0006,
PolicyFailure = 0x0007,
Inactive = 0x0008,
InvalidAddress = 0x0009,
BadSignature = 0x000A,
BadMeasurement = 0x000B,
AsidOwned = 0x000C,
InvalidAsid = 0x000D,
WbinvdRequired = 0x000E,
DfFlushRequired = 0x000F,
InvalidGuest = 0x0010,
InvalidCommand = 0x0011,
Active = 0x0012,
HardwarePlatform = 0x0013,
HardwareUnsafe = 0x0014,
Unsupported = 0x0015,
InvalidParam = 0x0016,
ResourceLimit = 0x0017,
SecureDataInvalid = 0x0018,
InvalidPageSize = 0x0019,
InvalidPageState = 0x001A,
InvalidMdataEntry = 0x001B,
InvalidPageOwner = 0x001C,
AEADOFlow = 0x001D,
RbModeExited = 0x001F,
RMPInitRequired = 0x0020,
BadSvn = 0x0021,
BadVersion = 0x0022,
ShutdownRequired = 0x0023,
UpdateFailed = 0x0024,
RestoreRequired = 0x0025,
RMPInitFailed = 0x0026,
InvalidKey = 0x0027,
UnknownError = 0x0000,
}
impl std::fmt::Display for SevError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let code = *self as u32;
match self {
SevError::InvalidPlatformState => write!(f,"Status Code: 0x{:x}: Invalid platform state.", code),
SevError::InvalidGuestState => write!(f,"Status Code: 0x{:x}: Invalid guest state.", code),
SevError::InvalidConfig => write!(f,"Status Code: 0x{:x}: Platform configuration invalid.", code),
SevError::InvalidLen => write!(f,"Status Code: 0x{:x}: Memory buffer too small.", code),
SevError::AlreadyOwned => write!(f,"Status Code: 0x{:x}: Platform is already owned.", code),
SevError::InvalidCertificate => write!(f,"Status Code: 0x{:x}: Invalid certificate.", code),
SevError::PolicyFailure => write!(f,"Status Code: 0x{:x}: Policy failure.", code),
SevError::Inactive => write!(f,"Status Code: 0x{:x}: Guest is inactive.", code),
SevError::InvalidAddress => write!(f,"Status Code: 0x{:x}: Provided address is invalid.", code),
SevError::BadSignature => write!(f,"Status Code: 0x{:x}: Provided signature is invalid.", code),
SevError::BadMeasurement => write!(f,"Status Code: 0x{:x}: Provided measurement is invalid.", code),
SevError::AsidOwned => write!(f,"Status Code: 0x{:x}: ASID is already owned.", code),
SevError::InvalidAsid => write!(f,"Status Code: 0x{:x}: ASID is invalid.", code),
SevError::WbinvdRequired => write!(f,"Status Code: 0x{:x}: WBINVD instruction required.", code),
SevError::DfFlushRequired => write!(f,"Status Code: 0x{:x}: DF_FLUSH invocation required.", code),
SevError::InvalidGuest => write!(f,"Status Code: 0x{:x}: Guest handle is invalid.", code),
SevError::InvalidCommand => write!(f,"Status Code: 0x{:x}: Issued command is invalid.", code),
SevError::Active => write!(f,"Status Code: 0x{:x}: Guest is active.", code),
SevError::HardwarePlatform => {
write!(f,"Status Code: 0x{:x}: Hardware condition occured, safe to re-allocate parameter buffers.", code)
}
SevError::HardwareUnsafe => {
write!(f,"Status Code: 0x{:x}: Hardware condition occured, unsafe to re-allocate parameter buffers.", code)
}
SevError::Unsupported => write!(f,"Status Code: 0x{:x}: Feature is unsupported.", code),
SevError::InvalidParam => write!(f,"Status Code: 0x{:x}: Given parameter is invalid.", code),
SevError::ResourceLimit => {
write!(f,"Status Code: 0x{:x}: SEV firmware has run out of required resources to carry out command.", code)
}
SevError::SecureDataInvalid => write!(f,"Status Code: 0x{:x}: SEV platform observed a failed integrity check.", code),
SevError::InvalidPageSize => write!(f,"Status Code: 0x{:x}: The RMP page size is incorrect.", code),
SevError::InvalidPageState => write!(f,"Status Code: 0x{:x}: The RMP page state is incorrect.", code),
SevError::InvalidMdataEntry => write!(f,"Status Code: 0x{:x}: The metadata entry is invalid.", code),
SevError::InvalidPageOwner => write!(f,"Status Code: 0x{:x}: The page ownership is incorrect.", code),
SevError::AEADOFlow => write!(f,"Status Code: 0x{:x}: The AEAD algorithm would have overflowed.", code),
SevError::RbModeExited => write!(f,"Status Code: 0x{:x}: A Mailbox mode command was sent while the SEV FW was in Ring Buffer \
mode. Ring Buffer mode has been exited; the Mailbox mode command has \
been ignored. Retry is recommended.", code),
SevError::RMPInitRequired => write!(f,"Status Code: 0x{:x}: The RMP must be reinitialized.", code),
SevError::BadSvn => write!(f,"Status Code: 0x{:x}: SVN of provided image is lower than the committed SVN.", code),
SevError::BadVersion => write!(f,"Status Code: 0x{:x}: Firmware version anti-rollback.", code),
SevError::ShutdownRequired => write!(f,"Status Code: 0x{:x}: An invocation of SNP_SHUTDOWN is required to complete this action.", code),
SevError::UpdateFailed => write!(f,"Status Code: 0x{:x}: Update of the firmware internal state or a guest context page has failed.", code),
SevError::RestoreRequired => write!(f,"Status Code: 0x{:x}: Installation of the committed firmware image required.", code),
SevError::RMPInitFailed => write!(f,"Status Code: 0x{:x}: The RMP initialization failed.", code),
SevError::InvalidKey => write!(f,"Status Code: 0x{:x}: The key requested is invalid, not present, or not allowed.", code),
SevError::UnknownError => write!(f,"Unknown SEV Error"),
}
}
}
impl From<u64> for SevError {
fn from(value: u64) -> Self {
Self::from(value as u32)
}
}
impl From<u32> for SevError {
#[inline]
fn from(error: u32) -> SevError {
match error {
0x01 => SevError::InvalidPlatformState,
0x02 => SevError::InvalidGuestState,
0x03 => SevError::InvalidConfig,
0x04 => SevError::InvalidLen,
0x05 => SevError::AlreadyOwned,
0x06 => SevError::InvalidCertificate,
0x07 => SevError::PolicyFailure,
0x08 => SevError::Inactive,
0x09 => SevError::InvalidAddress,
0x0A => SevError::BadSignature,
0x0B => SevError::BadMeasurement,
0x0C => SevError::AsidOwned,
0x0D => SevError::InvalidAsid,
0x0E => SevError::WbinvdRequired,
0x0F => SevError::DfFlushRequired,
0x10 => SevError::InvalidGuest,
0x11 => SevError::InvalidCommand,
0x12 => SevError::Active,
0x13 => SevError::HardwarePlatform,
0x14 => SevError::HardwareUnsafe,
0x15 => SevError::Unsupported,
0x16 => SevError::InvalidParam,
0x17 => SevError::ResourceLimit,
0x18 => SevError::SecureDataInvalid,
0x19 => SevError::InvalidPageSize,
0x1A => SevError::InvalidPageState,
0x1B => SevError::InvalidMdataEntry,
0x1C => SevError::InvalidPageOwner,
0x1D => SevError::AEADOFlow,
0x1F => SevError::RbModeExited,
0x20 => SevError::RMPInitRequired,
0x21 => SevError::BadSvn,
0x22 => SevError::BadVersion,
0x23 => SevError::ShutdownRequired,
0x24 => SevError::UpdateFailed,
0x25 => SevError::RestoreRequired,
0x26 => SevError::RMPInitFailed,
0x27 => SevError::InvalidKey,
_ => SevError::UnknownError,
}
}
}
impl From<SevError> for c_int {
fn from(err: SevError) -> Self {
match err {
SevError::InvalidPlatformState => 0x01,
SevError::InvalidGuestState => 0x02,
SevError::InvalidConfig => 0x03,
SevError::InvalidLen => 0x04,
SevError::AlreadyOwned => 0x05,
SevError::InvalidCertificate => 0x06,
SevError::PolicyFailure => 0x07,
SevError::Inactive => 0x08,
SevError::InvalidAddress => 0x09,
SevError::BadSignature => 0x0A,
SevError::BadMeasurement => 0x0B,
SevError::AsidOwned => 0x0C,
SevError::InvalidAsid => 0x0D,
SevError::WbinvdRequired => 0x0E,
SevError::DfFlushRequired => 0x0F,
SevError::InvalidGuest => 0x10,
SevError::InvalidCommand => 0x11,
SevError::Active => 0x12,
SevError::HardwarePlatform => 0x13,
SevError::HardwareUnsafe => 0x14,
SevError::Unsupported => 0x15,
SevError::InvalidParam => 0x16,
SevError::ResourceLimit => 0x17,
SevError::SecureDataInvalid => 0x18,
SevError::InvalidPageSize => 0x19,
SevError::InvalidPageState => 0x1A,
SevError::InvalidMdataEntry => 0x1B,
SevError::InvalidPageOwner => 0x1C,
SevError::AEADOFlow => 0x1D,
SevError::RbModeExited => 0x1F,
SevError::RMPInitRequired => 0x20,
SevError::BadSvn => 0x21,
SevError::BadVersion => 0x22,
SevError::ShutdownRequired => 0x23,
SevError::UpdateFailed => 0x24,
SevError::RestoreRequired => 0x25,
SevError::RMPInitFailed => 0x26,
SevError::InvalidKey => 0x27,
SevError::UnknownError => -1,
}
}
}
impl std::error::Error for SevError {}
#[derive(Debug)]
pub enum FirmwareError {
KnownSevError(SevError),
UnknownSevError(u32),
IoError(std::io::Error),
}
impl error::Error for FirmwareError {}
impl Display for FirmwareError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let err_description = match self {
FirmwareError::KnownSevError(error) => format!("Known SEV FW Error: {error}"),
FirmwareError::UnknownSevError(code) => {
format!("Unknown SEV FW Error Encountered: {code}")
}
FirmwareError::IoError(error) => format!("IO Error Encountered: {error}"),
};
write!(f, "{err_description}")
}
}
impl std::convert::From<SevError> for FirmwareError {
fn from(sev_error: SevError) -> Self {
match sev_error {
SevError::UnknownError => FirmwareError::UnknownSevError(sev_error as u32),
_ => FirmwareError::KnownSevError(sev_error),
}
}
}
impl From<io::Error> for FirmwareError {
#[inline]
fn from(error: io::Error) -> FirmwareError {
FirmwareError::IoError(error)
}
}
impl From<u64> for FirmwareError {
fn from(value: u64) -> Self {
Self::from(value as u32)
}
}
impl From<u32> for FirmwareError {
#[inline]
fn from(error: u32) -> FirmwareError {
match error {
0x00 => FirmwareError::IoError(io::Error::last_os_error()),
0x01..0x027 => FirmwareError::KnownSevError(error.into()),
_ => FirmwareError::UnknownSevError(error),
}
}
}
impl From<FirmwareError> for c_int {
fn from(err: FirmwareError) -> Self {
match err {
FirmwareError::UnknownSevError(_) | FirmwareError::IoError(_) => -0x01,
FirmwareError::KnownSevError(e) => e.into(),
}
}
}
#[derive(Debug)]
pub enum UserApiError {
FirmwareError(FirmwareError),
IOError(io::Error),
ApiError(CertError),
VmmError(VmmError),
UuidError(uuid::Error),
HashstickError(HashstickError),
VmplError,
AttestationReportError(AttestationReportError),
Unknown,
}
impl error::Error for UserApiError {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
Self::ApiError(uapi_error) => Some(uapi_error),
Self::FirmwareError(firmware_error) => Some(firmware_error),
Self::IOError(io_error) => Some(io_error),
Self::UuidError(uuid_error) => Some(uuid_error),
Self::VmmError(vmm_error) => Some(vmm_error),
Self::HashstickError(hashstick_error) => Some(hashstick_error),
Self::VmplError => None,
Self::AttestationReportError(attestation_error) => Some(attestation_error),
Self::Unknown => None,
}
}
}
impl std::fmt::Display for UserApiError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let err_msg: String = match self {
Self::FirmwareError(error) => format!("Firmware Error Encountered: {error}"),
Self::IOError(error) => format!("I/O Error Encountered: {error}"),
Self::ApiError(error) => format!("Certificate Error Encountered: {error}"),
Self::UuidError(error) => format!("UUID Error Encountered: {error}"),
Self::VmmError(error) => format!("VMM Error Encountered: {error}"),
Self::HashstickError(error) => format!("VLEK Hashstick Error Encountered: {error}"),
Self::VmplError => "Invalid VM Permission Level (VMPL)".to_string(),
Self::AttestationReportError(error) => {
format!("Attestation Report Error Encountered: {error}")
}
Self::Unknown => "Unknown Error Encountered!".to_string(),
};
write!(f, "{err_msg}")
}
}
impl std::convert::From<HashstickError> for UserApiError {
fn from(value: HashstickError) -> Self {
Self::HashstickError(value)
}
}
impl std::convert::From<VmmError> for UserApiError {
fn from(value: VmmError) -> Self {
Self::VmmError(value)
}
}
impl std::convert::From<uuid::Error> for UserApiError {
fn from(uuid_error: uuid::Error) -> Self {
Self::UuidError(uuid_error)
}
}
impl std::convert::From<FirmwareError> for UserApiError {
fn from(firmware_error: FirmwareError) -> Self {
Self::FirmwareError(firmware_error)
}
}
impl std::convert::From<SevError> for UserApiError {
fn from(sev_error: SevError) -> Self {
Self::FirmwareError(sev_error.into())
}
}
impl std::convert::From<std::io::Error> for UserApiError {
fn from(io_error: std::io::Error) -> Self {
Self::IOError(io_error)
}
}
impl From<UserApiError> for io::Error {
fn from(value: UserApiError) -> Self {
io::Error::new(io::ErrorKind::Other, value)
}
}
impl std::convert::From<CertError> for UserApiError {
fn from(cert_error: CertError) -> Self {
Self::ApiError(cert_error)
}
}
impl std::convert::From<AttestationReportError> for UserApiError {
fn from(attestation_error: AttestationReportError) -> Self {
Self::AttestationReportError(attestation_error)
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum HashstickError {
InvalidLength,
EmptyHashstickBuffer,
InvalidReservedField,
UnknownError,
}
impl std::error::Error for HashstickError {}
impl std::fmt::Display for HashstickError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
HashstickError::InvalidLength => {
write!(
f,
"VLEK hashstick is an invalid length. Should be 432 bytes in size."
)
}
HashstickError::EmptyHashstickBuffer => write!(f, "Hashstick buffer is empty."),
HashstickError::InvalidReservedField => {
write!(f, "Reserved field in the VLEK Hashstick is invalid.")
}
HashstickError::UnknownError => {
write!(
f,
"Unknown error encountered when handling the VLEK Hashstick."
)
}
}
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum CertError {
InvalidGUID,
PageMisalignment,
BufferOverflow,
EmptyCertBuffer,
UnknownError,
}
impl std::fmt::Display for CertError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
CertError::InvalidGUID => write!(f, "Invalid GUID provided in certificate chain."),
CertError::PageMisalignment => {
write!(f, "Certificate Buffer not aligned with 4K Pages.")
}
CertError::BufferOverflow => {
write!(f, "Buffer overflow prevented: Bytes provided exceed space allocated for the buffer provided.")
}
CertError::UnknownError => {
write!(f, "Unknown Error encountered within the certificate chain.")
}
CertError::EmptyCertBuffer => {
write!(
f,
"No certificates were provided by the host, please contact your CSP."
)
}
}
}
}
impl error::Error for CertError {}
#[derive(Debug)]
pub enum AttestationReportError {
UnsupportedReportVersion(u32),
UnsupportedField(String),
MaskedChipId,
}
impl std::fmt::Display for AttestationReportError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
AttestationReportError::MaskedChipId => write!(f, "MASK_CHIP_ID is enabled, preventing the identification of the CPU generation."),
AttestationReportError::UnsupportedReportVersion(version) => write!(f, "The encountered Attestation Report version {version} is not supported by the library yet."),
AttestationReportError::UnsupportedField(field) => write!(f,"The field {field} is not supported in the provided Attestation Report version"),
}
}
}
impl From<AttestationReportError> for std::io::Error {
fn from(value: AttestationReportError) -> Self {
std::io::Error::new(std::io::ErrorKind::Other, value)
}
}
impl error::Error for AttestationReportError {}
#[derive(Debug)]
pub enum GCTXError {
InvalidPageSize(usize, usize),
InvalidBlockSize,
MissingData,
MissingBlockSize,
UnknownError,
}
impl std::fmt::Display for GCTXError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
GCTXError::InvalidPageSize(actual, expected) => write!(
f,
"Page information was not the correct length ({actual} vs {expected})"
),
GCTXError::InvalidBlockSize => {
write!(f, "Provided data does not conform to a 4096 block size")
}
GCTXError::MissingData => {
write!(f, "Did not provide data to perform page update")
}
GCTXError::MissingBlockSize => {
write!(f, "Did not provide block size to perform page update")
}
GCTXError::UnknownError => write!(f, "An unknown Guest Context error encountered"),
}
}
}
impl std::error::Error for GCTXError {}
#[derive(Debug)]
pub enum OVMFError {
InvalidSectionType,
SEVMetadataVerification(String),
EntryMissingInTable(String),
GetTableItemError,
InvalidSize(String, usize, usize),
MismatchingGUID,
UnknownError,
}
impl std::fmt::Display for OVMFError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
OVMFError::InvalidSectionType => write!(f, "An invalid section type was found"),
OVMFError::SEVMetadataVerification(section) => {
write!(f, "Wrong SEV metadata {section}")
}
OVMFError::EntryMissingInTable(entry) => {
write!(f, "Can't find {entry} entry in OVMF table")
}
OVMFError::GetTableItemError => {
write!(f, "OVMF table failed to return item")
}
OVMFError::InvalidSize(entry, actual, expected) => {
write!(f, "Invalid size of {entry}: {actual} < {expected}")
}
OVMFError::MismatchingGUID => {
write!(f, "OVMF table footer GUID does not match expected GUID")
}
OVMFError::UnknownError => write!(f, "An unknown OVMF error encountered"),
}
}
}
impl std::error::Error for OVMFError {}
#[derive(Debug)]
pub enum SevHashError {
InvalidSize(usize, usize),
InvalidOffset(usize, usize),
UnknownError,
}
impl std::fmt::Display for SevHashError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
SevHashError::InvalidOffset(actual, expected) => {
write!(f, "Invalid page Offset: {actual} vs {expected}")
}
SevHashError::InvalidSize(actual, expected) => {
write!(f, "Invalid page Size: {actual} vs {expected}")
}
SevHashError::UnknownError => write!(f, "An unknown SEV Hashing error encountered"),
}
}
}
impl std::error::Error for SevHashError {}
#[derive(Debug)]
pub enum ArrayError {
SliceError(TryFromSliceError),
VectorError(String),
}
impl std::fmt::Display for ArrayError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
ArrayError::SliceError(error) => {
write!(f, "Error when trying from slice: {error}")
}
ArrayError::VectorError(error) => {
write!(f, "Error when trying from vector: {error}")
}
}
}
}
impl std::error::Error for ArrayError {}
impl std::convert::From<TryFromSliceError> for ArrayError {
fn from(value: TryFromSliceError) -> Self {
Self::SliceError(value)
}
}
#[derive(Debug)]
pub enum IdBlockError {
#[cfg(all(feature = "snp", feature = "openssl"))]
CryptoErrorStack(openssl::error::ErrorStack),
LargeArrayError(ArrayError),
FileError(std::io::Error),
FromSliceError(TryFromSliceError),
SevCurveError(),
SevEcsdsaSigError(String),
BadVectorError(usize, usize),
}
impl std::fmt::Display for IdBlockError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
#[cfg(all(feature = "snp", feature = "openssl"))]
IdBlockError::CryptoErrorStack(e) => write!(f, "Error when with OPENSSL: {e}"),
IdBlockError::LargeArrayError(e) => write!(f, "{e}"),
IdBlockError::FileError(e) => write!(f, "Failed handling file: {e}"),
IdBlockError::FromSliceError(e) => write!(f, "Error converting slice: {e}"),
IdBlockError::SevCurveError() => {
write!(f, "Wrong curve used in the provided private key")
}
IdBlockError::SevEcsdsaSigError(msg) => {
write!(f, "Error validation SEV signature: {msg}")
}
IdBlockError::BadVectorError(vec_size, expected) => write!(
f,
"Bad vector length: Got {vec_size}, and expected: {expected}"
),
}
}
}
impl std::error::Error for IdBlockError {}
#[cfg(all(feature = "snp", feature = "openssl"))]
impl std::convert::From<openssl::error::ErrorStack> for IdBlockError {
fn from(value: openssl::error::ErrorStack) -> Self {
Self::CryptoErrorStack(value)
}
}
impl std::convert::From<ArrayError> for IdBlockError {
fn from(value: ArrayError) -> Self {
Self::LargeArrayError(value)
}
}
impl std::convert::From<std::io::Error> for IdBlockError {
fn from(value: std::io::Error) -> Self {
Self::FileError(value)
}
}
impl std::convert::From<TryFromSliceError> for IdBlockError {
fn from(value: TryFromSliceError) -> Self {
Self::FromSliceError(value)
}
}
#[derive(Debug)]
pub enum MeasurementError {
FromSliceError(TryFromSliceError),
UUIDError(uuid::Error),
FileError(std::io::Error),
FromHexError(hex::FromHexError),
GCTXError(GCTXError),
OVMFError(OVMFError),
SevHashError(SevHashError),
IdBlockError(IdBlockError),
LargeArrayError(ArrayError),
InvalidVcpuTypeError(String),
InvalidVcpuSignatureError(String),
InvalidVmmError(String),
InvalidSevModeError(String),
InvalidOvmfKernelError,
MissingSection(String),
}
impl std::fmt::Display for MeasurementError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
MeasurementError::FromSliceError(e) => write!(f, "Error converting slice: {e}"),
MeasurementError::UUIDError(e) => write!(f, "UUID Error encountered: {e}"),
MeasurementError::FileError(e) => write!(f, "Failed handling file: {e}"),
MeasurementError::FromHexError(e) => write!(f, "Converting hex to vector error: {e}"),
MeasurementError::GCTXError(e) => write!(f, "GCTX Error Encountered: {e}"),
MeasurementError::OVMFError(e) => write!(f, "OVMF Error Encountered: {e}"),
MeasurementError::SevHashError(e) => write!(f, "Sev hash Error Encountered: {e}"),
MeasurementError::IdBlockError(e) => write!(f, "Id Block Error Encountered: {e}"),
MeasurementError::LargeArrayError(e) => {
write!(f, "Error when handling Large arrays: {e}")
}
MeasurementError::InvalidVcpuTypeError(value) => {
write!(f, "Invalid VCPU type value provided: {value}")
}
MeasurementError::InvalidVcpuSignatureError(value) => {
write!(f, "Invalid VCPU signature provided: {value}")
}
MeasurementError::InvalidVmmError(value) => {
write!(f, "Invalid VMM type provided: {value}")
}
MeasurementError::InvalidSevModeError(value) => {
write!(f, "Invalid SEV mode provided: {value}")
}
MeasurementError::InvalidOvmfKernelError => write!(
f,
"Kernel specified but OVMF doesn't support kernel/initrd/cmdline measurement"
),
MeasurementError::MissingSection(section) => write!(
f,
"Kernel specified but OVMF metadata doesn't include {section} section"
),
}
}
}
impl std::error::Error for MeasurementError {}
impl std::convert::From<TryFromSliceError> for MeasurementError {
fn from(value: TryFromSliceError) -> Self {
Self::FromSliceError(value)
}
}
impl std::convert::From<uuid::Error> for MeasurementError {
fn from(value: uuid::Error) -> Self {
Self::UUIDError(value)
}
}
impl std::convert::From<std::io::Error> for MeasurementError {
fn from(value: std::io::Error) -> Self {
Self::FileError(value)
}
}
impl std::convert::From<hex::FromHexError> for MeasurementError {
fn from(value: hex::FromHexError) -> Self {
Self::FromHexError(value)
}
}
impl std::convert::From<GCTXError> for MeasurementError {
fn from(value: GCTXError) -> Self {
Self::GCTXError(value)
}
}
impl std::convert::From<OVMFError> for MeasurementError {
fn from(value: OVMFError) -> Self {
Self::OVMFError(value)
}
}
impl std::convert::From<SevHashError> for MeasurementError {
fn from(value: SevHashError) -> Self {
Self::SevHashError(value)
}
}
impl std::convert::From<IdBlockError> for MeasurementError {
fn from(value: IdBlockError) -> Self {
Self::IdBlockError(value)
}
}
impl std::convert::From<ArrayError> for MeasurementError {
fn from(value: ArrayError) -> Self {
Self::LargeArrayError(value)
}
}
#[cfg(feature = "openssl")]
#[derive(Debug)]
pub enum SessionError {
RandError(ErrorCode),
OpenSSLStack(ErrorStack),
IOError(std::io::Error),
}
#[cfg(feature = "openssl")]
impl From<ErrorCode> for SessionError {
fn from(value: ErrorCode) -> Self {
Self::RandError(value)
}
}
#[cfg(feature = "openssl")]
impl From<std::io::Error> for SessionError {
fn from(value: std::io::Error) -> Self {
Self::IOError(value)
}
}
#[cfg(feature = "openssl")]
impl From<ErrorStack> for SessionError {
fn from(value: ErrorStack) -> Self {
Self::OpenSSLStack(value)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::{
convert::{TryFrom, TryInto},
error::Error,
};
#[test]
fn test_vmm_error_complete() {
let variants = vec![
(1u32, VmmError::InvalidCertificatePageLength),
(2u32, VmmError::RateLimitRetryRequest),
(999u32, VmmError::Unknown),
];
for (code, expected) in variants {
assert_eq!(VmmError::from(code), expected);
assert_eq!(VmmError::from((code as u64) << 32), expected);
assert!(!expected.to_string().is_empty());
assert!(std::error::Error::source(&expected).is_none());
}
}
#[test]
fn test_sev_error_complete() {
for code in 0x01..=0x27u32 {
if code == 0x1E {
continue;
} let err = SevError::from(code);
assert!(!matches!(err, SevError::UnknownError));
let err64 = SevError::from(code as u64);
assert_eq!(err, err64);
assert!(!err.to_string().is_empty());
let c_val: c_int = err.into();
assert_eq!(c_val as u32, code);
}
assert_eq!(SevError::from(0u32), SevError::UnknownError);
assert_eq!(SevError::from(0x28u32), SevError::UnknownError);
assert!(!SevError::from(0u32).to_string().is_empty());
assert!(!SevError::from(0x28u32).to_string().is_empty());
let err: SevError = SevError::UnknownError;
let c_val: c_int = err.into();
assert_eq!(c_val as u32, u32::MAX);
}
#[test]
fn test_raw_fw_error_complete() {
let raw = RawFwError(0x100000000u64);
assert!(raw.to_string().contains("RawFwError: 4294967296"));
assert!(format!("{:?}", raw).contains("RawFwError"));
assert_eq!(RawFwError::from(0x100000000u64), raw);
let (upper, lower): (u32, u32) = raw.into();
assert_eq!(upper, 1);
assert_eq!(lower, 0);
let raw2 = RawFwError(0x100000000u64);
let (vmm, _sev): (VmmError, SevError) = raw2.into();
assert_eq!(vmm, VmmError::InvalidCertificatePageLength);
}
#[test]
fn test_firmware_error_complete() {
let io_err = std::io::Error::new(std::io::ErrorKind::Other, "test");
let variants = vec![
FirmwareError::IoError(io_err),
FirmwareError::KnownSevError(SevError::InvalidPlatformState),
FirmwareError::UnknownSevError(999),
];
for err in variants {
assert!(!err.to_string().is_empty());
let c_val: c_int = err.into();
assert!(c_val == -1 || c_val > 0);
}
let from_u32: FirmwareError = 0x0u32.into();
assert!(matches!(from_u32, FirmwareError::IoError(_)));
let from_u32: FirmwareError = 0x1u32.into();
assert!(matches!(from_u32, FirmwareError::KnownSevError(_)));
let from_u32: FirmwareError = 0x28u32.into();
assert!(matches!(from_u32, FirmwareError::UnknownSevError(_)));
let from_u64: FirmwareError = 0x1u64.into();
assert!(matches!(from_u64, FirmwareError::KnownSevError(_)));
}
#[test]
fn test_firmware_error_conversions() {
let sev_err = SevError::InvalidPlatformState;
let fw_err = FirmwareError::from(sev_err);
assert!(matches!(
fw_err,
FirmwareError::KnownSevError(SevError::InvalidPlatformState)
));
let unknown_sev = SevError::UnknownError;
let fw_err = FirmwareError::from(unknown_sev);
assert!(matches!(fw_err, FirmwareError::UnknownSevError(_)));
let io_err = std::io::Error::new(std::io::ErrorKind::Other, "test");
let fw_err = FirmwareError::from(io_err);
assert!(matches!(fw_err, FirmwareError::IoError(_)));
}
#[test]
fn test_user_api_error_complete() {
let variants = vec![
FirmwareError::UnknownSevError(0).into(),
std::io::Error::new(std::io::ErrorKind::Other, "test").into(),
CertError::UnknownError.into(),
VmmError::Unknown.into(),
uuid::Uuid::try_from("").unwrap_err().into(),
HashstickError::UnknownError.into(),
UserApiError::VmplError, UserApiError::Unknown, ];
for err in variants {
assert!(!err.to_string().is_empty());
match &err {
UserApiError::VmplError | UserApiError::Unknown => assert!(err.source().is_none()),
_ => assert!(err.source().is_some()),
}
let _: std::io::Error = err.into();
}
let sev_error: SevError = SevError::InvalidPlatformState;
let uapi_error: UserApiError = sev_error.into();
assert!(matches!(uapi_error, UserApiError::FirmwareError(_)));
}
#[test]
fn test_hashstick_error_complete() {
let variants = vec![
HashstickError::InvalidLength,
HashstickError::EmptyHashstickBuffer,
HashstickError::UnknownError,
];
for err in variants {
assert!(!err.to_string().is_empty());
assert!(std::error::Error::source(&err).is_none());
}
}
#[test]
fn test_cert_error_complete() {
let variants = vec![
CertError::InvalidGUID,
CertError::PageMisalignment,
CertError::BufferOverflow,
CertError::EmptyCertBuffer,
CertError::UnknownError,
];
for err in variants {
assert!(!err.to_string().is_empty());
assert!(std::error::Error::source(&err).is_none());
}
}
#[test]
fn test_gctx_error_complete() {
let variants = vec![
GCTXError::InvalidPageSize(100, 200),
GCTXError::InvalidBlockSize,
GCTXError::MissingData,
GCTXError::MissingBlockSize,
GCTXError::UnknownError,
];
for err in variants {
assert!(!err.to_string().is_empty());
assert!(std::error::Error::source(&err).is_none());
}
}
#[test]
fn test_ovmf_error_complete() {
let variants = vec![
OVMFError::InvalidSectionType,
OVMFError::SEVMetadataVerification("test".into()),
OVMFError::EntryMissingInTable("test".into()),
OVMFError::GetTableItemError,
OVMFError::InvalidSize("test".into(), 1, 2),
OVMFError::MismatchingGUID,
OVMFError::UnknownError,
];
for err in variants {
assert!(!err.to_string().is_empty());
assert!(std::error::Error::source(&err).is_none());
}
}
#[test]
fn test_sev_hash_error_complete() {
let variants = vec![
SevHashError::InvalidSize(1, 2),
SevHashError::InvalidOffset(1, 2),
SevHashError::UnknownError,
];
for err in variants {
assert!(!err.to_string().is_empty());
assert!(std::error::Error::source(&err).is_none());
}
}
#[test]
fn test_large_array_error_complete() {
let slice_err: Result<[u8; 2], TryFromSliceError> = vec![1u8].as_slice().try_into();
let variants = vec![
slice_err.unwrap_err().into(),
ArrayError::VectorError("test".into()),
];
for err in variants {
assert!(!err.to_string().is_empty());
assert!(std::error::Error::source(&err).is_none());
}
}
#[test]
fn test_id_block_error_complete() {
let slice_err: Result<[u8; 2], TryFromSliceError> = vec![1u8].as_slice().try_into();
let variants = vec![
ArrayError::VectorError("test".into()).into(),
std::io::Error::new(std::io::ErrorKind::Other, "test").into(),
slice_err.unwrap_err().into(),
IdBlockError::SevCurveError(),
IdBlockError::SevEcsdsaSigError("test".into()),
];
for err in variants {
assert!(!err.to_string().is_empty());
assert!(std::error::Error::source(&err).is_none());
}
let arr_err = ArrayError::VectorError("test".into());
assert!(matches!(
IdBlockError::from(arr_err),
IdBlockError::LargeArrayError(_)
));
}
#[test]
fn test_measurement_error_complete() {
let slice_err: Result<[u8; 2], TryFromSliceError> = vec![1u8].as_slice().try_into();
let uuid_err = uuid::Uuid::try_from("").unwrap_err();
let variants = vec![
slice_err.unwrap_err().into(),
uuid_err.into(),
std::io::Error::new(std::io::ErrorKind::Other, "test").into(),
hex::FromHexError::OddLength.into(),
GCTXError::UnknownError.into(),
OVMFError::UnknownError.into(),
SevHashError::UnknownError.into(),
IdBlockError::SevCurveError().into(),
ArrayError::VectorError("test".into()).into(),
MeasurementError::InvalidVcpuTypeError("test".into()),
MeasurementError::InvalidVcpuSignatureError("test".into()),
MeasurementError::InvalidVmmError("test".into()),
MeasurementError::InvalidSevModeError("test".into()),
MeasurementError::InvalidOvmfKernelError,
MeasurementError::MissingSection("test".into()),
];
for err in variants {
assert!(!err.to_string().is_empty());
assert!(
err.source().is_some()
|| matches!(
err,
MeasurementError::FromSliceError(_)
| MeasurementError::UUIDError(_)
| MeasurementError::FileError(_)
| MeasurementError::FromHexError(_)
| MeasurementError::GCTXError(_)
| MeasurementError::OVMFError(_)
| MeasurementError::SevHashError(_)
| MeasurementError::IdBlockError(_)
| MeasurementError::LargeArrayError(_)
| MeasurementError::InvalidVcpuTypeError(_)
| MeasurementError::InvalidVcpuSignatureError(_)
| MeasurementError::InvalidVmmError(_)
| MeasurementError::InvalidSevModeError(_)
| MeasurementError::InvalidOvmfKernelError
| MeasurementError::MissingSection(_)
)
);
}
}
#[cfg(feature = "openssl")]
#[test]
fn test_openssl_features_complete() {
let cert_err = CertFormatError::UnknownFormat;
assert!(!cert_err.to_string().is_empty());
assert!(std::error::Error::source(&cert_err).is_none());
let io_err = std::io::Error::new(std::io::ErrorKind::Other, "test");
let variants = vec![
SessionError::RandError(ErrorCode::HardwareFailure),
SessionError::IOError(io_err),
SessionError::OpenSSLStack(ErrorStack::get()),
];
for err in variants {
let debug_str = format!("{:?}", err);
match err {
SessionError::RandError(_) => assert!(debug_str.contains("RandError")),
SessionError::IOError(_) => assert!(debug_str.contains("IOError")),
SessionError::OpenSSLStack(_) => assert!(debug_str.contains("OpenSSLStack")),
}
}
let from_io = SessionError::from(std::io::Error::new(std::io::ErrorKind::Other, "test"));
assert!(matches!(from_io, SessionError::IOError(_)));
let from_code = SessionError::from(ErrorCode::HardwareFailure);
assert!(matches!(from_code, SessionError::RandError(_)));
let from_stack = SessionError::from(ErrorStack::get());
assert!(matches!(from_stack, SessionError::OpenSSLStack(_)));
}
}