Skip to main content

identity_kit/keys/
error.rs

1//! Error type of the `keys` module.
2
3use std::error::Error;
4use std::path::PathBuf;
5
6use super::KeyId;
7use crate::cause::cause;
8use crate::jose::{JwsAlgorithm, KeyType};
9
10/// Why a [`KeyStore`](super::KeyStore) operation failed.
11///
12/// The first variants are the contract every backend follows (the test suite checks them); the
13/// file variants are reported by [`SoftwareKeyStore`](super::SoftwareKeyStore), and
14/// [`Backend`](Self::Backend) carries whatever a remote backend reports.
15#[derive(Debug, thiserror::Error)]
16#[non_exhaustive]
17pub enum KeyStoreError {
18    /// No key has this id.
19    #[error("key `{0}` not found")]
20    NotFound(KeyId),
21    /// A key with this id exists already, so it cannot be generated or imported.
22    #[error("key `{0}` already exists")]
23    AlreadyExists(KeyId),
24    /// The key signs with another algorithm than the one requested.
25    #[error("key `{key}` signs with {key_alg}, not {requested}")]
26    AlgorithmMismatch {
27        /// The key.
28        key: KeyId,
29        /// The algorithm the key was created for.
30        key_alg: JwsAlgorithm,
31        /// The algorithm that was requested.
32        requested: JwsAlgorithm,
33    },
34    /// The backend does not implement this operation (`generate` or `delete`).
35    #[error("key store does not support `{0}`")]
36    Unsupported(&'static str),
37    /// The backend does not sign with this algorithm; see
38    /// [`KeyStoreCapabilities::algorithms`](super::KeyStoreCapabilities::algorithms).
39    #[error("key store does not support {0}")]
40    UnsupportedAlgorithm(JwsAlgorithm),
41    /// The backend cannot generate keys of this type.
42    #[error("key store does not support {0:?} keys")]
43    UnsupportedKeyType(KeyType),
44    /// The algorithm of a [`KeySpec`](super::KeySpec) does not fit its key type, for example
45    /// `ES256` with an Ed25519 key.
46    #[error("{alg} cannot be used with {key_type:?} keys")]
47    InvalidSpec {
48        /// The requested key type.
49        key_type: KeyType,
50        /// The requested algorithm.
51        alg: JwsAlgorithm,
52    },
53    /// The key exists but its material cannot be used: it does not decode, the public part does
54    /// not match the private part, the type is unknown, and so on. The source is the error that
55    /// says why, when there is one: the [`JwkError`](crate::jose::JwkError) of a public key that
56    /// does not convert to a JWK, the error of a private scalar out of range.
57    #[error("key `{key}` is unusable: {reason}{}", cause(.source.as_ref()))]
58    InvalidKey {
59        /// The key.
60        key: KeyId,
61        /// What is wrong with it.
62        reason: String,
63        /// The underlying error.
64        source: Option<Box<dyn Error + Send + Sync + 'static>>,
65    },
66    /// Reading or writing the key store file failed.
67    #[error("key store file `{}`: {source}", path.display())]
68    Io {
69        /// The file.
70        path: PathBuf,
71        /// The I/O error.
72        #[source]
73        source: std::io::Error,
74    },
75    /// The key store file is readable or writable by other users.
76    #[error(
77        "key store file `{}` has mode {mode:04o}; make it private (0600) or opt in with `allow_insecure_permissions`",
78        path.display()
79    )]
80    InsecurePermissions {
81        /// The file.
82        path: PathBuf,
83        /// Its permission bits.
84        mode: u32,
85    },
86    /// The key store file is not a usable JWK set. The source is the JSON error, or the error
87    /// that makes one of its keys unusable, when there is one.
88    #[error(
89        "key store file `{}` is not a usable JWK set: {reason}{}",
90        path.display(),
91        cause(.source.as_ref())
92    )]
93    InvalidKeySet {
94        /// The file.
95        path: PathBuf,
96        /// What is wrong with it.
97        reason: String,
98        /// The underlying error.
99        source: Option<Box<dyn Error + Send + Sync + 'static>>,
100    },
101    /// An error of a remote backend (an HSM, a cloud service).
102    #[error("key store backend error: {0}")]
103    Backend(#[source] Box<dyn Error + Send + Sync + 'static>),
104}
105
106impl KeyStoreError {
107    /// [`KeyStoreError::InvalidKey`] for `key`, without an underlying error.
108    pub fn invalid_key(key: KeyId, reason: impl Into<String>) -> Self {
109        Self::InvalidKey {
110            key,
111            reason: reason.into(),
112            source: None,
113        }
114    }
115
116    /// Wraps a backend's own error as [`KeyStoreError::Backend`].
117    pub fn backend<E: Error + Send + Sync + 'static>(error: E) -> Self {
118        Self::Backend(Box::new(error))
119    }
120}