1
//! Code for managing multiple [`Keystore`](crate::Keystore)s.
2
//!
3
//! See the [`KeyMgr`] docs for more details.
4

            
5
use crate::{
6
    ArtiPath, BoxedKeystore, KeyCertificateSpecifier, KeyPath, KeyPathError, KeyPathInfo,
7
    KeyPathInfoExtractor, KeyPathPattern, KeySpecifier, KeystoreCorruptionError, KeystoreId,
8
    KeystoreSelector, Result,
9
};
10

            
11
use itertools::Itertools;
12
use std::iter;
13
use std::result::Result as StdResult;
14
use tor_error::{bad_api_usage, internal, into_bad_api_usage};
15
use 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
2808
#[derive(derive_builder::Builder)]
43
#[builder(pattern = "owned", build_fn(private, name = "build_unvalidated"))]
44
pub 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)]
66
pub 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

            
76
impl KeyMgrBuilder {
77
    /// Construct a [`KeyMgr`] from this builder.
78
936
    pub fn build(self) -> StdResult<KeyMgr, KeyMgrBuilderError> {
79
        use itertools::Itertools as _;
80

            
81
936
        let mut keymgr = self.build_unvalidated()?;
82

            
83
995
        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
936
        }
88
936

            
89
936
        keymgr.key_info_extractors = inventory::iter::<&'static dyn KeyPathInfoExtractor>
90
936
            .into_iter()
91
936
            .copied()
92
936
            .collect();
93
936

            
94
936
        Ok(keymgr)
95
936
    }
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
102
impl 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
14
    pub fn secondary_stores(&mut self) -> &mut Vec<BoxedKeystore> {
109
14
        self.secondary_stores.get_or_insert(Default::default())
110
14
    }
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

            
133
inventory::collect!(&'static dyn crate::KeyPathInfoExtractor);
134

            
135
impl 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
1306
    pub fn get<K: ToEncodableKey>(&self, key_spec: &dyn KeySpecifier) -> Result<Option<K>> {
143
1306
        let result = self.get_from_store(key_spec, &K::Key::item_type(), self.all_stores())?;
144
1306
        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
330
            if let Some(key_pair_spec) = key_spec.keypair_specifier() {
148
80
                return Ok(self.get::<K::KeyPair>(&*key_pair_spec)?.map(|k| k.into()));
149
250
            }
150
976
        }
151
1226
        Ok(result)
152
1306
    }
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
8
    pub fn get_entry<K: ToEncodableKey>(&self, entry: &KeystoreEntry) -> Result<Option<K>> {
162
8
        let selector = entry.keystore_id().into();
163
8
        let store = self.select_keystore(&selector)?;
164
8
        self.get_from_store(entry.key_path(), entry.key_type(), [store].into_iter())
165
8
    }
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
148
    pub fn get_or_generate<K>(
179
148
        &self,
180
148
        key_spec: &dyn KeySpecifier,
181
148
        selector: KeystoreSelector,
182
148
        rng: &mut dyn KeygenRng,
183
148
    ) -> Result<K>
184
148
    where
185
148
        K: ToEncodableKey,
186
148
        K::Key: Keygen,
187
148
    {
188
148
        match self.get(key_spec)? {
189
146
            Some(k) => Ok(k),
190
2
            None => self.generate(key_spec, selector, rng, false),
191
        }
192
148
    }
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
212
    pub fn generate<K>(
215
212
        &self,
216
212
        key_spec: &dyn KeySpecifier,
217
212
        selector: KeystoreSelector,
218
212
        rng: &mut dyn KeygenRng,
219
212
        overwrite: bool,
220
212
    ) -> Result<K>
221
212
    where
222
212
        K: ToEncodableKey,
223
212
        K::Key: Keygen,
224
212
    {
225
212
        let store = self.select_keystore(&selector)?;
226

            
227
212
        if overwrite || !store.contains(key_spec, &K::Key::item_type())? {
228
210
            let key = K::Key::generate(rng)?;
229
210
            store.insert(&key, key_spec)?;
230

            
231
210
            Ok(K::from_encodable_key(key))
232
        } else {
233
2
            Err(crate::Error::KeyAlreadyExists)
234
        }
235
212
    }
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
66
    pub fn insert<K: ToEncodableKey>(
250
66
        &self,
251
66
        key: K,
252
66
        key_spec: &dyn KeySpecifier,
253
66
        selector: KeystoreSelector,
254
66
        overwrite: bool,
255
66
    ) -> Result<Option<K>> {
256
66
        let key = key.to_encodable_key();
257
66
        let store = self.select_keystore(&selector)?;
258
66
        let key_type = K::Key::item_type();
259
66
        let old_key: Option<K> = self.get_from_store(key_spec, &key_type, [store].into_iter())?;
260

            
261
66
        if old_key.is_some() && !overwrite {
262
2
            Err(crate::Error::KeyAlreadyExists)
263
        } else {
264
64
            let () = store.insert(&key, key_spec)?;
265
64
            Ok(old_key)
266
        }
267
66
    }
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
40
    pub fn remove<K: ToEncodableKey>(
280
40
        &self,
281
40
        key_spec: &dyn KeySpecifier,
282
40
        selector: KeystoreSelector,
283
40
    ) -> Result<Option<K>> {
284
40
        let store = self.select_keystore(&selector)?;
285
38
        let key_type = K::Key::item_type();
286
38
        let old_key: Option<K> = self.get_from_store(key_spec, &key_type, [store].into_iter())?;
287

            
288
38
        store.remove(key_spec, &key_type)?;
289

            
290
38
        Ok(old_key)
291
40
    }
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
644
    pub fn remove_entry(&self, entry: &KeystoreEntry) -> Result<Option<()>> {
305
644
        let selector = entry.keystore_id().into();
306
644
        let store = self.select_keystore(&selector)?;
307

            
308
644
        store.remove(entry.key_path(), entry.key_type())
309
644
    }
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
482
    pub fn list_matching(&self, pat: &KeyPathPattern) -> Result<Vec<KeystoreEntry>> {
315
482
        self.all_stores()
316
499
            .map(|store| -> Result<Vec<_>> {
317
486
                Ok(store
318
486
                    .list()?
319
486
                    .into_iter()
320
3526
                    .filter(|(key_path, _): &(KeyPath, KeystoreItemType)| key_path.matches(pat))
321
3526
                    .map(|(path, key_type)| KeystoreEntry {
322
3524
                        key_path: path.clone(),
323
3524
                        key_type,
324
3524
                        keystore_id: store.id(),
325
3526
                    })
326
486
                    .collect::<Vec<_>>())
327
499
            })
328
482
            .flatten_ok()
329
482
            .collect::<Result<Vec<_>>>()
330
482
    }
