Skip to main content

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