1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
// Copyright 2020 Contributors to the Parsec project.
// SPDX-License-Identifier: Apache-2.0

//! # PSA Status Codes
//!
//! This module defines success and error codes returned by any PSA function.

use log::error;
use zeroize::Zeroize;

#[cfg(not(feature = "no-std"))]
use std::fmt;

/// Result type returned by any PSA operation
pub type Result<T> = core::result::Result<T, Error>;

/// Definition of a PSA status code
#[derive(Clone, Copy, Debug, PartialEq, Zeroize)]
pub enum Status {
    /// Status code for success
    Success,
    /// Status codes for errors
    Error(Error),
}

impl Status {
    /// Convert the Status into a Result returning the empty tuple
    ///
    /// # Example
    ///
    /// ```
    /// use psa_crypto::types::status::{Status, Error};
    ///
    /// let status_err = Status::Error(Error::GenericError);
    /// assert!(status_err.to_result().is_err());
    ///
    /// let status_ok = Status::Success;
    /// assert!(status_ok.to_result().is_ok());
    /// ```
    pub fn to_result(self) -> Result<()> {
        match self {
            Status::Success => Ok(()),
            Status::Error(error) => Err(error),
        }
    }
}

/// Definition of a PSA status code
#[derive(Clone, Copy, Debug, PartialEq, Zeroize)]
pub enum Error {
    /// An error occurred that does not correspond to any defined failure cause
    GenericError,
    /// The requested operation or a parameter is not supported by this implementation
    NotSupported,
    /// The requested action is denied by a policy
    NotPermitted,
    /// An output buffer is too small
    BufferTooSmall,
    /// Asking for an item that already exists
    AlreadyExists,
    /// Asking for an item that doesn't exist
    DoesNotExist,
    /// The requested action cannot be performed in the current state
    BadState,
    /// The parameters passed to the function are invalid
    InvalidArgument,
    /// There is not enough runtime memory
    InsufficientMemory,
    /// There is not enough persistent storage
    InsufficientStorage,
    /// There was a communication failure inside the implementation
    CommunicationFailure,
    /// There was a storage failure that may have led to data loss
    StorageFailure,
    /// Stored data has been corrupted
    DataCorrupt,
    /// Data read from storage is not valid for the implementation
    DataInvalid,
    /// A hardware failure was detected
    HardwareFailure,
    /// A tampering attempt was detected
    CorruptionDetected,
    /// There is not enough entropy to generate random data needed for the requested action
    InsufficientEntropy,
    /// The signature, MAC or hash is incorrect
    InvalidSignature,
    /// The decrypted padding is incorrect
    InvalidPadding,
    /// Insufficient data when attempting to read from a resource
    InsufficientData,
    /// The key handle is not valid
    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());
    }
}