331

            
332
    /// Describe the specified key.
333
    ///
334
    /// Returns [`KeyPathError::Unrecognized`] if none of the registered
335
    /// [`KeyPathInfoExtractor`]s is able to parse the specified [`KeyPath`].
336
    ///
337
    /// This function uses the [`KeyPathInfoExtractor`]s registered using
338
    /// [`register_key_info_extractor`](crate::register_key_info_extractor),
339
    /// or by [`DefaultKeySpecifier`](crate::derive_deftly_template_KeySpecifier).
340
    pub fn describe(&self, path: &KeyPath) -> StdResult<KeyPathInfo, KeyPathError> {
341
        for info_extractor in &self.key_info_extractors {
342
            if let Ok(info) = info_extractor.describe(path) {
343
                return Ok(info);
344
            }
345
        }
346

            
347
        Err(KeyPathError::Unrecognized(path.clone()))
348
    }
349

            
350
    /// Attempt to retrieve a key from one of the specified `stores`.
351
    ///
352
    /// Returns the `<K as ToEncodableKey>::Key` representation of the key.
353
    ///
354
    /// See [`KeyMgr::get`] for more details.
355
1434
    fn get_from_store_raw<'a, K: ItemType>(
356
1434
        &self,
357
1434
        key_spec: &dyn KeySpecifier,
358
1434
        key_type: &KeystoreItemType,
359
1434
        stores: impl Iterator<Item = &'a BoxedKeystore>,
360
1434
    ) -> Result<Option<K>> {
361
1434
        let static_key_type = K::item_type();
362
1434
        if key_type != &static_key_type {
363
            return Err(internal!(
364
                "key type {:?} does not match the key type {:?} of requested key K::Key",
365
                key_type,
366
                static_key_type
367
            )
368
            .into());
369
1434
        }
370

            
371
1906
        for store in stores {
372
1496
            let key = match store.get(key_spec, &K::item_type()) {
373
                Ok(None) => {
374
                    // The key doesn't exist in this store, so we check the next one...
375
472
                    continue;
376
                }
377
1024
                Ok(Some(k)) => k,
378
                Err(e) => {
379
                    // Note: we immediately return if one of the keystores is inaccessible.
380
                    return Err(e);
381
                }
382
            };
383

            
384
            // Found it! Now try to downcast it to the right type (this should _not_ fail)...
385
1024
            let key: K = key
386
1024
                .downcast::<K>()
387
1024
                .map(|k| *k)
388
1024
                .map_err(|_| internal!("failed to downcast key to requested type"))?;
389

            
390
1024
            return Ok(Some(key));
391
        }
392

            
393
410
        Ok(None)
394
1434
    }
395

            
396
    /// Attempt to retrieve a key from one of the specified `stores`.
397
    ///
398
    /// See [`KeyMgr::get`] for more details.
399
1426
    fn get_from_store<'a, K: ToEncodableKey>(
400
1426
        &self,
401
1426
        key_spec: &dyn KeySpecifier,
402
1426
        key_type: &KeystoreItemType,
403
1426
        stores: impl Iterator<Item = &'a BoxedKeystore>,
404
1426
    ) -> Result<Option<K>> {
405
1426
        let Some(key) = self.get_from_store_raw::<K::Key>(key_spec, key_type, stores)? else {
406
402
            return Ok(None);
407
        };
408

            
409
1024
        Ok(Some(K::from_encodable_key(key)))
410
1426
    }
411

            
412
    /// Read the specified key and certificate from one of the key stores,
413
    /// deserializing the subject key as `K::Key`, the cert as `C::Cert`,
414
    /// and the signing key as `C::SigningKey`.
415
    ///
416
    /// Returns `Ok(None)` if none of the key stores have the requested key.
417
    ///
418
    // Note: the behavior of this function is a bit inconsistent with
419
    // get_or_generate_key_and_cert: here, if the cert is absent but
420
    // its subject key is not, we return Ok(None).
421
    // In get_or_generate_key_and_cert, OTOH< we return an error in that case
422
    // (because we can't possibly generate the missing subject key
423
    // without overwriting the cert of the missing key).
424
    ///
425
    /// This function validates the certificate using [`ToEncodableCert::validate`],
426
    /// returning an error if it is invalid or missing.
427
    #[cfg(feature = "experimental-api")]
428
    pub fn get_key_and_cert<K, C>(
429
        &self,
430
        spec: &dyn KeyCertificateSpecifier,
431
    ) -> Result<Option<(K, C)>>
432
    where
433
        K: ToEncodableKey,
434
        C: ToEncodableCert<K>,
435
    {
436
        let subject_key_spec = spec.subject_key_specifier();
437
        // Get the subject key...
438
        let Some(key) =
439
            self.get_from_store::<K>(subject_key_spec, &K::Key::item_type(), self.all_stores())?
440
        else {
441
            return Ok(None);
442
        };
443

            
444
        let subject_key_arti_path = subject_key_spec
445
            .arti_path()
446
            .map_err(|_| bad_api_usage!("subject key does not have an ArtiPath?!"))?;
447
        let cert_spec =
448
            ArtiPath::from_path_and_denotators(subject_key_arti_path, &spec.cert_denotators())
449
                .map_err(into_bad_api_usage!("invalid certificate specifier"))?;
450

            
451
        let Some(cert) = self.get_from_store_raw::<C::ParsedCert>(
452
            &cert_spec,
453
            &<C::ParsedCert as ItemType>::item_type(),
454
            self.all_stores(),
455
        )?
456
        else {
457
            return Err(KeystoreCorruptionError::MissingCertificate.into());
458
        };
459

            
460
        // Finally, get the signing key and validate the cert
461
        let signed_with = self.get_cert_signing_key::<K, C>(spec)?;
462
        let cert = C::validate(cert, &key, &signed_with)?;
463

            
464
        Ok(Some((key, cert)))
465
    }
466

            
467
    /// Like [`KeyMgr::get_key_and_cert`], except this function also generates the subject key
468
    /// and its corresponding certificate if they don't already exist.
469
    ///
470
    /// If the key certificate is missing, it will be generated
471
    /// from the subject key and signing key using the provided `make_certificate` callback.
472
    ///
473
    /// Generates the missing key and/or certificate as follows:
