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