tor_keymgr/
mgr.rs

1//! Code for managing multiple [`Keystore`](crate::Keystore)s.
2//!
3//! See the [`KeyMgr`] docs for more details.
4
5use crate::{
6    ArtiPath, BoxedKeystore, KeyCertificateSpecifier, KeyPath, KeyPathError, KeyPathInfo,
7    KeyPathInfoExtractor, KeyPathPattern, KeySpecifier, KeystoreCorruptionError,
8    KeystoreEntryResult, KeystoreId, KeystoreSelector, Result,
9};
10
11use itertools::Itertools;
12use std::iter;
13use std::result::Result as StdResult;
14use tor_error::{bad_api_usage, internal, into_bad_api_usage};
15use tor_key_forge::{
16    ItemType, Keygen, KeygenRng, KeystoreItemType, ToEncodableCert, ToEncodableKey,
17};
18
19/// A key manager that acts as a frontend to a primary [`Keystore`](crate::Keystore) and
20/// any number of secondary [`Keystore`](crate::Keystore)s.
21///
22/// Note: [`KeyMgr`] is a low-level utility and does not implement caching (the key stores are
23/// accessed for every read/write).
24///
25/// The `KeyMgr` accessors - currently just [`get()`](KeyMgr::get) -
26/// search the configured key stores in order: first the primary key store,
27/// and then the secondary stores, in order.
28///
29///
30/// ## Concurrent key store access
31///
32/// The key stores will allow concurrent modification by different processes. In
33/// order to implement this safely without locking, the key store operations (get,
34/// insert, remove) will need to be atomic.
35///
36/// **Note**: [`KeyMgr::generate`] and [`KeyMgr::get_or_generate`] should **not** be used
37/// concurrently with any other `KeyMgr` operation that mutates the same key
38/// (i.e. a key with the same `ArtiPath`), because
39/// their outcome depends on whether the selected key store
40/// [`contains`][crate::Keystore::contains]
41/// the specified key (and thus suffers from a TOCTOU race).
42#[derive(derive_builder::Builder)]
43#[builder(pattern = "owned", build_fn(private, name = "build_unvalidated"))]
44pub struct KeyMgr {
45    /// The primary key store.
46    primary_store: BoxedKeystore,
47    /// The secondary key stores.
48    #[builder(default, setter(custom))]
49    secondary_stores: Vec<BoxedKeystore>,
50    /// The key info extractors.
51    ///
52    /// These are initialized internally by [`KeyMgrBuilder::build`], using the values collected
53    /// using `inventory`.
54    #[builder(default, setter(skip))]
55    key_info_extractors: Vec<&'static dyn KeyPathInfoExtractor>,
56}
57
58/// A keystore entry descriptor.
59///
60/// This identifies a key entry from a specific keystore.
61/// The key entry can be retrieved, using [`KeyMgr::get_entry`],
62/// or removed, using [`KeyMgr::remove_entry`].
63///
64/// Returned from [`KeyMgr::list_matching`].
65#[derive(Clone, Debug, PartialEq, amplify::Getters)]
66pub struct KeystoreEntry<'a> {
67    /// The [`KeyPath`] of the key.
68    key_path: KeyPath,
69    /// The [`KeystoreItemType`] of the key.
70    key_type: KeystoreItemType,
71    /// The [`KeystoreId`] that of the keystore where the key was found.
72    #[getter(as_copy)]
73    keystore_id: &'a KeystoreId,
74}
75
76impl KeyMgrBuilder {
77    /// Construct a [`KeyMgr`] from this builder.
78    pub fn build(self) -> StdResult<KeyMgr, KeyMgrBuilderError> {
79        use itertools::Itertools as _;
80
81        let mut keymgr = self.build_unvalidated()?;
82
83        if !keymgr.all_stores().map(|s| s.id()).all_unique() {
84            return Err(KeyMgrBuilderError::ValidationError(
85                "the keystore IDs are not pairwise unique".into(),
86            ));
87        }
88
89        keymgr.key_info_extractors = inventory::iter::<&'static dyn KeyPathInfoExtractor>
90            .into_iter()
91            .copied()
92            .collect();
93
94        Ok(keymgr)
95    }
96}
97
98// TODO: auto-generate using define_list_builder_accessors/define_list_builder_helper
99// when that becomes possible.
100//
101// See https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/1760#note_2969841
102impl KeyMgrBuilder {
103    /// Access the being-built list of secondary stores (resolving default)
104    ///
105    /// If the field has not yet been set or accessed, the default list will be
106    /// constructed and a mutable reference to the now-defaulted list of builders
107    /// will be returned.
108    pub fn secondary_stores(&mut self) -> &mut Vec<BoxedKeystore> {
109        self.secondary_stores.get_or_insert(Default::default())
110    }
111
112    /// Set the whole list (overriding the default)
113    pub fn set_secondary_stores(mut self, list: Vec<BoxedKeystore>) -> Self {
114        self.secondary_stores = Some(list);
115        self
116    }
117
118    /// Inspect the being-built list (with default unresolved)
119    ///
120    /// If the list has not yet been set, or accessed, `&None` is returned.
121    pub fn opt_secondary_stores(&self) -> &Option<Vec<BoxedKeystore>> {
122        &self.secondary_stores
123    }
124
125    /// Mutably access the being-built list (with default unresolved)
126    ///
127    /// If the list has not yet been set, or accessed, `&mut None` is returned.
128    pub fn opt_secondary_stores_mut(&mut self) -> &mut Option<Vec<BoxedKeystore>> {
129        &mut self.secondary_stores
130    }
131}
132
133inventory::collect!(&'static dyn crate::KeyPathInfoExtractor);
134
135impl KeyMgr {
136    /// Read a key from one of the key stores, and try to deserialize it as `K::Key`.
137    ///
138    /// The key returned is retrieved from the first key store that contains an entry for the given
139    /// specifier.
140    ///
141    /// Returns `Ok(None)` if none of the key stores have the requested key.
142    pub fn get<K: ToEncodableKey>(&self, key_spec: &dyn KeySpecifier) -> Result<Option<K>> {
143        let result = self.get_from_store(key_spec, &K::Key::item_type(), self.all_stores())?;
144        if result.is_none() {
145            // If the key_spec is the specifier for the public part of a keypair,
146            // try getting the pair and extracting the public portion from it.
147            if let Some(key_pair_spec) = key_spec.keypair_specifier() {
148                return Ok(self.get::<K::KeyPair>(&*key_pair_spec)?.map(|k| k.into()));
149            }
150        }
151        Ok(result)
152    }
153
154    /// Retrieve the specified keystore entry, and try to deserialize it as `K::Key`.
155    ///
156    /// The key returned is retrieved from the key store specified in the [`KeystoreEntry`].
157    ///
158    /// Returns `Ok(None)` if the key store does not contain the requested entry.
159    ///
160    /// Returns an error if the specified `key_type` does not match `K::Key::item_type()`.
161    pub fn get_entry<K: ToEncodableKey>(&self, entry: &KeystoreEntry) -> Result<Option<K>> {
162        let selector = entry.keystore_id().into();
163        let store = self.select_keystore(&selector)?;
164        self.get_from_store(entry.key_path(), entry.key_type(), [store].into_iter())
165    }
166
167    /// Read the key identified by `key_spec`.
168    ///
169    /// The key returned is retrieved from the first key store that contains an entry for the given
170    /// specifier.
171    ///
172    /// If the requested key does not exist in any of the key stores, this generates a new key of
173    /// type `K` from the key created using using `K::Key`'s [`Keygen`] implementation, and inserts
174    /// it into the specified keystore, returning the newly inserted value.
175    ///
176    /// This is a convenience wrapper around [`get()`](KeyMgr::get) and
177    /// [`generate()`](KeyMgr::generate).
178    pub fn get_or_generate<K>(
179        &self,
180        key_spec: &dyn KeySpecifier,
181        selector: KeystoreSelector,
182        rng: &mut dyn KeygenRng,
183    ) -> Result<K>
184    where
185        K: ToEncodableKey,
186        K::Key: Keygen,
187    {
188        match self.get(key_spec)? {
189            Some(k) => Ok(k),
190            None => self.generate(key_spec, selector, rng, false),
191        }
192    }
193
194    /// Generate a new key of type `K`, and insert it into the key store specified by `selector`.
195    ///
196    /// If the key already exists in the specified key store, the `overwrite` flag is used to
197    /// decide whether to overwrite it with a newly generated key.
198    ///
199    /// On success, this function returns the newly generated key.
200    ///
201    /// Returns [`Error::KeyAlreadyExists`](crate::Error::KeyAlreadyExists)
202    /// if the key already exists in the specified key store and `overwrite` is `false`.
203    ///
204    /// **IMPORTANT**: using this function concurrently with any other `KeyMgr` operation that
205    /// mutates the key store state is **not** recommended, as it can yield surprising results! The
206    /// outcome of [`KeyMgr::generate`] depends on whether the selected key store
207    /// [`contains`][crate::Keystore::contains] the specified key, and thus suffers from a TOCTOU race.
208    //
209    // TODO (#1119): can we make this less racy without a lock? Perhaps we should say we'll always
210    // overwrite any existing keys.
211    //
212    // TODO: consider replacing the overwrite boolean with a GenerateOptions type
213    // (sort of like std::fs::OpenOptions)
214    pub fn generate<K>(
215        &self,
216        key_spec: &dyn KeySpecifier,
217        selector: KeystoreSelector,
218        rng: &mut dyn KeygenRng,
219        overwrite: bool,
220    ) -> Result<K>
221    where
222        K: ToEncodableKey,
223        K::Key: Keygen,
224    {
225        let store = self.select_keystore(&selector)?;
226
227        if overwrite || !store.contains(key_spec, &K::Key::item_type())? {
228            let key = K::Key::generate(rng)?;
229            store.insert(&key, key_spec)?;
230
231            Ok(K::from_encodable_key(key))
232        } else {
233            Err(crate::Error::KeyAlreadyExists)
234        }
235    }
236
237    /// Insert `key` into the [`Keystore`](crate::Keystore) specified by `selector`.
238    ///
239    /// If the key already exists in the specified key store, the `overwrite` flag is used to
240    /// decide whether to overwrite it with the provided key.
241    ///
242    /// If this key is not already in the keystore, `None` is returned.
243    ///
244    /// If this key already exists in the keystore, its value is updated
245    /// and the old value is returned.
246    ///
247    /// Returns an error if the selected keystore is not the primary keystore or one of the
248    /// configured secondary stores.
249    pub fn insert<K: ToEncodableKey>(
250        &self,
251        key: K,
252        key_spec: &dyn KeySpecifier,
253        selector: KeystoreSelector,
254        overwrite: bool,
255    ) -> Result<Option<K>> {
256        let key = key.to_encodable_key();
257        let store = self.select_keystore(&selector)?;
258        let key_type = K::Key::item_type();
259        let old_key: Option<K> = self.get_from_store(key_spec, &key_type, [store].into_iter())?;
260
261        if old_key.is_some() && !overwrite {
262            Err(crate::Error::KeyAlreadyExists)
263        } else {
264            let () = store.insert(&key, key_spec)?;
265            Ok(old_key)
266        }
267    }
268
269    /// Remove the key identified by `key_spec` from the [`Keystore`](crate::Keystore)
270    /// specified by `selector`.
271    ///
272    /// Returns an error if the selected keystore is not the primary keystore or one of the
273    /// configured secondary stores.
274    ///
275    /// Returns the value of the removed key,
276    /// or `Ok(None)` if the key does not exist in the requested keystore.
277    ///
278    /// Returns `Err` if an error occurred while trying to remove the key.
279    pub fn remove<K: ToEncodableKey>(
280        &self,
281        key_spec: &dyn KeySpecifier,
282        selector: KeystoreSelector,
283    ) -> Result<Option<K>> {
284        let store = self.select_keystore(&selector)?;
285        let key_type = K::Key::item_type();
286        let old_key: Option<K> = self.get_from_store(key_spec, &key_type, [store].into_iter())?;
287
288        store.remove(key_spec, &key_type)?;
289
290        Ok(old_key)
291    }
292
293    /// Remove the specified keystore entry.
294    ///
295    /// Like [`KeyMgr::remove`], except this function does not return the value of the removed key.
296    ///
297    /// A return value of `Ok(None)` indicates the key was not found in the specified key store,
298    /// whereas `Ok(Some(())` means the key was successfully removed.
299    //
300    // TODO: We should be consistent and return the removed key.
301    //
302    // This probably will involve changing the return type of Keystore::remove
303    // to Result<Option<ErasedKey>>.
304    pub fn remove_entry(&self, entry: &KeystoreEntry) -> Result<Option<()>> {
305        let selector = entry.keystore_id().into();
306        let store = self.select_keystore(&selector)?;
307
308        store.remove(entry.key_path(), entry.key_type())
309    }
310
311    /// Return the keystore entry descriptors of the keys matching the specified [`KeyPathPattern`].
312    ///
313    /// NOTE: This searches for matching keys in _all_ keystores.
314    ///
315    /// NOTE: This function only returns the *recognized* entries that match the provided pattern.
316    /// The unrecognized entries (i.e. those that do not have a valid [`KeyPath`]) will be filtered out,
317    /// even if they match the specified pattern.
318    pub fn list_matching(&self, pat: &KeyPathPattern) -> Result<Vec<KeystoreEntry>> {
319        self.all_stores()
320            .map(|store| -> Result<Vec<_>> {
321                Ok(store
322                    .list()?
323                    .into_iter()
324                    .filter_map(|entry| entry.ok())
325                    .filter(|(key_path, _): &(KeyPath, KeystoreItemType)| key_path.matches(pat))
326                    .map(|(path, key_type)| KeystoreEntry {
327                        key_path: path.clone(),
328                        key_type,
329                        keystore_id: store.id(),
330                    })
331                    .collect::<Vec<_>>())
332            })
333            .flatten_ok()
334            .collect::<Result<Vec<_>>>()
335    }
336
337    /// List keys and certificates of the specified keystore.
338    #[cfg(feature = "onion-service-cli-extra")]
339    pub fn list_by_id(
340        &self,
341        id: &KeystoreId,
342    ) -> Result<Vec<KeystoreEntryResult<(KeyPath, KeystoreItemType)>>> {
343        self.find_keystore(id)?.list()
344    }
345
346    /// List keys and certificates of all the keystores.
347    #[cfg(feature = "onion-service-cli-extra")]
348    pub fn list(&self) -> Result<Vec<KeystoreEntryResult<KeystoreEntry>>> {
349        self.all_stores()
350            .map(|store| -> Result<Vec<_>> {
351                Ok(store
352                    .list()?
353                    .into_iter()
354                    .map(|entry| match entry {
355                        Ok((key_path, key_type)) => Ok(KeystoreEntry {
356                            key_path: key_path.clone(),
357                            key_type,
358                            keystore_id: store.id(),
359                        }),
360                        Err(e) => Err(e),
361                    })
362                    .collect::<Vec<_>>())
363            })
364            .flatten_ok()
365            .collect::<Result<Vec<_>>>()
366    }
367
368    /// List keys and certificates of a specific keystore.
369    #[cfg(feature = "onion-service-cli-extra")]
370    pub fn list_keystores(&self) -> Vec<KeystoreId> {
371        self.all_stores()
372            .map(|store| store.id().to_owned())
373            .collect()
374    }
375
376    /// Describe the specified key.
377    ///
378    /// Returns [`KeyPathError::Unrecognized`] if none of the registered
379    /// [`KeyPathInfoExtractor`]s is able to parse the specified [`KeyPath`].
380    ///
381    /// This function uses the [`KeyPathInfoExtractor`]s registered using
382    /// [`register_key_info_extractor`](crate::register_key_info_extractor),
383    /// or by [`DefaultKeySpecifier`](crate::derive_deftly_template_KeySpecifier).
384    pub fn describe(&self, path: &KeyPath) -> StdResult<KeyPathInfo, KeyPathError> {
385        for info_extractor in &self.key_info_extractors {
386            if let Ok(info) = info_extractor.describe(path) {
387                return Ok(info);
388            }
389        }
390
391        Err(KeyPathError::Unrecognized(path.clone()))
392    }
393
394    /// Attempt to retrieve a key from one of the specified `stores`.
395    ///
396    /// Returns the `<K as ToEncodableKey>::Key` representation of the key.
397    ///
398    /// See [`KeyMgr::get`] for more details.
399    fn get_from_store_raw<'a, K: ItemType>(
400        &self,
401        key_spec: &dyn KeySpecifier,
402        key_type: &KeystoreItemType,
403        stores: impl Iterator<Item = &'a BoxedKeystore>,
404    ) -> Result<Option<K>> {
405        let static_key_type = K::item_type();
406        if key_type != &static_key_type {
407            return Err(internal!(
408                "key type {:?} does not match the key type {:?} of requested key K::Key",
409                key_type,
410                static_key_type
411            )
412            .into());
413        }
414
415        for store in stores {
416            let key = match store.get(key_spec, &K::item_type()) {
417                Ok(None) => {
418                    // The key doesn't exist in this store, so we check the next one...
419                    continue;
420                }
421                Ok(Some(k)) => k,
422                Err(e) => {
423                    // Note: we immediately return if one of the keystores is inaccessible.
424                    return Err(e);
425                }
426            };
427
428            // Found it! Now try to downcast it to the right type (this should _not_ fail)...
429            let key: K = key
430                .downcast::<K>()
431                .map(|k| *k)
432                .map_err(|_| internal!("failed to downcast key to requested type"))?;
433
434            return Ok(Some(key));
435        }
436
437        Ok(None)
438    }
439
440    /// Attempt to retrieve a key from one of the specified `stores`.
441    ///
442    /// See [`KeyMgr::get`] for more details.
443    fn get_from_store<'a, K: ToEncodableKey>(
444        &self,
445        key_spec: &dyn KeySpecifier,
446        key_type: &KeystoreItemType,
447        stores: impl Iterator<Item = &'a BoxedKeystore>,
448    ) -> Result<Option<K>> {
449        let Some(key) = self.get_from_store_raw::<K::Key>(key_spec, key_type, stores)? else {
450            return Ok(None);
451        };
452
453        Ok(Some(K::from_encodable_key(key)))
454    }
455
456    /// Read the specified key and certificate from one of the key stores,
457    /// deserializing the subject key as `K::Key`, the cert as `C::Cert`,
458    /// and the signing key as `C::SigningKey`.
459    ///
460    /// Returns `Ok(None)` if none of the key stores have the requested key.
461    ///
462    // Note: the behavior of this function is a bit inconsistent with
463    // get_or_generate_key_and_cert: here, if the cert is absent but
464    // its subject key is not, we return Ok(None).
465    // In get_or_generate_key_and_cert, OTOH< we return an error in that case
466    // (because we can't possibly generate the missing subject key
467    // without overwriting the cert of the missing key).
468    ///
469    /// This function validates the certificate using [`ToEncodableCert::validate`],
470    /// returning an error if it is invalid or missing.
471    #[cfg(feature = "experimental-api")]
472    pub fn get_key_and_cert<K, C>(
473        &self,
474        spec: &dyn KeyCertificateSpecifier,
475    ) -> Result<Option<(K, C)>>
476    where
477        K: ToEncodableKey,
478        C: ToEncodableCert<K>,
479    {
480        let subject_key_spec = spec.subject_key_specifier();
481        // Get the subject key...
482        let Some(key) =
483            self.get_from_store::<K>(subject_key_spec, &K::Key::item_type(), self.all_stores())?
484        else {
485            return Ok(None);
486        };
487
488        let subject_key_arti_path = subject_key_spec
489            .arti_path()
490            .map_err(|_| bad_api_usage!("subject key does not have an ArtiPath?!"))?;
491        let cert_spec =
492            ArtiPath::from_path_and_denotators(subject_key_arti_path, &spec.cert_denotators())
493                .map_err(into_bad_api_usage!("invalid certificate specifier"))?;
494
495        let Some(cert) = self.get_from_store_raw::<C::ParsedCert>(
496            &cert_spec,
497            &<C::ParsedCert as ItemType>::item_type(),
498            self.all_stores(),
499        )?
500        else {
501            return Err(KeystoreCorruptionError::MissingCertificate.into());
502        };
503
504        // Finally, get the signing key and validate the cert
505        let signed_with = self.get_cert_signing_key::<K, C>(spec)?;
506        let cert = C::validate(cert, &key, &signed_with)?;
507
508        Ok(Some((key, cert)))
509    }
510
511    /// Like [`KeyMgr::get_key_and_cert`], except this function also generates the subject key
512    /// and its corresponding certificate if they don't already exist.
513    ///
514    /// If the key certificate is missing, it will be generated
515    /// from the subject key and signing key using the provided `make_certificate` callback.
516    ///
517    /// Generates the missing key and/or certificate as follows:
518    ///
519    /// ```text
520    /// | Subject Key exists | Signing Key exists | Cert exists | Action                                 |
521    /// |--------------------|--------------------|-------------|----------------------------------------|
522    /// | Y                  | Y                  | Y           | Validate cert, return key and cert     |
523    /// |                    |                    |             | if valid, error otherwise              |
524    /// |--------------------|--------------------|-------------|----------------------------------------|
525    /// | N                  | Y                  | N           | Generate subject key and               |
526    /// |                    |                    |             | a new cert signed with signing key     |
527    /// |--------------------|--------------------|-------------|----------------------------------------|
528    /// | Y                  | Y                  | N           | Generate cert signed with signing key  |
529    /// |--------------------|--------------------|-------------|----------------------------------------|
530    /// | Y                  | N                  | N           | Error - cannot validate cert           |
531    /// |                    |                    |             | if signing key is not available        |
532    /// |--------------------|--------------------|-------------|----------------------------------------|
533    /// | Y/N                | N                  | N           | Error - cannot generate cert           |
534    /// |                    |                    |             | if signing key is not available        |
535    /// |--------------------|--------------------|-------------|----------------------------------------|
536    /// | N                  | Y/N                | Y           | Error - subject key was removed?       |
537    /// |                    |                    |             | (we found the cert,                    |
538    /// |                    |                    |             | but the subject key is missing)        |
539    /// ```
540    ///
541    //
542    // Note; the table above isn't a markdown table because CommonMark-flavor markdown
543    // doesn't support multiline text in tables. Even if we trim down the text,
544    // the resulting markdown table would be pretty unreadable in raw form
545    // (it would have several excessively long lines, over 120 chars in len).
546    #[cfg(feature = "experimental-api")]
547    pub fn get_or_generate_key_and_cert<K, C>(
548        &self,
549        spec: &dyn KeyCertificateSpecifier,
550        make_certificate: impl FnOnce(&K, &<C as ToEncodableCert<K>>::SigningKey) -> C,
551        selector: KeystoreSelector,
552        rng: &mut dyn KeygenRng,
553    ) -> Result<(K, C)>
554    where
555        K: ToEncodableKey,
556        K::Key: Keygen,
557        C: ToEncodableCert<K>,
558    {
559        let subject_key_spec = spec.subject_key_specifier();
560        let subject_key_arti_path = subject_key_spec
561            .arti_path()
562            .map_err(|_| bad_api_usage!("subject key does not have an ArtiPath?!"))?;
563
564        let cert_specifier =
565            ArtiPath::from_path_and_denotators(subject_key_arti_path, &spec.cert_denotators())
566                .map_err(into_bad_api_usage!("invalid certificate specifier"))?;
567
568        let maybe_cert = self.get_from_store_raw::<C::ParsedCert>(
569            &cert_specifier,
570            &C::ParsedCert::item_type(),
571            self.all_stores(),
572        )?;
573
574        let maybe_subject_key = self.get::<K>(subject_key_spec)?;
575
576        match (&maybe_cert, &maybe_subject_key) {
577            (Some(_), None) => {
578                return Err(KeystoreCorruptionError::MissingSubjectKey.into());
579            }
580            _ => {
581                // generate key and/or cert
582            }
583        }
584        let subject_key = match maybe_subject_key {
585            Some(key) => key,
586            _ => self.generate(subject_key_spec, selector, rng, false)?,
587        };
588
589        let signed_with = self.get_cert_signing_key::<K, C>(spec)?;
590        let cert = match maybe_cert {
591            Some(cert) => C::validate(cert, &subject_key, &signed_with)?,
592            None => {
593                let cert = make_certificate(&subject_key, &signed_with);
594
595                let () = self.insert_cert(cert.clone(), &cert_specifier, selector)?;
596
597                cert
598            }
599        };
600
601        Ok((subject_key, cert))
602    }
603
604    /// Return an iterator over all configured stores.
605    fn all_stores(&self) -> impl Iterator<Item = &BoxedKeystore> {
606        iter::once(&self.primary_store).chain(self.secondary_stores.iter())
607    }
608
609    /// Return the [`Keystore`](crate::Keystore) matching the specified `selector`.
610    ///
611    /// Returns an error if the selected keystore is not the primary keystore or one of the
612    /// configured secondary stores.
613    fn select_keystore(&self, selector: &KeystoreSelector) -> Result<&BoxedKeystore> {
614        match selector {
615            KeystoreSelector::Id(keystore_id) => self.find_keystore(keystore_id),
616            KeystoreSelector::Primary => Ok(&self.primary_store),
617        }
618    }
619
620    /// Return the [`Keystore`](crate::Keystore) with the specified `id`.
621    ///
622    /// Returns an error if the specified ID is not the ID of the primary keystore or
623    /// the ID of one of the configured secondary stores.
624    fn find_keystore(&self, id: &KeystoreId) -> Result<&BoxedKeystore> {
625        self.all_stores()
626            .find(|keystore| keystore.id() == id)
627            .ok_or_else(|| bad_api_usage!("could not find keystore with ID {id}").into())
628    }
629
630    /// Get the signing key of the certificate described by `spec`.
631    ///
632    /// Returns a [`KeystoreCorruptionError::MissingSigningKey`] error
633    /// if the signing key doesn't exist in any of the keystores.
634    #[cfg(feature = "experimental-api")]
635    fn get_cert_signing_key<K, C>(
636        &self,
637        spec: &dyn KeyCertificateSpecifier,
638    ) -> Result<C::SigningKey>
639    where
640        K: ToEncodableKey,
641        C: ToEncodableCert<K>,
642    {
643        let Some(signing_key_spec) = spec.signing_key_specifier() else {
644            return Err(bad_api_usage!(
645                "signing key specifier is None, but external signing key was not provided?"
646            )
647            .into());
648        };
649
650        let Some(signing_key) = self.get_from_store::<C::SigningKey>(
651            signing_key_spec,
652            &<C::SigningKey as ToEncodableKey>::Key::item_type(),
653            self.all_stores(),
654        )?
655        else {
656            return Err(KeystoreCorruptionError::MissingSigningKey.into());
657        };
658
659        Ok(signing_key)
660    }
661
662    /// Insert `cert` into the [`Keystore`](crate::Keystore) specified by `selector`.
663    ///
664    /// If the key already exists in the specified key store, it will be overwritten.
665    ///
666    // NOTE: if we ever make this public we should rethink/improve its API.
667    // TODO: maybe fold this into insert() somehow?
668    fn insert_cert<K, C>(
669        &self,
670        cert: C,
671        cert_spec: &dyn KeySpecifier,
672        selector: KeystoreSelector,
673    ) -> Result<()>
674    where
675        K: ToEncodableKey,
676        K::Key: Keygen,
677        C: ToEncodableCert<K>,
678    {
679        let cert = cert.to_encodable_cert();
680        let store = self.select_keystore(&selector)?;
681
682        let () = store.insert(&cert, cert_spec)?;
683        Ok(())
684    }
685}
686
687#[cfg(test)]
688mod tests {
689    // @@ begin test lint list maintained by maint/add_warning @@
690    #![allow(clippy::bool_assert_comparison)]
691    #![allow(clippy::clone_on_copy)]
692    #![allow(clippy::dbg_macro)]
693    #![allow(clippy::mixed_attributes_style)]
694    #![allow(clippy::print_stderr)]
695    #![allow(clippy::print_stdout)]
696    #![allow(clippy::single_char_pattern)]
697    #![allow(clippy::unwrap_used)]
698    #![allow(clippy::unchecked_duration_subtraction)]
699    #![allow(clippy::useless_vec)]
700    #![allow(clippy::needless_pass_by_value)]
701    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
702    use super::*;
703    use crate::keystore::arti::err::{ArtiNativeKeystoreError, MalformedPathError};
704    use crate::{
705        ArtiPath, ArtiPathUnavailableError, Error, KeyPath, Keystore, KeystoreEntryResult,
706        KeystoreError, UnrecognizedEntryError, UnrecognizedEntryId,
707    };
708    use std::collections::HashMap;
709    use std::path::PathBuf;
710    use std::result::Result as StdResult;
711    use std::str::FromStr;
712    use std::sync::{Arc, RwLock};
713    use std::time::{Duration, SystemTime};
714    use tor_basic_utils::test_rng::testing_rng;
715    use tor_cert::CertifiedKey;
716    use tor_cert::Ed25519Cert;
717    use tor_error::{ErrorKind, HasKind};
718    use tor_key_forge::{
719        CertData, EncodableItem, ErasedKey, InvalidCertError, KeyType, KeystoreItem,
720    };
721    use tor_llcrypto::pk::ed25519::{self, Ed25519PublicKey as _};
722    use tor_llcrypto::rng::FakeEntropicRng;
723
724    /// Metadata structure for tracking key operations in tests.
725    #[derive(Clone, Debug, PartialEq)]
726    struct KeyMetadata {
727        /// The identifier for the item (e.g., "coot", "moorhen").
728        item_id: String,
729        /// The keystore from which the item was retrieved.
730        ///
731        /// Set by `Keystore::get`.
732        retrieved_from: Option<KeystoreId>,
733        /// Whether the item was generated via `Keygen::generate`.
734        is_generated: bool,
735    }
736
737    /// Metadata structure for tracking certificate operations in tests.
738    #[derive(Clone, Debug, PartialEq)]
739    struct CertMetadata {
740        /// The identifier for the subject key (e.g., "coot").
741        subject_key_id: String,
742        /// The identifier for the signing key (e.g., "moorhen").
743        signing_key_id: String,
744        /// The keystore from which the certificate was retrieved.
745        ///
746        /// Set by `Keystore::get`.
747        retrieved_from: Option<KeystoreId>,
748        /// Whether the certificate was freshly generated (i.e. returned from the "or generate"
749        /// branch of `get_or_generate()`) or retrieved from a keystore.
750        is_generated: bool,
751    }
752
753    /// Metadata structure for tracking item operations in tests.
754    #[derive(Clone, Debug, PartialEq, derive_more::From)]
755    enum ItemMetadata {
756        /// Metadata about a key.
757        Key(KeyMetadata),
758        /// Metadata about a certificate.
759        Cert(CertMetadata),
760    }
761
762    impl ItemMetadata {
763        /// Get the item ID.
764        ///
765        /// For keys, this returns the key's ID.
766        /// For certificates, this returns a formatted string identifying the subject key.
767        fn item_id(&self) -> &str {
768            match self {
769                ItemMetadata::Key(k) => &k.item_id,
770                ItemMetadata::Cert(c) => &c.subject_key_id,
771            }
772        }
773
774        /// Get retrieved_from.
775        fn retrieved_from(&self) -> Option<&KeystoreId> {
776            match self {
777                ItemMetadata::Key(k) => k.retrieved_from.as_ref(),
778                ItemMetadata::Cert(c) => c.retrieved_from.as_ref(),
779            }
780        }
781
782        /// Get is_generated.
783        fn is_generated(&self) -> bool {
784            match self {
785                ItemMetadata::Key(k) => k.is_generated,
786                ItemMetadata::Cert(c) => c.is_generated,
787            }
788        }
789
790        /// Set the retrieved_from field to the specified keystore ID.
791        fn set_retrieved_from(&mut self, id: KeystoreId) {
792            match self {
793                ItemMetadata::Key(meta) => meta.retrieved_from = Some(id),
794                ItemMetadata::Cert(meta) => meta.retrieved_from = Some(id),
795            }
796        }
797
798        /// Returns a reference to key metadata if this is a Key variant.
799        fn as_key(&self) -> Option<&KeyMetadata> {
800            match self {
801                ItemMetadata::Key(meta) => Some(meta),
802                _ => None,
803            }
804        }
805
806        /// Returns a reference to certificate metadata if this is a Cert variant.
807        fn as_cert(&self) -> Option<&CertMetadata> {
808            match self {
809                ItemMetadata::Cert(meta) => Some(meta),
810                _ => None,
811            }
812        }
813    }
814
815    /// The type of "key" stored in the test key stores.
816    #[derive(Clone, Debug)]
817    struct TestItem {
818        /// The underlying key.
819        item: KeystoreItem,
820        /// Metadata about the key.
821        meta: ItemMetadata,
822    }
823
824    /// A "certificate" used for testing purposes.
825    #[derive(Clone, Debug)]
826    struct AlwaysValidCert(TestItem);
827
828    /// The corresponding fake public key type.
829    #[derive(Clone, Debug)]
830    struct TestPublicKey {
831        /// The underlying key.
832        key: KeystoreItem,
833    }
834
835    impl From<TestItem> for TestPublicKey {
836        fn from(tk: TestItem) -> TestPublicKey {
837            TestPublicKey { key: tk.item }
838        }
839    }
840
841    impl TestItem {
842        /// Create a new test key with the specified metadata.
843        fn new(item_id: &str) -> Self {
844            let mut rng = testing_rng();
845            TestItem {
846                item: ed25519::Keypair::generate(&mut rng)
847                    .as_keystore_item()
848                    .unwrap(),
849                meta: ItemMetadata::Key(KeyMetadata {
850                    item_id: item_id.to_string(),
851                    retrieved_from: None,
852                    is_generated: false,
853                }),
854            }
855        }
856    }
857
858    impl Keygen for TestItem {
859        fn generate(mut rng: &mut dyn KeygenRng) -> tor_key_forge::Result<Self>
860        where
861            Self: Sized,
862        {
863            Ok(TestItem {
864                item: ed25519::Keypair::generate(&mut rng).as_keystore_item()?,
865                meta: ItemMetadata::Key(KeyMetadata {
866                    item_id: "generated_test_key".to_string(),
867                    retrieved_from: None,
868                    is_generated: true,
869                }),
870            })
871        }
872    }
873
874    impl ItemType for TestItem {
875        fn item_type() -> KeystoreItemType
876        where
877            Self: Sized,
878        {
879            // Dummy value
880            KeyType::Ed25519Keypair.into()
881        }
882    }
883
884    impl EncodableItem for TestItem {
885        fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
886            Ok(self.item.clone())
887        }
888    }
889
890    impl ToEncodableKey for TestItem {
891        type Key = Self;
892        type KeyPair = Self;
893
894        fn to_encodable_key(self) -> Self::Key {
895            self
896        }
897
898        fn from_encodable_key(key: Self::Key) -> Self {
899            key
900        }
901    }
902
903    impl ItemType for TestPublicKey {
904        fn item_type() -> KeystoreItemType
905        where
906            Self: Sized,
907        {
908            KeyType::Ed25519PublicKey.into()
909        }
910    }
911
912    impl EncodableItem for TestPublicKey {
913        fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
914            Ok(self.key.clone())
915        }
916    }
917
918    impl ToEncodableKey for TestPublicKey {
919        type Key = Self;
920        type KeyPair = TestItem;
921
922        fn to_encodable_key(self) -> Self::Key {
923            self
924        }
925
926        fn from_encodable_key(key: Self::Key) -> Self {
927            key
928        }
929    }
930
931    impl ToEncodableCert<TestItem> for AlwaysValidCert {
932        type ParsedCert = TestItem;
933        type EncodableCert = TestItem;
934        type SigningKey = TestItem;
935
936        fn validate(
937            cert: Self::ParsedCert,
938            _subject: &TestItem,
939            _signed_with: &Self::SigningKey,
940        ) -> StdResult<Self, InvalidCertError> {
941            // AlwaysValidCert is always valid
942            Ok(Self(cert))
943        }
944
945        /// Convert this cert to a type that implements [`EncodableKey`].
946        fn to_encodable_cert(self) -> Self::EncodableCert {
947            self.0
948        }
949    }
950
951    const KEYSTORE_LIST_MOCK_ID: &str = "keystore_list_mock";
952    const KEYSTORE_LIST_MOCK_UNRECOGNIZED_PATH_STR: &str = "unrecognized_entry";
953
954    struct KeystoreListMock {
955        id: KeystoreId,
956        valid_key_path: KeyPath,
957        invalid_key_path: PathBuf,
958    }
959
960    impl Default for KeystoreListMock {
961        fn default() -> Self {
962            Self {
963                id: KeystoreId::from_str(KEYSTORE_LIST_MOCK_ID).unwrap(),
964                valid_key_path: KeyPath::Arti(TestKeySpecifierListMock.arti_path().unwrap()),
965                invalid_key_path: PathBuf::from_str(KEYSTORE_LIST_MOCK_UNRECOGNIZED_PATH_STR)
966                    .unwrap(),
967            }
968        }
969    }
970
971    impl Keystore for KeystoreListMock {
972        fn id(&self) -> &KeystoreId {
973            &self.id
974        }
975
976        fn get(
977            &self,
978            _key_spec: &dyn KeySpecifier,
979            _item_type: &KeystoreItemType,
980        ) -> Result<Option<ErasedKey>> {
981            Err(Error::Keystore(Arc::new(
982                KeystoreListMockError::MethodNotSuppored,
983            )))
984        }
985
986        fn list(&self) -> Result<Vec<KeystoreEntryResult<(KeyPath, KeystoreItemType)>>> {
987            // Provide two entries, a recognized one and an unrecognized one
988            Ok(vec![
989                Ok((
990                    self.valid_key_path.clone(),
991                    TestItem::new("capibara").item.item_type().unwrap(),
992                )),
993                Err(UnrecognizedEntryError::new(
994                    UnrecognizedEntryId::Path(self.invalid_key_path.clone()),
995                    Arc::new(ArtiNativeKeystoreError::MalformedPath {
996                        path: self.invalid_key_path.clone(),
997                        err: MalformedPathError::NoExtension,
998                    }),
999                )),
1000            ])
1001        }
1002
1003        fn insert(&self, _key: &dyn EncodableItem, _key_spec: &dyn KeySpecifier) -> Result<()> {
1004            Err(Error::Keystore(Arc::new(
1005                KeystoreListMockError::MethodNotSuppored,
1006            )))
1007        }
1008
1009        fn remove(
1010            &self,
1011            _key_spec: &dyn KeySpecifier,
1012            _item_type: &KeystoreItemType,
1013        ) -> Result<Option<()>> {
1014            Err(Error::Keystore(Arc::new(
1015                KeystoreListMockError::MethodNotSuppored,
1016            )))
1017        }
1018
1019        fn contains(
1020            &self,
1021            _key_spec: &dyn KeySpecifier,
1022            _item_type: &KeystoreItemType,
1023        ) -> Result<bool> {
1024            Err(Error::Keystore(Arc::new(
1025                KeystoreListMockError::MethodNotSuppored,
1026            )))
1027        }
1028    }
1029
1030    #[derive(thiserror::Error, Debug, Clone, derive_more::Display)]
1031    enum KeystoreListMockError {
1032        MethodNotSuppored,
1033    }
1034
1035    impl KeystoreError for KeystoreListMockError {}
1036
1037    impl HasKind for KeystoreListMockError {
1038        fn kind(&self) -> ErrorKind {
1039            ErrorKind::BadApiUsage
1040        }
1041    }
1042
1043    macro_rules! impl_keystore {
1044        ($name:tt, $id:expr) => {
1045            struct $name {
1046                inner: RwLock<HashMap<(ArtiPath, KeystoreItemType), TestItem>>,
1047                id: KeystoreId,
1048            }
1049
1050            impl Default for $name {
1051                fn default() -> Self {
1052                    Self {
1053                        inner: Default::default(),
1054                        id: KeystoreId::from_str($id).unwrap(),
1055                    }
1056                }
1057            }
1058
1059            #[allow(dead_code)] // this is only dead code for Keystore1
1060            impl $name {
1061                fn new_boxed() -> BoxedKeystore {
1062                    Box::<Self>::default()
1063                }
1064            }
1065
1066            impl crate::Keystore for $name {
1067                fn contains(
1068                    &self,
1069                    key_spec: &dyn KeySpecifier,
1070                    item_type: &KeystoreItemType,
1071                ) -> Result<bool> {
1072                    Ok(self
1073                        .inner
1074                        .read()
1075                        .unwrap()
1076                        .contains_key(&(key_spec.arti_path().unwrap(), item_type.clone())))
1077                }
1078
1079                fn id(&self) -> &KeystoreId {
1080                    &self.id
1081                }
1082
1083                fn get(
1084                    &self,
1085                    key_spec: &dyn KeySpecifier,
1086                    item_type: &KeystoreItemType,
1087                ) -> Result<Option<ErasedKey>> {
1088                    Ok(self
1089                        .inner
1090                        .read()
1091                        .unwrap()
1092                        .get(&(key_spec.arti_path().unwrap(), item_type.clone()))
1093                        .map(|k| {
1094                            let mut k = k.clone();
1095                            k.meta.set_retrieved_from(self.id().clone());
1096                            Box::new(k) as Box<dyn ItemType>
1097                        }))
1098                }
1099
1100                fn insert(
1101                    &self,
1102                    key: &dyn EncodableItem,
1103                    key_spec: &dyn KeySpecifier,
1104                ) -> Result<()> {
1105                    let key = key.downcast_ref::<TestItem>().unwrap();
1106
1107                    let item = key.as_keystore_item()?;
1108                    let meta = key.meta.clone();
1109
1110                    let item_type = item.item_type()?;
1111                    let key = TestItem { item, meta };
1112
1113                    self.inner
1114                        .write()
1115                        .unwrap()
1116                        .insert((key_spec.arti_path().unwrap(), item_type), key);
1117
1118                    Ok(())
1119                }
1120
1121                fn remove(
1122                    &self,
1123                    key_spec: &dyn KeySpecifier,
1124                    item_type: &KeystoreItemType,
1125                ) -> Result<Option<()>> {
1126                    Ok(self
1127                        .inner
1128                        .write()
1129                        .unwrap()
1130                        .remove(&(key_spec.arti_path().unwrap(), item_type.clone()))
1131                        .map(|_| ()))
1132                }
1133
1134                fn list(&self) -> Result<Vec<KeystoreEntryResult<(KeyPath, KeystoreItemType)>>> {
1135                    Ok(self
1136                        .inner
1137                        .read()
1138                        .unwrap()
1139                        .iter()
1140                        .map(|((arti_path, item_type), _)| {
1141                            Ok((KeyPath::Arti(arti_path.clone()), item_type.clone()))
1142                        })
1143                        .collect())
1144                }
1145            }
1146        };
1147    }
1148
1149    macro_rules! impl_specifier {
1150        ($name:tt, $id:expr) => {
1151            struct $name;
1152
1153            impl KeySpecifier for $name {
1154                fn arti_path(&self) -> StdResult<ArtiPath, ArtiPathUnavailableError> {
1155                    Ok(ArtiPath::new($id.into()).map_err(|e| tor_error::internal!("{e}"))?)
1156                }
1157
1158                fn ctor_path(&self) -> Option<crate::CTorPath> {
1159                    None
1160                }
1161
1162                fn keypair_specifier(&self) -> Option<Box<dyn KeySpecifier>> {
1163                    None
1164                }
1165            }
1166        };
1167    }
1168
1169    impl_keystore!(Keystore1, "keystore1");
1170    impl_keystore!(Keystore2, "keystore2");
1171    impl_keystore!(Keystore3, "keystore3");
1172
1173    impl_specifier!(TestKeySpecifier1, "spec1");
1174    impl_specifier!(TestKeySpecifier2, "spec2");
1175    impl_specifier!(TestKeySpecifier3, "spec3");
1176    impl_specifier!(TestKeySpecifier4, "spec4");
1177    impl_specifier!(TestKeySpecifierListMock, "recognized_entry");
1178
1179    impl_specifier!(TestPublicKeySpecifier1, "pub-spec1");
1180
1181    /// Create a test `KeystoreEntry`.
1182    fn entry_descriptor(specifier: impl KeySpecifier, keystore_id: &KeystoreId) -> KeystoreEntry {
1183        KeystoreEntry {
1184            key_path: specifier.arti_path().unwrap().into(),
1185            key_type: TestItem::item_type(),
1186            keystore_id,
1187        }
1188    }
1189
1190    #[test]
1191    #[allow(clippy::cognitive_complexity)]
1192    fn insert_and_get() {
1193        let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1194
1195        builder
1196            .secondary_stores()
1197            .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1198
1199        let mgr = builder.build().unwrap();
1200
1201        // Insert a key into Keystore2
1202        let old_key = mgr
1203            .insert(
1204                TestItem::new("coot"),
1205                &TestKeySpecifier1,
1206                KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1207                true,
1208            )
1209            .unwrap();
1210
1211        assert!(old_key.is_none());
1212        let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1213        assert_eq!(key.meta.item_id(), "coot");
1214        assert_eq!(
1215            key.meta.retrieved_from(),
1216            Some(&KeystoreId::from_str("keystore2").unwrap())
1217        );
1218        assert_eq!(key.meta.is_generated(), false);
1219
1220        // Insert a different key using the _same_ key specifier.
1221        let old_key = mgr
1222            .insert(
1223                TestItem::new("gull"),
1224                &TestKeySpecifier1,
1225                KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1226                true,
1227            )
1228            .unwrap()
1229            .unwrap();
1230        assert_eq!(old_key.meta.item_id(), "coot");
1231        assert_eq!(
1232            old_key.meta.retrieved_from(),
1233            Some(&KeystoreId::from_str("keystore2").unwrap())
1234        );
1235        assert_eq!(old_key.meta.is_generated(), false);
1236        // Check that the original value was overwritten:
1237        let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1238        assert_eq!(key.meta.item_id(), "gull");
1239        assert_eq!(
1240            key.meta.retrieved_from(),
1241            Some(&KeystoreId::from_str("keystore2").unwrap())
1242        );
1243        assert_eq!(key.meta.is_generated(), false);
1244
1245        // Insert a different key using the _same_ key specifier (overwrite = false)
1246        let err = mgr
1247            .insert(
1248                TestItem::new("gull"),
1249                &TestKeySpecifier1,
1250                KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1251                false,
1252            )
1253            .unwrap_err();
1254        assert!(matches!(err, crate::Error::KeyAlreadyExists));
1255
1256        // Insert a new key into Keystore2 (overwrite = false)
1257        let old_key = mgr
1258            .insert(
1259                TestItem::new("penguin"),
1260                &TestKeySpecifier2,
1261                KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1262                false,
1263            )
1264            .unwrap();
1265        assert!(old_key.is_none());
1266
1267        // Insert a key into the primary keystore
1268        let old_key = mgr
1269            .insert(
1270                TestItem::new("moorhen"),
1271                &TestKeySpecifier3,
1272                KeystoreSelector::Primary,
1273                true,
1274            )
1275            .unwrap();
1276        assert!(old_key.is_none());
1277        let key = mgr.get::<TestItem>(&TestKeySpecifier3).unwrap().unwrap();
1278        assert_eq!(key.meta.item_id(), "moorhen");
1279        assert_eq!(
1280            key.meta.retrieved_from(),
1281            Some(&KeystoreId::from_str("keystore1").unwrap())
1282        );
1283        assert_eq!(key.meta.is_generated(), false);
1284
1285        // The key doesn't exist in any of the stores yet.
1286        assert!(mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().is_none());
1287
1288        // Insert the same key into all 3 key stores, in reverse order of keystore priority
1289        // (otherwise KeyMgr::get will return the key from the primary store for each iteration and
1290        // we won't be able to see the key was actually inserted in each store).
1291        for store in ["keystore3", "keystore2", "keystore1"] {
1292            let old_key = mgr
1293                .insert(
1294                    TestItem::new("cormorant"),
1295                    &TestKeySpecifier4,
1296                    KeystoreSelector::Id(&KeystoreId::from_str(store).unwrap()),
1297                    true,
1298                )
1299                .unwrap();
1300            assert!(old_key.is_none());
1301
1302            // Ensure the key now exists in `store`.
1303            let key = mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().unwrap();
1304            assert_eq!(key.meta.item_id(), "cormorant");
1305            assert_eq!(
1306                key.meta.retrieved_from(),
1307                Some(&KeystoreId::from_str(store).unwrap())
1308            );
1309            assert_eq!(key.meta.is_generated(), false);
1310        }
1311
1312        // The key exists in all key stores, but if no keystore_id is specified, we return the
1313        // value from the first key store it is found in (in this case, Keystore1)
1314        let key = mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().unwrap();
1315        assert_eq!(key.meta.item_id(), "cormorant");
1316        assert_eq!(
1317            key.meta.retrieved_from(),
1318            Some(&KeystoreId::from_str("keystore1").unwrap())
1319        );
1320        assert_eq!(key.meta.is_generated(), false);
1321    }
1322
1323    #[test]
1324    fn remove() {
1325        let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1326
1327        builder
1328            .secondary_stores()
1329            .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1330
1331        let mgr = builder.build().unwrap();
1332
1333        assert!(!mgr.secondary_stores[0]
1334            .contains(&TestKeySpecifier1, &TestItem::item_type())
1335            .unwrap());
1336
1337        // Insert a key into Keystore2
1338        mgr.insert(
1339            TestItem::new("coot"),
1340            &TestKeySpecifier1,
1341            KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1342            true,
1343        )
1344        .unwrap();
1345        let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1346        assert_eq!(key.meta.item_id(), "coot");
1347        assert_eq!(
1348            key.meta.retrieved_from(),
1349            Some(&KeystoreId::from_str("keystore2").unwrap())
1350        );
1351        assert_eq!(key.meta.is_generated(), false);
1352
1353        // Try to remove the key from a non-existent key store
1354        assert!(mgr
1355            .remove::<TestItem>(
1356                &TestKeySpecifier1,
1357                KeystoreSelector::Id(&KeystoreId::from_str("not_an_id_we_know_of").unwrap())
1358            )
1359            .is_err());
1360        // The key still exists in Keystore2
1361        assert!(mgr.secondary_stores[0]
1362            .contains(&TestKeySpecifier1, &TestItem::item_type())
1363            .unwrap());
1364
1365        // Try to remove the key from the primary key store
1366        assert!(mgr
1367            .remove::<TestItem>(&TestKeySpecifier1, KeystoreSelector::Primary)
1368            .unwrap()
1369            .is_none());
1370
1371        // The key still exists in Keystore2
1372        assert!(mgr.secondary_stores[0]
1373            .contains(&TestKeySpecifier1, &TestItem::item_type())
1374            .unwrap());
1375
1376        // Removing from Keystore2 should succeed.
1377        let removed_key = mgr
1378            .remove::<TestItem>(
1379                &TestKeySpecifier1,
1380                KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1381            )
1382            .unwrap()
1383            .unwrap();
1384        assert_eq!(removed_key.meta.item_id(), "coot");
1385        assert_eq!(
1386            removed_key.meta.retrieved_from(),
1387            Some(&KeystoreId::from_str("keystore2").unwrap())
1388        );
1389        assert_eq!(removed_key.meta.is_generated(), false);
1390
1391        // The key doesn't exist in Keystore2 anymore
1392        assert!(!mgr.secondary_stores[0]
1393            .contains(&TestKeySpecifier1, &TestItem::item_type())
1394            .unwrap());
1395    }
1396
1397    #[test]
1398    fn keygen() {
1399        let mut rng = FakeEntropicRng(testing_rng());
1400        let mgr = KeyMgrBuilder::default()
1401            .primary_store(Box::<Keystore1>::default())
1402            .build()
1403            .unwrap();
1404
1405        mgr.insert(
1406            TestItem::new("coot"),
1407            &TestKeySpecifier1,
1408            KeystoreSelector::Primary,
1409            true,
1410        )
1411        .unwrap();
1412
1413        // There is no corresponding public key entry.
1414        assert!(mgr
1415            .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1416            .unwrap()
1417            .is_none());
1418
1419        // Try to generate a new key (overwrite = false)
1420        let err = mgr
1421            .generate::<TestItem>(
1422                &TestKeySpecifier1,
1423                KeystoreSelector::Primary,
1424                &mut rng,
1425                false,
1426            )
1427            .unwrap_err();
1428
1429        assert!(matches!(err, crate::Error::KeyAlreadyExists));
1430
1431        // The previous entry was not overwritten because overwrite = false
1432        let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1433        assert_eq!(key.meta.item_id(), "coot");
1434        assert_eq!(
1435            key.meta.retrieved_from(),
1436            Some(&KeystoreId::from_str("keystore1").unwrap())
1437        );
1438        assert_eq!(key.meta.is_generated(), false);
1439
1440        // We don't store public keys in the keystore
1441        assert!(mgr
1442            .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1443            .unwrap()
1444            .is_none());
1445
1446        // Try to generate a new key (overwrite = true)
1447        let generated_key = mgr
1448            .generate::<TestItem>(
1449                &TestKeySpecifier1,
1450                KeystoreSelector::Primary,
1451                &mut rng,
1452                true,
1453            )
1454            .unwrap();
1455
1456        assert_eq!(generated_key.meta.item_id(), "generated_test_key");
1457        // Not set in a freshly generated key, because KeyMgr::generate()
1458        // returns it straight away, without going through Keystore::get()
1459        assert_eq!(generated_key.meta.retrieved_from(), None);
1460        assert_eq!(generated_key.meta.is_generated(), true);
1461
1462        // Retrieve the inserted key
1463        let retrieved_key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1464        assert_eq!(retrieved_key.meta.item_id(), "generated_test_key");
1465        assert_eq!(
1466            retrieved_key.meta.retrieved_from(),
1467            Some(&KeystoreId::from_str("keystore1").unwrap())
1468        );
1469        assert_eq!(retrieved_key.meta.is_generated(), true);
1470
1471        // We don't store public keys in the keystore
1472        assert!(mgr
1473            .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1474            .unwrap()
1475            .is_none());
1476    }
1477
1478    #[test]
1479    fn get_or_generate() {
1480        let mut rng = FakeEntropicRng(testing_rng());
1481        let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1482
1483        builder
1484            .secondary_stores()
1485            .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1486
1487        let mgr = builder.build().unwrap();
1488
1489        let keystore2 = KeystoreId::from_str("keystore2").unwrap();
1490        let entry_desc1 = entry_descriptor(TestKeySpecifier1, &keystore2);
1491        assert!(mgr.get_entry::<TestItem>(&entry_desc1).unwrap().is_none());
1492
1493        mgr.insert(
1494            TestItem::new("coot"),
1495            &TestKeySpecifier1,
1496            KeystoreSelector::Id(&keystore2),
1497            true,
1498        )
1499        .unwrap();
1500
1501        // The key already exists in keystore 2 so it won't be auto-generated.
1502        let key = mgr
1503            .get_or_generate::<TestItem>(&TestKeySpecifier1, KeystoreSelector::Primary, &mut rng)
1504            .unwrap();
1505        assert_eq!(key.meta.item_id(), "coot");
1506        assert_eq!(
1507            key.meta.retrieved_from(),
1508            Some(&KeystoreId::from_str("keystore2").unwrap())
1509        );
1510        assert_eq!(key.meta.is_generated(), false);
1511
1512        assert_eq!(
1513            mgr.get_entry::<TestItem>(&entry_desc1)
1514                .unwrap()
1515                .map(|k| k.meta),
1516            Some(ItemMetadata::Key(KeyMetadata {
1517                item_id: "coot".to_string(),
1518                retrieved_from: Some(keystore2.clone()),
1519                is_generated: false,
1520            }))
1521        );
1522
1523        // This key doesn't exist in any of the keystores, so it will be auto-generated and
1524        // inserted into keystore 3.
1525        let keystore3 = KeystoreId::from_str("keystore3").unwrap();
1526        let generated_key = mgr
1527            .get_or_generate::<TestItem>(
1528                &TestKeySpecifier2,
1529                KeystoreSelector::Id(&keystore3),
1530                &mut rng,
1531            )
1532            .unwrap();
1533        assert_eq!(generated_key.meta.item_id(), "generated_test_key");
1534        // Not set in a freshly generated key, because KeyMgr::get_or_generate()
1535        // returns it straight away, without going through Keystore::get()
1536        assert_eq!(generated_key.meta.retrieved_from(), None);
1537        assert_eq!(generated_key.meta.is_generated(), true);
1538
1539        // Retrieve the inserted key
1540        let retrieved_key = mgr.get::<TestItem>(&TestKeySpecifier2).unwrap().unwrap();
1541        assert_eq!(retrieved_key.meta.item_id(), "generated_test_key");
1542        assert_eq!(
1543            retrieved_key.meta.retrieved_from(),
1544            Some(&KeystoreId::from_str("keystore3").unwrap())
1545        );
1546        assert_eq!(retrieved_key.meta.is_generated(), true);
1547
1548        let entry_desc2 = entry_descriptor(TestKeySpecifier2, &keystore3);
1549        assert_eq!(
1550            mgr.get_entry::<TestItem>(&entry_desc2)
1551                .unwrap()
1552                .map(|k| k.meta),
1553            Some(ItemMetadata::Key(KeyMetadata {
1554                item_id: "generated_test_key".to_string(),
1555                retrieved_from: Some(keystore3.clone()),
1556                is_generated: true,
1557            }))
1558        );
1559
1560        let arti_pat = KeyPathPattern::Arti("*".to_string());
1561        let matching = mgr.list_matching(&arti_pat).unwrap();
1562
1563        assert_eq!(matching.len(), 2);
1564        assert!(matching.contains(&entry_desc1));
1565        assert!(matching.contains(&entry_desc2));
1566
1567        assert_eq!(mgr.remove_entry(&entry_desc2).unwrap(), Some(()));
1568        assert!(mgr.get_entry::<TestItem>(&entry_desc2).unwrap().is_none());
1569        assert!(mgr.remove_entry(&entry_desc2).unwrap().is_none());
1570    }
1571
1572    #[test]
1573    fn list_matching_ignores_unrecognized_keys() {
1574        let builder = KeyMgrBuilder::default().primary_store(Box::new(KeystoreListMock::default()));
1575
1576        let mgr = builder.build().unwrap();
1577
1578        let arti_pat = KeyPathPattern::Arti("*".to_string());
1579        let matching = mgr.list_matching(&arti_pat).unwrap();
1580        // assert the unrecognized key has been filterd out
1581        assert_eq!(matching.len(), 1);
1582        assert_eq!(
1583            matching.first().unwrap().key_path(),
1584            &KeystoreListMock::default().valid_key_path
1585        );
1586    }
1587
1588    #[cfg(feature = "onion-service-cli-extra")]
1589    #[test]
1590    fn lists() {
1591        let mut builder =
1592            KeyMgrBuilder::default().primary_store(Box::new(KeystoreListMock::default()));
1593        builder
1594            .secondary_stores()
1595            .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1596
1597        let mgr = builder.build().unwrap();
1598        let keystore2id = KeystoreId::from_str("keystore2").unwrap();
1599        let keystore3id = KeystoreId::from_str("keystore3").unwrap();
1600
1601        // Insert a key into Keystore2
1602        let _ = mgr
1603            .insert(
1604                TestItem::new("coot"),
1605                &TestKeySpecifier2,
1606                KeystoreSelector::Id(&keystore2id),
1607                true,
1608            )
1609            .unwrap();
1610
1611        // Insert a key into Keystore3
1612        let _ = mgr
1613            .insert(
1614                TestItem::new("penguin"),
1615                &TestKeySpecifier3,
1616                KeystoreSelector::Id(&keystore3id),
1617                true,
1618            )
1619            .unwrap();
1620
1621        // Test `list_by_id`
1622        let entries = mgr
1623            .list_by_id(&KeystoreId::from_str(KEYSTORE_LIST_MOCK_ID).unwrap())
1624            .unwrap();
1625
1626        let assert_key = |path, ty, expected_path: &ArtiPath, expected_type| {
1627            assert_eq!(ty, expected_type);
1628            assert_eq!(path, &KeyPath::Arti(expected_path.clone()));
1629        };
1630        let item_type = TestItem::new("axolotl").item.item_type().unwrap();
1631        let unrecognized_entry_id = UnrecognizedEntryId::Path(
1632            PathBuf::from_str(KEYSTORE_LIST_MOCK_UNRECOGNIZED_PATH_STR).unwrap(),
1633        );
1634        let list_mock_key_spec = TestKeySpecifierListMock.arti_path().unwrap();
1635
1636        // Primary keystore contains a valid key and an unrecognized key
1637        let mut recognized_entries = 0;
1638        let mut unrecognized_entries = 0;
1639        for entry in entries.iter() {
1640            match entry {
1641                Ok((key_path, key_type)) => {
1642                    assert_key(key_path, key_type, &list_mock_key_spec, &item_type);
1643                    recognized_entries += 1;
1644                }
1645                Err(u) => {
1646                    assert_eq!(u.entry(), &unrecognized_entry_id);
1647                    unrecognized_entries += 1;
1648                }
1649            }
1650        }
1651        assert_eq!(recognized_entries, 1);
1652        assert_eq!(unrecognized_entries, 1);
1653
1654        // Test `list`
1655        let entries = mgr.list().unwrap();
1656
1657        let expected_items = [
1658            (
1659                KeystoreId::from_str("keystore_list_mock").unwrap(),
1660                TestKeySpecifierListMock.arti_path().unwrap(),
1661            ),
1662            (keystore2id, TestKeySpecifier2.arti_path().unwrap()),
1663            (keystore3id, TestKeySpecifier3.arti_path().unwrap()),
1664        ];
1665
1666        // Secondary keystores contain 1 valid key each
1667        let mut recognized_entries = 0;
1668        let mut unrecognized_entries = 0;
1669        for entry in entries.iter() {
1670            match entry {
1671                Ok(e) => {
1672                    if let Some((_, expected_arti_path)) = expected_items
1673                        .iter()
1674                        .find(|(keystore_id, _)| keystore_id == e.keystore_id())
1675                    {
1676                        assert_key(e.key_path(), e.key_type(), expected_arti_path, &item_type);
1677                        recognized_entries += 1;
1678                        continue;
1679                    }
1680
1681                    panic!("Unexpected key encountered {:?}", e);
1682                }
1683                Err(u) => {
1684                    assert_eq!(u.entry(), &unrecognized_entry_id);
1685                    unrecognized_entries += 1;
1686                }
1687            }
1688        }
1689        assert_eq!(recognized_entries, 3);
1690        assert_eq!(unrecognized_entries, 1);
1691
1692        // Test `list_keystores`
1693        let keystores = mgr.list_keystores().iter().len();
1694
1695        assert_eq!(keystores, 3);
1696    }
1697
1698    /// Whether to generate a given item before running the `run_certificate_test`.
1699    #[cfg(feature = "experimental-api")]
1700    #[derive(Clone, Copy, Debug, PartialEq)]
1701    enum GenerateItem {
1702        Yes,
1703        No,
1704    }
1705
1706    #[cfg(feature = "experimental-api")]
1707    macro_rules! run_certificate_test {
1708        (
1709            generate_subject_key = $generate_subject_key:expr,
1710            generate_signing_key = $generate_signing_key:expr,
1711            $($expected_err:tt)?
1712        ) => {{
1713            use GenerateItem::*;
1714
1715            let mut rng = FakeEntropicRng(testing_rng());
1716            let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1717
1718            builder
1719                .secondary_stores()
1720                .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1721
1722            let mgr = builder.build().unwrap();
1723
1724            let spec = crate::test_utils::TestCertSpecifier {
1725                subject_key_spec: TestKeySpecifier1,
1726                signing_key_spec: TestKeySpecifier2,
1727                denotator: vec!["foo".into()],
1728            };
1729
1730            if $generate_subject_key == Yes {
1731                let _ = mgr
1732                    .generate::<TestItem>(
1733                        &TestKeySpecifier1,
1734                        KeystoreSelector::Primary,
1735                        &mut rng,
1736                        false,
1737                    )
1738                    .unwrap();
1739            }
1740
1741            if $generate_signing_key == Yes {
1742                let _ = mgr
1743                    .generate::<TestItem>(
1744                        &TestKeySpecifier2,
1745                        KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1746                        &mut rng,
1747                        false,
1748                    )
1749                    .unwrap();
1750            }
1751
1752            let make_certificate = move |subject_key: &TestItem, signed_with: &TestItem| {
1753                let subject_id = subject_key.meta.as_key().unwrap().item_id.clone();
1754                let signing_id = signed_with.meta.as_key().unwrap().item_id.clone();
1755
1756                let meta = ItemMetadata::Cert(CertMetadata {
1757                    subject_key_id: subject_id,
1758                    signing_key_id: signing_id,
1759                    retrieved_from: None,
1760                    is_generated: true,
1761                });
1762
1763                // Note: this is not really a cert for `subject_key` signed with the `signed_with`
1764                // key!. The two are `TestItem`s and not keys, so we can't really generate a real
1765                // cert from them. We can, however, pretend we did, for testing purposes.
1766                // Eventually we might want to rewrite these tests to use real items
1767                // (like the `ArtiNativeKeystore` tests)
1768                let mut rng = FakeEntropicRng(testing_rng());
1769                let keypair = ed25519::Keypair::generate(&mut rng);
1770                let encoded_cert = Ed25519Cert::constructor()
1771                    .cert_type(tor_cert::CertType::IDENTITY_V_SIGNING)
1772                    .expiration(SystemTime::now() + Duration::from_secs(180))
1773                    .signing_key(keypair.public_key().into())
1774                    .cert_key(CertifiedKey::Ed25519(keypair.public_key().into()))
1775                    .encode_and_sign(&keypair)
1776                    .unwrap();
1777                let test_cert = CertData::TorEd25519Cert(encoded_cert);
1778                AlwaysValidCert(TestItem {
1779                    item: KeystoreItem::Cert(test_cert),
1780                    meta,
1781                })
1782            };
1783
1784            let res = mgr
1785                .get_or_generate_key_and_cert::<TestItem, AlwaysValidCert>(
1786                    &spec,
1787                    &make_certificate,
1788                    KeystoreSelector::Primary,
1789                    &mut rng,
1790                );
1791
1792            #[allow(unused_assignments)]
1793            #[allow(unused_mut)]
1794            let mut has_error = false;
1795            $(
1796                has_error = true;
1797                let err = res.clone().unwrap_err();
1798                assert!(
1799                    matches!(
1800                        err,
1801                        crate::Error::Corruption(KeystoreCorruptionError::$expected_err)
1802                    ),
1803                    "unexpected error: {err:?}",
1804                );
1805            )?
1806
1807            if !has_error {
1808                let (key, cert) = res.unwrap();
1809
1810                let expected_subj_key_id = if $generate_subject_key == Yes {
1811                    "generated_test_key"
1812                } else {
1813                    "generated_test_key"
1814                };
1815
1816                assert_eq!(key.meta.item_id(), expected_subj_key_id);
1817                assert_eq!(
1818                    cert.0.meta.as_cert().unwrap().subject_key_id,
1819                    expected_subj_key_id
1820                );
1821                assert_eq!(
1822                    cert.0.meta.as_cert().unwrap().signing_key_id,
1823                    "generated_test_key"
1824                );
1825                assert_eq!(cert.0.meta.is_generated(), true);
1826            }
1827        }}
1828    }
1829
1830    #[test]
1831    #[cfg(feature = "experimental-api")]
1832    #[rustfmt::skip] // preserve the layout for readability
1833    #[allow(clippy::cognitive_complexity)] // clippy seems confused here...
1834    fn get_certificate() {
1835        run_certificate_test!(
1836            generate_subject_key = No,
1837            generate_signing_key = No,
1838            MissingSigningKey
1839        );
1840
1841        run_certificate_test!(
1842            generate_subject_key = Yes,
1843            generate_signing_key = No,
1844            MissingSigningKey
1845        );
1846
1847        run_certificate_test!(
1848            generate_subject_key = No,
1849            generate_signing_key = Yes,
1850        );
1851
1852        run_certificate_test!(
1853            generate_subject_key = Yes,
1854            generate_signing_key = Yes,
1855        );
1856    }
1857}