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}