474
    ///
475
    /// ```text
476
    /// | Subject Key exists | Signing Key exists | Cert exists | Action                                 |
477
    /// |--------------------|--------------------|-------------|----------------------------------------|
478
    /// | Y                  | Y                  | Y           | Validate cert, return key and cert     |
479
    /// |                    |                    |             | if valid, error otherwise              |
480
    /// |--------------------|--------------------|-------------|----------------------------------------|
481
    /// | N                  | Y                  | N           | Generate subject key and               |
482
    /// |                    |                    |             | a new cert signed with signing key     |
483
    /// |--------------------|--------------------|-------------|----------------------------------------|
484
    /// | Y                  | Y                  | N           | Generate cert signed with signing key  |
485
    /// |--------------------|--------------------|-------------|----------------------------------------|
486
    /// | Y                  | N                  | N           | Error - cannot validate cert           |
487
    /// |                    |                    |             | if signing key is not available        |
488
    /// |--------------------|--------------------|-------------|----------------------------------------|
489
    /// | Y/N                | N                  | N           | Error - cannot generate cert           |
490
    /// |                    |                    |             | if signing key is not available        |
491
    /// |--------------------|--------------------|-------------|----------------------------------------|
492
    /// | N                  | Y/N                | Y           | Error - subject key was removed?       |
493
    /// |                    |                    |             | (we found the cert,                    |
494
    /// |                    |                    |             | but the subject key is missing)        |
495
    /// ```
496
    ///
497
    //
498
    // Note; the table above isn't a markdown table because CommonMark-flavor markdown
499
    // doesn't support multiline text in tables. Even if we trim down the text,
500
    // the resulting markdown table would be pretty unreadable in raw form
501
    // (it would have several excessively long lines, over 120 chars in len).
502
    #[cfg(feature = "experimental-api")]
503
8
    pub fn get_or_generate_key_and_cert<K, C>(
504
8
        &self,
505
8
        spec: &dyn KeyCertificateSpecifier,
506
8
        make_certificate: impl FnOnce(&K, &<C as ToEncodableCert<K>>::SigningKey) -> C,
507
8
        selector: KeystoreSelector,
508
8
        rng: &mut dyn KeygenRng,
509
8
    ) -> Result<(K, C)>
510
8
    where
511
8
        K: ToEncodableKey,
512
8
        K::Key: Keygen,
513
8
        C: ToEncodableCert<K>,
514
8
    {
515
8
        let subject_key_spec = spec.subject_key_specifier();
516
8
        let subject_key_arti_path = subject_key_spec
517
8
            .arti_path()
518
8
            .map_err(|_| bad_api_usage!("subject key does not have an ArtiPath?!"))?;
519

            
520
8
        let cert_specifier =
521
8
            ArtiPath::from_path_and_denotators(subject_key_arti_path, &spec.cert_denotators())
522
8
                .map_err(into_bad_api_usage!("invalid certificate specifier"))?;
523

            
524
8
        let maybe_cert = self.get_from_store_raw::<C::ParsedCert>(
525
8
            &cert_specifier,
526
8
            &C::ParsedCert::item_type(),
527
8
            self.all_stores(),
528
8
        )?;
529

            
530
8
        let maybe_subject_key = self.get::<K>(subject_key_spec)?;
531

            
532
8
        match (&maybe_cert, &maybe_subject_key) {
533
            (Some(_), None) => {
534
                return Err(KeystoreCorruptionError::MissingSubjectKey.into());
535
            }
536
8
            _ => {
537
8
                // generate key and/or cert
538
8
            }
539
        }
540
8
        let subject_key = match maybe_subject_key {
541
4
            Some(key) => key,
542
4
            _ => self.generate(subject_key_spec, selector, rng, false)?,
543
        };
544

            
545
8
        let signed_with = self.get_cert_signing_key::<K, C>(spec)?;
546
4
        let cert = match maybe_cert {
547
            Some(cert) => C::validate(cert, &subject_key, &signed_with)?,
548
            None => {
549
4
                let cert = make_certificate(&subject_key, &signed_with);
550
4

            
551
4
                let () = self.insert_cert(cert.clone(), &cert_specifier, selector)?;
552

            
553
4
                cert
554
            }
555
        };
556

            
557
4
        Ok((subject_key, cert))
558
8
    }
559

            
560
    /// Return an iterator over all configured stores.
561
22156
    fn all_stores(&self) -> impl Iterator<Item = &BoxedKeystore> {
562
22156
        iter::once(&self.primary_store).chain(self.secondary_stores.iter())
563
22156
    }
564

            
565
    /// Return the [`Keystore`](crate::Keystore) matching the specified `selector`.
566
    ///
567
    /// Returns an error if the selected keystore is not the primary keystore or one of the
568
    /// configured secondary stores.
569
2942
    fn select_keystore(&self, selector: &KeystoreSelector) -> Result<&BoxedKeystore> {
570
2942
        match selector {
571
680
            KeystoreSelector::Id(keystore_id) => self.find_keystore(keystore_id),
572
2262
            KeystoreSelector::Primary => Ok(&self.primary_store),
573
        }
574
2942
    }
575

            
576
    /// Return the [`Keystore`](crate::Keystore) with the specified `id`.
577
    ///
578
    /// Returns an error if the specified ID is not the ID of the primary keystore or
579
    /// the ID of one of the configured secondary stores.
580
680
    fn find_keystore(&self, id: &KeystoreId) -> Result<&BoxedKeystore> {
581
680
        self.all_stores()
582
768
            .find(|keystore| keystore.id() == id)
583
681
            .ok_or_else(|| bad_api_usage!("could not find keystore with ID {id}").into())
584
680
    }
585

            
586
    /// Get the signing key of the certificate described by `spec`.
587
    ///
588
    /// Returns a [`KeystoreCorruptionError::MissingSigningKey`] error
589
    /// if the signing key doesn't exist in any of the keystores.
590
    #[cfg(feature = "experimental-api")]
591
8
    fn get_cert_signing_key<K, C>(
592
8
        &self,
593
8
        spec: &dyn KeyCertificateSpecifier,
594
8
    ) -> Result<C::SigningKey>
595
8
    where
596
8
        K: ToEncodableKey,
597
8
        C: ToEncodableCert<K>,
