Skip to main content

tor_keymgr/
err.rs

1//! An error type for the `tor-keymgr` crate.
2
3use tor_error::HasKind;
4
5use dyn_clone::DynClone;
6use tor_persist::slug::BadSlug;
7
8use std::error::Error as StdError;
9use std::fmt;
10use std::sync::Arc;
11
12use crate::raw::RawEntryId;
13use crate::{KeyPath, KeyPathError, KeystoreId};
14
15/// An Error type for this crate.
16#[derive(thiserror::Error, Debug, Clone)]
17#[non_exhaustive]
18pub enum Error {
19    /// Detected keustore corruption.
20    #[error("{0}")]
21    Corruption(#[from] KeystoreCorruptionError),
22
23    /// An opaque error returned by a [`Keystore`](crate::Keystore).
24    #[error("{0}")]
25    Keystore(#[from] Arc<dyn KeystoreError>),
26
27    /// An error returned when the [`KeyMgr`](crate::KeyMgr) is asked to generate a key that already exists.
28    ///
29    /// Note that because there is no locking of the keystore,
30    /// this situation is not reliably detected
31    /// in the presence of concurrent tasks trying to generate the same key.
32    ///
33    /// So this error is provided to help the human user,
34    /// but mustn't be relied on for correctness.
35    #[error("Key already exists")]
36    KeyAlreadyExists,
37
38    /// Error coming from the tor-key-forgecrate
39    #[error("{0}")]
40    KeyForge(#[from] tor_key_forge::Error),
41
42    /// An error caused by an invalid certificate.
43    #[error("{0}")]
44    InvalidCert(#[from] tor_key_forge::InvalidCertError),
45
46    /// An error returned when the [`KeyMgr`](crate::KeyMgr) is unable to
47    /// find a [`Keystore`](crate::Keystore) matching a given [`KeystoreId`]
48    /// in either its `primary_store` field or the `secondary_stores` collection.
49    #[error("Keystore {0} not found")]
50    KeystoreNotFound(KeystoreId),
51
52    /// An internal error.
53    #[error("Internal error")]
54    Bug(#[from] tor_error::Bug),
55}
56
57/// An error returned by a [`Keystore`](crate::Keystore).
58pub trait KeystoreError:
59    HasKind + StdError + DynClone + fmt::Debug + fmt::Display + Send + Sync + 'static
60{
61}
62
63impl HasKind for Error {
64    fn kind(&self) -> tor_error::ErrorKind {
65        use Error as E;
66        use tor_error::ErrorKind as EK;
67
68        match self {
69            E::Keystore(e) => e.kind(),
70            E::Corruption(_) => EK::KeystoreCorrupted,
71            E::KeyAlreadyExists => EK::BadApiUsage, // TODO: not strictly right
72            E::KeystoreNotFound(_) => EK::BadApiUsage, // TODO: not strictly right
73            E::KeyForge(_) => EK::BadApiUsage,
74            E::InvalidCert(_) => EK::BadApiUsage, // TODO: not strictly right
75            E::Bug(e) => e.kind(),
76        }
77    }
78}
79
80/// An error caused by a syntactically invalid [`ArtiPath`](crate::ArtiPath).
81///
82/// The `ArtiPath` is not in the legal syntax: it contains bad characters,
83/// or a syntactically invalid components.
84///
85/// (Does not include any errors arising from paths which are invalid
86/// *for the particular key*.)
87#[derive(thiserror::Error, Debug, Clone)]
88#[error("Invalid ArtiPath")]
89#[non_exhaustive]
90pub enum ArtiPathSyntaxError {
91    /// One of the path slugs was invalid.
92    #[error("{0}")]
93    Slug(#[from] BadSlug),
94
95    /// An internal error.
96    #[error("Internal error")]
97    Bug(#[from] tor_error::Bug),
98}
99
100/// An error caused by keystore corruption.
101#[derive(thiserror::Error, Debug, Clone)]
102#[error("Keystore corruption")]
103#[non_exhaustive]
104pub enum KeystoreCorruptionError {
105    /// A keystore contains a key that has an invalid [`KeyPath`].
106    #[error("{0}")]
107    KeyPath(#[from] KeyPathError),
108
109    /// A keystore contains an unrecognized [`KeyPath`].
110    #[error("Unrecognized key path {0}")]
111    Unrecognized(KeyPath),
112
113    /// Missing certificate for key.
114    #[error("Missing certificate for key")]
115    MissingCertificate,
116
117    /// Missing the subject key of a certificate we own.
118    #[error("Subject key of certificate not found")]
119    MissingSubjectKey,
120
121    /// Missing signing key for certificate.
122    #[error("Missing signing key for certificate")]
123    MissingSigningKey,
124}
125
126/// An error that happens when we encounter an unknown key type.
127#[derive(thiserror::Error, PartialEq, Eq, Debug, Clone)]
128#[error("unknown key type: arti_extension={arti_extension}")]
129pub struct UnknownKeyTypeError {
130    /// The extension used for keys of this type in an Arti keystore.
131    pub(crate) arti_extension: String,
132}
133
134/// An unrecognized keystore entry.
135#[derive(Clone, Debug, amplify::Getters, thiserror::Error)]
136#[error("Unrecognized keystore entry")]
137pub struct UnrecognizedEntryError {
138    /// An identifier of the entry that caused the error.
139    entry: UnrecognizedEntry,
140    /// The underlying error that occurred.
141    // TODO: This should be an `Error` specific for the situation.
142    //
143    // [`KeystoreError`] is a provvisory solution that presents
144    // some issues, for example:
145    //
146    // * not all variants of `KeystoreError` are relevant
147    // * redundancy with some other Error types like
148    // [`MalformedServiceKeyError::NotAKey`](crate::keystore::ctor::err::MalformedServiceKeyError)
149    // * [`Keystore::list`](crate::Keystore) returns
150    // `StdResult<Vec<StdResult<(KeyPath, KeystoreItemType), UnrecognizedEntryError>>, KeystoreError>`,
151    // `KeystoreError` presents itself twice at 2 different levels, there is ambiguity
152    #[source]
153    error: Arc<dyn KeystoreError>,
154}
155
156impl UnrecognizedEntryError {
157    /// Create a new instance of `KeystoreListError` given an `UnrecognizedEntry`
158    /// and an `Arc<dyn KeystoreError>`.
159    pub(crate) fn new(entry: UnrecognizedEntry, error: Arc<dyn KeystoreError>) -> Self {
160        Self { entry, error }
161    }
162}
163
164/// The opaque identifier of an unrecognized key inside a [`Keystore`](crate::Keystore).
165#[derive(Debug, Clone, PartialEq, amplify::Getters)]
166pub struct UnrecognizedEntry {
167    /// The [`RawEntryId`] of the key, an identifier used in `arti raw` operations.
168    #[cfg_attr(not(feature = "onion-service-cli-extra"), getter(skip))]
169    raw_id: RawEntryId,
170    /// The [`KeystoreId`] of the keystore where the entry was found.
171    keystore_id: KeystoreId,
172}
173
174impl UnrecognizedEntry {
175    /// Create a new [`UnrecognizedEntry`] from a raw identifier.
176    pub(crate) fn new(raw_id: RawEntryId, keystore_id: KeystoreId) -> Self {
177        Self {
178            raw_id,
179            keystore_id,
180        }
181    }
182}
183
184#[cfg(test)]
185mod tests {
186    // @@ begin test lint list maintained by maint/add_warning @@
187    #![allow(clippy::bool_assert_comparison)]
188    #![allow(clippy::clone_on_copy)]
189    #![allow(clippy::dbg_macro)]
190    #![allow(clippy::mixed_attributes_style)]
191    #![allow(clippy::print_stderr)]
192    #![allow(clippy::print_stdout)]
193    #![allow(clippy::single_char_pattern)]
194    #![allow(clippy::unwrap_used)]
195    #![allow(clippy::unchecked_time_subtraction)]
196    #![allow(clippy::useless_vec)]
197    #![allow(clippy::needless_pass_by_value)]
198    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
199    use super::*;
200    use tor_error::ErrorKind;
201
202    #[derive(Debug, Copy, Clone, PartialEq, thiserror::Error)]
203    #[error("The source of a test error")]
204    struct TestErrorSource;
205
206    #[derive(Debug, Clone, thiserror::Error)]
207    #[error("A test error")]
208    struct TestError(#[from] TestErrorSource);
209
210    impl KeystoreError for TestError {}
211
212    impl HasKind for TestError {
213        fn kind(&self) -> ErrorKind {
214            ErrorKind::Other
215        }
216    }
217
218    #[test]
219    fn error_source() {
220        let e: Error = (Arc::new(TestError(TestErrorSource)) as Arc<dyn KeystoreError>).into();
221
222        assert_eq!(
223            e.source().unwrap().to_string(),
224            TestError(TestErrorSource).to_string()
225        );
226    }
227}