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