598
8
    {
599
8
        let Some(signing_key_spec) = spec.signing_key_specifier() else {
600
            return Err(bad_api_usage!(
601
                "signing key specifier is None, but external signing key was not provided?"
602
            )
603
            .into());
604
        };
605

            
606
8
        let Some(signing_key) = self.get_from_store::<C::SigningKey>(
607
8
            signing_key_spec,
608
8
            &<C::SigningKey as ToEncodableKey>::Key::item_type(),
609
8
            self.all_stores(),
610
8
        )?
611
        else {
612
4
            return Err(KeystoreCorruptionError::MissingSigningKey.into());
613
        };
614

            
615
4
        Ok(signing_key)
616
8
    }
617

            
618
    /// Insert `cert` into the [`Keystore`](crate::Keystore) specified by `selector`.
619
    ///
620
    /// If the key already exists in the specified key store, it will be overwritten.
621
    ///
622
    // NOTE: if we ever make this public we should rethink/improve its API.
623
    // TODO: maybe fold this into insert() somehow?
624
4
    fn insert_cert<K, C>(
625
4
        &self,
626
4
        cert: C,
627
4
        cert_spec: &dyn KeySpecifier,
628
4
        selector: KeystoreSelector,
629
4
    ) -> Result<()>
630
4
    where
631
4
        K: ToEncodableKey,
632
4
        K::Key: Keygen,
633
4
        C: ToEncodableCert<K>,
634
4
    {
635
4
        let cert = cert.to_encodable_cert();
636
4
        let store = self.select_keystore(&selector)?;
637

            
638
4
        let () = store.insert(&cert, cert_spec)?;
639
4
        Ok(())
640
4
    }
641
}
642

            
643
#[cfg(test)]
644
mod tests {
645
    // @@ begin test lint list maintained by maint/add_warning @@
646
    #![allow(clippy::bool_assert_comparison)]
647
    #![allow(clippy::clone_on_copy)]
648
    #![allow(clippy::dbg_macro)]
649
    #![allow(clippy::mixed_attributes_style)]
650
    #![allow(clippy::print_stderr)]
651
    #![allow(clippy::print_stdout)]
652
    #![allow(clippy::single_char_pattern)]
653
    #![allow(clippy::unwrap_used)]
654
    #![allow(clippy::unchecked_duration_subtraction)]
655
    #![allow(clippy::useless_vec)]
656
    #![allow(clippy::needless_pass_by_value)]
657
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
658
    use super::*;
659
    use crate::{ArtiPath, ArtiPathUnavailableError, KeyPath};
660
    use std::collections::HashMap;
661
    use std::result::Result as StdResult;
662
    use std::str::FromStr;
663
    use std::sync::RwLock;
664
    use std::time::{Duration, SystemTime};
665
    use tor_basic_utils::test_rng::testing_rng;
666
    use tor_cert::CertifiedKey;
667
    use tor_cert::Ed25519Cert;
668
    use tor_key_forge::{
669
        CertData, EncodableItem, ErasedKey, InvalidCertError, KeyType, KeystoreItem,
670
    };
671
    use tor_llcrypto::pk::ed25519::{self, Ed25519PublicKey as _};
672
    use tor_llcrypto::rng::FakeEntropicRng;
673

            
674
    /// Metadata structure for tracking key operations in tests.
675
    #[derive(Clone, Debug, PartialEq)]
676
    struct KeyMetadata {
677
        /// The identifier for the item (e.g., "coot", "moorhen").
678
        item_id: String,
679
        /// The keystore from which the item was retrieved.
680
        ///
681
        /// Set by `Keystore::get`.
682
        retrieved_from: Option<KeystoreId>,
683
        /// Whether the item was generated via `Keygen::generate`.
684
        is_generated: bool,
685
    }
686

            
687
    /// Metadata structure for tracking certificate operations in tests.
688
    #[derive(Clone, Debug, PartialEq)]
689
    struct CertMetadata {
690
        /// The identifier for the subject key (e.g., "coot").
691
        subject_key_id: String,
692
        /// The identifier for the signing key (e.g., "moorhen").
693
        signing_key_id: String,
694
        /// The keystore from which the certificate was retrieved.
695
        ///
696
        /// Set by `Keystore::get`.
697
        retrieved_from: Option<KeystoreId>,
698
        /// Whether the certificate was freshly generated (i.e. returned from the "or generate"
699
        /// branch of `get_or_generate()`) or retrieved from a keystore.
700
        is_generated: bool,
701
    }
702

            
703
    /// Metadata structure for tracking item operations in tests.
704
    #[derive(Clone, Debug, PartialEq, derive_more::From)]
705
    enum ItemMetadata {
706
        /// Metadata about a key.
707
        Key(KeyMetadata),
708
        /// Metadata about a certificate.
709
        Cert(CertMetadata),
710
    }
711

            
712
    impl ItemMetadata {
713
        /// Get the item ID.
714
        ///
715
        /// For keys, this returns the key's ID.
716
        /// For certificates, this returns a formatted string identifying the subject key.
717
        fn item_id(&self) -> &str {
718
            match self {
719
                ItemMetadata::Key(k) => &k.item_id,
720
                ItemMetadata::Cert(c) => &c.subject_key_id,
721
            }
722
        }
723

            
724
        /// Get retrieved_from.
725
        fn retrieved_from(&self) -> Option<&KeystoreId> {
726
            match self {
727
                ItemMetadata::Key(k) => k.retrieved_from.as_ref(),
728
                ItemMetadata::Cert(c) => c.retrieved_from.as_ref(),
729
            }
730
        }
731

            
732
        /// Get is_generated.
733
        fn is_generated(&self) -> bool {
734
            match self {
735
                ItemMetadata::Key(k) => k.is_generated,
736
                ItemMetadata::Cert(c) => c.is_generated,
737
            }
738
        }
739

            
740
        /// Set the retrieved_from field to the specified keystore ID.
741
        fn set_retrieved_from(&mut self, id: KeystoreId) {
742
            match self {
743
                ItemMetadata::Key(meta) => meta.retrieved_from = Some(id),
744
                ItemMetadata::Cert(meta) => meta.retrieved_from = Some(id),
745
            }
746
        }
747

            
748
        /// Returns a reference to key metadata if this is a Key variant.
749
        fn as_key(&self) -> Option<&KeyMetadata> {
750
            match self {
751
                ItemMetadata::Key(meta) => Some(meta),
752
                _ => None,
753
            }
754
        }
755

            
756
        /// Returns a reference to certificate metadata if this is a Cert variant.
757
        fn as_cert(&self) -> Option<&CertMetadata> {
758
            match self {
759
                ItemMetadata::Cert(meta) => Some(meta),
760
                _ => None,
761
            }
762
        }
763
    }
764

            
765
    /// The type of "key" stored in the test key stores.
766
    #[derive(Clone, Debug)]
767
    struct TestItem {
768
        /// The underlying key.
769
        item: KeystoreItem,
770
        /// Metadata about the key.
771
        meta: ItemMetadata,
772
    }
773

            
774
    /// A "certificate" used for testing purposes.
775
    #[derive(Clone, Debug)]
776
    struct AlwaysValidCert(TestItem);
777

            
778
    /// The corresponding fake public key type.
779
    #[derive(Clone, Debug)]
780
    struct TestPublicKey {
781
        /// The underlying key.
782
        key: KeystoreItem,
783
    }
784

            
785
    impl From<TestItem> for TestPublicKey {
786
        fn from(tk: TestItem) -> TestPublicKey {
787
            TestPublicKey { key: tk.item }
788
        }
789
    }
790

            
791
    impl TestItem {
792
        /// Create a new test key with the specified metadata.
793
        fn new(item_id: &str) -> Self {
794
            let mut rng = testing_rng();
795
            TestItem {
796
                item: ed25519::Keypair::generate(&mut rng)
797
                    .as_keystore_item()
798
                    .unwrap(),
799
                meta: ItemMetadata::Key(KeyMetadata {
800
                    item_id: item_id.to_string(),
801
                    retrieved_from: None,
802
                    is_generated: false,
803
                }),
804
            }
805
        }
806
    }
807

            
808
    impl Keygen for TestItem {
809
        fn generate(mut rng: &mut dyn KeygenRng) -> tor_key_forge::Result<Self>
810
        where
811
            Self: Sized,
812
        {
813
            Ok(TestItem {
814
                item: ed25519::Keypair::generate(&mut rng).as_keystore_item()?,
815
                meta: ItemMetadata::Key(KeyMetadata {
816
                    item_id: "generated_test_key".to_string(),
817
                    retrieved_from: None,
818
                    is_generated: true,
819
                }),
820
            })
821
        }
822
    }
823

            
824
    impl ItemType for TestItem {
825
        fn item_type() -> KeystoreItemType
826
        where
827
            Self: Sized,
828
        {
829
            // Dummy value
830
            KeyType::Ed25519Keypair.into()
831
        }
832
    }
833

            
834
    impl EncodableItem for TestItem {
835
        fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
836
            Ok(self.item.clone())
837
        }
838
    }
