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