1use crate::raw::{RawEntryId, RawKeystoreEntry};
6use crate::{
7 ArtiPath, BoxedKeystore, KeyCertificateSpecifier, KeyPath, KeyPathError, KeyPathInfo,
8 KeyPathInfoExtractor, KeyPathPattern, KeySpecifier, KeystoreCorruptionError,
9 KeystoreEntryResult, KeystoreId, KeystoreSelector, Result,
10};
11
12use itertools::Itertools;
13use std::iter;
14use std::result::Result as StdResult;
15use tor_error::{bad_api_usage, internal, into_bad_api_usage};
16use tor_key_forge::{
17 ItemType, Keygen, KeygenRng, KeystoreItemType, ToEncodableCert, ToEncodableKey,
18};
19
20#[derive(derive_builder::Builder)]
44#[builder(pattern = "owned", build_fn(private, name = "build_unvalidated"))]
45pub struct KeyMgr {
46 primary_store: BoxedKeystore,
48 #[builder(default, setter(custom))]
50 secondary_stores: Vec<BoxedKeystore>,
51 #[builder(default, setter(skip))]
56 key_info_extractors: Vec<&'static dyn KeyPathInfoExtractor>,
57}
58
59#[derive(Clone, Debug, PartialEq, amplify::Getters)]
67pub struct KeystoreEntry<'a> {
68 key_path: KeyPath,
70 key_type: KeystoreItemType,
72 #[getter(as_copy)]
74 keystore_id: &'a KeystoreId,
75 #[getter(skip)]
78 raw_id: RawEntryId,
79}
80
81impl<'a> KeystoreEntry<'a> {
82 pub(crate) fn new(
84 key_path: KeyPath,
85 key_type: KeystoreItemType,
86 keystore_id: &'a KeystoreId,
87 raw_id: RawEntryId,
88 ) -> Self {
89 Self {
90 key_path,
91 key_type,
92 keystore_id,
93 raw_id,
94 }
95 }
96
97 #[cfg(feature = "onion-service-cli-extra")]
99 #[cfg_attr(docsrs, doc(cfg(feature = "onion-service-cli-extra")))]
100 pub fn raw_entry(&self) -> RawKeystoreEntry {
101 RawKeystoreEntry::new(self.raw_id.clone(), self.keystore_id.clone())
102 }
103}
104
105impl<'a> From<KeystoreEntry<'a>> for KeystoreEntryResult<KeystoreEntry<'a>> {
110 fn from(val: KeystoreEntry<'a>) -> Self {
111 Ok(val)
112 }
113}
114
115impl KeyMgrBuilder {
116 pub fn build(self) -> StdResult<KeyMgr, KeyMgrBuilderError> {
118 use itertools::Itertools as _;
119
120 let mut keymgr = self.build_unvalidated()?;
121
122 if !keymgr.all_stores().map(|s| s.id()).all_unique() {
123 return Err(KeyMgrBuilderError::ValidationError(
124 "the keystore IDs are not pairwise unique".into(),
125 ));
126 }
127
128 keymgr.key_info_extractors = inventory::iter::<&'static dyn KeyPathInfoExtractor>
129 .into_iter()
130 .copied()
131 .collect();
132
133 Ok(keymgr)
134 }
135}
136
137impl KeyMgrBuilder {
142 pub fn secondary_stores(&mut self) -> &mut Vec<BoxedKeystore> {
148 self.secondary_stores.get_or_insert(Default::default())
149 }
150
151 pub fn set_secondary_stores(mut self, list: Vec<BoxedKeystore>) -> Self {
153 self.secondary_stores = Some(list);
154 self
155 }
156
157 pub fn opt_secondary_stores(&self) -> &Option<Vec<BoxedKeystore>> {
161 &self.secondary_stores
162 }
163
164 pub fn opt_secondary_stores_mut(&mut self) -> &mut Option<Vec<BoxedKeystore>> {
168 &mut self.secondary_stores
169 }
170}
171
172inventory::collect!(&'static dyn crate::KeyPathInfoExtractor);
173
174impl KeyMgr {
175 pub fn get<K: ToEncodableKey>(&self, key_spec: &dyn KeySpecifier) -> Result<Option<K>> {
182 let result = self.get_from_store(key_spec, &K::Key::item_type(), self.all_stores())?;
183 if result.is_none() {
184 if let Some(key_pair_spec) = key_spec.keypair_specifier() {
187 return Ok(self.get::<K::KeyPair>(&*key_pair_spec)?.map(|k| k.into()));
188 }
189 }
190 Ok(result)
191 }
192
193 pub fn get_entry<K: ToEncodableKey>(&self, entry: &KeystoreEntry) -> Result<Option<K>> {
201 let selector = entry.keystore_id().into();
202 let store = self.select_keystore(&selector)?;
203 self.get_from_store(entry.key_path(), entry.key_type(), [store].into_iter())
204 }
205
206 pub fn get_or_generate<K>(
218 &self,
219 key_spec: &dyn KeySpecifier,
220 selector: KeystoreSelector,
221 rng: &mut dyn KeygenRng,
222 ) -> Result<K>
223 where
224 K: ToEncodableKey,
225 K::Key: Keygen,
226 {
227 match self.get(key_spec)? {
228 Some(k) => Ok(k),
229 None => self.generate(key_spec, selector, rng, false),
230 }
231 }
232
233 pub fn generate<K>(
254 &self,
255 key_spec: &dyn KeySpecifier,
256 selector: KeystoreSelector,
257 rng: &mut dyn KeygenRng,
258 overwrite: bool,
259 ) -> Result<K>
260 where
261 K: ToEncodableKey,
262 K::Key: Keygen,
263 {
264 let store = self.select_keystore(&selector)?;
265
266 if overwrite || !store.contains(key_spec, &K::Key::item_type())? {
267 let key = K::Key::generate(rng)?;
268 store.insert(&key, key_spec)?;
269
270 Ok(K::from_encodable_key(key))
271 } else {
272 Err(crate::Error::KeyAlreadyExists)
273 }
274 }
275
276 pub fn insert<K: ToEncodableKey>(
289 &self,
290 key: K,
291 key_spec: &dyn KeySpecifier,
292 selector: KeystoreSelector,
293 overwrite: bool,
294 ) -> Result<Option<K>> {
295 let key = key.to_encodable_key();
296 let store = self.select_keystore(&selector)?;
297 let key_type = K::Key::item_type();
298 let old_key: Option<K> = self.get_from_store(key_spec, &key_type, [store].into_iter())?;
299
300 if old_key.is_some() && !overwrite {
301 Err(crate::Error::KeyAlreadyExists)
302 } else {
303 let () = store.insert(&key, key_spec)?;
304 Ok(old_key)
305 }
306 }
307
308 pub fn remove<K: ToEncodableKey>(
319 &self,
320 key_spec: &dyn KeySpecifier,
321 selector: KeystoreSelector,
322 ) -> Result<Option<K>> {
323 let store = self.select_keystore(&selector)?;
324 let key_type = K::Key::item_type();
325 let old_key: Option<K> = self.get_from_store(key_spec, &key_type, [store].into_iter())?;
326
327 store.remove(key_spec, &key_type)?;
328
329 Ok(old_key)
330 }
331
332 pub fn remove_entry(&self, entry: &KeystoreEntry) -> Result<Option<()>> {
344 let selector = entry.keystore_id().into();
345 let store = self.select_keystore(&selector)?;
346
347 store.remove(entry.key_path(), entry.key_type())
348 }
349
350 #[cfg(feature = "onion-service-cli-extra")]
358 pub fn remove_unchecked(&self, raw_id: &str, keystore_id: &KeystoreId) -> Result<()> {
359 let selector = KeystoreSelector::from(keystore_id);
360 let store = self.select_keystore(&selector)?;
361 let raw_id = store.raw_entry_id(raw_id)?;
362 let store = self.select_keystore(&selector)?;
363 store.remove_unchecked(&raw_id)
364 }
365
366 pub fn list_matching(&self, pat: &KeyPathPattern) -> Result<Vec<KeystoreEntry>> {
374 self.all_stores()
375 .map(|store| -> Result<Vec<_>> {
376 Ok(store
377 .list()?
378 .into_iter()
379 .filter_map(|entry| entry.ok())
380 .filter(|entry| entry.key_path().matches(pat))
381 .collect::<Vec<_>>())
382 })
383 .flatten_ok()
384 .collect::<Result<Vec<_>>>()
385 }
386
387 #[cfg(feature = "onion-service-cli-extra")]
389 pub fn list_by_id(&self, id: &KeystoreId) -> Result<Vec<KeystoreEntryResult<KeystoreEntry>>> {
390 self.find_keystore(id)?.list()
391 }
392
393 #[cfg(feature = "onion-service-cli-extra")]
395 pub fn list(&self) -> Result<Vec<KeystoreEntryResult<KeystoreEntry>>> {
396 self.all_stores()
397 .map(|store| -> Result<Vec<_>> { store.list() })
398 .flatten_ok()
399 .collect::<Result<Vec<_>>>()
400 }
401
402 #[cfg(feature = "onion-service-cli-extra")]
404 pub fn list_keystores(&self) -> Vec<KeystoreId> {
405 self.all_stores()
406 .map(|store| store.id().to_owned())
407 .collect()
408 }
409
410 pub fn describe(&self, path: &KeyPath) -> StdResult<KeyPathInfo, KeyPathError> {
419 for info_extractor in &self.key_info_extractors {
420 if let Ok(info) = info_extractor.describe(path) {
421 return Ok(info);
422 }
423 }
424
425 Err(KeyPathError::Unrecognized(path.clone()))
426 }
427
428 fn get_from_store_raw<'a, K: ItemType>(
434 &self,
435 key_spec: &dyn KeySpecifier,
436 key_type: &KeystoreItemType,
437 stores: impl Iterator<Item = &'a BoxedKeystore>,
438 ) -> Result<Option<K>> {
439 let static_key_type = K::item_type();
440 if key_type != &static_key_type {
441 return Err(internal!(
442 "key type {:?} does not match the key type {:?} of requested key K::Key",
443 key_type,
444 static_key_type
445 )
446 .into());
447 }
448
449 for store in stores {
450 let key = match store.get(key_spec, &K::item_type()) {
451 Ok(None) => {
452 continue;
454 }
455 Ok(Some(k)) => k,
456 Err(e) => {
457 return Err(e);
459 }
460 };
461
462 let key: K = key
464 .downcast::<K>()
465 .map(|k| *k)
466 .map_err(|_| internal!("failed to downcast key to requested type"))?;
467
468 return Ok(Some(key));
469 }
470
471 Ok(None)
472 }
473
474 fn get_from_store<'a, K: ToEncodableKey>(
478 &self,
479 key_spec: &dyn KeySpecifier,
480 key_type: &KeystoreItemType,
481 stores: impl Iterator<Item = &'a BoxedKeystore>,
482 ) -> Result<Option<K>> {
483 let Some(key) = self.get_from_store_raw::<K::Key>(key_spec, key_type, stores)? else {
484 return Ok(None);
485 };
486
487 Ok(Some(K::from_encodable_key(key)))
488 }
489
490 #[cfg(feature = "experimental-api")]
506 pub fn get_key_and_cert<K, C>(
507 &self,
508 spec: &dyn KeyCertificateSpecifier,
509 ) -> Result<Option<(K, C)>>
510 where
511 K: ToEncodableKey,
512 C: ToEncodableCert<K>,
513 {
514 let subject_key_spec = spec.subject_key_specifier();
515 let Some(key) =
517 self.get_from_store::<K>(subject_key_spec, &K::Key::item_type(), self.all_stores())?
518 else {
519 return Ok(None);
520 };
521
522 let subject_key_arti_path = subject_key_spec
523 .arti_path()
524 .map_err(|_| bad_api_usage!("subject key does not have an ArtiPath?!"))?;
525 let cert_spec =
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 Some(cert) = self.get_from_store_raw::<C::ParsedCert>(
530 &cert_spec,
531 &<C::ParsedCert as ItemType>::item_type(),
532 self.all_stores(),
533 )?
534 else {
535 return Err(KeystoreCorruptionError::MissingCertificate.into());
536 };
537
538 let signed_with = self.get_cert_signing_key::<K, C>(spec)?;
540 let cert = C::validate(cert, &key, &signed_with)?;
541
542 Ok(Some((key, cert)))
543 }
544
545 #[cfg(feature = "experimental-api")]
581 pub fn get_or_generate_key_and_cert<K, C>(
582 &self,
583 spec: &dyn KeyCertificateSpecifier,
584 make_certificate: impl FnOnce(&K, &<C as ToEncodableCert<K>>::SigningKey) -> C,
585 selector: KeystoreSelector,
586 rng: &mut dyn KeygenRng,
587 ) -> Result<(K, C)>
588 where
589 K: ToEncodableKey,
590 K::Key: Keygen,
591 C: ToEncodableCert<K>,
592 {
593 let subject_key_spec = spec.subject_key_specifier();
594 let subject_key_arti_path = subject_key_spec
595 .arti_path()
596 .map_err(|_| bad_api_usage!("subject key does not have an ArtiPath?!"))?;
597
598 let cert_specifier =
599 ArtiPath::from_path_and_denotators(subject_key_arti_path, &spec.cert_denotators())
600 .map_err(into_bad_api_usage!("invalid certificate specifier"))?;
601
602 let maybe_cert = self.get_from_store_raw::<C::ParsedCert>(
603 &cert_specifier,
604 &C::ParsedCert::item_type(),
605 self.all_stores(),
606 )?;
607
608 let maybe_subject_key = self.get::<K>(subject_key_spec)?;
609
610 match (&maybe_cert, &maybe_subject_key) {
611 (Some(_), None) => {
612 return Err(KeystoreCorruptionError::MissingSubjectKey.into());
613 }
614 _ => {
615 }
617 }
618 let subject_key = match maybe_subject_key {
619 Some(key) => key,
620 _ => self.generate(subject_key_spec, selector, rng, false)?,
621 };
622
623 let signed_with = self.get_cert_signing_key::<K, C>(spec)?;
624 let cert = match maybe_cert {
625 Some(cert) => C::validate(cert, &subject_key, &signed_with)?,
626 None => {
627 let cert = make_certificate(&subject_key, &signed_with);
628
629 let () = self.insert_cert(cert.clone(), &cert_specifier, selector)?;
630
631 cert
632 }
633 };
634
635 Ok((subject_key, cert))
636 }
637
638 fn all_stores(&self) -> impl Iterator<Item = &BoxedKeystore> {
640 iter::once(&self.primary_store).chain(self.secondary_stores.iter())
641 }
642
643 fn select_keystore(&self, selector: &KeystoreSelector) -> Result<&BoxedKeystore> {
648 match selector {
649 KeystoreSelector::Id(keystore_id) => self.find_keystore(keystore_id),
650 KeystoreSelector::Primary => Ok(&self.primary_store),
651 }
652 }
653
654 fn find_keystore(&self, id: &KeystoreId) -> Result<&BoxedKeystore> {
659 self.all_stores()
660 .find(|keystore| keystore.id() == id)
661 .ok_or_else(|| crate::Error::KeystoreNotFound(id.clone()))
662 }
663
664 #[cfg(feature = "experimental-api")]
669 fn get_cert_signing_key<K, C>(
670 &self,
671 spec: &dyn KeyCertificateSpecifier,
672 ) -> Result<C::SigningKey>
673 where
674 K: ToEncodableKey,
675 C: ToEncodableCert<K>,
676 {
677 let Some(signing_key_spec) = spec.signing_key_specifier() else {
678 return Err(bad_api_usage!(
679 "signing key specifier is None, but external signing key was not provided?"
680 )
681 .into());
682 };
683
684 let Some(signing_key) = self.get_from_store::<C::SigningKey>(
685 signing_key_spec,
686 &<C::SigningKey as ToEncodableKey>::Key::item_type(),
687 self.all_stores(),
688 )?
689 else {
690 return Err(KeystoreCorruptionError::MissingSigningKey.into());
691 };
692
693 Ok(signing_key)
694 }
695
696 fn insert_cert<K, C>(
703 &self,
704 cert: C,
705 cert_spec: &dyn KeySpecifier,
706 selector: KeystoreSelector,
707 ) -> Result<()>
708 where
709 K: ToEncodableKey,
710 K::Key: Keygen,
711 C: ToEncodableCert<K>,
712 {
713 let cert = cert.to_encodable_cert();
714 let store = self.select_keystore(&selector)?;
715
716 let () = store.insert(&cert, cert_spec)?;
717 Ok(())
718 }
719}
720
721#[cfg(test)]
722mod tests {
723 #![allow(clippy::bool_assert_comparison)]
725 #![allow(clippy::clone_on_copy)]
726 #![allow(clippy::dbg_macro)]
727 #![allow(clippy::mixed_attributes_style)]
728 #![allow(clippy::print_stderr)]
729 #![allow(clippy::print_stdout)]
730 #![allow(clippy::single_char_pattern)]
731 #![allow(clippy::unwrap_used)]
732 #![allow(clippy::unchecked_duration_subtraction)]
733 #![allow(clippy::useless_vec)]
734 #![allow(clippy::needless_pass_by_value)]
735 use super::*;
737 use crate::keystore::arti::err::{ArtiNativeKeystoreError, MalformedPathError};
738 use crate::raw::{RawEntryId, RawKeystoreEntry};
739 use crate::{
740 ArtiPath, ArtiPathUnavailableError, Error, KeyPath, KeystoreEntryResult, KeystoreError,
741 UnrecognizedEntryError,
742 };
743 use std::path::PathBuf;
744 use std::result::Result as StdResult;
745 use std::str::FromStr;
746 use std::sync::{Arc, RwLock};
747 use std::time::{Duration, SystemTime};
748 use tor_basic_utils::test_rng::testing_rng;
749 use tor_cert::CertifiedKey;
750 use tor_cert::Ed25519Cert;
751 use tor_error::{ErrorKind, HasKind};
752 use tor_key_forge::{
753 CertData, EncodableItem, ErasedKey, InvalidCertError, KeyType, KeystoreItem,
754 };
755 use tor_llcrypto::pk::ed25519::{self, Ed25519PublicKey as _};
756 use tor_llcrypto::rng::FakeEntropicRng;
757
758 #[derive(Clone, Debug, PartialEq)]
760 struct KeyMetadata {
761 item_id: String,
763 retrieved_from: Option<KeystoreId>,
767 is_generated: bool,
769 }
770
771 #[derive(Clone, Debug, PartialEq)]
773 struct CertMetadata {
774 subject_key_id: String,
776 signing_key_id: String,
778 retrieved_from: Option<KeystoreId>,
782 is_generated: bool,
785 }
786
787 #[derive(Clone, Debug, PartialEq, derive_more::From)]
789 enum ItemMetadata {
790 Key(KeyMetadata),
792 Cert(CertMetadata),
794 }
795
796 impl ItemMetadata {
797 fn item_id(&self) -> &str {
802 match self {
803 ItemMetadata::Key(k) => &k.item_id,
804 ItemMetadata::Cert(c) => &c.subject_key_id,
805 }
806 }
807
808 fn retrieved_from(&self) -> Option<&KeystoreId> {
810 match self {
811 ItemMetadata::Key(k) => k.retrieved_from.as_ref(),
812 ItemMetadata::Cert(c) => c.retrieved_from.as_ref(),
813 }
814 }
815
816 fn is_generated(&self) -> bool {
818 match self {
819 ItemMetadata::Key(k) => k.is_generated,
820 ItemMetadata::Cert(c) => c.is_generated,
821 }
822 }
823
824 fn set_retrieved_from(&mut self, id: KeystoreId) {
826 match self {
827 ItemMetadata::Key(meta) => meta.retrieved_from = Some(id),
828 ItemMetadata::Cert(meta) => meta.retrieved_from = Some(id),
829 }
830 }
831
832 fn as_key(&self) -> Option<&KeyMetadata> {
834 match self {
835 ItemMetadata::Key(meta) => Some(meta),
836 _ => None,
837 }
838 }
839
840 fn as_cert(&self) -> Option<&CertMetadata> {
842 match self {
843 ItemMetadata::Cert(meta) => Some(meta),
844 _ => None,
845 }
846 }
847 }
848
849 #[derive(Clone, Debug)]
851 struct TestItem {
852 item: KeystoreItem,
854 meta: ItemMetadata,
856 }
857
858 #[derive(Clone, Debug)]
860 struct AlwaysValidCert(TestItem);
861
862 #[derive(Clone, Debug)]
864 struct TestPublicKey {
865 key: KeystoreItem,
867 }
868
869 impl From<TestItem> for TestPublicKey {
870 fn from(tk: TestItem) -> TestPublicKey {
871 TestPublicKey { key: tk.item }
872 }
873 }
874
875 impl TestItem {
876 fn new(item_id: &str) -> Self {
878 let mut rng = testing_rng();
879 TestItem {
880 item: ed25519::Keypair::generate(&mut rng)
881 .as_keystore_item()
882 .unwrap(),
883 meta: ItemMetadata::Key(KeyMetadata {
884 item_id: item_id.to_string(),
885 retrieved_from: None,
886 is_generated: false,
887 }),
888 }
889 }
890 }
891
892 impl Keygen for TestItem {
893 fn generate(mut rng: &mut dyn KeygenRng) -> tor_key_forge::Result<Self>
894 where
895 Self: Sized,
896 {
897 Ok(TestItem {
898 item: ed25519::Keypair::generate(&mut rng).as_keystore_item()?,
899 meta: ItemMetadata::Key(KeyMetadata {
900 item_id: "generated_test_key".to_string(),
901 retrieved_from: None,
902 is_generated: true,
903 }),
904 })
905 }
906 }
907
908 impl ItemType for TestItem {
909 fn item_type() -> KeystoreItemType
910 where
911 Self: Sized,
912 {
913 KeyType::Ed25519Keypair.into()
915 }
916 }
917
918 impl EncodableItem for TestItem {
919 fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
920 Ok(self.item.clone())
921 }
922 }
923
924 impl ToEncodableKey for TestItem {
925 type Key = Self;
926 type KeyPair = Self;
927
928 fn to_encodable_key(self) -> Self::Key {
929 self
930 }
931
932 fn from_encodable_key(key: Self::Key) -> Self {
933 key
934 }
935 }
936
937 impl ItemType for TestPublicKey {
938 fn item_type() -> KeystoreItemType
939 where
940 Self: Sized,
941 {
942 KeyType::Ed25519PublicKey.into()
943 }
944 }
945
946 impl EncodableItem for TestPublicKey {
947 fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
948 Ok(self.key.clone())
949 }
950 }
951
952 impl ToEncodableKey for TestPublicKey {
953 type Key = Self;
954 type KeyPair = TestItem;
955
956 fn to_encodable_key(self) -> Self::Key {
957 self
958 }
959
960 fn from_encodable_key(key: Self::Key) -> Self {
961 key
962 }
963 }
964
965 impl ToEncodableCert<TestItem> for AlwaysValidCert {
966 type ParsedCert = TestItem;
967 type EncodableCert = TestItem;
968 type SigningKey = TestItem;
969
970 fn validate(
971 cert: Self::ParsedCert,
972 _subject: &TestItem,
973 _signed_with: &Self::SigningKey,
974 ) -> StdResult<Self, InvalidCertError> {
975 Ok(Self(cert))
977 }
978
979 fn to_encodable_cert(self) -> Self::EncodableCert {
981 self.0
982 }
983 }
984
985 #[derive(thiserror::Error, Debug, Clone, derive_more::Display)]
986 enum MockKeystoreError {
987 NotFound,
988 }
989
990 impl KeystoreError for MockKeystoreError {}
991
992 impl HasKind for MockKeystoreError {
993 fn kind(&self) -> ErrorKind {
994 tor_error::ErrorKind::Other
996 }
997 }
998
999 fn build_raw_id_path<T: ToString>(key_path: &T, key_type: &KeystoreItemType) -> RawEntryId {
1000 let mut path = key_path.to_string();
1001 path.push('.');
1002 path.push_str(&key_type.arti_extension());
1003 RawEntryId::Path(PathBuf::from(&path))
1004 }
1005
1006 macro_rules! impl_keystore {
1007 ($name:tt, $id:expr $(,$unrec:expr)?) => {
1008 struct $name {
1009 inner: RwLock<
1010 Vec<StdResult<(ArtiPath, KeystoreItemType, TestItem), UnrecognizedEntryError>>,
1011 >,
1012 id: KeystoreId,
1013 }
1014
1015 impl Default for $name {
1016 fn default() -> Self {
1017 let id = KeystoreId::from_str($id).unwrap();
1018 let inner: RwLock<
1019 Vec<
1020 StdResult<
1021 (ArtiPath, KeystoreItemType, TestItem),
1022 UnrecognizedEntryError,
1023 >,
1024 >,
1025 > = Default::default();
1026 $(
1029 for i in 0..$unrec {
1030 let invalid_key_path =
1031 PathBuf::from(&format!("unrecognized_entry{}", i));
1032 let raw_id = RawEntryId::Path(invalid_key_path.clone());
1033 let entry = RawKeystoreEntry::new(raw_id, id.clone()).into();
1034 let entry = UnrecognizedEntryError::new(
1035 entry,
1036 Arc::new(ArtiNativeKeystoreError::MalformedPath {
1037 path: invalid_key_path,
1038 err: MalformedPathError::NoExtension,
1039 }),
1040 );
1041 inner.write().unwrap().push(Err(entry));
1042 }
1043 )?
1044 Self {
1045 inner,
1046 id,
1047 }
1048 }
1049 }
1050
1051 #[allow(dead_code)] impl $name {
1053 fn new_boxed() -> BoxedKeystore {
1054 Box::<Self>::default()
1055 }
1056 }
1057
1058 impl crate::Keystore for $name {
1059 fn contains(
1060 &self,
1061 key_spec: &dyn KeySpecifier,
1062 item_type: &KeystoreItemType,
1063 ) -> Result<bool> {
1064 let wanted_arti_path = key_spec.arti_path().unwrap();
1065 Ok(self
1066 .inner
1067 .read()
1068 .unwrap()
1069 .iter()
1070 .find(|res| match res {
1071 Ok((spec, ty, _)) => spec == &wanted_arti_path && ty == item_type,
1072 Err(_) => false,
1073 })
1074 .is_some())
1075 }
1076
1077 fn id(&self) -> &KeystoreId {
1078 &self.id
1079 }
1080
1081 fn get(
1082 &self,
1083 key_spec: &dyn KeySpecifier,
1084 item_type: &KeystoreItemType,
1085 ) -> Result<Option<ErasedKey>> {
1086 let key_spec = key_spec.arti_path().unwrap();
1087
1088 Ok(self.inner.read().unwrap().iter().find_map(|res| {
1089 match res {
1090 Ok((arti_path, ty, k)) => {
1091 if arti_path == &key_spec && ty == item_type {
1092 let mut k = k.clone();
1093 k.meta.set_retrieved_from(self.id().clone());
1094 return Some(Box::new(k) as Box<dyn ItemType>);
1095 }
1096 }
1097 Err(_) => {}
1098 }
1099 None
1100 }))
1101 }
1102
1103 #[cfg(feature = "onion-service-cli-extra")]
1104 fn raw_entry_id(&self, raw_id: &str) -> Result<RawEntryId> {
1105 Ok(RawEntryId::Path(
1106 PathBuf::from(raw_id.to_string()),
1107 ))
1108 }
1109
1110 fn insert(
1111 &self,
1112 key: &dyn EncodableItem,
1113 key_spec: &dyn KeySpecifier,
1114 ) -> Result<()> {
1115 let key = key.downcast_ref::<TestItem>().unwrap();
1116
1117 let item = key.as_keystore_item()?;
1118 let meta = key.meta.clone();
1119
1120 let item_type = item.item_type()?;
1121 let key = TestItem { item, meta };
1122
1123 self.inner
1124 .write()
1125 .unwrap()
1126 .insert(0, (Ok((key_spec.arti_path().unwrap(), item_type, key))));
1131
1132 Ok(())
1133 }
1134
1135 fn remove(
1136 &self,
1137 key_spec: &dyn KeySpecifier,
1138 item_type: &KeystoreItemType,
1139 ) -> Result<Option<()>> {
1140 let wanted_arti_path = key_spec.arti_path().unwrap();
1141 let index = self.inner.read().unwrap().iter().position(|res| {
1142 if let Ok((arti_path, ty, _)) = res {
1143 arti_path == &wanted_arti_path && ty == item_type
1144 } else {
1145 false
1146 }
1147 });
1148 let Some(index) = index else {
1149 return Ok(None);
1150 };
1151 let _ = self.inner.write().unwrap().remove(index);
1152
1153 Ok(Some(()))
1154 }
1155
1156 #[cfg(feature = "onion-service-cli-extra")]
1157 fn remove_unchecked(&self, entry_id: &RawEntryId) -> Result<()> {
1158 let index = self.inner.read().unwrap().iter().position(|res| match res {
1159 Ok((spec, ty, _)) => {
1160 let id = build_raw_id_path(spec, ty);
1161 entry_id == &id
1162 }
1163 Err(e) => {
1164 e.entry().raw_id() == entry_id
1165 }
1166 });
1167 let Some(index) = index else {
1168 return Err(Error::Keystore(Arc::new(MockKeystoreError::NotFound)));
1169 };
1170 let _ = self.inner.write().unwrap().remove(index);
1171 Ok(())
1172 }
1173
1174 fn list(&self) -> Result<Vec<KeystoreEntryResult<KeystoreEntry>>> {
1175 Ok(self
1176 .inner
1177 .read()
1178 .unwrap()
1179 .iter()
1180 .map(|res| match res {
1181 Ok((arti_path, ty, _)) => {
1182 let raw_id = RawEntryId::Path(
1183 PathBuf::from(
1184 &arti_path.to_string(),
1185 )
1186 );
1187
1188 Ok(KeystoreEntry::new(KeyPath::Arti(arti_path.clone()), ty.clone(), self.id(), raw_id))
1189 }
1190 Err(e) => Err(e.clone()),
1191 })
1192 .collect())
1193 }
1194 }
1195 };
1196 }
1197
1198 macro_rules! impl_specifier {
1199 ($name:tt, $id:expr) => {
1200 struct $name;
1201
1202 impl KeySpecifier for $name {
1203 fn arti_path(&self) -> StdResult<ArtiPath, ArtiPathUnavailableError> {
1204 Ok(ArtiPath::new($id.into()).map_err(|e| tor_error::internal!("{e}"))?)
1205 }
1206
1207 fn ctor_path(&self) -> Option<crate::CTorPath> {
1208 None
1209 }
1210
1211 fn keypair_specifier(&self) -> Option<Box<dyn KeySpecifier>> {
1212 None
1213 }
1214 }
1215 };
1216 }
1217
1218 impl_keystore!(Keystore1, "keystore1");
1219 impl_keystore!(Keystore2, "keystore2");
1220 impl_keystore!(Keystore3, "keystore3");
1221 impl_keystore!(KeystoreUnrec1, "keystore_unrec1", 1);
1222
1223 impl_specifier!(TestKeySpecifier1, "spec1");
1224 impl_specifier!(TestKeySpecifier2, "spec2");
1225 impl_specifier!(TestKeySpecifier3, "spec3");
1226 impl_specifier!(TestKeySpecifier4, "spec4");
1227
1228 impl_specifier!(TestPublicKeySpecifier1, "pub-spec1");
1229
1230 fn entry_descriptor(specifier: impl KeySpecifier, keystore_id: &KeystoreId) -> KeystoreEntry {
1232 let arti_path = specifier.arti_path().unwrap();
1233 let raw_id = RawEntryId::Path(PathBuf::from(arti_path.as_ref()));
1234 KeystoreEntry {
1235 key_path: arti_path.into(),
1236 key_type: TestItem::item_type(),
1237 keystore_id,
1238 raw_id,
1239 }
1240 }
1241
1242 #[test]
1243 #[allow(clippy::cognitive_complexity)]
1244 fn insert_and_get() {
1245 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1246
1247 builder
1248 .secondary_stores()
1249 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1250
1251 let mgr = builder.build().unwrap();
1252
1253 let old_key = mgr
1255 .insert(
1256 TestItem::new("coot"),
1257 &TestKeySpecifier1,
1258 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1259 true,
1260 )
1261 .unwrap();
1262
1263 assert!(old_key.is_none());
1264 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1265 assert_eq!(key.meta.item_id(), "coot");
1266 assert_eq!(
1267 key.meta.retrieved_from(),
1268 Some(&KeystoreId::from_str("keystore2").unwrap())
1269 );
1270 assert_eq!(key.meta.is_generated(), false);
1271
1272 let old_key = mgr
1274 .insert(
1275 TestItem::new("gull"),
1276 &TestKeySpecifier1,
1277 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1278 true,
1279 )
1280 .unwrap()
1281 .unwrap();
1282 assert_eq!(old_key.meta.item_id(), "coot");
1283 assert_eq!(
1284 old_key.meta.retrieved_from(),
1285 Some(&KeystoreId::from_str("keystore2").unwrap())
1286 );
1287 assert_eq!(old_key.meta.is_generated(), false);
1288 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1290 assert_eq!(key.meta.item_id(), "gull");
1291 assert_eq!(
1292 key.meta.retrieved_from(),
1293 Some(&KeystoreId::from_str("keystore2").unwrap())
1294 );
1295 assert_eq!(key.meta.is_generated(), false);
1296
1297 let err = mgr
1299 .insert(
1300 TestItem::new("gull"),
1301 &TestKeySpecifier1,
1302 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1303 false,
1304 )
1305 .unwrap_err();
1306 assert!(matches!(err, crate::Error::KeyAlreadyExists));
1307
1308 let old_key = mgr
1310 .insert(
1311 TestItem::new("penguin"),
1312 &TestKeySpecifier2,
1313 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1314 false,
1315 )
1316 .unwrap();
1317 assert!(old_key.is_none());
1318
1319 let old_key = mgr
1321 .insert(
1322 TestItem::new("moorhen"),
1323 &TestKeySpecifier3,
1324 KeystoreSelector::Primary,
1325 true,
1326 )
1327 .unwrap();
1328 assert!(old_key.is_none());
1329 let key = mgr.get::<TestItem>(&TestKeySpecifier3).unwrap().unwrap();
1330 assert_eq!(key.meta.item_id(), "moorhen");
1331 assert_eq!(
1332 key.meta.retrieved_from(),
1333 Some(&KeystoreId::from_str("keystore1").unwrap())
1334 );
1335 assert_eq!(key.meta.is_generated(), false);
1336
1337 assert!(mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().is_none());
1339
1340 for store in ["keystore3", "keystore2", "keystore1"] {
1344 let old_key = mgr
1345 .insert(
1346 TestItem::new("cormorant"),
1347 &TestKeySpecifier4,
1348 KeystoreSelector::Id(&KeystoreId::from_str(store).unwrap()),
1349 true,
1350 )
1351 .unwrap();
1352 assert!(old_key.is_none());
1353
1354 let key = mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().unwrap();
1356 assert_eq!(key.meta.item_id(), "cormorant");
1357 assert_eq!(
1358 key.meta.retrieved_from(),
1359 Some(&KeystoreId::from_str(store).unwrap())
1360 );
1361 assert_eq!(key.meta.is_generated(), false);
1362 }
1363
1364 let key = mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().unwrap();
1367 assert_eq!(key.meta.item_id(), "cormorant");
1368 assert_eq!(
1369 key.meta.retrieved_from(),
1370 Some(&KeystoreId::from_str("keystore1").unwrap())
1371 );
1372 assert_eq!(key.meta.is_generated(), false);
1373 }
1374
1375 #[test]
1376 fn remove() {
1377 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1378
1379 builder
1380 .secondary_stores()
1381 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1382
1383 let mgr = builder.build().unwrap();
1384
1385 assert!(!mgr.secondary_stores[0]
1386 .contains(&TestKeySpecifier1, &TestItem::item_type())
1387 .unwrap());
1388
1389 mgr.insert(
1391 TestItem::new("coot"),
1392 &TestKeySpecifier1,
1393 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1394 true,
1395 )
1396 .unwrap();
1397 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1398 assert_eq!(key.meta.item_id(), "coot");
1399 assert_eq!(
1400 key.meta.retrieved_from(),
1401 Some(&KeystoreId::from_str("keystore2").unwrap())
1402 );
1403 assert_eq!(key.meta.is_generated(), false);
1404
1405 assert!(mgr
1407 .remove::<TestItem>(
1408 &TestKeySpecifier1,
1409 KeystoreSelector::Id(&KeystoreId::from_str("not_an_id_we_know_of").unwrap())
1410 )
1411 .is_err());
1412 assert!(mgr.secondary_stores[0]
1414 .contains(&TestKeySpecifier1, &TestItem::item_type())
1415 .unwrap());
1416
1417 assert!(mgr
1419 .remove::<TestItem>(&TestKeySpecifier1, KeystoreSelector::Primary)
1420 .unwrap()
1421 .is_none());
1422
1423 assert!(mgr.secondary_stores[0]
1425 .contains(&TestKeySpecifier1, &TestItem::item_type())
1426 .unwrap());
1427
1428 let removed_key = mgr
1430 .remove::<TestItem>(
1431 &TestKeySpecifier1,
1432 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1433 )
1434 .unwrap()
1435 .unwrap();
1436 assert_eq!(removed_key.meta.item_id(), "coot");
1437 assert_eq!(
1438 removed_key.meta.retrieved_from(),
1439 Some(&KeystoreId::from_str("keystore2").unwrap())
1440 );
1441 assert_eq!(removed_key.meta.is_generated(), false);
1442
1443 assert!(!mgr.secondary_stores[0]
1445 .contains(&TestKeySpecifier1, &TestItem::item_type())
1446 .unwrap());
1447 }
1448
1449 #[test]
1450 fn keygen() {
1451 let mut rng = FakeEntropicRng(testing_rng());
1452 let mgr = KeyMgrBuilder::default()
1453 .primary_store(Box::<Keystore1>::default())
1454 .build()
1455 .unwrap();
1456
1457 mgr.insert(
1458 TestItem::new("coot"),
1459 &TestKeySpecifier1,
1460 KeystoreSelector::Primary,
1461 true,
1462 )
1463 .unwrap();
1464
1465 assert!(mgr
1467 .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1468 .unwrap()
1469 .is_none());
1470
1471 let err = mgr
1473 .generate::<TestItem>(
1474 &TestKeySpecifier1,
1475 KeystoreSelector::Primary,
1476 &mut rng,
1477 false,
1478 )
1479 .unwrap_err();
1480
1481 assert!(matches!(err, crate::Error::KeyAlreadyExists));
1482
1483 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1485 assert_eq!(key.meta.item_id(), "coot");
1486 assert_eq!(
1487 key.meta.retrieved_from(),
1488 Some(&KeystoreId::from_str("keystore1").unwrap())
1489 );
1490 assert_eq!(key.meta.is_generated(), false);
1491
1492 assert!(mgr
1494 .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1495 .unwrap()
1496 .is_none());
1497
1498 let generated_key = mgr
1500 .generate::<TestItem>(
1501 &TestKeySpecifier1,
1502 KeystoreSelector::Primary,
1503 &mut rng,
1504 true,
1505 )
1506 .unwrap();
1507
1508 assert_eq!(generated_key.meta.item_id(), "generated_test_key");
1509 assert_eq!(generated_key.meta.retrieved_from(), None);
1512 assert_eq!(generated_key.meta.is_generated(), true);
1513
1514 let retrieved_key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1516 assert_eq!(retrieved_key.meta.item_id(), "generated_test_key");
1517 assert_eq!(
1518 retrieved_key.meta.retrieved_from(),
1519 Some(&KeystoreId::from_str("keystore1").unwrap())
1520 );
1521 assert_eq!(retrieved_key.meta.is_generated(), true);
1522
1523 assert!(mgr
1525 .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1526 .unwrap()
1527 .is_none());
1528 }
1529
1530 #[test]
1531 fn get_or_generate() {
1532 let mut rng = FakeEntropicRng(testing_rng());
1533 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1534
1535 builder
1536 .secondary_stores()
1537 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1538
1539 let mgr = builder.build().unwrap();
1540
1541 let keystore2 = KeystoreId::from_str("keystore2").unwrap();
1542 let entry_desc1 = entry_descriptor(TestKeySpecifier1, &keystore2);
1543 assert!(mgr.get_entry::<TestItem>(&entry_desc1).unwrap().is_none());
1544
1545 mgr.insert(
1546 TestItem::new("coot"),
1547 &TestKeySpecifier1,
1548 KeystoreSelector::Id(&keystore2),
1549 true,
1550 )
1551 .unwrap();
1552
1553 let key = mgr
1555 .get_or_generate::<TestItem>(&TestKeySpecifier1, KeystoreSelector::Primary, &mut rng)
1556 .unwrap();
1557 assert_eq!(key.meta.item_id(), "coot");
1558 assert_eq!(
1559 key.meta.retrieved_from(),
1560 Some(&KeystoreId::from_str("keystore2").unwrap())
1561 );
1562 assert_eq!(key.meta.is_generated(), false);
1563
1564 assert_eq!(
1565 mgr.get_entry::<TestItem>(&entry_desc1)
1566 .unwrap()
1567 .map(|k| k.meta),
1568 Some(ItemMetadata::Key(KeyMetadata {
1569 item_id: "coot".to_string(),
1570 retrieved_from: Some(keystore2.clone()),
1571 is_generated: false,
1572 }))
1573 );
1574
1575 let keystore3 = KeystoreId::from_str("keystore3").unwrap();
1578 let generated_key = mgr
1579 .get_or_generate::<TestItem>(
1580 &TestKeySpecifier2,
1581 KeystoreSelector::Id(&keystore3),
1582 &mut rng,
1583 )
1584 .unwrap();
1585 assert_eq!(generated_key.meta.item_id(), "generated_test_key");
1586 assert_eq!(generated_key.meta.retrieved_from(), None);
1589 assert_eq!(generated_key.meta.is_generated(), true);
1590
1591 let retrieved_key = mgr.get::<TestItem>(&TestKeySpecifier2).unwrap().unwrap();
1593 assert_eq!(retrieved_key.meta.item_id(), "generated_test_key");
1594 assert_eq!(
1595 retrieved_key.meta.retrieved_from(),
1596 Some(&KeystoreId::from_str("keystore3").unwrap())
1597 );
1598 assert_eq!(retrieved_key.meta.is_generated(), true);
1599
1600 let entry_desc2 = entry_descriptor(TestKeySpecifier2, &keystore3);
1601 assert_eq!(
1602 mgr.get_entry::<TestItem>(&entry_desc2)
1603 .unwrap()
1604 .map(|k| k.meta),
1605 Some(ItemMetadata::Key(KeyMetadata {
1606 item_id: "generated_test_key".to_string(),
1607 retrieved_from: Some(keystore3.clone()),
1608 is_generated: true,
1609 }))
1610 );
1611
1612 let arti_pat = KeyPathPattern::Arti("*".to_string());
1613 let matching = mgr.list_matching(&arti_pat).unwrap();
1614
1615 assert_eq!(matching.len(), 2);
1616 assert!(matching.contains(&entry_desc1));
1617 assert!(matching.contains(&entry_desc2));
1618
1619 assert_eq!(mgr.remove_entry(&entry_desc2).unwrap(), Some(()));
1620 assert!(mgr.get_entry::<TestItem>(&entry_desc2).unwrap().is_none());
1621 assert!(mgr.remove_entry(&entry_desc2).unwrap().is_none());
1622 }
1623
1624 #[test]
1625 fn list_matching_ignores_unrecognized_keys() {
1626 let builder = KeyMgrBuilder::default().primary_store(Box::new(KeystoreUnrec1::default()));
1627
1628 let mgr = builder.build().unwrap();
1629
1630 let unrec_1 = KeystoreId::from_str("keystore_unrec1").unwrap();
1631 mgr.insert(
1632 TestItem::new("whale shark"),
1633 &TestKeySpecifier1,
1634 KeystoreSelector::Id(&unrec_1),
1635 true,
1636 )
1637 .unwrap();
1638
1639 let arti_pat = KeyPathPattern::Arti("*".to_string());
1640 let valid_key_path = KeyPath::Arti(TestKeySpecifier1.arti_path().unwrap());
1641 let matching = mgr.list_matching(&arti_pat).unwrap();
1642 assert_eq!(matching.len(), 1);
1644 assert_eq!(matching.first().unwrap().key_path(), &valid_key_path);
1645 }
1646
1647 #[cfg(feature = "onion-service-cli-extra")]
1648 #[test]
1649 fn keys_subcommands() {
1652 let mut builder =
1653 KeyMgrBuilder::default().primary_store(Box::new(KeystoreUnrec1::default()));
1654 builder
1655 .secondary_stores()
1656 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1657
1658 let mgr = builder.build().unwrap();
1659 let ks_unrec1id = KeystoreId::from_str("keystore_unrec1").unwrap();
1660 let keystore2id = KeystoreId::from_str("keystore2").unwrap();
1661 let keystore3id = KeystoreId::from_str("keystore3").unwrap();
1662
1663 let _ = mgr
1665 .insert(
1666 TestItem::new("pangolin"),
1667 &TestKeySpecifier1,
1668 KeystoreSelector::Id(&ks_unrec1id),
1669 true,
1670 )
1671 .unwrap();
1672
1673 let _ = mgr
1675 .insert(
1676 TestItem::new("coot"),
1677 &TestKeySpecifier2,
1678 KeystoreSelector::Id(&keystore2id),
1679 true,
1680 )
1681 .unwrap();
1682
1683 let _ = mgr
1685 .insert(
1686 TestItem::new("penguin"),
1687 &TestKeySpecifier3,
1688 KeystoreSelector::Id(&keystore3id),
1689 true,
1690 )
1691 .unwrap();
1692
1693 let assert_key = |path, ty, expected_path: &ArtiPath, expected_type| {
1694 assert_eq!(ty, expected_type);
1695 assert_eq!(path, &KeyPath::Arti(expected_path.clone()));
1696 };
1697 let item_type = TestItem::new("axolotl").item.item_type().unwrap();
1698 let unrecognized_entry_id = RawEntryId::Path(PathBuf::from("unrecognized_entry0"));
1699
1700 let entries = mgr.list().unwrap();
1702
1703 let expected_items = [
1704 (ks_unrec1id, TestKeySpecifier1.arti_path().unwrap()),
1705 (keystore2id, TestKeySpecifier2.arti_path().unwrap()),
1706 (keystore3id, TestKeySpecifier3.arti_path().unwrap()),
1707 ];
1708
1709 let mut recognized_entries = 0;
1711 let mut unrecognized_entries = 0;
1712 for entry in entries.iter() {
1713 match entry {
1714 Ok(e) => {
1715 if let Some((_, expected_arti_path)) = expected_items
1716 .iter()
1717 .find(|(keystore_id, _)| keystore_id == e.keystore_id())
1718 {
1719 assert_key(e.key_path(), e.key_type(), expected_arti_path, &item_type);
1720 recognized_entries += 1;
1721 continue;
1722 }
1723
1724 panic!("Unexpected key encountered {:?}", e);
1725 }
1726 Err(u) => {
1727 assert_eq!(u.entry().raw_id(), &unrecognized_entry_id);
1728 unrecognized_entries += 1;
1729 }
1730 }
1731 }
1732 assert_eq!(recognized_entries, 3);
1733 assert_eq!(unrecognized_entries, 1);
1734
1735 let keystores = mgr.list_keystores().iter().len();
1737
1738 assert_eq!(keystores, 3);
1739
1740 let primary_keystore_id = KeystoreId::from_str("keystore_unrec1").unwrap();
1742 let entries = mgr.list_by_id(&primary_keystore_id).unwrap();
1743
1744 let mut recognized_entries = 0;
1746 let mut unrecognized_entries = 0;
1747 let mut all_entries = vec![];
1749 for entry in entries.iter() {
1750 match entry {
1751 Ok(entry) => {
1752 assert_key(
1753 entry.key_path(),
1754 entry.key_type(),
1755 &TestKeySpecifier1.arti_path().unwrap(),
1756 &item_type,
1757 );
1758 recognized_entries += 1;
1759 all_entries.push(RawKeystoreEntry::new(
1760 build_raw_id_path(entry.key_path(), entry.key_type()),
1761 primary_keystore_id.clone(),
1762 ));
1763 }
1764 Err(u) => {
1765 assert_eq!(u.entry().raw_id(), &unrecognized_entry_id);
1766 unrecognized_entries += 1;
1767 all_entries.push(u.entry().into());
1768 }
1769 }
1770 }
1771 assert_eq!(recognized_entries, 1);
1772 assert_eq!(unrecognized_entries, 1);
1773
1774 for entry in all_entries {
1776 mgr.remove_unchecked(&entry.raw_id().to_string(), entry.keystore_id())
1777 .unwrap();
1778 }
1779
1780 let entries = mgr.list_by_id(&primary_keystore_id).unwrap();
1782 assert_eq!(entries.len(), 0);
1783 }
1784
1785 #[cfg(feature = "experimental-api")]
1787 #[derive(Clone, Copy, Debug, PartialEq)]
1788 enum GenerateItem {
1789 Yes,
1790 No,
1791 }
1792
1793 #[cfg(feature = "experimental-api")]
1794 macro_rules! run_certificate_test {
1795 (
1796 generate_subject_key = $generate_subject_key:expr,
1797 generate_signing_key = $generate_signing_key:expr,
1798 $($expected_err:tt)?
1799 ) => {{
1800 use GenerateItem::*;
1801
1802 let mut rng = FakeEntropicRng(testing_rng());
1803 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1804
1805 builder
1806 .secondary_stores()
1807 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1808
1809 let mgr = builder.build().unwrap();
1810
1811 let spec = crate::test_utils::TestCertSpecifier {
1812 subject_key_spec: TestKeySpecifier1,
1813 signing_key_spec: TestKeySpecifier2,
1814 denotator: vec!["foo".into()],
1815 };
1816
1817 if $generate_subject_key == Yes {
1818 let _ = mgr
1819 .generate::<TestItem>(
1820 &TestKeySpecifier1,
1821 KeystoreSelector::Primary,
1822 &mut rng,
1823 false,
1824 )
1825 .unwrap();
1826 }
1827
1828 if $generate_signing_key == Yes {
1829 let _ = mgr
1830 .generate::<TestItem>(
1831 &TestKeySpecifier2,
1832 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1833 &mut rng,
1834 false,
1835 )
1836 .unwrap();
1837 }
1838
1839 let make_certificate = move |subject_key: &TestItem, signed_with: &TestItem| {
1840 let subject_id = subject_key.meta.as_key().unwrap().item_id.clone();
1841 let signing_id = signed_with.meta.as_key().unwrap().item_id.clone();
1842
1843 let meta = ItemMetadata::Cert(CertMetadata {
1844 subject_key_id: subject_id,
1845 signing_key_id: signing_id,
1846 retrieved_from: None,
1847 is_generated: true,
1848 });
1849
1850 let mut rng = FakeEntropicRng(testing_rng());
1856 let keypair = ed25519::Keypair::generate(&mut rng);
1857 let encoded_cert = Ed25519Cert::constructor()
1858 .cert_type(tor_cert::CertType::IDENTITY_V_SIGNING)
1859 .expiration(SystemTime::now() + Duration::from_secs(180))
1860 .signing_key(keypair.public_key().into())
1861 .cert_key(CertifiedKey::Ed25519(keypair.public_key().into()))
1862 .encode_and_sign(&keypair)
1863 .unwrap();
1864 let test_cert = CertData::TorEd25519Cert(encoded_cert);
1865 AlwaysValidCert(TestItem {
1866 item: KeystoreItem::Cert(test_cert),
1867 meta,
1868 })
1869 };
1870
1871 let res = mgr
1872 .get_or_generate_key_and_cert::<TestItem, AlwaysValidCert>(
1873 &spec,
1874 &make_certificate,
1875 KeystoreSelector::Primary,
1876 &mut rng,
1877 );
1878
1879 #[allow(unused_assignments)]
1880 #[allow(unused_mut)]
1881 let mut has_error = false;
1882 $(
1883 has_error = true;
1884 let err = res.clone().unwrap_err();
1885 assert!(
1886 matches!(
1887 err,
1888 crate::Error::Corruption(KeystoreCorruptionError::$expected_err)
1889 ),
1890 "unexpected error: {err:?}",
1891 );
1892 )?
1893
1894 if !has_error {
1895 let (key, cert) = res.unwrap();
1896
1897 let expected_subj_key_id = if $generate_subject_key == Yes {
1898 "generated_test_key"
1899 } else {
1900 "generated_test_key"
1901 };
1902
1903 assert_eq!(key.meta.item_id(), expected_subj_key_id);
1904 assert_eq!(
1905 cert.0.meta.as_cert().unwrap().subject_key_id,
1906 expected_subj_key_id
1907 );
1908 assert_eq!(
1909 cert.0.meta.as_cert().unwrap().signing_key_id,
1910 "generated_test_key"
1911 );
1912 assert_eq!(cert.0.meta.is_generated(), true);
1913 }
1914 }}
1915 }
1916
1917 #[test]
1918 #[cfg(feature = "experimental-api")]
1919 #[rustfmt::skip] #[allow(clippy::cognitive_complexity)] fn get_certificate() {
1922 run_certificate_test!(
1923 generate_subject_key = No,
1924 generate_signing_key = No,
1925 MissingSigningKey
1926 );
1927
1928 run_certificate_test!(
1929 generate_subject_key = Yes,
1930 generate_signing_key = No,
1931 MissingSigningKey
1932 );
1933
1934 run_certificate_test!(
1935 generate_subject_key = No,
1936 generate_signing_key = Yes,
1937 );
1938
1939 run_certificate_test!(
1940 generate_subject_key = Yes,
1941 generate_signing_key = Yes,
1942 );
1943 }
1944}