839

            
840
    impl ToEncodableKey for TestItem {
841
        type Key = Self;
842
        type KeyPair = Self;
843

            
844
        fn to_encodable_key(self) -> Self::Key {
845
            self
846
        }
847

            
848
        fn from_encodable_key(key: Self::Key) -> Self {
849
            key
850
        }
851
    }
852

            
853
    impl ItemType for TestPublicKey {
854
        fn item_type() -> KeystoreItemType
855
        where
856
            Self: Sized,
857
        {
858
            KeyType::Ed25519PublicKey.into()
859
        }
860
    }
861

            
862
    impl EncodableItem for TestPublicKey {
863
        fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
864
            Ok(self.key.clone())
865
        }
866
    }
867

            
868
    impl ToEncodableKey for TestPublicKey {
869
        type Key = Self;
870
        type KeyPair = TestItem;
871

            
872
        fn to_encodable_key(self) -> Self::Key {
873
            self
874
        }
875

            
876
        fn from_encodable_key(key: Self::Key) -> Self {
877
            key
878
        }
879
    }
880

            
881
    impl ToEncodableCert<TestItem> for AlwaysValidCert {
882
        type ParsedCert = TestItem;
883
        type EncodableCert = TestItem;
884
        type SigningKey = TestItem;
885

            
886
        fn validate(
887
            cert: Self::ParsedCert,
888
            _subject: &TestItem,
889
            _signed_with: &Self::SigningKey,
890
        ) -> StdResult<Self, InvalidCertError> {
891
            // AlwaysValidCert is always valid
892
            Ok(Self(cert))
893
        }
894

            
895
        /// Convert this cert to a type that implements [`EncodableKey`].
896
        fn to_encodable_cert(self) -> Self::EncodableCert {
897
            self.0
898
        }
899
    }
