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