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