Skip to main content

psa_crypto/types/
status.rs

1// Copyright 2020 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3
4//! # PSA Status Codes
5//!
6//! This module defines success and error codes returned by any PSA function.
7
8use log::error;
9use zeroize::Zeroize;
10
11#[cfg(feature = "std")]
12use std::fmt;
13
14/// Result type returned by any PSA operation
15pub type Result<T> = core::result::Result<T, Error>;
16
17/// Definition of a PSA status code
18#[derive(Clone, Copy, Debug, PartialEq, Eq, Zeroize)]
19pub enum Status {
20    /// Status code for success
21    Success,
22    /// Status codes for errors
23    Error(Error),
24}
25
26impl Status {
27    /// Convert the Status into a Result returning the empty tuple
28    ///
29    /// # Example
30    ///
31    /// ```
32    /// use psa_crypto::types::status::{Status, Error};
33    ///
34    /// let status_err = Status::Error(Error::GenericError);
35    /// assert!(status_err.to_result().is_err());
36    ///
37    /// let status_ok = Status::Success;
38    /// assert!(status_ok.to_result().is_ok());
39    /// ```
40    pub fn to_result(self) -> Result<()> {
41        match self {
42            Status::Success => Ok(()),
43            Status::Error(error) => Err(error),
44        }
45    }
46}
47
48/// Definition of a PSA status code
49#[derive(Clone, Copy, Debug, PartialEq, Eq, Zeroize)]
50pub enum Error {
51    /// An error occurred that does not correspond to any defined failure cause
52    GenericError,
53    /// The requested operation or a parameter is not supported by this implementation
54    NotSupported,
55    /// The requested action is denied by a policy
56    NotPermitted,
57    /// An output buffer is too small
58    BufferTooSmall,
59    /// Asking for an item that already exists
60    AlreadyExists,
61    /// Asking for an item that doesn't exist
62    DoesNotExist,
63    /// The requested action cannot be performed in the current state
64    BadState,
65    /// The parameters passed to the function are invalid
66    InvalidArgument,
67    /// There is not enough runtime memory
68    InsufficientMemory,
69    /// There is not enough persistent storage
70    InsufficientStorage,
71    /// There was a communication failure inside the implementation
72    CommunicationFailure,
73    /// There was a storage failure that may have led to data loss
74    StorageFailure,
75    /// Stored data has been corrupted
76    DataCorrupt,
77    /// Data read from storage is not valid for the implementation
78    DataInvalid,
79    /// A hardware failure was detected
80    HardwareFailure,
81    /// A tampering attempt was detected
82    CorruptionDetected,
83    /// There is not enough entropy to generate random data needed for the requested action
84    InsufficientEntropy,
85    /// The signature, MAC or hash is incorrect
86    InvalidSignature,
87    /// The decrypted padding is incorrect
88    InvalidPadding,
89    /// Insufficient data when attempting to read from a resource
90    InsufficientData,
91    /// The key handle is not valid
92    InvalidHandle,
93}
94
95#[cfg(feature = "std")]
96impl fmt::Display for Error {
97    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98        match self {
99            Error::GenericError => write!(
100                f,
101                "An error occurred that does not correspond to any defined failure cause"
102            ),
103            Error::NotSupported => write!(
104                f,
105                "The requested operation or a parameter is not supported by this implementation"
106            ),
107            Error::NotPermitted => write!(f, "The requested action is denied by a policy"),
108            Error::BufferTooSmall => write!(f, "An output buffer is too small"),
109            Error::AlreadyExists => write!(f, "Asking for an item that already exists"),
110            Error::DoesNotExist => write!(f, "Asking for an item that doesn't exist"),
111            Error::BadState => write!(
112                f,
113                "The requested action cannot be performed in the current state"
114            ),
115            Error::InvalidArgument => {
116                write!(f, "The parameters passed to the function are invalid")
117            }
118            Error::InsufficientMemory => write!(f, "There is not enough runtime memory"),
119            Error::InsufficientStorage => write!(f, "There is not enough persistent storage"),
120            Error::CommunicationFailure => write!(
121                f,
122                "There was a communication failure inside the implementation"
123            ),
124            Error::StorageFailure => write!(
125                f,
126                "There was a storage failure that may have led to data loss"
127            ),
128            Error::DataCorrupt => write!(f, "Stored data has been corrupted"),
129            Error::DataInvalid => write!(
130                f,
131                "Data read from storage is not valid for the implementation"
132            ),
133            Error::HardwareFailure => write!(f, "A hardware failure was detected"),
134            Error::CorruptionDetected => write!(f, "A tampering attempt was detected"),
135            Error::InsufficientEntropy => write!(
136                f,
137                "There is not enough entropy to generate random data needed for the requested action"
138            ),
139            Error::InvalidSignature => write!(
140                f,
141                "The signature, MAC or hash is incorrect"
142            ),
143            Error::InvalidPadding => write!(
144                f,
145                "The decrypted padding is incorrect"
146            ),
147            Error::InsufficientData => write!(
148                f,
149                "Insufficient data when attempting to read from a resource"
150            ),
151            Error::InvalidHandle => write!(
152                f,
153                "The key handle is not valid"
154            ),
155        }
156    }
157}
158
159#[cfg(feature = "std")]
160impl std::error::Error for Error {}
161
162impl From<Error> for Status {
163    fn from(error: Error) -> Self {
164        Status::Error(error)
165    }
166}
167
168impl From<psa_crypto_sys::psa_status_t> for Status {
169    fn from(status: psa_crypto_sys::psa_status_t) -> Self {
170        match status {
171            psa_crypto_sys::PSA_SUCCESS => Status::Success,
172            psa_crypto_sys::PSA_ERROR_GENERIC_ERROR => Error::GenericError.into(),
173            psa_crypto_sys::PSA_ERROR_NOT_SUPPORTED => Error::NotSupported.into(),
174            psa_crypto_sys::PSA_ERROR_NOT_PERMITTED => Error::NotPermitted.into(),
175            psa_crypto_sys::PSA_ERROR_BUFFER_TOO_SMALL => Error::BufferTooSmall.into(),
176            psa_crypto_sys::PSA_ERROR_ALREADY_EXISTS => Error::AlreadyExists.into(),
177            psa_crypto_sys::PSA_ERROR_DOES_NOT_EXIST => Error::DoesNotExist.into(),
178            psa_crypto_sys::PSA_ERROR_BAD_STATE => Error::BadState.into(),
179            psa_crypto_sys::PSA_ERROR_INVALID_ARGUMENT => Error::InvalidArgument.into(),
180            psa_crypto_sys::PSA_ERROR_INSUFFICIENT_MEMORY => Error::InsufficientMemory.into(),
181            psa_crypto_sys::PSA_ERROR_INSUFFICIENT_STORAGE => Error::InsufficientStorage.into(),
182            psa_crypto_sys::PSA_ERROR_COMMUNICATION_FAILURE => Error::CommunicationFailure.into(),
183            psa_crypto_sys::PSA_ERROR_STORAGE_FAILURE => Error::StorageFailure.into(),
184            psa_crypto_sys::PSA_ERROR_HARDWARE_FAILURE => Error::HardwareFailure.into(),
185            psa_crypto_sys::PSA_ERROR_INSUFFICIENT_ENTROPY => Error::InsufficientEntropy.into(),
186            psa_crypto_sys::PSA_ERROR_INVALID_SIGNATURE => Error::InvalidSignature.into(),
187            psa_crypto_sys::PSA_ERROR_INVALID_PADDING => Error::InvalidPadding.into(),
188            psa_crypto_sys::PSA_ERROR_INSUFFICIENT_DATA => Error::InsufficientData.into(),
189            psa_crypto_sys::PSA_ERROR_INVALID_HANDLE => Error::InvalidHandle.into(),
190            psa_crypto_sys::PSA_ERROR_CORRUPTION_DETECTED => Error::CorruptionDetected.into(),
191            psa_crypto_sys::PSA_ERROR_DATA_CORRUPT => Error::DataCorrupt.into(),
192            psa_crypto_sys::PSA_ERROR_DATA_INVALID => Error::DataInvalid.into(),
193            s => {
194                error!("{} not recognised as a valid PSA status.", s);
195                Status::Error(Error::GenericError)
196            }
197        }
198    }
199}
200
201impl From<Status> for psa_crypto_sys::psa_status_t {
202    fn from(status: Status) -> psa_crypto_sys::psa_status_t {
203        match status {
204            Status::Success => psa_crypto_sys::PSA_SUCCESS,
205            Status::Error(error) => error.into(),
206        }
207    }
208}
209
210impl From<Error> for psa_crypto_sys::psa_status_t {
211    fn from(error: Error) -> psa_crypto_sys::psa_status_t {
212        match error {
213            Error::GenericError => psa_crypto_sys::PSA_ERROR_GENERIC_ERROR,
214            Error::NotSupported => psa_crypto_sys::PSA_ERROR_NOT_SUPPORTED,
215            Error::NotPermitted => psa_crypto_sys::PSA_ERROR_NOT_PERMITTED,
216            Error::BufferTooSmall => psa_crypto_sys::PSA_ERROR_BUFFER_TOO_SMALL,
217            Error::AlreadyExists => psa_crypto_sys::PSA_ERROR_ALREADY_EXISTS,
218            Error::DoesNotExist => psa_crypto_sys::PSA_ERROR_DOES_NOT_EXIST,
219            Error::BadState => psa_crypto_sys::PSA_ERROR_BAD_STATE,
220            Error::InvalidArgument => psa_crypto_sys::PSA_ERROR_INVALID_ARGUMENT,
221            Error::InsufficientMemory => psa_crypto_sys::PSA_ERROR_INSUFFICIENT_MEMORY,
222            Error::InsufficientStorage => psa_crypto_sys::PSA_ERROR_INSUFFICIENT_STORAGE,
223            Error::CommunicationFailure => psa_crypto_sys::PSA_ERROR_COMMUNICATION_FAILURE,
224            Error::StorageFailure => psa_crypto_sys::PSA_ERROR_STORAGE_FAILURE,
225            Error::DataCorrupt => psa_crypto_sys::PSA_ERROR_DATA_CORRUPT,
226            Error::DataInvalid => psa_crypto_sys::PSA_ERROR_DATA_INVALID,
227            Error::HardwareFailure => psa_crypto_sys::PSA_ERROR_HARDWARE_FAILURE,
228            Error::CorruptionDetected => psa_crypto_sys::PSA_ERROR_CORRUPTION_DETECTED,
229            Error::InsufficientEntropy => psa_crypto_sys::PSA_ERROR_INSUFFICIENT_ENTROPY,
230            Error::InvalidSignature => psa_crypto_sys::PSA_ERROR_INVALID_SIGNATURE,
231            Error::InvalidPadding => psa_crypto_sys::PSA_ERROR_INVALID_PADDING,
232            Error::InsufficientData => psa_crypto_sys::PSA_ERROR_INSUFFICIENT_DATA,
233            Error::InvalidHandle => psa_crypto_sys::PSA_ERROR_INVALID_HANDLE,
234        }
235    }
236}
237
238impl From<Status> for Result<()> {
239    fn from(status: Status) -> Self {
240        status.to_result()
241    }
242}
243
244#[cfg(test)]
245mod test {
246    use crate::types::status::{Error, Status};
247
248    #[test]
249    fn conversion() {
250        assert_eq!(psa_crypto_sys::PSA_SUCCESS, Status::Success.into());
251        assert_eq!(
252            psa_crypto_sys::PSA_ERROR_HARDWARE_FAILURE,
253            Status::Error(Error::HardwareFailure).into()
254        );
255        assert_eq!(
256            Status::Error(Error::HardwareFailure),
257            psa_crypto_sys::PSA_ERROR_HARDWARE_FAILURE.into()
258        );
259        assert_ne!(
260            Status::Error(Error::InsufficientEntropy),
261            psa_crypto_sys::PSA_ERROR_HARDWARE_FAILURE.into()
262        );
263        assert_eq!(Status::Error(Error::GenericError), 0x0EAD_BEEF.into());
264    }
265}