use log::error;
use zeroize::Zeroize;
#[cfg(not(feature = "no-std"))]
use std::fmt;
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Clone, Copy, Debug, PartialEq, Zeroize)]
pub enum Status {
Success,
Error(Error),
}
impl Status {
pub fn to_result(self) -> Result<()> {
match self {
Status::Success => Ok(()),
Status::Error(error) => Err(error),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Zeroize)]
pub enum Error {
GenericError,
NotSupported,
NotPermitted,
BufferTooSmall,
AlreadyExists,
DoesNotExist,
BadState,
InvalidArgument,
InsufficientMemory,
InsufficientStorage,
CommunicationFailure,
StorageFailure,
DataCorrupt,
DataInvalid,
HardwareFailure,
CorruptionDetected,
InsufficientEntropy,
InvalidSignature,
InvalidPadding,
InsufficientData,
InvalidHandle,
}
#[cfg(not(feature = "no-std"))]
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::GenericError => write!(
f,
"An error occurred that does not correspond to any defined failure cause"
),
Error::NotSupported => write!(
f,
"The requested operation or a parameter is not supported by this implementation"
),
Error::NotPermitted => write!(f, "The requested action is denied by a policy"),
Error::BufferTooSmall => write!(f, "An output buffer is too small"),
Error::AlreadyExists => write!(f, "Asking for an item that already exists"),
Error::DoesNotExist => write!(f, "Asking for an item that doesn't exist"),
Error::BadState => write!(
f,
"The requested action cannot be performed in the current state"
),
Error::InvalidArgument => {
write!(f, "The parameters passed to the function are invalid")
}
Error::InsufficientMemory => write!(f, "There is not enough runtime memory"),
Error::InsufficientStorage => write!(f, "There is not enough persistent storage"),
Error::CommunicationFailure => write!(
f,
"There was a communication failure inside the implementation"
),
Error::StorageFailure => write!(
f,
"There was a storage failure that may have led to data loss"
),
Error::DataCorrupt => write!(f, "Stored data has been corrupted"),
Error::DataInvalid => write!(
f,
"Data read from storage is not valid for the implementation"
),
Error::HardwareFailure => write!(f, "A hardware failure was detected"),
Error::CorruptionDetected => write!(f, "A tampering attempt was detected"),
Error::InsufficientEntropy => write!(
f,
"There is not enough entropy to generate random data needed for the requested action"
),
Error::InvalidSignature => write!(
f,
"The signature, MAC or hash is incorrect"
),
Error::InvalidPadding => write!(
f,
"The decrypted padding is incorrect"
),
Error::InsufficientData => write!(
f,
"Insufficient data when attempting to read from a resource"
),
Error::InvalidHandle => write!(
f,
"The key handle is not valid"
),
}
}
}
#[cfg(not(feature = "no-std"))]
impl std::error::Error for Error {}
impl From<Error> for Status {
fn from(error: Error) -> Self {
Status::Error(error)
}
}
impl From<psa_crypto_sys::psa_status_t> for Status {
fn from(status: psa_crypto_sys::psa_status_t) -> Self {
match status {
psa_crypto_sys::PSA_SUCCESS => Status::Success,
psa_crypto_sys::PSA_ERROR_GENERIC_ERROR => Error::GenericError.into(),
psa_crypto_sys::PSA_ERROR_NOT_SUPPORTED => Error::NotSupported.into(),
psa_crypto_sys::PSA_ERROR_NOT_PERMITTED => Error::NotPermitted.into(),
psa_crypto_sys::PSA_ERROR_BUFFER_TOO_SMALL => Error::BufferTooSmall.into(),
psa_crypto_sys::PSA_ERROR_ALREADY_EXISTS => Error::AlreadyExists.into(),
psa_crypto_sys::PSA_ERROR_DOES_NOT_EXIST => Error::DoesNotExist.into(),
psa_crypto_sys::PSA_ERROR_BAD_STATE => Error::BadState.into(),
psa_crypto_sys::PSA_ERROR_INVALID_ARGUMENT => Error::InvalidArgument.into(),
psa_crypto_sys::PSA_ERROR_INSUFFICIENT_MEMORY => Error::InsufficientMemory.into(),
psa_crypto_sys::PSA_ERROR_INSUFFICIENT_STORAGE => Error::InsufficientStorage.into(),
psa_crypto_sys::PSA_ERROR_COMMUNICATION_FAILURE => Error::CommunicationFailure.into(),
psa_crypto_sys::PSA_ERROR_STORAGE_FAILURE => Error::StorageFailure.into(),
psa_crypto_sys::PSA_ERROR_HARDWARE_FAILURE => Error::HardwareFailure.into(),
psa_crypto_sys::PSA_ERROR_INSUFFICIENT_ENTROPY => Error::InsufficientEntropy.into(),
psa_crypto_sys::PSA_ERROR_INVALID_SIGNATURE => Error::InvalidSignature.into(),
psa_crypto_sys::PSA_ERROR_INVALID_PADDING => Error::InvalidPadding.into(),
psa_crypto_sys::PSA_ERROR_INSUFFICIENT_DATA => Error::InsufficientData.into(),
psa_crypto_sys::PSA_ERROR_INVALID_HANDLE => Error::InvalidHandle.into(),
psa_crypto_sys::PSA_ERROR_CORRUPTION_DETECTED => Error::CorruptionDetected.into(),
psa_crypto_sys::PSA_ERROR_DATA_CORRUPT => Error::DataCorrupt.into(),
psa_crypto_sys::PSA_ERROR_DATA_INVALID => Error::DataInvalid.into(),
s => {
error!("{} not recognised as a valid PSA status.", s);
Status::Error(Error::GenericError)
}
}
}
}
impl From<Status> for psa_crypto_sys::psa_status_t {
fn from(status: Status) -> psa_crypto_sys::psa_status_t {
match status {
Status::Success => psa_crypto_sys::PSA_SUCCESS,
Status::Error(error) => error.into(),
}
}
}
impl From<Error> for psa_crypto_sys::psa_status_t {
fn from(error: Error) -> psa_crypto_sys::psa_status_t {
match error {
Error::GenericError => psa_crypto_sys::PSA_ERROR_GENERIC_ERROR,
Error::NotSupported => psa_crypto_sys::PSA_ERROR_NOT_SUPPORTED,
Error::NotPermitted => psa_crypto_sys::PSA_ERROR_NOT_PERMITTED,
Error::BufferTooSmall => psa_crypto_sys::PSA_ERROR_BUFFER_TOO_SMALL,
Error::AlreadyExists => psa_crypto_sys::PSA_ERROR_ALREADY_EXISTS,
Error::DoesNotExist => psa_crypto_sys::PSA_ERROR_DOES_NOT_EXIST,
Error::BadState => psa_crypto_sys::PSA_ERROR_BAD_STATE,
Error::InvalidArgument => psa_crypto_sys::PSA_ERROR_INVALID_ARGUMENT,
Error::InsufficientMemory => psa_crypto_sys::PSA_ERROR_INSUFFICIENT_MEMORY,
Error::InsufficientStorage => psa_crypto_sys::PSA_ERROR_INSUFFICIENT_STORAGE,
Error::CommunicationFailure => psa_crypto_sys::PSA_ERROR_COMMUNICATION_FAILURE,
Error::StorageFailure => psa_crypto_sys::PSA_ERROR_STORAGE_FAILURE,
Error::DataCorrupt => psa_crypto_sys::PSA_ERROR_DATA_CORRUPT,
Error::DataInvalid => psa_crypto_sys::PSA_ERROR_DATA_INVALID,
Error::HardwareFailure => psa_crypto_sys::PSA_ERROR_HARDWARE_FAILURE,
Error::CorruptionDetected => psa_crypto_sys::PSA_ERROR_CORRUPTION_DETECTED,
Error::InsufficientEntropy => psa_crypto_sys::PSA_ERROR_INSUFFICIENT_ENTROPY,
Error::InvalidSignature => psa_crypto_sys::PSA_ERROR_INVALID_SIGNATURE,
Error::InvalidPadding => psa_crypto_sys::PSA_ERROR_INVALID_PADDING,
Error::InsufficientData => psa_crypto_sys::PSA_ERROR_INSUFFICIENT_DATA,
Error::InvalidHandle => psa_crypto_sys::PSA_ERROR_INVALID_HANDLE,
}
}
}
impl From<Status> for Result<()> {
fn from(status: Status) -> Self {
status.to_result()
}
}
#[cfg(test)]
mod test {
use crate::types::status::{Error, Status};
#[test]
fn conversion() {
assert_eq!(psa_crypto_sys::PSA_SUCCESS, Status::Success.into());
assert_eq!(
psa_crypto_sys::PSA_ERROR_HARDWARE_FAILURE,
Status::Error(Error::HardwareFailure).into()
);
assert_eq!(
Status::Error(Error::HardwareFailure),
psa_crypto_sys::PSA_ERROR_HARDWARE_FAILURE.into()
);
assert_ne!(
Status::Error(Error::InsufficientEntropy),
psa_crypto_sys::PSA_ERROR_HARDWARE_FAILURE.into()
);
assert_eq!(Status::Error(Error::GenericError), 0x0EAD_BEEF.into());
}
}