1
//! An error type for the `tor-keymgr` crate.
2

            
3
use tor_error::HasKind;
4

            
5
use dyn_clone::DynClone;
6
use tor_persist::slug::BadSlug;
7

            
8
use std::error::Error as StdError;
9
use std::fmt;
10
use std::sync::Arc;
11

            
12
use crate::raw::RawEntryId;
13
use crate::{KeyPath, KeyPathError, KeystoreId};
14

            
15
/// An Error type for this crate.
16
#[derive(thiserror::Error, Debug, Clone)]
17
#[non_exhaustive]
18
pub 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).
58
pub trait KeystoreError:
59
    HasKind + StdError + DynClone + fmt::Debug + fmt::Display + Send + Sync + 'static
60
{
61
}
62

            
63
impl HasKind for Error {
64
4
    fn kind(&self) -> tor_error::ErrorKind {
65
        use Error as E;
66
        use tor_error::ErrorKind as EK;
67

            
68
4
        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
4
            E::Bug(e) => e.kind(),
76
        }
77
4
    }
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]
90
pub 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]
104
pub 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}")]
129
pub 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")]
137
pub 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

            
156
impl UnrecognizedEntryError {
157
    /// Create a new instance of `KeystoreListError` given an `UnrecognizedEntry`
158
    /// and an `Arc<dyn KeystoreError>`.
159
1264
    pub(crate) fn new(entry: UnrecognizedEntry, error: Arc<dyn KeystoreError>) -> Self {
160
1264
        Self { entry, error }
161
1264
    }
162
}
163

            
164
/// The opaque identifier of an unrecognized key inside a [`Keystore`](crate::Keystore).
165
#[derive(Debug, Clone, PartialEq, amplify::Getters)]
166
pub 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

            
174
impl UnrecognizedEntry {
175
    /// Create a new [`UnrecognizedEntry`] from a raw identifier.
176
1266
    pub(crate) fn new(raw_id: RawEntryId, keystore_id: KeystoreId) -> Self {
177
1266
        Self {
178
1266
            raw_id,
179
1266
            keystore_id,
180
1266
        }
181
1266
    }
182
}
183

            
184
#[cfg(test)]
185
mod 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
    #![allow(clippy::string_slice)] // See arti#2571
199
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
200
    use super::*;
201
    use tor_error::ErrorKind;
202

            
203
    #[derive(Debug, Copy, Clone, PartialEq, thiserror::Error)]
204
    #[error("The source of a test error")]
205
    struct TestErrorSource;
206

            
207
    #[derive(Debug, Clone, thiserror::Error)]
208
    #[error("A test error")]
209
    struct TestError(#[from] TestErrorSource);
210

            
211
    impl KeystoreError for TestError {}
212

            
213
    impl HasKind for TestError {
214
        fn kind(&self) -> ErrorKind {
215
            ErrorKind::Other
216
        }
217
    }
218

            
219
    #[test]
220
    fn error_source() {
221
        let e: Error = (Arc::new(TestError(TestErrorSource)) as Arc<dyn KeystoreError>).into();
222

            
223
        assert_eq!(
224
            e.source().unwrap().to_string(),
225
            TestError(TestErrorSource).to_string()
226
        );
227
    }
228
}