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::{
6    ArtiPath, BoxedKeystore, KeyCertificateSpecifier, KeyPath, KeyPathError, KeyPathInfo,
7    KeyPathInfoExtractor, KeyPathPattern, KeySpecifier, KeystoreCorruptionError, KeystoreId,
8    KeystoreSelector, Result,
9};
10
11use itertools::Itertools;
12use std::iter;
13use std::result::Result as StdResult;
14use tor_error::{bad_api_usage, internal, into_bad_api_usage};
15use tor_key_forge::{
16    ItemType, Keygen, KeygenRng, KeystoreItemType, ToEncodableCert, ToEncodableKey,
17};
18
19/// A key manager that acts as a frontend to a primary [`Keystore`](crate::Keystore) and
20/// any number of secondary [`Keystore`](crate::Keystore)s.
21///
22/// Note: [`KeyMgr`] is a low-level utility and does not implement caching (the key stores are
23/// accessed for every read/write).
24///
25/// The `KeyMgr` accessors - currently just [`get()`](KeyMgr::get) -
26/// search the configured key stores in order: first the primary key store,
27/// and then the secondary stores, in order.
28///
29///
30/// ## Concurrent key store access
31///
32/// The key stores will allow concurrent modification by different processes. In
33/// order to implement this safely without locking, the key store operations (get,
34/// insert, remove) will need to be atomic.
35///
36/// **Note**: [`KeyMgr::generate`] and [`KeyMgr::get_or_generate`] should **not** be used
37/// concurrently with any other `KeyMgr` operation that mutates the same key
38/// (i.e. a key with the same `ArtiPath`), because
39/// their outcome depends on whether the selected key store
40/// [`contains`][crate::Keystore::contains]
41/// the specified key (and thus suffers from a TOCTOU race).
42#[derive(derive_builder::Builder)]
43#[builder(pattern = "owned", build_fn(private, name = "build_unvalidated"))]
44pub struct KeyMgr {
45    /// The primary key store.
46    primary_store: BoxedKeystore,
47    /// The secondary key stores.
48    #[builder(default, setter(custom))]
49    secondary_stores: Vec<BoxedKeystore>,
50    /// The key info extractors.
51    ///
52    /// These are initialized internally by [`KeyMgrBuilder::build`], using the values collected
53    /// using `inventory`.
54    #[builder(default, setter(skip))]
55    key_info_extractors: Vec<&'static dyn KeyPathInfoExtractor>,
56}
57
58/// A keystore entry descriptor.
59///
60/// This identifies a key entry from a specific keystore.
61/// The key entry can be retrieved, using [`KeyMgr::get_entry`],
62/// or removed, using [`KeyMgr::remove_entry`].
63///
64/// Returned from [`KeyMgr::list_matching`].
65#[derive(Clone, Debug, PartialEq, amplify::Getters)]
66pub struct KeystoreEntry<'a> {
67    /// The [`KeyPath`] of the key.
68    key_path: KeyPath,
69    /// The [`KeystoreItemType`] of the key.
70    key_type: KeystoreItemType,
71    /// The [`KeystoreId`] that of the keystore where the key was found.
72    #[getter(as_copy)]
73    keystore_id: &'a KeystoreId,
74}
75
76impl KeyMgrBuilder {
77    /// Construct a [`KeyMgr`] from this builder.
78    pub fn build(self) -> StdResult<KeyMgr, KeyMgrBuilderError> {
79        use itertools::Itertools as _;
80
81        let mut keymgr = self.build_unvalidated()?;
82
83        if !keymgr.all_stores().map(|s| s.id()).all_unique() {
84            return Err(KeyMgrBuilderError::ValidationError(
85                "the keystore IDs are not pairwise unique".into(),
86            ));
87        }
88
89        keymgr.key_info_extractors = inventory::iter::<&'static dyn KeyPathInfoExtractor>
90            .into_iter()
91            .copied()
92            .collect();
93
94        Ok(keymgr)
95    }
96}
97
98// TODO: auto-generate using define_list_builder_accessors/define_list_builder_helper
99// when that becomes possible.
100//
101// See https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/1760#note_2969841
102impl KeyMgrBuilder {
103    /// Access the being-built list of secondary stores (resolving default)
104    ///
105    /// If the field has not yet been set or accessed, the default list will be
106    /// constructed and a mutable reference to the now-defaulted list of builders
107    /// will be returned.
108    pub fn secondary_stores(&mut self) -> &mut Vec<BoxedKeystore> {
109        self.secondary_stores.get_or_insert(Default::default())
110    }
111
112    /// Set the whole list (overriding the default)
113    pub fn set_secondary_stores(mut self, list: Vec<BoxedKeystore>) -> Self {
114        self.secondary_stores = Some(list);
115        self
116    }
117
118    /// Inspect the being-built list (with default unresolved)
119    ///
120    /// If the list has not yet been set, or accessed, `&None` is returned.
121    pub fn opt_secondary_stores(&self) -> &Option<Vec<BoxedKeystore>> {
122        &self.secondary_stores
123    }
124
125    /// Mutably access the being-built list (with default unresolved)
126    ///
127    /// If the list has not yet been set, or accessed, `&mut None` is returned.
128    pub fn opt_secondary_stores_mut(&mut self) -> &mut Option<Vec<BoxedKeystore>> {
129        &mut self.secondary_stores
130    }
131}
132
133inventory::collect!(&'static dyn crate::KeyPathInfoExtractor);
134
135impl KeyMgr {
136    /// Read a key from one of the key stores, and try to deserialize it as `K::Key`.
137    ///
138    /// The key returned is retrieved from the first key store that contains an entry for the given
139    /// specifier.
140    ///
141    /// Returns `Ok(None)` if none of the key stores have the requested key.
142    pub fn get<K: ToEncodableKey>(&self, key_spec: &dyn KeySpecifier) -> Result<Option<K>> {
143        let result = self.get_from_store(key_spec, &K::Key::item_type(), self.all_stores())?;
144        if result.is_none() {
145            // If the key_spec is the specifier for the public part of a keypair,
146            // try getting the pair and extracting the public portion from it.
147            if let Some(key_pair_spec) = key_spec.keypair_specifier() {
148                return Ok(self.get::<K::KeyPair>(&*key_pair_spec)?.map(|k| k.into()));
149            }
150        }
151        Ok(result)
152    }
153
154    /// Retrieve the specified keystore entry, and try to deserialize it as `K::Key`.
155    ///
156    /// The key returned is retrieved from the key store specified in the [`KeystoreEntry`].
157    ///
158    /// Returns `Ok(None)` if the key store does not contain the requested entry.
159    ///
160    /// Returns an error if the specified `key_type` does not match `K::Key::item_type()`.
161    pub fn get_entry<K: ToEncodableKey>(&self, entry: &KeystoreEntry) -> Result<Option<K>> {
162        let selector = entry.keystore_id().into();
163        let store = self.select_keystore(&selector)?;
164        self.get_from_store(entry.key_path(), entry.key_type(), [store].into_iter())
165    }
166
167    /// Read the key identified by `key_spec`.
168    ///
169    /// The key returned is retrieved from the first key store that contains an entry for the given
170    /// specifier.
171    ///
172    /// If the requested key does not exist in any of the key stores, this generates a new key of
173    /// type `K` from the key created using using `K::Key`'s [`Keygen`] implementation, and inserts
174    /// it into the specified keystore, returning the newly inserted value.
175    ///
176    /// This is a convenience wrapper around [`get()`](KeyMgr::get) and
177    /// [`generate()`](KeyMgr::generate).
178    pub fn get_or_generate<K>(
179        &self,
180        key_spec: &dyn KeySpecifier,
181        selector: KeystoreSelector,
182        rng: &mut dyn KeygenRng,
183    ) -> Result<K>
184    where
185        K: ToEncodableKey,
186        K::Key: Keygen,
187    {
188        match self.get(key_spec)? {
189            Some(k) => Ok(k),
190            None => self.generate(key_spec, selector, rng, false),
191        }
192    }
193
194    /// Generate a new key of type `K`, and insert it into the key store specified by `selector`.
195    ///
196    /// If the key already exists in the specified key store, the `overwrite` flag is used to
197    /// decide whether to overwrite it with a newly generated key.
198    ///
199    /// On success, this function returns the newly generated key.
200    ///
201    /// Returns [`Error::KeyAlreadyExists`](crate::Error::KeyAlreadyExists)
202    /// if the key already exists in the specified key store and `overwrite` is `false`.
203    ///
204    /// **IMPORTANT**: using this function concurrently with any other `KeyMgr` operation that
205    /// mutates the key store state is **not** recommended, as it can yield surprising results! The
206    /// outcome of [`KeyMgr::generate`] depends on whether the selected key store
207    /// [`contains`][crate::Keystore::contains] the specified key, and thus suffers from a TOCTOU race.
208    //
209    // TODO (#1119): can we make this less racy without a lock? Perhaps we should say we'll always
210    // overwrite any existing keys.
211    //
212    // TODO: consider replacing the overwrite boolean with a GenerateOptions type
213    // (sort of like std::fs::OpenOptions)
214    pub fn generate<K>(
215        &self,
216        key_spec: &dyn KeySpecifier,
217        selector: KeystoreSelector,
218        rng: &mut dyn KeygenRng,
219        overwrite: bool,
220    ) -> Result<K>
221    where
222        K: ToEncodableKey,
223        K::Key: Keygen,
224    {
225        let store = self.select_keystore(&selector)?;
226
227        if overwrite || !store.contains(key_spec, &K::Key::item_type())? {
228            let key = K::Key::generate(rng)?;
229            store.insert(&key, key_spec)?;
230
231            Ok(K::from_encodable_key(key))
232        } else {
233            Err(crate::Error::KeyAlreadyExists)
234        }
235    }
236
237    /// Insert `key` into the [`Keystore`](crate::Keystore) specified by `selector`.
238    ///
239    /// If the key already exists in the specified key store, the `overwrite` flag is used to
240    /// decide whether to overwrite it with the provided key.
241    ///
242    /// If this key is not already in the keystore, `None` is returned.
243    ///
244    /// If this key already exists in the keystore, its value is updated
245    /// and the old value is returned.
246    ///
247    /// Returns an error if the selected keystore is not the primary keystore or one of the
248    /// configured secondary stores.
249    pub fn insert<K: ToEncodableKey>(
250        &self,
251        key: K,
252        key_spec: &dyn KeySpecifier,
253        selector: KeystoreSelector,
254        overwrite: bool,
255    ) -> Result<Option<K>> {
256        let key = key.to_encodable_key();
257        let store = self.select_keystore(&selector)?;
258        let key_type = K::Key::item_type();
259        let old_key: Option<K> = self.get_from_store(key_spec, &key_type, [store].into_iter())?;
260
261        if old_key.is_some() && !overwrite {
262            Err(crate::Error::KeyAlreadyExists)
263        } else {
264            let () = store.insert(&key, key_spec)?;
265            Ok(old_key)
266        }
267    }
268
269    /// Remove the key identified by `key_spec` from the [`Keystore`](crate::Keystore)
270    /// specified by `selector`.
271    ///
272    /// Returns an error if the selected keystore is not the primary keystore or one of the
273    /// configured secondary stores.
274    ///
275    /// Returns the value of the removed key,
276    /// or `Ok(None)` if the key does not exist in the requested keystore.
277    ///
278    /// Returns `Err` if an error occurred while trying to remove the key.
279    pub fn remove<K: ToEncodableKey>(
280        &self,
281        key_spec: &dyn KeySpecifier,
282        selector: KeystoreSelector,
283    ) -> Result<Option<K>> {
284        let store = self.select_keystore(&selector)?;
285        let key_type = K::Key::item_type();
286        let old_key: Option<K> = self.get_from_store(key_spec, &key_type, [store].into_iter())?;
287
288        store.remove(key_spec, &key_type)?;
289
290        Ok(old_key)
291    }
292
293    /// Remove the specified keystore entry.
294    ///
295    /// Like [`KeyMgr::remove`], except this function does not return the value of the removed key.
296    ///
297    /// A return value of `Ok(None)` indicates the key was not found in the specified key store,
298    /// whereas `Ok(Some(())` means the key was successfully removed.
299    //
300    // TODO: We should be consistent and return the removed key.
301    //
302    // This probably will involve changing the return type of Keystore::remove
303    // to Result<Option<ErasedKey>>.
304    pub fn remove_entry(&self, entry: &KeystoreEntry) -> Result<Option<()>> {
305        let selector = entry.keystore_id().into();
306        let store = self.select_keystore(&selector)?;
307
308        store.remove(entry.key_path(), entry.key_type())
309    }
310
311    /// Return the keystore entry descriptors of the keys matching the specified [`KeyPathPattern`].
312    ///
313    /// NOTE: This searches for matching keys in _all_ keystores.
314    ///
315    /// NOTE: This function only returns the *recognized* entries that match the provided pattern.
316    /// The unrecognized entries (i.e. those that do not have a valid [`KeyPath`]) will be filtered out,
317    /// even if they match the specified pattern.
318    pub fn list_matching(&self, pat: &KeyPathPattern) -> Result<Vec<KeystoreEntry>> {
319        self.all_stores()
320            .map(|store| -> Result<Vec<_>> {
321                Ok(store
322                    .list()?
323                    .into_iter()
324                    .filter_map(|entry| entry.ok())
325                    .filter(|(key_path, _): &(KeyPath, KeystoreItemType)| key_path.matches(pat))
326                    .map(|(path, key_type)| KeystoreEntry {
327                        key_path: path.clone(),
328                        key_type,
329                        keystore_id: store.id(),
330                    })
331                    .collect::<Vec<_>>())
332            })
333            .flatten_ok()
334            .collect::<Result<Vec<_>>>()
335    }
336
337    /// Describe the specified key.
338    ///
339    /// Returns [`KeyPathError::Unrecognized`] if none of the registered
340    /// [`KeyPathInfoExtractor`]s is able to parse the specified [`KeyPath`].
341    ///
342    /// This function uses the [`KeyPathInfoExtractor`]s registered using
343    /// [`register_key_info_extractor`](crate::register_key_info_extractor),
344    /// or by [`DefaultKeySpecifier`](crate::derive_deftly_template_KeySpecifier).
345    pub fn describe(&self, path: &KeyPath) -> StdResult<KeyPathInfo, KeyPathError> {
346        for info_extractor in &self.key_info_extractors {
347            if let Ok(info) = info_extractor.describe(path) {
348                return Ok(info);
349            }
350        }
351
352        Err(KeyPathError::Unrecognized(path.clone()))
353    }
354
355    /// Attempt to retrieve a key from one of the specified `stores`.
356    ///
357    /// Returns the `<K as ToEncodableKey>::Key` representation of the key.
358    ///
359    /// See [`KeyMgr::get`] for more details.
360    fn get_from_store_raw<'a, K: ItemType>(
361        &self,
362        key_spec: &dyn KeySpecifier,
363        key_type: &KeystoreItemType,
364        stores: impl Iterator<Item = &'a BoxedKeystore>,
365    ) -> Result<Option<K>> {
366        let static_key_type = K::item_type();
367        if key_type != &static_key_type {
368            return Err(internal!(
369                "key type {:?} does not match the key type {:?} of requested key K::Key",
370                key_type,
371                static_key_type
372            )
373            .into());
374        }
375
376        for store in stores {
377            let key = match store.get(key_spec, &K::item_type()) {
378                Ok(None) => {
379                    // The key doesn't exist in this store, so we check the next one...
380                    continue;
381                }
382                Ok(Some(k)) => k,
383                Err(e) => {
384                    // Note: we immediately return if one of the keystores is inaccessible.
385                    return Err(e);
386                }
387            };
388
389            // Found it! Now try to downcast it to the right type (this should _not_ fail)...
390            let key: K = key
391                .downcast::<K>()
392                .map(|k| *k)
393                .map_err(|_| internal!("failed to downcast key to requested type"))?;
394
395            return Ok(Some(key));
396        }
397
398        Ok(None)
399    }
400
401    /// Attempt to retrieve a key from one of the specified `stores`.
402    ///
403    /// See [`KeyMgr::get`] for more details.
404    fn get_from_store<'a, K: ToEncodableKey>(
405        &self,
406        key_spec: &dyn KeySpecifier,
407        key_type: &KeystoreItemType,
408        stores: impl Iterator<Item = &'a BoxedKeystore>,
409    ) -> Result<Option<K>> {
410        let Some(key) = self.get_from_store_raw::<K::Key>(key_spec, key_type, stores)? else {
411            return Ok(None);
412        };
413
414        Ok(Some(K::from_encodable_key(key)))
415    }
416
417    /// Read the specified key and certificate from one of the key stores,
418    /// deserializing the subject key as `K::Key`, the cert as `C::Cert`,
419    /// and the signing key as `C::SigningKey`.
420    ///
421    /// Returns `Ok(None)` if none of the key stores have the requested key.
422    ///
423    // Note: the behavior of this function is a bit inconsistent with
424    // get_or_generate_key_and_cert: here, if the cert is absent but
425    // its subject key is not, we return Ok(None).
426    // In get_or_generate_key_and_cert, OTOH< we return an error in that case
427    // (because we can't possibly generate the missing subject key
428    // without overwriting the cert of the missing key).
429    ///
430    /// This function validates the certificate using [`ToEncodableCert::validate`],
431    /// returning an error if it is invalid or missing.
432    #[cfg(feature = "experimental-api")]
433    pub fn get_key_and_cert<K, C>(
434        &self,
435        spec: &dyn KeyCertificateSpecifier,
436    ) -> Result<Option<(K, C)>>
437    where
438        K: ToEncodableKey,
439        C: ToEncodableCert<K>,
440    {
441        let subject_key_spec = spec.subject_key_specifier();
442        // Get the subject key...
443        let Some(key) =
444            self.get_from_store::<K>(subject_key_spec, &K::Key::item_type(), self.all_stores())?
445        else {
446            return Ok(None);
447        };
448
449        let subject_key_arti_path = subject_key_spec
450            .arti_path()
451            .map_err(|_| bad_api_usage!("subject key does not have an ArtiPath?!"))?;
452        let cert_spec =
453            ArtiPath::from_path_and_denotators(subject_key_arti_path, &spec.cert_denotators())
454                .map_err(into_bad_api_usage!("invalid certificate specifier"))?;
455
456        let Some(cert) = self.get_from_store_raw::<C::ParsedCert>(
457            &cert_spec,
458            &<C::ParsedCert as ItemType>::item_type(),
459            self.all_stores(),
460        )?
461        else {
462            return Err(KeystoreCorruptionError::MissingCertificate.into());
463        };
464
465        // Finally, get the signing key and validate the cert
466        let signed_with = self.get_cert_signing_key::<K, C>(spec)?;
467        let cert = C::validate(cert, &key, &signed_with)?;
468
469        Ok(Some((key, cert)))
470    }
471
472    /// Like [`KeyMgr::get_key_and_cert`], except this function also generates the subject key
473    /// and its corresponding certificate if they don't already exist.
474    ///
475    /// If the key certificate is missing, it will be generated
476    /// from the subject key and signing key using the provided `make_certificate` callback.
477    ///
478    /// Generates the missing key and/or certificate as follows:
479    ///
480    /// ```text
481    /// | Subject Key exists | Signing Key exists | Cert exists | Action                                 |
482    /// |--------------------|--------------------|-------------|----------------------------------------|
483    /// | Y                  | Y                  | Y           | Validate cert, return key and cert     |
484    /// |                    |                    |             | if valid, error otherwise              |
485    /// |--------------------|--------------------|-------------|----------------------------------------|
486    /// | N                  | Y                  | N           | Generate subject key and               |
487    /// |                    |                    |             | a new cert signed with signing key     |
488    /// |--------------------|--------------------|-------------|----------------------------------------|
489    /// | Y                  | Y                  | N           | Generate cert signed with signing key  |
490    /// |--------------------|--------------------|-------------|----------------------------------------|
491    /// | Y                  | N                  | N           | Error - cannot validate cert           |
492    /// |                    |                    |             | if signing key is not available        |
493    /// |--------------------|--------------------|-------------|----------------------------------------|
494    /// | Y/N                | N                  | N           | Error - cannot generate cert           |
495    /// |                    |                    |             | if signing key is not available        |
496    /// |--------------------|--------------------|-------------|----------------------------------------|
497    /// | N                  | Y/N                | Y           | Error - subject key was removed?       |
498    /// |                    |                    |             | (we found the cert,                    |
499    /// |                    |                    |             | but the subject key is missing)        |
500    /// ```
501    ///
502    //
503    // Note; the table above isn't a markdown table because CommonMark-flavor markdown
504    // doesn't support multiline text in tables. Even if we trim down the text,
505    // the resulting markdown table would be pretty unreadable in raw form
506    // (it would have several excessively long lines, over 120 chars in len).
507    #[cfg(feature = "experimental-api")]
508    pub fn get_or_generate_key_and_cert<K, C>(
509        &self,
510        spec: &dyn KeyCertificateSpecifier,
511        make_certificate: impl FnOnce(&K, &<C as ToEncodableCert<K>>::SigningKey) -> C,
512        selector: KeystoreSelector,
513        rng: &mut dyn KeygenRng,
514    ) -> Result<(K, C)>
515    where
516        K: ToEncodableKey,
517        K::Key: Keygen,
518        C: ToEncodableCert<K>,
519    {
520        let subject_key_spec = spec.subject_key_specifier();
521        let subject_key_arti_path = subject_key_spec
522            .arti_path()
523            .map_err(|_| bad_api_usage!("subject key does not have an ArtiPath?!"))?;
524
525        let cert_specifier =
526            ArtiPath::from_path_and_denotators(subject_key_arti_path, &spec.cert_denotators())
527                .map_err(into_bad_api_usage!("invalid certificate specifier"))?;
528
529        let maybe_cert = self.get_from_store_raw::<C::ParsedCert>(
530            &cert_specifier,
531            &C::ParsedCert::item_type(),
532            self.all_stores(),
533        )?;
534
535        let maybe_subject_key = self.get::<K>(subject_key_spec)?;
536
537        match (&maybe_cert, &maybe_subject_key) {
538            (Some(_), None) => {
539                return Err(KeystoreCorruptionError::MissingSubjectKey.into());
540            }
541            _ => {
542                // generate key and/or cert
543            }
544        }
545        let subject_key = match maybe_subject_key {
546            Some(key) => key,
547            _ => self.generate(subject_key_spec, selector, rng, false)?,
548        };
549
550        let signed_with = self.get_cert_signing_key::<K, C>(spec)?;
551        let cert = match maybe_cert {
552            Some(cert) => C::validate(cert, &subject_key, &signed_with)?,
553            None => {
554                let cert = make_certificate(&subject_key, &signed_with);
555
556                let () = self.insert_cert(cert.clone(), &cert_specifier, selector)?;
557
558                cert
559            }
560        };
561
562        Ok((subject_key, cert))
563    }
564
565    /// Return an iterator over all configured stores.
566    fn all_stores(&self) -> impl Iterator<Item = &BoxedKeystore> {
567        iter::once(&self.primary_store).chain(self.secondary_stores.iter())
568    }
569
570    /// Return the [`Keystore`](crate::Keystore) matching the specified `selector`.
571    ///
572    /// Returns an error if the selected keystore is not the primary keystore or one of the
573    /// configured secondary stores.
574    fn select_keystore(&self, selector: &KeystoreSelector) -> Result<&BoxedKeystore> {
575        match selector {
576            KeystoreSelector::Id(keystore_id) => self.find_keystore(keystore_id),
577            KeystoreSelector::Primary => Ok(&self.primary_store),
578        }
579    }
580
581    /// Return the [`Keystore`](crate::Keystore) with the specified `id`.
582    ///
583    /// Returns an error if the specified ID is not the ID of the primary keystore or
584    /// the ID of one of the configured secondary stores.
585    fn find_keystore(&self, id: &KeystoreId) -> Result<&BoxedKeystore> {
586        self.all_stores()
587            .find(|keystore| keystore.id() == id)
588            .ok_or_else(|| bad_api_usage!("could not find keystore with ID {id}").into())
589    }
590
591    /// Get the signing key of the certificate described by `spec`.
592    ///
593    /// Returns a [`KeystoreCorruptionError::MissingSigningKey`] error
594    /// if the signing key doesn't exist in any of the keystores.
595    #[cfg(feature = "experimental-api")]
596    fn get_cert_signing_key<K, C>(
597        &self,
598        spec: &dyn KeyCertificateSpecifier,
599    ) -> Result<C::SigningKey>
600    where
601        K: ToEncodableKey,
602        C: ToEncodableCert<K>,
603    {
604        let Some(signing_key_spec) = spec.signing_key_specifier() else {
605            return Err(bad_api_usage!(
606                "signing key specifier is None, but external signing key was not provided?"
607            )
608            .into());
609        };
610
611        let Some(signing_key) = self.get_from_store::<C::SigningKey>(
612            signing_key_spec,
613            &<C::SigningKey as ToEncodableKey>::Key::item_type(),
614            self.all_stores(),
615        )?
616        else {
617            return Err(KeystoreCorruptionError::MissingSigningKey.into());
618        };
619
620        Ok(signing_key)
621    }
622
623    /// Insert `cert` into the [`Keystore`](crate::Keystore) specified by `selector`.
624    ///
625    /// If the key already exists in the specified key store, it will be overwritten.
626    ///
627    // NOTE: if we ever make this public we should rethink/improve its API.
628    // TODO: maybe fold this into insert() somehow?
629    fn insert_cert<K, C>(
630        &self,
631        cert: C,
632        cert_spec: &dyn KeySpecifier,
633        selector: KeystoreSelector,
634    ) -> Result<()>
635    where
636        K: ToEncodableKey,
637        K::Key: Keygen,
638        C: ToEncodableCert<K>,
639    {
640        let cert = cert.to_encodable_cert();
641        let store = self.select_keystore(&selector)?;
642
643        let () = store.insert(&cert, cert_spec)?;
644        Ok(())
645    }
646}
647
648#[cfg(test)]
649mod tests {
650    // @@ begin test lint list maintained by maint/add_warning @@
651    #![allow(clippy::bool_assert_comparison)]
652    #![allow(clippy::clone_on_copy)]
653    #![allow(clippy::dbg_macro)]
654    #![allow(clippy::mixed_attributes_style)]
655    #![allow(clippy::print_stderr)]
656    #![allow(clippy::print_stdout)]
657    #![allow(clippy::single_char_pattern)]
658    #![allow(clippy::unwrap_used)]
659    #![allow(clippy::unchecked_duration_subtraction)]
660    #![allow(clippy::useless_vec)]
661    #![allow(clippy::needless_pass_by_value)]
662    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
663    use super::*;
664    use crate::keystore::arti::err::{ArtiNativeKeystoreError, MalformedPathError};
665    use crate::{
666        ArtiPath, ArtiPathUnavailableError, Error, KeyPath, Keystore, KeystoreEntryResult,
667        KeystoreError, UnrecognizedEntryError, UnrecognizedEntryId,
668    };
669    use std::collections::HashMap;
670    use std::path::PathBuf;
671    use std::result::Result as StdResult;
672    use std::str::FromStr;
673    use std::sync::{Arc, RwLock};
674    use std::time::{Duration, SystemTime};
675    use tor_basic_utils::test_rng::testing_rng;
676    use tor_cert::CertifiedKey;
677    use tor_cert::Ed25519Cert;
678    use tor_error::{ErrorKind, HasKind};
679    use tor_key_forge::{
680        CertData, EncodableItem, ErasedKey, InvalidCertError, KeyType, KeystoreItem,
681    };
682    use tor_llcrypto::pk::ed25519::{self, Ed25519PublicKey as _};
683    use tor_llcrypto::rng::FakeEntropicRng;
684
685    /// Metadata structure for tracking key operations in tests.
686    #[derive(Clone, Debug, PartialEq)]
687    struct KeyMetadata {
688        /// The identifier for the item (e.g., "coot", "moorhen").
689        item_id: String,
690        /// The keystore from which the item was retrieved.
691        ///
692        /// Set by `Keystore::get`.
693        retrieved_from: Option<KeystoreId>,
694        /// Whether the item was generated via `Keygen::generate`.
695        is_generated: bool,
696    }
697
698    /// Metadata structure for tracking certificate operations in tests.
699    #[derive(Clone, Debug, PartialEq)]
700    struct CertMetadata {
701        /// The identifier for the subject key (e.g., "coot").
702        subject_key_id: String,
703        /// The identifier for the signing key (e.g., "moorhen").
704        signing_key_id: String,
705        /// The keystore from which the certificate was retrieved.
706        ///
707        /// Set by `Keystore::get`.
708        retrieved_from: Option<KeystoreId>,
709        /// Whether the certificate was freshly generated (i.e. returned from the "or generate"
710        /// branch of `get_or_generate()`) or retrieved from a keystore.
711        is_generated: bool,
712    }
713
714    /// Metadata structure for tracking item operations in tests.
715    #[derive(Clone, Debug, PartialEq, derive_more::From)]
716    enum ItemMetadata {
717        /// Metadata about a key.
718        Key(KeyMetadata),
719        /// Metadata about a certificate.
720        Cert(CertMetadata),
721    }
722
723    impl ItemMetadata {
724        /// Get the item ID.
725        ///
726        /// For keys, this returns the key's ID.
727        /// For certificates, this returns a formatted string identifying the subject key.
728        fn item_id(&self) -> &str {
729            match self {
730                ItemMetadata::Key(k) => &k.item_id,
731                ItemMetadata::Cert(c) => &c.subject_key_id,
732            }
733        }
734
735        /// Get retrieved_from.
736        fn retrieved_from(&self) -> Option<&KeystoreId> {
737            match self {
738                ItemMetadata::Key(k) => k.retrieved_from.as_ref(),
739                ItemMetadata::Cert(c) => c.retrieved_from.as_ref(),
740            }
741        }
742
743        /// Get is_generated.
744        fn is_generated(&self) -> bool {
745            match self {
746                ItemMetadata::Key(k) => k.is_generated,
747                ItemMetadata::Cert(c) => c.is_generated,
748            }
749        }
750
751        /// Set the retrieved_from field to the specified keystore ID.
752        fn set_retrieved_from(&mut self, id: KeystoreId) {
753            match self {
754                ItemMetadata::Key(meta) => meta.retrieved_from = Some(id),
755                ItemMetadata::Cert(meta) => meta.retrieved_from = Some(id),
756            }
757        }
758
759        /// Returns a reference to key metadata if this is a Key variant.
760        fn as_key(&self) -> Option<&KeyMetadata> {
761            match self {
762                ItemMetadata::Key(meta) => Some(meta),
763                _ => None,
764            }
765        }
766
767        /// Returns a reference to certificate metadata if this is a Cert variant.
768        fn as_cert(&self) -> Option<&CertMetadata> {
769            match self {
770                ItemMetadata::Cert(meta) => Some(meta),
771                _ => None,
772            }
773        }
774    }
775
776    /// The type of "key" stored in the test key stores.
777    #[derive(Clone, Debug)]
778    struct TestItem {
779        /// The underlying key.
780        item: KeystoreItem,
781        /// Metadata about the key.
782        meta: ItemMetadata,
783    }
784
785    /// A "certificate" used for testing purposes.
786    #[derive(Clone, Debug)]
787    struct AlwaysValidCert(TestItem);
788
789    /// The corresponding fake public key type.
790    #[derive(Clone, Debug)]
791    struct TestPublicKey {
792        /// The underlying key.
793        key: KeystoreItem,
794    }
795
796    impl From<TestItem> for TestPublicKey {
797        fn from(tk: TestItem) -> TestPublicKey {
798            TestPublicKey { key: tk.item }
799        }
800    }
801
802    impl TestItem {
803        /// Create a new test key with the specified metadata.
804        fn new(item_id: &str) -> Self {
805            let mut rng = testing_rng();
806            TestItem {
807                item: ed25519::Keypair::generate(&mut rng)
808                    .as_keystore_item()
809                    .unwrap(),
810                meta: ItemMetadata::Key(KeyMetadata {
811                    item_id: item_id.to_string(),
812                    retrieved_from: None,
813                    is_generated: false,
814                }),
815            }
816        }
817    }
818
819    impl Keygen for TestItem {
820        fn generate(mut rng: &mut dyn KeygenRng) -> tor_key_forge::Result<Self>
821        where
822            Self: Sized,
823        {
824            Ok(TestItem {
825                item: ed25519::Keypair::generate(&mut rng).as_keystore_item()?,
826                meta: ItemMetadata::Key(KeyMetadata {
827                    item_id: "generated_test_key".to_string(),
828                    retrieved_from: None,
829                    is_generated: true,
830                }),
831            })
832        }
833    }
834
835    impl ItemType for TestItem {
836        fn item_type() -> KeystoreItemType
837        where
838            Self: Sized,
839        {
840            // Dummy value
841            KeyType::Ed25519Keypair.into()
842        }
843    }
844
845    impl EncodableItem for TestItem {
846        fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
847            Ok(self.item.clone())
848        }
849    }
850
851    impl ToEncodableKey for TestItem {
852        type Key = Self;
853        type KeyPair = Self;
854
855        fn to_encodable_key(self) -> Self::Key {
856            self
857        }
858
859        fn from_encodable_key(key: Self::Key) -> Self {
860            key
861        }
862    }
863
864    impl ItemType for TestPublicKey {
865        fn item_type() -> KeystoreItemType
866        where
867            Self: Sized,
868        {
869            KeyType::Ed25519PublicKey.into()
870        }
871    }
872
873    impl EncodableItem for TestPublicKey {
874        fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
875            Ok(self.key.clone())
876        }
877    }
878
879    impl ToEncodableKey for TestPublicKey {
880        type Key = Self;
881        type KeyPair = TestItem;
882
883        fn to_encodable_key(self) -> Self::Key {
884            self
885        }
886
887        fn from_encodable_key(key: Self::Key) -> Self {
888            key
889        }
890    }
891
892    impl ToEncodableCert<TestItem> for AlwaysValidCert {
893        type ParsedCert = TestItem;
894        type EncodableCert = TestItem;
895        type SigningKey = TestItem;
896
897        fn validate(
898            cert: Self::ParsedCert,
899            _subject: &TestItem,
900            _signed_with: &Self::SigningKey,
901        ) -> StdResult<Self, InvalidCertError> {
902            // AlwaysValidCert is always valid
903            Ok(Self(cert))
904        }
905
906        /// Convert this cert to a type that implements [`EncodableKey`].
907        fn to_encodable_cert(self) -> Self::EncodableCert {
908            self.0
909        }
910    }
911
912    struct KeystoreListMock {
913        id: KeystoreId,
914        valid_key_path: KeyPath,
915        invalid_key_path: PathBuf,
916    }
917
918    impl Default for KeystoreListMock {
919        fn default() -> Self {
920            Self {
921                id: KeystoreId::from_str("keystore_list_mock").unwrap(),
922                valid_key_path: KeyPath::Arti(
923                    ArtiPath::new("recognized_entry".to_owned()).unwrap(),
924                ),
925                invalid_key_path: PathBuf::from_str("unrecognized_entry").unwrap(),
926            }
927        }
928    }
929
930    impl Keystore for KeystoreListMock {
931        fn id(&self) -> &KeystoreId {
932            &self.id
933        }
934
935        fn get(
936            &self,
937            _key_spec: &dyn KeySpecifier,
938            _item_type: &KeystoreItemType,
939        ) -> Result<Option<ErasedKey>> {
940            Err(Error::Keystore(Arc::new(
941                KeystoreListMockError::MethodNotSuppored,
942            )))
943        }
944
945        fn list(&self) -> Result<Vec<KeystoreEntryResult<(KeyPath, KeystoreItemType)>>> {
946            // Provide two entries, a recognized one and an unrecognized one
947            Ok(vec![
948                Ok((
949                    self.valid_key_path.clone(),
950                    KeystoreItemType::Key(KeyType::Ed25519PublicKey),
951                )),
952                Err(UnrecognizedEntryError::new(
953                    UnrecognizedEntryId::Path(self.invalid_key_path.clone()),
954                    Arc::new(ArtiNativeKeystoreError::MalformedPath {
955                        path: self.invalid_key_path.clone(),
956                        err: MalformedPathError::NoExtension,
957                    }),
958                )),
959            ])
960        }
961
962        fn insert(&self, _key: &dyn EncodableItem, _key_spec: &dyn KeySpecifier) -> Result<()> {
963            Err(Error::Keystore(Arc::new(
964                KeystoreListMockError::MethodNotSuppored,
965            )))
966        }
967
968        fn remove(
969            &self,
970            _key_spec: &dyn KeySpecifier,
971            _item_type: &KeystoreItemType,
972        ) -> Result<Option<()>> {
973            Err(Error::Keystore(Arc::new(
974                KeystoreListMockError::MethodNotSuppored,
975            )))
976        }
977
978        fn contains(
979            &self,
980            _key_spec: &dyn KeySpecifier,
981            _item_type: &KeystoreItemType,
982        ) -> Result<bool> {
983            Err(Error::Keystore(Arc::new(
984                KeystoreListMockError::MethodNotSuppored,
985            )))
986        }
987    }
988
989    #[derive(thiserror::Error, Debug, Clone, derive_more::Display)]
990    enum KeystoreListMockError {
991        MethodNotSuppored,
992    }
993
994    impl KeystoreError for KeystoreListMockError {}
995
996    impl HasKind for KeystoreListMockError {
997        fn kind(&self) -> ErrorKind {
998            ErrorKind::BadApiUsage
999        }
1000    }
1001
1002    macro_rules! impl_keystore {
1003        ($name:tt, $id:expr) => {
1004            struct $name {
1005                inner: RwLock<HashMap<(ArtiPath, KeystoreItemType), TestItem>>,
1006                id: KeystoreId,
1007            }
1008
1009            impl Default for $name {
1010                fn default() -> Self {
1011                    Self {
1012                        inner: Default::default(),
1013                        id: KeystoreId::from_str($id).unwrap(),
1014                    }
1015                }
1016            }
1017
1018            #[allow(dead_code)] // this is only dead code for Keystore1
1019            impl $name {
1020                fn new_boxed() -> BoxedKeystore {
1021                    Box::<Self>::default()
1022                }
1023            }
1024
1025            impl crate::Keystore for $name {
1026                fn contains(
1027                    &self,
1028                    key_spec: &dyn KeySpecifier,
1029                    item_type: &KeystoreItemType,
1030                ) -> Result<bool> {
1031                    Ok(self
1032                        .inner
1033                        .read()
1034                        .unwrap()
1035                        .contains_key(&(key_spec.arti_path().unwrap(), item_type.clone())))
1036                }
1037
1038                fn id(&self) -> &KeystoreId {
1039                    &self.id
1040                }
1041
1042                fn get(
1043                    &self,
1044                    key_spec: &dyn KeySpecifier,
1045                    item_type: &KeystoreItemType,
1046                ) -> Result<Option<ErasedKey>> {
1047                    Ok(self
1048                        .inner
1049                        .read()
1050                        .unwrap()
1051                        .get(&(key_spec.arti_path().unwrap(), item_type.clone()))
1052                        .map(|k| {
1053                            let mut k = k.clone();
1054                            k.meta.set_retrieved_from(self.id().clone());
1055                            Box::new(k) as Box<dyn ItemType>
1056                        }))
1057                }
1058
1059                fn insert(
1060                    &self,
1061                    key: &dyn EncodableItem,
1062                    key_spec: &dyn KeySpecifier,
1063                ) -> Result<()> {
1064                    let key = key.downcast_ref::<TestItem>().unwrap();
1065
1066                    let item = key.as_keystore_item()?;
1067                    let meta = key.meta.clone();
1068
1069                    let item_type = item.item_type()?;
1070                    let key = TestItem { item, meta };
1071
1072                    self.inner
1073                        .write()
1074                        .unwrap()
1075                        .insert((key_spec.arti_path().unwrap(), item_type), key);
1076
1077                    Ok(())
1078                }
1079
1080                fn remove(
1081                    &self,
1082                    key_spec: &dyn KeySpecifier,
1083                    item_type: &KeystoreItemType,
1084                ) -> Result<Option<()>> {
1085                    Ok(self
1086                        .inner
1087                        .write()
1088                        .unwrap()
1089                        .remove(&(key_spec.arti_path().unwrap(), item_type.clone()))
1090                        .map(|_| ()))
1091                }
1092
1093                fn list(&self) -> Result<Vec<KeystoreEntryResult<(KeyPath, KeystoreItemType)>>> {
1094                    Ok(self
1095                        .inner
1096                        .read()
1097                        .unwrap()
1098                        .iter()
1099                        .map(|((arti_path, item_type), _)| {
1100                            Ok((KeyPath::Arti(arti_path.clone()), item_type.clone()))
1101                        })
1102                        .collect())
1103                }
1104            }
1105        };
1106    }
1107
1108    macro_rules! impl_specifier {
1109        ($name:tt, $id:expr) => {
1110            struct $name;
1111
1112            impl KeySpecifier for $name {
1113                fn arti_path(&self) -> StdResult<ArtiPath, ArtiPathUnavailableError> {
1114                    Ok(ArtiPath::new($id.into()).map_err(|e| tor_error::internal!("{e}"))?)
1115                }
1116
1117                fn ctor_path(&self) -> Option<crate::CTorPath> {
1118                    None
1119                }
1120
1121                fn keypair_specifier(&self) -> Option<Box<dyn KeySpecifier>> {
1122                    None
1123                }
1124            }
1125        };
1126    }
1127
1128    impl_keystore!(Keystore1, "keystore1");
1129    impl_keystore!(Keystore2, "keystore2");
1130    impl_keystore!(Keystore3, "keystore3");
1131
1132    impl_specifier!(TestKeySpecifier1, "spec1");
1133    impl_specifier!(TestKeySpecifier2, "spec2");
1134    impl_specifier!(TestKeySpecifier3, "spec3");
1135    impl_specifier!(TestKeySpecifier4, "spec4");
1136
1137    impl_specifier!(TestPublicKeySpecifier1, "pub-spec1");
1138
1139    /// Create a test `KeystoreEntry`.
1140    fn entry_descriptor(specifier: impl KeySpecifier, keystore_id: &KeystoreId) -> KeystoreEntry {
1141        KeystoreEntry {
1142            key_path: specifier.arti_path().unwrap().into(),
1143            key_type: TestItem::item_type(),
1144            keystore_id,
1145        }
1146    }
1147
1148    #[test]
1149    #[allow(clippy::cognitive_complexity)]
1150    fn insert_and_get() {
1151        let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1152
1153        builder
1154            .secondary_stores()
1155            .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1156
1157        let mgr = builder.build().unwrap();
1158
1159        // Insert a key into Keystore2
1160        let old_key = mgr
1161            .insert(
1162                TestItem::new("coot"),
1163                &TestKeySpecifier1,
1164                KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1165                true,
1166            )
1167            .unwrap();
1168
1169        assert!(old_key.is_none());
1170        let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1171        assert_eq!(key.meta.item_id(), "coot");
1172        assert_eq!(
1173            key.meta.retrieved_from(),
1174            Some(&KeystoreId::from_str("keystore2").unwrap())
1175        );
1176        assert_eq!(key.meta.is_generated(), false);
1177
1178        // Insert a different key using the _same_ key specifier.
1179        let old_key = mgr
1180            .insert(
1181                TestItem::new("gull"),
1182                &TestKeySpecifier1,
1183                KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1184                true,
1185            )
1186            .unwrap()
1187            .unwrap();
1188        assert_eq!(old_key.meta.item_id(), "coot");
1189        assert_eq!(
1190            old_key.meta.retrieved_from(),
1191            Some(&KeystoreId::from_str("keystore2").unwrap())
1192        );
1193        assert_eq!(old_key.meta.is_generated(), false);
1194        // Check that the original value was overwritten:
1195        let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1196        assert_eq!(key.meta.item_id(), "gull");
1197        assert_eq!(
1198            key.meta.retrieved_from(),
1199            Some(&KeystoreId::from_str("keystore2").unwrap())
1200        );
1201        assert_eq!(key.meta.is_generated(), false);
1202
1203        // Insert a different key using the _same_ key specifier (overwrite = false)
1204        let err = mgr
1205            .insert(
1206                TestItem::new("gull"),
1207                &TestKeySpecifier1,
1208                KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1209                false,
1210            )
1211            .unwrap_err();
1212        assert!(matches!(err, crate::Error::KeyAlreadyExists));
1213
1214        // Insert a new key into Keystore2 (overwrite = false)
1215        let old_key = mgr
1216            .insert(
1217                TestItem::new("penguin"),
1218                &TestKeySpecifier2,
1219                KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1220                false,
1221            )
1222            .unwrap();
1223        assert!(old_key.is_none());
1224
1225        // Insert a key into the primary keystore
1226        let old_key = mgr
1227            .insert(
1228                TestItem::new("moorhen"),
1229                &TestKeySpecifier3,
1230                KeystoreSelector::Primary,
1231                true,
1232            )
1233            .unwrap();
1234        assert!(old_key.is_none());
1235        let key = mgr.get::<TestItem>(&TestKeySpecifier3).unwrap().unwrap();
1236        assert_eq!(key.meta.item_id(), "moorhen");
1237        assert_eq!(
1238            key.meta.retrieved_from(),
1239            Some(&KeystoreId::from_str("keystore1").unwrap())
1240        );
1241        assert_eq!(key.meta.is_generated(), false);
1242
1243        // The key doesn't exist in any of the stores yet.
1244        assert!(mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().is_none());
1245
1246        // Insert the same key into all 3 key stores, in reverse order of keystore priority
1247        // (otherwise KeyMgr::get will return the key from the primary store for each iteration and
1248        // we won't be able to see the key was actually inserted in each store).
1249        for store in ["keystore3", "keystore2", "keystore1"] {
1250            let old_key = mgr
1251                .insert(
1252                    TestItem::new("cormorant"),
1253                    &TestKeySpecifier4,
1254                    KeystoreSelector::Id(&KeystoreId::from_str(store).unwrap()),
1255                    true,
1256                )
1257                .unwrap();
1258            assert!(old_key.is_none());
1259
1260            // Ensure the key now exists in `store`.
1261            let key = mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().unwrap();
1262            assert_eq!(key.meta.item_id(), "cormorant");
1263            assert_eq!(
1264                key.meta.retrieved_from(),
1265                Some(&KeystoreId::from_str(store).unwrap())
1266            );
1267            assert_eq!(key.meta.is_generated(), false);
1268        }
1269
1270        // The key exists in all key stores, but if no keystore_id is specified, we return the
1271        // value from the first key store it is found in (in this case, Keystore1)
1272        let key = mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().unwrap();
1273        assert_eq!(key.meta.item_id(), "cormorant");
1274        assert_eq!(
1275            key.meta.retrieved_from(),
1276            Some(&KeystoreId::from_str("keystore1").unwrap())
1277        );
1278        assert_eq!(key.meta.is_generated(), false);
1279    }
1280
1281    #[test]
1282    fn remove() {
1283        let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1284
1285        builder
1286            .secondary_stores()
1287            .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1288
1289        let mgr = builder.build().unwrap();
1290
1291        assert!(!mgr.secondary_stores[0]
1292            .contains(&TestKeySpecifier1, &TestItem::item_type())
1293            .unwrap());
1294
1295        // Insert a key into Keystore2
1296        mgr.insert(
1297            TestItem::new("coot"),
1298            &TestKeySpecifier1,
1299            KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1300            true,
1301        )
1302        .unwrap();
1303        let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1304        assert_eq!(key.meta.item_id(), "coot");
1305        assert_eq!(
1306            key.meta.retrieved_from(),
1307            Some(&KeystoreId::from_str("keystore2").unwrap())
1308        );
1309        assert_eq!(key.meta.is_generated(), false);
1310
1311        // Try to remove the key from a non-existent key store
1312        assert!(mgr
1313            .remove::<TestItem>(
1314                &TestKeySpecifier1,
1315                KeystoreSelector::Id(&KeystoreId::from_str("not_an_id_we_know_of").unwrap())
1316            )
1317            .is_err());
1318        // The key still exists in Keystore2
1319        assert!(mgr.secondary_stores[0]
1320            .contains(&TestKeySpecifier1, &TestItem::item_type())
1321            .unwrap());
1322
1323        // Try to remove the key from the primary key store
1324        assert!(mgr
1325            .remove::<TestItem>(&TestKeySpecifier1, KeystoreSelector::Primary)
1326            .unwrap()
1327            .is_none());
1328
1329        // The key still exists in Keystore2
1330        assert!(mgr.secondary_stores[0]
1331            .contains(&TestKeySpecifier1, &TestItem::item_type())
1332            .unwrap());
1333
1334        // Removing from Keystore2 should succeed.
1335        let removed_key = mgr
1336            .remove::<TestItem>(
1337                &TestKeySpecifier1,
1338                KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1339            )
1340            .unwrap()
1341            .unwrap();
1342        assert_eq!(removed_key.meta.item_id(), "coot");
1343        assert_eq!(
1344            removed_key.meta.retrieved_from(),
1345            Some(&KeystoreId::from_str("keystore2").unwrap())
1346        );
1347        assert_eq!(removed_key.meta.is_generated(), false);
1348
1349        // The key doesn't exist in Keystore2 anymore
1350        assert!(!mgr.secondary_stores[0]
1351            .contains(&TestKeySpecifier1, &TestItem::item_type())
1352            .unwrap());
1353    }
1354
1355    #[test]
1356    fn keygen() {
1357        let mut rng = FakeEntropicRng(testing_rng());
1358        let mgr = KeyMgrBuilder::default()
1359            .primary_store(Box::<Keystore1>::default())
1360            .build()
1361            .unwrap();
1362
1363        mgr.insert(
1364            TestItem::new("coot"),
1365            &TestKeySpecifier1,
1366            KeystoreSelector::Primary,
1367            true,
1368        )
1369        .unwrap();
1370
1371        // There is no corresponding public key entry.
1372        assert!(mgr
1373            .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1374            .unwrap()
1375            .is_none());
1376
1377        // Try to generate a new key (overwrite = false)
1378        let err = mgr
1379            .generate::<TestItem>(
1380                &TestKeySpecifier1,
1381                KeystoreSelector::Primary,
1382                &mut rng,
1383                false,
1384            )
1385            .unwrap_err();
1386
1387        assert!(matches!(err, crate::Error::KeyAlreadyExists));
1388
1389        // The previous entry was not overwritten because overwrite = false
1390        let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1391        assert_eq!(key.meta.item_id(), "coot");
1392        assert_eq!(
1393            key.meta.retrieved_from(),
1394            Some(&KeystoreId::from_str("keystore1").unwrap())
1395        );
1396        assert_eq!(key.meta.is_generated(), false);
1397
1398        // We don't store public keys in the keystore
1399        assert!(mgr
1400            .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1401            .unwrap()
1402            .is_none());
1403
1404        // Try to generate a new key (overwrite = true)
1405        let generated_key = mgr
1406            .generate::<TestItem>(
1407                &TestKeySpecifier1,
1408                KeystoreSelector::Primary,
1409                &mut rng,
1410                true,
1411            )
1412            .unwrap();
1413
1414        assert_eq!(generated_key.meta.item_id(), "generated_test_key");
1415        // Not set in a freshly generated key, because KeyMgr::generate()
1416        // returns it straight away, without going through Keystore::get()
1417        assert_eq!(generated_key.meta.retrieved_from(), None);
1418        assert_eq!(generated_key.meta.is_generated(), true);
1419
1420        // Retrieve the inserted key
1421        let retrieved_key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1422        assert_eq!(retrieved_key.meta.item_id(), "generated_test_key");
1423        assert_eq!(
1424            retrieved_key.meta.retrieved_from(),
1425            Some(&KeystoreId::from_str("keystore1").unwrap())
1426        );
1427        assert_eq!(retrieved_key.meta.is_generated(), true);
1428
1429        // We don't store public keys in the keystore
1430        assert!(mgr
1431            .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1432            .unwrap()
1433            .is_none());
1434    }
1435
1436    #[test]
1437    fn get_or_generate() {
1438        let mut rng = FakeEntropicRng(testing_rng());
1439        let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1440
1441        builder
1442            .secondary_stores()
1443            .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1444
1445        let mgr = builder.build().unwrap();
1446
1447        let keystore2 = KeystoreId::from_str("keystore2").unwrap();
1448        let entry_desc1 = entry_descriptor(TestKeySpecifier1, &keystore2);
1449        assert!(mgr.get_entry::<TestItem>(&entry_desc1).unwrap().is_none());
1450
1451        mgr.insert(
1452            TestItem::new("coot"),
1453            &TestKeySpecifier1,
1454            KeystoreSelector::Id(&keystore2),
1455            true,
1456        )
1457        .unwrap();
1458
1459        // The key already exists in keystore 2 so it won't be auto-generated.
1460        let key = mgr
1461            .get_or_generate::<TestItem>(&TestKeySpecifier1, KeystoreSelector::Primary, &mut rng)
1462            .unwrap();
1463        assert_eq!(key.meta.item_id(), "coot");
1464        assert_eq!(
1465            key.meta.retrieved_from(),
1466            Some(&KeystoreId::from_str("keystore2").unwrap())
1467        );
1468        assert_eq!(key.meta.is_generated(), false);
1469
1470        assert_eq!(
1471            mgr.get_entry::<TestItem>(&entry_desc1)
1472                .unwrap()
1473                .map(|k| k.meta),
1474            Some(ItemMetadata::Key(KeyMetadata {
1475                item_id: "coot".to_string(),
1476                retrieved_from: Some(keystore2.clone()),
1477                is_generated: false,
1478            }))
1479        );
1480
1481        // This key doesn't exist in any of the keystores, so it will be auto-generated and
1482        // inserted into keystore 3.
1483        let keystore3 = KeystoreId::from_str("keystore3").unwrap();
1484        let generated_key = mgr
1485            .get_or_generate::<TestItem>(
1486                &TestKeySpecifier2,
1487                KeystoreSelector::Id(&keystore3),
1488                &mut rng,
1489            )
1490            .unwrap();
1491        assert_eq!(generated_key.meta.item_id(), "generated_test_key");
1492        // Not set in a freshly generated key, because KeyMgr::get_or_generate()
1493        // returns it straight away, without going through Keystore::get()
1494        assert_eq!(generated_key.meta.retrieved_from(), None);
1495        assert_eq!(generated_key.meta.is_generated(), true);
1496
1497        // Retrieve the inserted key
1498        let retrieved_key = mgr.get::<TestItem>(&TestKeySpecifier2).unwrap().unwrap();
1499        assert_eq!(retrieved_key.meta.item_id(), "generated_test_key");
1500        assert_eq!(
1501            retrieved_key.meta.retrieved_from(),
1502            Some(&KeystoreId::from_str("keystore3").unwrap())
1503        );
1504        assert_eq!(retrieved_key.meta.is_generated(), true);
1505
1506        let entry_desc2 = entry_descriptor(TestKeySpecifier2, &keystore3);
1507        assert_eq!(
1508            mgr.get_entry::<TestItem>(&entry_desc2)
1509                .unwrap()
1510                .map(|k| k.meta),
1511            Some(ItemMetadata::Key(KeyMetadata {
1512                item_id: "generated_test_key".to_string(),
1513                retrieved_from: Some(keystore3.clone()),
1514                is_generated: true,
1515            }))
1516        );
1517
1518        let arti_pat = KeyPathPattern::Arti("*".to_string());
1519        let matching = mgr.list_matching(&arti_pat).unwrap();
1520
1521        assert_eq!(matching.len(), 2);
1522        assert!(matching.contains(&entry_desc1));
1523        assert!(matching.contains(&entry_desc2));
1524
1525        assert_eq!(mgr.remove_entry(&entry_desc2).unwrap(), Some(()));
1526        assert!(mgr.get_entry::<TestItem>(&entry_desc2).unwrap().is_none());
1527        assert!(mgr.remove_entry(&entry_desc2).unwrap().is_none());
1528    }
1529
1530    #[test]
1531    fn list_matching_ignores_unrecognized_keys() {
1532        let builder = KeyMgrBuilder::default().primary_store(Box::new(KeystoreListMock::default()));
1533
1534        let mgr = builder.build().unwrap();
1535
1536        let arti_pat = KeyPathPattern::Arti("*".to_string());
1537        let matching = mgr.list_matching(&arti_pat).unwrap();
1538        // assert the unrecognized key has been filterd out
1539        assert_eq!(matching.len(), 1);
1540        assert_eq!(
1541            matching.first().unwrap().key_path(),
1542            &KeystoreListMock::default().valid_key_path
1543        );
1544    }
1545
1546    /// Whether to generate a given item before running the `run_certificate_test`.
1547    #[cfg(feature = "experimental-api")]
1548    #[derive(Clone, Copy, Debug, PartialEq)]
1549    enum GenerateItem {
1550        Yes,
1551        No,
1552    }
1553
1554    #[cfg(feature = "experimental-api")]
1555    macro_rules! run_certificate_test {
1556        (
1557            generate_subject_key = $generate_subject_key:expr,
1558            generate_signing_key = $generate_signing_key:expr,
1559            $($expected_err:tt)?
1560        ) => {{
1561            use GenerateItem::*;
1562
1563            let mut rng = FakeEntropicRng(testing_rng());
1564            let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1565
1566            builder
1567                .secondary_stores()
1568                .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1569
1570            let mgr = builder.build().unwrap();
1571
1572            let spec = crate::test_utils::TestCertSpecifier {
1573                subject_key_spec: TestKeySpecifier1,
1574                signing_key_spec: TestKeySpecifier2,
1575                denotator: vec!["foo".into()],
1576            };
1577
1578            if $generate_subject_key == Yes {
1579                let _ = mgr
1580                    .generate::<TestItem>(
1581                        &TestKeySpecifier1,
1582                        KeystoreSelector::Primary,
1583                        &mut rng,
1584                        false,
1585                    )
1586                    .unwrap();
1587            }
1588
1589            if $generate_signing_key == Yes {
1590                let _ = mgr
1591                    .generate::<TestItem>(
1592                        &TestKeySpecifier2,
1593                        KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1594                        &mut rng,
1595                        false,
1596                    )
1597                    .unwrap();
1598            }
1599
1600            let make_certificate = move |subject_key: &TestItem, signed_with: &TestItem| {
1601                let subject_id = subject_key.meta.as_key().unwrap().item_id.clone();
1602                let signing_id = signed_with.meta.as_key().unwrap().item_id.clone();
1603
1604                let meta = ItemMetadata::Cert(CertMetadata {
1605                    subject_key_id: subject_id,
1606                    signing_key_id: signing_id,
1607                    retrieved_from: None,
1608                    is_generated: true,
1609                });
1610
1611                // Note: this is not really a cert for `subject_key` signed with the `signed_with`
1612                // key!. The two are `TestItem`s and not keys, so we can't really generate a real
1613                // cert from them. We can, however, pretend we did, for testing purposes.
1614                // Eventually we might want to rewrite these tests to use real items
1615                // (like the `ArtiNativeKeystore` tests)
1616                let mut rng = FakeEntropicRng(testing_rng());
1617                let keypair = ed25519::Keypair::generate(&mut rng);
1618                let encoded_cert = Ed25519Cert::constructor()
1619                    .cert_type(tor_cert::CertType::IDENTITY_V_SIGNING)
1620                    .expiration(SystemTime::now() + Duration::from_secs(180))
1621                    .signing_key(keypair.public_key().into())
1622                    .cert_key(CertifiedKey::Ed25519(keypair.public_key().into()))
1623                    .encode_and_sign(&keypair)
1624                    .unwrap();
1625                let test_cert = CertData::TorEd25519Cert(encoded_cert);
1626                AlwaysValidCert(TestItem {
1627                    item: KeystoreItem::Cert(test_cert),
1628                    meta,
1629                })
1630            };
1631
1632            let res = mgr
1633                .get_or_generate_key_and_cert::<TestItem, AlwaysValidCert>(
1634                    &spec,
1635                    &make_certificate,
1636                    KeystoreSelector::Primary,
1637                    &mut rng,
1638                );
1639
1640            #[allow(unused_assignments)]
1641            #[allow(unused_mut)]
1642            let mut has_error = false;
1643            $(
1644                has_error = true;
1645                let err = res.clone().unwrap_err();
1646                assert!(
1647                    matches!(
1648                        err,
1649                        crate::Error::Corruption(KeystoreCorruptionError::$expected_err)
1650                    ),
1651                    "unexpected error: {err:?}",
1652                );
1653            )?
1654
1655            if !has_error {
1656                let (key, cert) = res.unwrap();
1657
1658                let expected_subj_key_id = if $generate_subject_key == Yes {
1659                    "generated_test_key"
1660                } else {
1661                    "generated_test_key"
1662                };
1663
1664                assert_eq!(key.meta.item_id(), expected_subj_key_id);
1665                assert_eq!(
1666                    cert.0.meta.as_cert().unwrap().subject_key_id,
1667                    expected_subj_key_id
1668                );
1669                assert_eq!(
1670                    cert.0.meta.as_cert().unwrap().signing_key_id,
1671                    "generated_test_key"
1672                );
1673                assert_eq!(cert.0.meta.is_generated(), true);
1674            }
1675        }}
1676    }
1677
1678    #[test]
1679    #[cfg(feature = "experimental-api")]
1680    #[rustfmt::skip] // preserve the layout for readability
1681    #[allow(clippy::cognitive_complexity)] // clippy seems confused here...
1682    fn get_certificate() {
1683        run_certificate_test!(
1684            generate_subject_key = No,
1685            generate_signing_key = No,
1686            MissingSigningKey
1687        );
1688
1689        run_certificate_test!(
1690            generate_subject_key = Yes,
1691            generate_signing_key = No,
1692            MissingSigningKey
1693        );
1694
1695        run_certificate_test!(
1696            generate_subject_key = No,
1697            generate_signing_key = Yes,
1698        );
1699
1700        run_certificate_test!(
1701            generate_subject_key = Yes,
1702            generate_signing_key = Yes,
1703        );
1704    }
1705}