900

            
901
    macro_rules! impl_keystore {
902
        ($name:tt, $id:expr) => {
903
            struct $name {
904
                inner: RwLock<HashMap<(ArtiPath, KeystoreItemType), TestItem>>,
905
                id: KeystoreId,
906
            }
907

            
908
            impl Default for $name {
909
                fn default() -> Self {
910
                    Self {
911
                        inner: Default::default(),
912
                        id: KeystoreId::from_str($id).unwrap(),
913
                    }
914
                }
915
            }
916

            
917
            #[allow(dead_code)] // this is only dead code for Keystore1
918
            impl $name {
919
                fn new_boxed() -> BoxedKeystore {
920
                    Box::<Self>::default()
921
                }
922
            }
923

            
924
            impl crate::Keystore for $name {
925
                fn contains(
926
                    &self,
927
                    key_spec: &dyn KeySpecifier,
928
                    item_type: &KeystoreItemType,
929
                ) -> Result<bool> {
930
                    Ok(self
931
                        .inner
932
                        .read()
933
                        .unwrap()
934
                        .contains_key(&(key_spec.arti_path().unwrap(), item_type.clone())))
935
                }
936

            
937
                fn id(&self) -> &KeystoreId {
938
                    &self.id
939
                }
940

            
941
                fn get(
942
                    &self,
943
                    key_spec: &dyn KeySpecifier,
944
                    item_type: &KeystoreItemType,
945
                ) -> Result<Option<ErasedKey>> {
946
                    Ok(self
947
                        .inner
948
                        .read()
949
                        .unwrap()
950
                        .get(&(key_spec.arti_path().unwrap(), item_type.clone()))
951
                        .map(|k| {
952
                            let mut k = k.clone();
953
                            k.meta.set_retrieved_from(self.id().clone());
954
                            Box::new(k) as Box<dyn ItemType>
955
                        }))
956
                }
957

            
958
                fn insert(
959
                    &self,
960
                    key: &dyn EncodableItem,
961
                    key_spec: &dyn KeySpecifier,
962
                ) -> Result<()> {
963
                    let key = key.downcast_ref::<TestItem>().unwrap();
964

            
965
                    let item = key.as_keystore_item()?;
966
                    let meta = key.meta.clone();
967

            
968
                    let item_type = item.item_type()?;
969
                    let key = TestItem { item, meta };
970

            
971
                    self.inner
972
                        .write()
973
                        .unwrap()
974
                        .insert((key_spec.arti_path().unwrap(), item_type), key);
975

            
976
                    Ok(())
977
                }
978

            
979
                fn remove(
980
                    &self,
981
                    key_spec: &dyn KeySpecifier,
982
                    item_type: &KeystoreItemType,
983
                ) -> Result<Option<()>> {
984
                    Ok(self
985
                        .inner
986
                        .write()
987
                        .unwrap()
988
                        .remove(&(key_spec.arti_path().unwrap(), item_type.clone()))
989
                        .map(|_| ()))
990
                }
991

            
992
                fn list(&self) -> Result<Vec<(KeyPath, KeystoreItemType)>> {
993
                    Ok(self
994
                        .inner
995
                        .read()
996
                        .unwrap()
997
                        .iter()
998
                        .map(|((arti_path, item_type), _)| {
999
                            (KeyPath::Arti(arti_path.clone()), item_type.clone())
                        })
                        .collect())
                }
            }
        };
    }
    macro_rules! impl_specifier {
        ($name:tt, $id:expr) => {
            struct $name;
            impl KeySpecifier for $name {
                fn arti_path(&self) -> StdResult<ArtiPath, ArtiPathUnavailableError> {
                    Ok(ArtiPath::new($id.into()).map_err(|e| tor_error::internal!("{e}"))?)
                }
                fn ctor_path(&self) -> Option<crate::CTorPath> {
                    None
                }
                fn keypair_specifier(&self) -> Option<Box<dyn KeySpecifier>> {
                    None
                }
            }
        };
    }
    impl_keystore!(Keystore1, "keystore1");
    impl_keystore!(Keystore2, "keystore2");
    impl_keystore!(Keystore3, "keystore3");
    impl_specifier!(TestKeySpecifier1, "spec1");
    impl_specifier!(TestKeySpecifier2, "spec2");
    impl_specifier!(TestKeySpecifier3, "spec3");
    impl_specifier!(TestKeySpecifier4, "spec4");
    impl_specifier!(TestPublicKeySpecifier1, "pub-spec1");
    /// Create a test `KeystoreEntry`.
    fn entry_descriptor(specifier: impl KeySpecifier, keystore_id: &KeystoreId) -> KeystoreEntry {
        KeystoreEntry {
            key_path: specifier.arti_path().unwrap().into(),
            key_type: TestItem::item_type(),
            keystore_id,
        }
    }
    #[test]
    #[allow(clippy::cognitive_complexity)]
    fn insert_and_get() {
        let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
        builder
            .secondary_stores()
            .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
        let mgr = builder.build().unwrap();
        // Insert a key into Keystore2
        let old_key = mgr
            .insert(
                TestItem::new("coot"),
                &TestKeySpecifier1,
                KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
                true,
            )
            .unwrap();
        assert!(old_key.is_none());
        let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
        assert_eq!(key.meta.item_id(), "coot");
        assert_eq!(
            key.meta.retrieved_from(),
            Some(&KeystoreId::from_str("keystore2").unwrap())
        );
        assert_eq!(key.meta.is_generated(), false);
        // Insert a different key using the _same_ key specifier.
        let old_key = mgr
            .insert(
                TestItem::new("gull"),
                &TestKeySpecifier1,
                KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
                true,
            )
            .unwrap()
            .unwrap();
        assert_eq!(old_key.meta.item_id(), "coot");
        assert_eq!(
            old_key.meta.retrieved_from(),
            Some(&KeystoreId::from_str("keystore2").unwrap())
        );
        assert_eq!(old_key.meta.is_generated(), false);
        // Check that the original value was overwritten:
        let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
        assert_eq!(key.meta.item_id(), "gull");
        assert_eq!(
            key.meta.retrieved_from(),
            Some(&KeystoreId::from_str("keystore2").unwrap())
        );
        assert_eq!(key.meta.is_generated(), false);
        // Insert a different key using the _same_ key specifier (overwrite = false)
        let err = mgr
            .insert(
                TestItem::new("gull"),
                &TestKeySpecifier1,
                KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
                false,
            )
            .unwrap_err();
        assert!(matches!(err, crate::Error::KeyAlreadyExists));
        // Insert a new key into Keystore2 (overwrite = false)
        let old_key = mgr
            .insert(
                TestItem::new("penguin"),
                &TestKeySpecifier2,
                KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
                false,
            )
            .unwrap();
        assert!(old_key.is_none());
        // Insert a key into the primary keystore
        let old_key = mgr
            .insert(
                TestItem::new("moorhen"),
                &TestKeySpecifier3,
                KeystoreSelector::Primary,
                true,
            )
            .unwrap();
        assert!(old_key.is_none());
        let key = mgr.get::<TestItem>(&TestKeySpecifier3).unwrap().unwrap();
        assert_eq!(key.meta.item_id(), "moorhen");
        assert_eq!(
            key.meta.retrieved_from(),
            Some(&KeystoreId::from_str("keystore1").unwrap())
        );
        assert_eq!(key.meta.is_generated(), false);
        // The key doesn't exist in any of the stores yet.
        assert!(mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().is_none());
        // Insert the same key into all 3 key stores, in reverse order of keystore priority
        // (otherwise KeyMgr::get will return the key from the primary store for each iteration and
        // we won't be able to see the key was actually inserted in each store).
        for store in ["keystore3", "keystore2", "keystore1"] {
            let old_key = mgr
                .insert(
                    TestItem::new("cormorant"),
                    &TestKeySpecifier4,
                    KeystoreSelector::Id(&KeystoreId::from_str(store).unwrap()),
                    true,
                )
                .unwrap();
            assert!(old_key.is_none());
            // Ensure the key now exists in `store`.
            let key = mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().unwrap();
            assert_eq!(key.meta.item_id(), "cormorant");
            assert_eq!(
                key.meta.retrieved_from(),
                Some(&KeystoreId::from_str(store).unwrap())
            );
            assert_eq!(key.meta.is_generated(), false);
        }
        // The key exists in all key stores, but if no keystore_id is specified, we return the
        // value from the first key store it is found in (in this case, Keystore1)
        let key = mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().unwrap();
        assert_eq!(key.meta.item_id(), "cormorant");
        assert_eq!(
            key.meta.retrieved_from(),
            Some(&KeystoreId::from_str("keystore1").unwrap())
        );
        assert_eq!(key.meta.is_generated(), false);
    }
    #[test]
    fn remove() {
        let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
        builder
            .secondary_stores()
            .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
        let mgr = builder.build().unwrap();
        assert!(!mgr.secondary_stores[0]
            .contains(&TestKeySpecifier1, &TestItem::item_type())
            .unwrap());
        // Insert a key into Keystore2
        mgr.insert(
            TestItem::new("coot"),
            &TestKeySpecifier1,
            KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
            true,
        )
        .unwrap();
        let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
        assert_eq!(key.meta.item_id(), "coot");
        assert_eq!(
            key.meta.retrieved_from(),
            Some(&KeystoreId::from_str("keystore2").unwrap())
        );
        assert_eq!(key.meta.is_generated(), false);
        // Try to remove the key from a non-existent key store
        assert!(mgr
            .remove::<TestItem>(
                &TestKeySpecifier1,
                KeystoreSelector::Id(&KeystoreId::from_str("not_an_id_we_know_of").unwrap())
            )
            .is_err());
        // The key still exists in Keystore2
        assert!(mgr.secondary_stores[0]
            .contains(&TestKeySpecifier1, &TestItem::item_type())
            .unwrap());
        // Try to remove the key from the primary key store
        assert!(mgr
            .remove::<TestItem>(&TestKeySpecifier1, KeystoreSelector::Primary)
            .unwrap()
            .is_none());
        // The key still exists in Keystore2
        assert!(mgr.secondary_stores[0]
            .contains(&TestKeySpecifier1, &TestItem::item_type())
            .unwrap());
        // Removing from Keystore2 should succeed.
        let removed_key = mgr
            .remove::<TestItem>(
                &TestKeySpecifier1,
                KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
            )
            .unwrap()
            .unwrap();
        assert_eq!(removed_key.meta.item_id(), "coot");
        assert_eq!(
            removed_key.meta.retrieved_from(),
            Some(&KeystoreId::from_str("keystore2").unwrap())
        );
        assert_eq!(removed_key.meta.is_generated(), false);
        // The key doesn't exist in Keystore2 anymore
        assert!(!mgr.secondary_stores[0]
            .contains(&TestKeySpecifier1, &TestItem::item_type())
            .unwrap());
    }
    #[test]
    fn keygen() {
        let mut rng = FakeEntropicRng(testing_rng());
        let mgr = KeyMgrBuilder::default()
            .primary_store(Box::<Keystore1>::default())
            .build()
            .unwrap();
        mgr.insert(
            TestItem::new("coot"),
            &TestKeySpecifier1,
            KeystoreSelector::Primary,
            true,
        )
        .unwrap();
        // There is no corresponding public key entry.
        assert!(mgr
            .get::<TestPublicKey>(&TestPublicKeySpecifier1)
            .unwrap()
            .is_none());
        // Try to generate a new key (overwrite = false)
        let err = mgr
            .generate::<TestItem>(
                &TestKeySpecifier1,
                KeystoreSelector::Primary,
                &mut rng,
                false,
            )
            .unwrap_err();
        assert!(matches!(err, crate::Error::KeyAlreadyExists));
        // The previous entry was not overwritten because overwrite = false
        let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
        assert_eq!(key.meta.item_id(), "coot");
        assert_eq!(
            key.meta.retrieved_from(),
            Some(&KeystoreId::from_str("keystore1").unwrap())
        );
        assert_eq!(key.meta.is_generated(), false);
        // We don't store public keys in the keystore
        assert!(mgr
            .get::<TestPublicKey>(&TestPublicKeySpecifier1)
            .unwrap()
            .is_none());
        // Try to generate a new key (overwrite = true)
        let generated_key = mgr
            .generate::<TestItem>(
                &TestKeySpecifier1,
                KeystoreSelector::Primary,
                &mut rng,
                true,
            )
            .unwrap();
        assert_eq!(generated_key.meta.item_id(), "generated_test_key");
        // Not set in a freshly generated key, because KeyMgr::generate()
        // returns it straight away, without going through Keystore::get()
        assert_eq!(generated_key.meta.retrieved_from(), None);
        assert_eq!(generated_key.meta.is_generated(), true);
        // Retrieve the inserted key
        let retrieved_key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
        assert_eq!(retrieved_key.meta.item_id(), "generated_test_key");
        assert_eq!(
            retrieved_key.meta.retrieved_from(),
            Some(&KeystoreId::from_str("keystore1").unwrap())
        );
        assert_eq!(retrieved_key.meta.is_generated(), true);
        // We don't store public keys in the keystore
        assert!(mgr
            .get::<TestPublicKey>(&TestPublicKeySpecifier1)
            .unwrap()
            .is_none());
    }
    #[test]
    fn get_or_generate() {
        let mut rng = FakeEntropicRng(testing_rng());
        let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
        builder
            .secondary_stores()
            .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
        let mgr = builder.build().unwrap();
        let keystore2 = KeystoreId::from_str("keystore2").unwrap();
        let entry_desc1 = entry_descriptor(TestKeySpecifier1, &keystore2);
        assert!(mgr.get_entry::<TestItem>(&entry_desc1).unwrap().is_none());
        mgr.insert(
            TestItem::new("coot"),
            &TestKeySpecifier1,
            KeystoreSelector::Id(&keystore2),
            true,
        )
        .unwrap();
        // The key already exists in keystore 2 so it won't be auto-generated.
        let key = mgr
            .get_or_generate::<TestItem>(&TestKeySpecifier1, KeystoreSelector::Primary, &mut rng)
            .unwrap();
        assert_eq!(key.meta.item_id(), "coot");
        assert_eq!(
            key.meta.retrieved_from(),
            Some(&KeystoreId::from_str("keystore2").unwrap())
        );
        assert_eq!(key.meta.is_generated(), false);
        assert_eq!(
            mgr.get_entry::<TestItem>(&entry_desc1)
                .unwrap()
                .map(|k| k.meta),
            Some(ItemMetadata::Key(KeyMetadata {
                item_id: "coot".to_string(),
                retrieved_from: Some(keystore2.clone()),
                is_generated: false,
            }))
        );
        // This key doesn't exist in any of the keystores, so it will be auto-generated and
        // inserted into keystore 3.
        let keystore3 = KeystoreId::from_str("keystore3").unwrap();
        let generated_key = mgr
            .get_or_generate::<TestItem>(
                &TestKeySpecifier2,
                KeystoreSelector::Id(&keystore3),
                &mut rng,
            )
            .unwrap();
        assert_eq!(generated_key.meta.item_id(), "generated_test_key");
        // Not set in a freshly generated key, because KeyMgr::get_or_generate()
        // returns it straight away, without going through Keystore::get()
        assert_eq!(generated_key.meta.retrieved_from(), None);
        assert_eq!(generated_key.meta.is_generated(), true);
        // Retrieve the inserted key
        let retrieved_key = mgr.get::<TestItem>(&TestKeySpecifier2).unwrap().unwrap();
        assert_eq!(retrieved_key.meta.item_id(), "generated_test_key");
        assert_eq!(
            retrieved_key.meta.retrieved_from(),
            Some(&KeystoreId::from_str("keystore3").unwrap())
        );
        assert_eq!(retrieved_key.meta.is_generated(), true);
        let entry_desc2 = entry_descriptor(TestKeySpecifier2, &keystore3);
        assert_eq!(
            mgr.get_entry::<TestItem>(&entry_desc2)
                .unwrap()
                .map(|k| k.meta),
            Some(ItemMetadata::Key(KeyMetadata {
                item_id: "generated_test_key".to_string(),
                retrieved_from: Some(keystore3.clone()),
                is_generated: true,
            }))
        );
        let arti_pat = KeyPathPattern::Arti("*".to_string());
        let matching = mgr.list_matching(&arti_pat).unwrap();
        assert_eq!(matching.len(), 2);
        assert!(matching.contains(&entry_desc1));
        assert!(matching.contains(&entry_desc2));
        assert_eq!(mgr.remove_entry(&entry_desc2).unwrap(), Some(()));
        assert!(mgr.get_entry::<TestItem>(&entry_desc2).unwrap().is_none());
        assert!(mgr.remove_entry(&entry_desc2).unwrap().is_none());
    }
    /// Whether to generate a given item before running the `run_certificate_test`.
    #[cfg(feature = "experimental-api")]
    #[derive(Clone, Copy, Debug, PartialEq)]
    enum GenerateItem {
        Yes,
        No,
    }
    #[cfg(feature = "experimental-api")]
    macro_rules! run_certificate_test {
        (
            generate_subject_key = $generate_subject_key:expr,
            generate_signing_key = $generate_signing_key:expr,
            $($expected_err:tt)?
        ) => {{
            use GenerateItem::*;
            let mut rng = FakeEntropicRng(testing_rng());
            let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
            builder
                .secondary_stores()
                .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
            let mgr = builder.build().unwrap();
            let spec = crate::test_utils::TestCertSpecifier {
                subject_key_spec: TestKeySpecifier1,
                signing_key_spec: TestKeySpecifier2,
                denotator: vec!["foo".into()],
            };
            if $generate_subject_key == Yes {
                let _ = mgr
                    .generate::<TestItem>(
                        &TestKeySpecifier1,
                        KeystoreSelector::Primary,
                        &mut rng,
                        false,
                    )
                    .unwrap();
            }
            if $generate_signing_key == Yes {
                let _ = mgr
                    .generate::<TestItem>(
                        &TestKeySpecifier2,
                        KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
                        &mut rng,
                        false,
                    )
                    .unwrap();
            }
            let make_certificate = move |subject_key: &TestItem, signed_with: &TestItem| {
                let subject_id = subject_key.meta.as_key().unwrap().item_id.clone();
                let signing_id = signed_with.meta.as_key().unwrap().item_id.clone();
                let meta = ItemMetadata::Cert(CertMetadata {
                    subject_key_id: subject_id,
                    signing_key_id: signing_id,
                    retrieved_from: None,
                    is_generated: true,
                });
                // Note: this is not really a cert for `subject_key` signed with the `signed_with`
                // key!. The two are `TestItem`s and not keys, so we can't really generate a real
                // cert from them. We can, however, pretend we did, for testing purposes.
                // Eventually we might want to rewrite these tests to use real items
                // (like the `ArtiNativeKeystore` tests)
                let mut rng = FakeEntropicRng(testing_rng());
                let keypair = ed25519::Keypair::generate(&mut rng);
                let encoded_cert = Ed25519Cert::constructor()
                    .cert_type(tor_cert::CertType::IDENTITY_V_SIGNING)
                    .expiration(SystemTime::now() + Duration::from_secs(180))
                    .signing_key(keypair.public_key().into())
                    .cert_key(CertifiedKey::Ed25519(keypair.public_key().into()))
                    .encode_and_sign(&keypair)
                    .unwrap();
                let test_cert = CertData::TorEd25519Cert(encoded_cert);
                AlwaysValidCert(TestItem {
                    item: KeystoreItem::Cert(test_cert),
                    meta,
                })
            };
            let res = mgr
                .get_or_generate_key_and_cert::<TestItem, AlwaysValidCert>(
                    &spec,
                    &make_certificate,
                    KeystoreSelector::Primary,
                    &mut rng,
                );
            #[allow(unused_assignments)]
            #[allow(unused_mut)]
            let mut has_error = false;
            $(
                has_error = true;
                let err = res.clone().unwrap_err();
                assert!(
                    matches!(
                        err,
                        crate::Error::Corruption(KeystoreCorruptionError::$expected_err)
                    ),
                    "unexpected error: {err:?}",
                );
            )?
            if !has_error {
                let (key, cert) = res.unwrap();
                let expected_subj_key_id = if $generate_subject_key == Yes {
                    "generated_test_key"
                } else {
                    "generated_test_key"
                };
                assert_eq!(key.meta.item_id(), expected_subj_key_id);
                assert_eq!(
                    cert.0.meta.as_cert().unwrap().subject_key_id,
                    expected_subj_key_id
                );
                assert_eq!(
                    cert.0.meta.as_cert().unwrap().signing_key_id,
                    "generated_test_key"
                );
                assert_eq!(cert.0.meta.is_generated(), true);
            }
        }}
    }
    #[test]
    #[cfg(feature = "experimental-api")]
    #[rustfmt::skip] // preserve the layout for readability
    #[allow(clippy::cognitive_complexity)] // clippy seems confused here...
    fn get_certificate() {
        run_certificate_test!(
            generate_subject_key = No,
            generate_signing_key = No,
            MissingSigningKey
        );
        run_certificate_test!(
            generate_subject_key = Yes,
            generate_signing_key = No,
            MissingSigningKey
        );
        run_certificate_test!(
            generate_subject_key = No,
            generate_signing_key = Yes,
        );
        run_certificate_test!(
            generate_subject_key = Yes,
            generate_signing_key = Yes,
        );
    }
}