1use crate::raw::{RawEntryId, RawKeystoreEntry};
6use crate::{
7 ArtiPath, BoxedKeystore, Error, 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 #[cfg(feature = "onion-service-cli-extra")]
243 pub fn get_from<K: ToEncodableKey>(
244 &self,
245 key_spec: &dyn KeySpecifier,
246 keystore_id: &KeystoreId,
247 ) -> Result<Option<K>> {
248 let store = std::iter::once(self.find_keystore(keystore_id)?);
249 self.get_from_store(key_spec, &K::Key::item_type(), store)
250 }
251
252 #[cfg(feature = "onion-service-cli-extra")]
266 pub fn validate_entry_integrity(&self, entry: &KeystoreEntry) -> Result<()> {
267 let selector = entry.keystore_id().into();
268 let store = self.select_keystore(&selector)?;
269 let _ = store.get(entry.key_path(), entry.key_type())?;
271
272 if !matches!(entry.key_path(), KeyPath::CTor(_)) {
274 let _ = self
276 .describe(entry.key_path())
277 .map_err(|e| Error::Corruption(e.into()))?;
279 }
280
281 Ok(())
282 }
283
284 pub fn generate<K>(
305 &self,
306 key_spec: &dyn KeySpecifier,
307 selector: KeystoreSelector,
308 rng: &mut dyn KeygenRng,
309 overwrite: bool,
310 ) -> Result<K>
311 where
312 K: ToEncodableKey,
313 K::Key: Keygen,
314 {
315 let store = self.select_keystore(&selector)?;
316
317 if overwrite || !store.contains(key_spec, &K::Key::item_type())? {
318 let key = K::Key::generate(rng)?;
319 store.insert(&key, key_spec)?;
320
321 Ok(K::from_encodable_key(key))
322 } else {
323 Err(crate::Error::KeyAlreadyExists)
324 }
325 }
326
327 pub fn insert<K: ToEncodableKey>(
340 &self,
341 key: K,
342 key_spec: &dyn KeySpecifier,
343 selector: KeystoreSelector,
344 overwrite: bool,
345 ) -> Result<Option<K>> {
346 let key = key.to_encodable_key();
347 let store = self.select_keystore(&selector)?;
348 let key_type = K::Key::item_type();
349 let old_key: Option<K> = self.get_from_store(key_spec, &key_type, [store].into_iter())?;
350
351 if old_key.is_some() && !overwrite {
352 Err(crate::Error::KeyAlreadyExists)
353 } else {
354 let () = store.insert(&key, key_spec)?;
355 Ok(old_key)
356 }
357 }
358
359 pub fn remove<K: ToEncodableKey>(
370 &self,
371 key_spec: &dyn KeySpecifier,
372 selector: KeystoreSelector,
373 ) -> Result<Option<K>> {
374 let store = self.select_keystore(&selector)?;
375 let key_type = K::Key::item_type();
376 let old_key: Option<K> = self.get_from_store(key_spec, &key_type, [store].into_iter())?;
377
378 store.remove(key_spec, &key_type)?;
379
380 Ok(old_key)
381 }
382
383 pub fn remove_entry(&self, entry: &KeystoreEntry) -> Result<Option<()>> {
395 let selector = entry.keystore_id().into();
396 let store = self.select_keystore(&selector)?;
397
398 store.remove(entry.key_path(), entry.key_type())
399 }
400
401 #[cfg(feature = "onion-service-cli-extra")]
409 pub fn remove_unchecked(&self, raw_id: &str, keystore_id: &KeystoreId) -> Result<()> {
410 let selector = KeystoreSelector::from(keystore_id);
411 let store = self.select_keystore(&selector)?;
412 let raw_id = store.raw_entry_id(raw_id)?;
413 let store = self.select_keystore(&selector)?;
414 store.remove_unchecked(&raw_id)
415 }
416
417 pub fn list_matching(&self, pat: &KeyPathPattern) -> Result<Vec<KeystoreEntry>> {
425 self.all_stores()
426 .map(|store| -> Result<Vec<_>> {
427 Ok(store
428 .list()?
429 .into_iter()
430 .filter_map(|entry| entry.ok())
431 .filter(|entry| entry.key_path().matches(pat))
432 .collect::<Vec<_>>())
433 })
434 .flatten_ok()
435 .collect::<Result<Vec<_>>>()
436 }
437
438 #[cfg(feature = "onion-service-cli-extra")]
440 pub fn list_by_id(&self, id: &KeystoreId) -> Result<Vec<KeystoreEntryResult<KeystoreEntry>>> {
441 self.find_keystore(id)?.list()
442 }
443
444 #[cfg(feature = "onion-service-cli-extra")]
446 pub fn list(&self) -> Result<Vec<KeystoreEntryResult<KeystoreEntry>>> {
447 self.all_stores()
448 .map(|store| -> Result<Vec<_>> { store.list() })
449 .flatten_ok()
450 .collect::<Result<Vec<_>>>()
451 }
452
453 #[cfg(feature = "onion-service-cli-extra")]
455 pub fn list_keystores(&self) -> Vec<KeystoreId> {
456 self.all_stores()
457 .map(|store| store.id().to_owned())
458 .collect()
459 }
460
461 pub fn describe(&self, path: &KeyPath) -> StdResult<KeyPathInfo, KeyPathError> {
470 for info_extractor in &self.key_info_extractors {
471 if let Ok(info) = info_extractor.describe(path) {
472 return Ok(info);
473 }
474 }
475
476 Err(KeyPathError::Unrecognized(path.clone()))
477 }
478
479 fn get_from_store_raw<'a, K: ItemType>(
485 &self,
486 key_spec: &dyn KeySpecifier,
487 key_type: &KeystoreItemType,
488 stores: impl Iterator<Item = &'a BoxedKeystore>,
489 ) -> Result<Option<K>> {
490 let static_key_type = K::item_type();
491 if key_type != &static_key_type {
492 return Err(internal!(
493 "key type {:?} does not match the key type {:?} of requested key K::Key",
494 key_type,
495 static_key_type
496 )
497 .into());
498 }
499
500 for store in stores {
501 let key = match store.get(key_spec, &K::item_type()) {
502 Ok(None) => {
503 continue;
505 }
506 Ok(Some(k)) => k,
507 Err(e) => {
508 return Err(e);
510 }
511 };
512
513 let key: K = key
515 .downcast::<K>()
516 .map(|k| *k)
517 .map_err(|_| internal!("failed to downcast key to requested type"))?;
518
519 return Ok(Some(key));
520 }
521
522 Ok(None)
523 }
524
525 fn get_from_store<'a, K: ToEncodableKey>(
529 &self,
530 key_spec: &dyn KeySpecifier,
531 key_type: &KeystoreItemType,
532 stores: impl Iterator<Item = &'a BoxedKeystore>,
533 ) -> Result<Option<K>> {
534 let Some(key) = self.get_from_store_raw::<K::Key>(key_spec, key_type, stores)? else {
535 return Ok(None);
536 };
537
538 Ok(Some(K::from_encodable_key(key)))
539 }
540
541 #[cfg(feature = "experimental-api")]
557 pub fn get_key_and_cert<K, C>(
558 &self,
559 spec: &dyn KeyCertificateSpecifier,
560 ) -> Result<Option<(K, C)>>
561 where
562 K: ToEncodableKey,
563 C: ToEncodableCert<K>,
564 {
565 let subject_key_spec = spec.subject_key_specifier();
566 let Some(key) =
568 self.get_from_store::<K>(subject_key_spec, &K::Key::item_type(), self.all_stores())?
569 else {
570 return Ok(None);
571 };
572
573 let subject_key_arti_path = subject_key_spec
574 .arti_path()
575 .map_err(|_| bad_api_usage!("subject key does not have an ArtiPath?!"))?;
576 let cert_spec =
577 ArtiPath::from_path_and_denotators(subject_key_arti_path, &spec.cert_denotators())
578 .map_err(into_bad_api_usage!("invalid certificate specifier"))?;
579
580 let Some(cert) = self.get_from_store_raw::<C::ParsedCert>(
581 &cert_spec,
582 &<C::ParsedCert as ItemType>::item_type(),
583 self.all_stores(),
584 )?
585 else {
586 return Err(KeystoreCorruptionError::MissingCertificate.into());
587 };
588
589 let signed_with = self.get_cert_signing_key::<K, C>(spec)?;
591 let cert = C::validate(cert, &key, &signed_with)?;
592
593 Ok(Some((key, cert)))
594 }
595
596 #[cfg(feature = "experimental-api")]
632 pub fn get_or_generate_key_and_cert<K, C>(
633 &self,
634 spec: &dyn KeyCertificateSpecifier,
635 make_certificate: impl FnOnce(&K, &<C as ToEncodableCert<K>>::SigningKey) -> C,
636 selector: KeystoreSelector,
637 rng: &mut dyn KeygenRng,
638 ) -> Result<(K, C)>
639 where
640 K: ToEncodableKey,
641 K::Key: Keygen,
642 C: ToEncodableCert<K>,
643 {
644 let subject_key_spec = spec.subject_key_specifier();
645 let subject_key_arti_path = subject_key_spec
646 .arti_path()
647 .map_err(|_| bad_api_usage!("subject key does not have an ArtiPath?!"))?;
648
649 let cert_specifier =
650 ArtiPath::from_path_and_denotators(subject_key_arti_path, &spec.cert_denotators())
651 .map_err(into_bad_api_usage!("invalid certificate specifier"))?;
652
653 let maybe_cert = self.get_from_store_raw::<C::ParsedCert>(
654 &cert_specifier,
655 &C::ParsedCert::item_type(),
656 self.all_stores(),
657 )?;
658
659 let maybe_subject_key = self.get::<K>(subject_key_spec)?;
660
661 match (&maybe_cert, &maybe_subject_key) {
662 (Some(_), None) => {
663 return Err(KeystoreCorruptionError::MissingSubjectKey.into());
664 }
665 _ => {
666 }
668 }
669 let subject_key = match maybe_subject_key {
670 Some(key) => key,
671 _ => self.generate(subject_key_spec, selector, rng, false)?,
672 };
673
674 let signed_with = self.get_cert_signing_key::<K, C>(spec)?;
675 let cert = match maybe_cert {
676 Some(cert) => C::validate(cert, &subject_key, &signed_with)?,
677 None => {
678 let cert = make_certificate(&subject_key, &signed_with);
679
680 let () = self.insert_cert(cert.clone(), &cert_specifier, selector)?;
681
682 cert
683 }
684 };
685
686 Ok((subject_key, cert))
687 }
688
689 fn all_stores(&self) -> impl Iterator<Item = &BoxedKeystore> {
691 iter::once(&self.primary_store).chain(self.secondary_stores.iter())
692 }
693
694 fn select_keystore(&self, selector: &KeystoreSelector) -> Result<&BoxedKeystore> {
699 match selector {
700 KeystoreSelector::Id(keystore_id) => self.find_keystore(keystore_id),
701 KeystoreSelector::Primary => Ok(&self.primary_store),
702 }
703 }
704
705 fn find_keystore(&self, id: &KeystoreId) -> Result<&BoxedKeystore> {
710 self.all_stores()
711 .find(|keystore| keystore.id() == id)
712 .ok_or_else(|| crate::Error::KeystoreNotFound(id.clone()))
713 }
714
715 #[cfg(feature = "experimental-api")]
720 fn get_cert_signing_key<K, C>(
721 &self,
722 spec: &dyn KeyCertificateSpecifier,
723 ) -> Result<C::SigningKey>
724 where
725 K: ToEncodableKey,
726 C: ToEncodableCert<K>,
727 {
728 let Some(signing_key_spec) = spec.signing_key_specifier() else {
729 return Err(bad_api_usage!(
730 "signing key specifier is None, but external signing key was not provided?"
731 )
732 .into());
733 };
734
735 let Some(signing_key) = self.get_from_store::<C::SigningKey>(
736 signing_key_spec,
737 &<C::SigningKey as ToEncodableKey>::Key::item_type(),
738 self.all_stores(),
739 )?
740 else {
741 return Err(KeystoreCorruptionError::MissingSigningKey.into());
742 };
743
744 Ok(signing_key)
745 }
746
747 fn insert_cert<K, C>(
754 &self,
755 cert: C,
756 cert_spec: &dyn KeySpecifier,
757 selector: KeystoreSelector,
758 ) -> Result<()>
759 where
760 K: ToEncodableKey,
761 K::Key: Keygen,
762 C: ToEncodableCert<K>,
763 {
764 let cert = cert.to_encodable_cert();
765 let store = self.select_keystore(&selector)?;
766
767 let () = store.insert(&cert, cert_spec)?;
768 Ok(())
769 }
770}
771
772#[cfg(test)]
773mod tests {
774 #![allow(clippy::bool_assert_comparison)]
776 #![allow(clippy::clone_on_copy)]
777 #![allow(clippy::dbg_macro)]
778 #![allow(clippy::mixed_attributes_style)]
779 #![allow(clippy::print_stderr)]
780 #![allow(clippy::print_stdout)]
781 #![allow(clippy::single_char_pattern)]
782 #![allow(clippy::unwrap_used)]
783 #![allow(clippy::unchecked_time_subtraction)]
784 #![allow(clippy::useless_vec)]
785 #![allow(clippy::needless_pass_by_value)]
786 use super::*;
788 use crate::keystore::arti::err::{ArtiNativeKeystoreError, MalformedPathError};
789 use crate::raw::{RawEntryId, RawKeystoreEntry};
790 use crate::{
791 ArtiPath, ArtiPathUnavailableError, Error, KeyPath, KeystoreEntryResult, KeystoreError,
792 UnrecognizedEntryError,
793 };
794 use std::path::PathBuf;
795 use std::result::Result as StdResult;
796 use std::str::FromStr;
797 use std::sync::{Arc, RwLock};
798 use std::time::{Duration, SystemTime};
799 use tor_basic_utils::test_rng::testing_rng;
800 use tor_cert::CertifiedKey;
801 use tor_cert::Ed25519Cert;
802 use tor_error::{ErrorKind, HasKind};
803 use tor_key_forge::{
804 CertData, EncodableItem, ErasedKey, InvalidCertError, KeyType, KeystoreItem,
805 };
806 use tor_llcrypto::pk::ed25519::{self, Ed25519PublicKey as _};
807 use tor_llcrypto::rng::FakeEntropicRng;
808
809 #[derive(Clone, Debug, PartialEq)]
811 struct KeyMetadata {
812 item_id: String,
814 retrieved_from: Option<KeystoreId>,
818 is_generated: bool,
820 }
821
822 #[derive(Clone, Debug, PartialEq)]
824 struct CertMetadata {
825 subject_key_id: String,
827 signing_key_id: String,
829 retrieved_from: Option<KeystoreId>,
833 is_generated: bool,
836 }
837
838 #[derive(Clone, Debug, PartialEq, derive_more::From)]
840 enum ItemMetadata {
841 Key(KeyMetadata),
843 Cert(CertMetadata),
845 }
846
847 impl ItemMetadata {
848 fn item_id(&self) -> &str {
853 match self {
854 ItemMetadata::Key(k) => &k.item_id,
855 ItemMetadata::Cert(c) => &c.subject_key_id,
856 }
857 }
858
859 fn retrieved_from(&self) -> Option<&KeystoreId> {
861 match self {
862 ItemMetadata::Key(k) => k.retrieved_from.as_ref(),
863 ItemMetadata::Cert(c) => c.retrieved_from.as_ref(),
864 }
865 }
866
867 fn is_generated(&self) -> bool {
869 match self {
870 ItemMetadata::Key(k) => k.is_generated,
871 ItemMetadata::Cert(c) => c.is_generated,
872 }
873 }
874
875 fn set_retrieved_from(&mut self, id: KeystoreId) {
877 match self {
878 ItemMetadata::Key(meta) => meta.retrieved_from = Some(id),
879 ItemMetadata::Cert(meta) => meta.retrieved_from = Some(id),
880 }
881 }
882
883 fn as_key(&self) -> Option<&KeyMetadata> {
885 match self {
886 ItemMetadata::Key(meta) => Some(meta),
887 _ => None,
888 }
889 }
890
891 fn as_cert(&self) -> Option<&CertMetadata> {
893 match self {
894 ItemMetadata::Cert(meta) => Some(meta),
895 _ => None,
896 }
897 }
898 }
899
900 #[derive(Clone, Debug)]
902 struct TestItem {
903 item: KeystoreItem,
905 meta: ItemMetadata,
907 }
908
909 #[derive(Clone, Debug)]
911 struct AlwaysValidCert(TestItem);
912
913 #[derive(Clone, Debug)]
915 struct TestPublicKey {
916 key: KeystoreItem,
918 }
919
920 impl From<TestItem> for TestPublicKey {
921 fn from(tk: TestItem) -> TestPublicKey {
922 TestPublicKey { key: tk.item }
923 }
924 }
925
926 impl TestItem {
927 fn new(item_id: &str) -> Self {
929 let mut rng = testing_rng();
930 TestItem {
931 item: ed25519::Keypair::generate(&mut rng)
932 .as_keystore_item()
933 .unwrap(),
934 meta: ItemMetadata::Key(KeyMetadata {
935 item_id: item_id.to_string(),
936 retrieved_from: None,
937 is_generated: false,
938 }),
939 }
940 }
941 }
942
943 impl Keygen for TestItem {
944 fn generate(mut rng: &mut dyn KeygenRng) -> tor_key_forge::Result<Self>
945 where
946 Self: Sized,
947 {
948 Ok(TestItem {
949 item: ed25519::Keypair::generate(&mut rng).as_keystore_item()?,
950 meta: ItemMetadata::Key(KeyMetadata {
951 item_id: "generated_test_key".to_string(),
952 retrieved_from: None,
953 is_generated: true,
954 }),
955 })
956 }
957 }
958
959 impl ItemType for TestItem {
960 fn item_type() -> KeystoreItemType
961 where
962 Self: Sized,
963 {
964 KeyType::Ed25519Keypair.into()
966 }
967 }
968
969 impl EncodableItem for TestItem {
970 fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
971 Ok(self.item.clone())
972 }
973 }
974
975 impl ToEncodableKey for TestItem {
976 type Key = Self;
977 type KeyPair = Self;
978
979 fn to_encodable_key(self) -> Self::Key {
980 self
981 }
982
983 fn from_encodable_key(key: Self::Key) -> Self {
984 key
985 }
986 }
987
988 impl ItemType for TestPublicKey {
989 fn item_type() -> KeystoreItemType
990 where
991 Self: Sized,
992 {
993 KeyType::Ed25519PublicKey.into()
994 }
995 }
996
997 impl EncodableItem for TestPublicKey {
998 fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
999 Ok(self.key.clone())
1000 }
1001 }
1002
1003 impl ToEncodableKey for TestPublicKey {
1004 type Key = Self;
1005 type KeyPair = TestItem;
1006
1007 fn to_encodable_key(self) -> Self::Key {
1008 self
1009 }
1010
1011 fn from_encodable_key(key: Self::Key) -> Self {
1012 key
1013 }
1014 }
1015
1016 impl ToEncodableCert<TestItem> for AlwaysValidCert {
1017 type ParsedCert = TestItem;
1018 type EncodableCert = TestItem;
1019 type SigningKey = TestItem;
1020
1021 fn validate(
1022 cert: Self::ParsedCert,
1023 _subject: &TestItem,
1024 _signed_with: &Self::SigningKey,
1025 ) -> StdResult<Self, InvalidCertError> {
1026 Ok(Self(cert))
1028 }
1029
1030 fn to_encodable_cert(self) -> Self::EncodableCert {
1032 self.0
1033 }
1034 }
1035
1036 #[derive(thiserror::Error, Debug, Clone, derive_more::Display)]
1037 enum MockKeystoreError {
1038 NotFound,
1039 }
1040
1041 impl KeystoreError for MockKeystoreError {}
1042
1043 impl HasKind for MockKeystoreError {
1044 fn kind(&self) -> ErrorKind {
1045 tor_error::ErrorKind::Other
1047 }
1048 }
1049
1050 fn build_raw_id_path<T: ToString>(key_path: &T, key_type: &KeystoreItemType) -> RawEntryId {
1051 let mut path = key_path.to_string();
1052 path.push('.');
1053 path.push_str(&key_type.arti_extension());
1054 RawEntryId::Path(PathBuf::from(&path))
1055 }
1056
1057 macro_rules! impl_keystore {
1058 ($name:tt, $id:expr $(,$unrec:expr)?) => {
1059 struct $name {
1060 inner: RwLock<
1061 Vec<StdResult<(ArtiPath, KeystoreItemType, TestItem), UnrecognizedEntryError>>,
1062 >,
1063 id: KeystoreId,
1064 }
1065
1066 impl Default for $name {
1067 fn default() -> Self {
1068 let id = KeystoreId::from_str($id).unwrap();
1069 let inner: RwLock<
1070 Vec<
1071 StdResult<
1072 (ArtiPath, KeystoreItemType, TestItem),
1073 UnrecognizedEntryError,
1074 >,
1075 >,
1076 > = Default::default();
1077 $(
1080 for i in 0..$unrec {
1081 let invalid_key_path =
1082 PathBuf::from(&format!("unrecognized_entry{}", i));
1083 let raw_id = RawEntryId::Path(invalid_key_path.clone());
1084 let entry = RawKeystoreEntry::new(raw_id, id.clone()).into();
1085 let entry = UnrecognizedEntryError::new(
1086 entry,
1087 Arc::new(ArtiNativeKeystoreError::MalformedPath {
1088 path: invalid_key_path,
1089 err: MalformedPathError::NoExtension,
1090 }),
1091 );
1092 inner.write().unwrap().push(Err(entry));
1093 }
1094 )?
1095 Self {
1096 inner,
1097 id,
1098 }
1099 }
1100 }
1101
1102 #[allow(dead_code)] impl $name {
1104 fn new_boxed() -> BoxedKeystore {
1105 Box::<Self>::default()
1106 }
1107 }
1108
1109 impl crate::Keystore for $name {
1110 fn contains(
1111 &self,
1112 key_spec: &dyn KeySpecifier,
1113 item_type: &KeystoreItemType,
1114 ) -> Result<bool> {
1115 let wanted_arti_path = key_spec.arti_path().unwrap();
1116 Ok(self
1117 .inner
1118 .read()
1119 .unwrap()
1120 .iter()
1121 .find(|res| match res {
1122 Ok((spec, ty, _)) => spec == &wanted_arti_path && ty == item_type,
1123 Err(_) => false,
1124 })
1125 .is_some())
1126 }
1127
1128 fn id(&self) -> &KeystoreId {
1129 &self.id
1130 }
1131
1132 fn get(
1133 &self,
1134 key_spec: &dyn KeySpecifier,
1135 item_type: &KeystoreItemType,
1136 ) -> Result<Option<ErasedKey>> {
1137 let key_spec = key_spec.arti_path().unwrap();
1138
1139 Ok(self.inner.read().unwrap().iter().find_map(|res| {
1140 match res {
1141 Ok((arti_path, ty, k)) => {
1142 if arti_path == &key_spec && ty == item_type {
1143 let mut k = k.clone();
1144 k.meta.set_retrieved_from(self.id().clone());
1145 return Some(Box::new(k) as Box<dyn ItemType>);
1146 }
1147 }
1148 Err(_) => {}
1149 }
1150 None
1151 }))
1152 }
1153
1154 #[cfg(feature = "onion-service-cli-extra")]
1155 fn raw_entry_id(&self, raw_id: &str) -> Result<RawEntryId> {
1156 Ok(RawEntryId::Path(
1157 PathBuf::from(raw_id.to_string()),
1158 ))
1159 }
1160
1161 fn insert(
1162 &self,
1163 key: &dyn EncodableItem,
1164 key_spec: &dyn KeySpecifier,
1165 ) -> Result<()> {
1166 let key = key.downcast_ref::<TestItem>().unwrap();
1167
1168 let item = key.as_keystore_item()?;
1169 let meta = key.meta.clone();
1170
1171 let item_type = item.item_type()?;
1172 let key = TestItem { item, meta };
1173
1174 self.inner
1175 .write()
1176 .unwrap()
1177 .insert(0, (Ok((key_spec.arti_path().unwrap(), item_type, key))));
1182
1183 Ok(())
1184 }
1185
1186 fn remove(
1187 &self,
1188 key_spec: &dyn KeySpecifier,
1189 item_type: &KeystoreItemType,
1190 ) -> Result<Option<()>> {
1191 let wanted_arti_path = key_spec.arti_path().unwrap();
1192 let index = self.inner.read().unwrap().iter().position(|res| {
1193 if let Ok((arti_path, ty, _)) = res {
1194 arti_path == &wanted_arti_path && ty == item_type
1195 } else {
1196 false
1197 }
1198 });
1199 let Some(index) = index else {
1200 return Ok(None);
1201 };
1202 let _ = self.inner.write().unwrap().remove(index);
1203
1204 Ok(Some(()))
1205 }
1206
1207 #[cfg(feature = "onion-service-cli-extra")]
1208 fn remove_unchecked(&self, entry_id: &RawEntryId) -> Result<()> {
1209 let index = self.inner.read().unwrap().iter().position(|res| match res {
1210 Ok((spec, ty, _)) => {
1211 let id = build_raw_id_path(spec, ty);
1212 entry_id == &id
1213 }
1214 Err(e) => {
1215 e.entry().raw_id() == entry_id
1216 }
1217 });
1218 let Some(index) = index else {
1219 return Err(Error::Keystore(Arc::new(MockKeystoreError::NotFound)));
1220 };
1221 let _ = self.inner.write().unwrap().remove(index);
1222 Ok(())
1223 }
1224
1225 fn list(&self) -> Result<Vec<KeystoreEntryResult<KeystoreEntry>>> {
1226 Ok(self
1227 .inner
1228 .read()
1229 .unwrap()
1230 .iter()
1231 .map(|res| match res {
1232 Ok((arti_path, ty, _)) => {
1233 let raw_id = RawEntryId::Path(
1234 PathBuf::from(
1235 &arti_path.to_string(),
1236 )
1237 );
1238
1239 Ok(KeystoreEntry::new(KeyPath::Arti(arti_path.clone()), ty.clone(), self.id(), raw_id))
1240 }
1241 Err(e) => Err(e.clone()),
1242 })
1243 .collect())
1244 }
1245 }
1246 };
1247 }
1248
1249 macro_rules! impl_specifier {
1250 ($name:tt, $id:expr) => {
1251 struct $name;
1252
1253 impl KeySpecifier for $name {
1254 fn arti_path(&self) -> StdResult<ArtiPath, ArtiPathUnavailableError> {
1255 Ok(ArtiPath::new($id.into()).map_err(|e| tor_error::internal!("{e}"))?)
1256 }
1257
1258 fn ctor_path(&self) -> Option<crate::CTorPath> {
1259 None
1260 }
1261
1262 fn keypair_specifier(&self) -> Option<Box<dyn KeySpecifier>> {
1263 None
1264 }
1265 }
1266 };
1267 }
1268
1269 impl_keystore!(Keystore1, "keystore1");
1270 impl_keystore!(Keystore2, "keystore2");
1271 impl_keystore!(Keystore3, "keystore3");
1272 impl_keystore!(KeystoreUnrec1, "keystore_unrec1", 1);
1273
1274 impl_specifier!(TestKeySpecifier1, "spec1");
1275 impl_specifier!(TestKeySpecifier2, "spec2");
1276 impl_specifier!(TestKeySpecifier3, "spec3");
1277 impl_specifier!(TestKeySpecifier4, "spec4");
1278
1279 impl_specifier!(TestPublicKeySpecifier1, "pub-spec1");
1280
1281 fn entry_descriptor(specifier: impl KeySpecifier, keystore_id: &KeystoreId) -> KeystoreEntry {
1283 let arti_path = specifier.arti_path().unwrap();
1284 let raw_id = RawEntryId::Path(PathBuf::from(arti_path.as_ref()));
1285 KeystoreEntry {
1286 key_path: arti_path.into(),
1287 key_type: TestItem::item_type(),
1288 keystore_id,
1289 raw_id,
1290 }
1291 }
1292
1293 #[test]
1294 #[allow(clippy::cognitive_complexity)]
1295 fn insert_and_get() {
1296 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1297
1298 builder
1299 .secondary_stores()
1300 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1301
1302 let mgr = builder.build().unwrap();
1303
1304 let old_key = mgr
1306 .insert(
1307 TestItem::new("coot"),
1308 &TestKeySpecifier1,
1309 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1310 true,
1311 )
1312 .unwrap();
1313
1314 assert!(old_key.is_none());
1315 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1316 assert_eq!(key.meta.item_id(), "coot");
1317 assert_eq!(
1318 key.meta.retrieved_from(),
1319 Some(&KeystoreId::from_str("keystore2").unwrap())
1320 );
1321 assert_eq!(key.meta.is_generated(), false);
1322
1323 let old_key = mgr
1325 .insert(
1326 TestItem::new("gull"),
1327 &TestKeySpecifier1,
1328 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1329 true,
1330 )
1331 .unwrap()
1332 .unwrap();
1333 assert_eq!(old_key.meta.item_id(), "coot");
1334 assert_eq!(
1335 old_key.meta.retrieved_from(),
1336 Some(&KeystoreId::from_str("keystore2").unwrap())
1337 );
1338 assert_eq!(old_key.meta.is_generated(), false);
1339 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1341 assert_eq!(key.meta.item_id(), "gull");
1342 assert_eq!(
1343 key.meta.retrieved_from(),
1344 Some(&KeystoreId::from_str("keystore2").unwrap())
1345 );
1346 assert_eq!(key.meta.is_generated(), false);
1347
1348 let err = mgr
1350 .insert(
1351 TestItem::new("gull"),
1352 &TestKeySpecifier1,
1353 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1354 false,
1355 )
1356 .unwrap_err();
1357 assert!(matches!(err, crate::Error::KeyAlreadyExists));
1358
1359 let old_key = mgr
1361 .insert(
1362 TestItem::new("penguin"),
1363 &TestKeySpecifier2,
1364 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1365 false,
1366 )
1367 .unwrap();
1368 assert!(old_key.is_none());
1369
1370 let old_key = mgr
1372 .insert(
1373 TestItem::new("moorhen"),
1374 &TestKeySpecifier3,
1375 KeystoreSelector::Primary,
1376 true,
1377 )
1378 .unwrap();
1379 assert!(old_key.is_none());
1380 let key = mgr.get::<TestItem>(&TestKeySpecifier3).unwrap().unwrap();
1381 assert_eq!(key.meta.item_id(), "moorhen");
1382 assert_eq!(
1383 key.meta.retrieved_from(),
1384 Some(&KeystoreId::from_str("keystore1").unwrap())
1385 );
1386 assert_eq!(key.meta.is_generated(), false);
1387
1388 assert!(mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().is_none());
1390
1391 for store in ["keystore3", "keystore2", "keystore1"] {
1395 let old_key = mgr
1396 .insert(
1397 TestItem::new("cormorant"),
1398 &TestKeySpecifier4,
1399 KeystoreSelector::Id(&KeystoreId::from_str(store).unwrap()),
1400 true,
1401 )
1402 .unwrap();
1403 assert!(old_key.is_none());
1404
1405 let key = mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().unwrap();
1407 assert_eq!(key.meta.item_id(), "cormorant");
1408 assert_eq!(
1409 key.meta.retrieved_from(),
1410 Some(&KeystoreId::from_str(store).unwrap())
1411 );
1412 assert_eq!(key.meta.is_generated(), false);
1413 }
1414
1415 let key = mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().unwrap();
1418 assert_eq!(key.meta.item_id(), "cormorant");
1419 assert_eq!(
1420 key.meta.retrieved_from(),
1421 Some(&KeystoreId::from_str("keystore1").unwrap())
1422 );
1423 assert_eq!(key.meta.is_generated(), false);
1424 }
1425
1426 #[test]
1427 #[cfg(feature = "onion-service-cli-extra")]
1428 fn get_from() {
1429 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1430
1431 builder
1432 .secondary_stores()
1433 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1434
1435 let mgr = builder.build().unwrap();
1436
1437 let keystore1_id = KeystoreId::from_str("keystore1").unwrap();
1438 let keystore2_id = KeystoreId::from_str("keystore2").unwrap();
1439 let key_id_1 = "mantis shrimp";
1440 let key_id_2 = "tardigrade";
1441
1442 let _ = mgr
1444 .insert(
1445 TestItem::new(key_id_1),
1446 &TestKeySpecifier1,
1447 KeystoreSelector::Id(&keystore1_id),
1448 true,
1449 )
1450 .unwrap();
1451
1452 let _ = mgr
1454 .insert(
1455 TestItem::new(key_id_2),
1456 &TestKeySpecifier1,
1457 KeystoreSelector::Id(&keystore2_id),
1458 true,
1459 )
1460 .unwrap();
1461
1462 let key = mgr
1464 .get_from::<TestItem>(&TestKeySpecifier1, &keystore2_id)
1465 .unwrap()
1466 .unwrap();
1467
1468 assert_eq!(key.meta.item_id(), key_id_2);
1469 assert_eq!(key.meta.retrieved_from(), Some(&keystore2_id));
1470 }
1471
1472 #[test]
1473 fn remove() {
1474 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1475
1476 builder
1477 .secondary_stores()
1478 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1479
1480 let mgr = builder.build().unwrap();
1481
1482 assert!(
1483 !mgr.secondary_stores[0]
1484 .contains(&TestKeySpecifier1, &TestItem::item_type())
1485 .unwrap()
1486 );
1487
1488 mgr.insert(
1490 TestItem::new("coot"),
1491 &TestKeySpecifier1,
1492 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1493 true,
1494 )
1495 .unwrap();
1496 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1497 assert_eq!(key.meta.item_id(), "coot");
1498 assert_eq!(
1499 key.meta.retrieved_from(),
1500 Some(&KeystoreId::from_str("keystore2").unwrap())
1501 );
1502 assert_eq!(key.meta.is_generated(), false);
1503
1504 assert!(
1506 mgr.remove::<TestItem>(
1507 &TestKeySpecifier1,
1508 KeystoreSelector::Id(&KeystoreId::from_str("not_an_id_we_know_of").unwrap())
1509 )
1510 .is_err()
1511 );
1512 assert!(
1514 mgr.secondary_stores[0]
1515 .contains(&TestKeySpecifier1, &TestItem::item_type())
1516 .unwrap()
1517 );
1518
1519 assert!(
1521 mgr.remove::<TestItem>(&TestKeySpecifier1, KeystoreSelector::Primary)
1522 .unwrap()
1523 .is_none()
1524 );
1525
1526 assert!(
1528 mgr.secondary_stores[0]
1529 .contains(&TestKeySpecifier1, &TestItem::item_type())
1530 .unwrap()
1531 );
1532
1533 let removed_key = mgr
1535 .remove::<TestItem>(
1536 &TestKeySpecifier1,
1537 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1538 )
1539 .unwrap()
1540 .unwrap();
1541 assert_eq!(removed_key.meta.item_id(), "coot");
1542 assert_eq!(
1543 removed_key.meta.retrieved_from(),
1544 Some(&KeystoreId::from_str("keystore2").unwrap())
1545 );
1546 assert_eq!(removed_key.meta.is_generated(), false);
1547
1548 assert!(
1550 !mgr.secondary_stores[0]
1551 .contains(&TestKeySpecifier1, &TestItem::item_type())
1552 .unwrap()
1553 );
1554 }
1555
1556 #[test]
1557 fn keygen() {
1558 let mut rng = FakeEntropicRng(testing_rng());
1559 let mgr = KeyMgrBuilder::default()
1560 .primary_store(Box::<Keystore1>::default())
1561 .build()
1562 .unwrap();
1563
1564 mgr.insert(
1565 TestItem::new("coot"),
1566 &TestKeySpecifier1,
1567 KeystoreSelector::Primary,
1568 true,
1569 )
1570 .unwrap();
1571
1572 assert!(
1574 mgr.get::<TestPublicKey>(&TestPublicKeySpecifier1)
1575 .unwrap()
1576 .is_none()
1577 );
1578
1579 let err = mgr
1581 .generate::<TestItem>(
1582 &TestKeySpecifier1,
1583 KeystoreSelector::Primary,
1584 &mut rng,
1585 false,
1586 )
1587 .unwrap_err();
1588
1589 assert!(matches!(err, crate::Error::KeyAlreadyExists));
1590
1591 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1593 assert_eq!(key.meta.item_id(), "coot");
1594 assert_eq!(
1595 key.meta.retrieved_from(),
1596 Some(&KeystoreId::from_str("keystore1").unwrap())
1597 );
1598 assert_eq!(key.meta.is_generated(), false);
1599
1600 assert!(
1602 mgr.get::<TestPublicKey>(&TestPublicKeySpecifier1)
1603 .unwrap()
1604 .is_none()
1605 );
1606
1607 let generated_key = mgr
1609 .generate::<TestItem>(
1610 &TestKeySpecifier1,
1611 KeystoreSelector::Primary,
1612 &mut rng,
1613 true,
1614 )
1615 .unwrap();
1616
1617 assert_eq!(generated_key.meta.item_id(), "generated_test_key");
1618 assert_eq!(generated_key.meta.retrieved_from(), None);
1621 assert_eq!(generated_key.meta.is_generated(), true);
1622
1623 let retrieved_key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1625 assert_eq!(retrieved_key.meta.item_id(), "generated_test_key");
1626 assert_eq!(
1627 retrieved_key.meta.retrieved_from(),
1628 Some(&KeystoreId::from_str("keystore1").unwrap())
1629 );
1630 assert_eq!(retrieved_key.meta.is_generated(), true);
1631
1632 assert!(
1634 mgr.get::<TestPublicKey>(&TestPublicKeySpecifier1)
1635 .unwrap()
1636 .is_none()
1637 );
1638 }
1639
1640 #[test]
1641 fn get_or_generate() {
1642 let mut rng = FakeEntropicRng(testing_rng());
1643 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1644
1645 builder
1646 .secondary_stores()
1647 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1648
1649 let mgr = builder.build().unwrap();
1650
1651 let keystore2 = KeystoreId::from_str("keystore2").unwrap();
1652 let entry_desc1 = entry_descriptor(TestKeySpecifier1, &keystore2);
1653 assert!(mgr.get_entry::<TestItem>(&entry_desc1).unwrap().is_none());
1654
1655 mgr.insert(
1656 TestItem::new("coot"),
1657 &TestKeySpecifier1,
1658 KeystoreSelector::Id(&keystore2),
1659 true,
1660 )
1661 .unwrap();
1662
1663 let key = mgr
1665 .get_or_generate::<TestItem>(&TestKeySpecifier1, KeystoreSelector::Primary, &mut rng)
1666 .unwrap();
1667 assert_eq!(key.meta.item_id(), "coot");
1668 assert_eq!(
1669 key.meta.retrieved_from(),
1670 Some(&KeystoreId::from_str("keystore2").unwrap())
1671 );
1672 assert_eq!(key.meta.is_generated(), false);
1673
1674 assert_eq!(
1675 mgr.get_entry::<TestItem>(&entry_desc1)
1676 .unwrap()
1677 .map(|k| k.meta),
1678 Some(ItemMetadata::Key(KeyMetadata {
1679 item_id: "coot".to_string(),
1680 retrieved_from: Some(keystore2.clone()),
1681 is_generated: false,
1682 }))
1683 );
1684
1685 let keystore3 = KeystoreId::from_str("keystore3").unwrap();
1688 let generated_key = mgr
1689 .get_or_generate::<TestItem>(
1690 &TestKeySpecifier2,
1691 KeystoreSelector::Id(&keystore3),
1692 &mut rng,
1693 )
1694 .unwrap();
1695 assert_eq!(generated_key.meta.item_id(), "generated_test_key");
1696 assert_eq!(generated_key.meta.retrieved_from(), None);
1699 assert_eq!(generated_key.meta.is_generated(), true);
1700
1701 let retrieved_key = mgr.get::<TestItem>(&TestKeySpecifier2).unwrap().unwrap();
1703 assert_eq!(retrieved_key.meta.item_id(), "generated_test_key");
1704 assert_eq!(
1705 retrieved_key.meta.retrieved_from(),
1706 Some(&KeystoreId::from_str("keystore3").unwrap())
1707 );
1708 assert_eq!(retrieved_key.meta.is_generated(), true);
1709
1710 let entry_desc2 = entry_descriptor(TestKeySpecifier2, &keystore3);
1711 assert_eq!(
1712 mgr.get_entry::<TestItem>(&entry_desc2)
1713 .unwrap()
1714 .map(|k| k.meta),
1715 Some(ItemMetadata::Key(KeyMetadata {
1716 item_id: "generated_test_key".to_string(),
1717 retrieved_from: Some(keystore3.clone()),
1718 is_generated: true,
1719 }))
1720 );
1721
1722 let arti_pat = KeyPathPattern::Arti("*".to_string());
1723 let matching = mgr.list_matching(&arti_pat).unwrap();
1724
1725 assert_eq!(matching.len(), 2);
1726 assert!(matching.contains(&entry_desc1));
1727 assert!(matching.contains(&entry_desc2));
1728
1729 assert_eq!(mgr.remove_entry(&entry_desc2).unwrap(), Some(()));
1730 assert!(mgr.get_entry::<TestItem>(&entry_desc2).unwrap().is_none());
1731 assert!(mgr.remove_entry(&entry_desc2).unwrap().is_none());
1732 }
1733
1734 #[test]
1735 fn list_matching_ignores_unrecognized_keys() {
1736 let builder = KeyMgrBuilder::default().primary_store(Box::new(KeystoreUnrec1::default()));
1737
1738 let mgr = builder.build().unwrap();
1739
1740 let unrec_1 = KeystoreId::from_str("keystore_unrec1").unwrap();
1741 mgr.insert(
1742 TestItem::new("whale shark"),
1743 &TestKeySpecifier1,
1744 KeystoreSelector::Id(&unrec_1),
1745 true,
1746 )
1747 .unwrap();
1748
1749 let arti_pat = KeyPathPattern::Arti("*".to_string());
1750 let valid_key_path = KeyPath::Arti(TestKeySpecifier1.arti_path().unwrap());
1751 let matching = mgr.list_matching(&arti_pat).unwrap();
1752 assert_eq!(matching.len(), 1);
1754 assert_eq!(matching.first().unwrap().key_path(), &valid_key_path);
1755 }
1756
1757 #[cfg(feature = "onion-service-cli-extra")]
1758 #[test]
1759 fn keys_subcommands() {
1762 let mut builder =
1763 KeyMgrBuilder::default().primary_store(Box::new(KeystoreUnrec1::default()));
1764 builder
1765 .secondary_stores()
1766 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1767
1768 let mgr = builder.build().unwrap();
1769 let ks_unrec1id = KeystoreId::from_str("keystore_unrec1").unwrap();
1770 let keystore2id = KeystoreId::from_str("keystore2").unwrap();
1771 let keystore3id = KeystoreId::from_str("keystore3").unwrap();
1772
1773 let _ = mgr
1775 .insert(
1776 TestItem::new("pangolin"),
1777 &TestKeySpecifier1,
1778 KeystoreSelector::Id(&ks_unrec1id),
1779 true,
1780 )
1781 .unwrap();
1782
1783 let _ = mgr
1785 .insert(
1786 TestItem::new("coot"),
1787 &TestKeySpecifier2,
1788 KeystoreSelector::Id(&keystore2id),
1789 true,
1790 )
1791 .unwrap();
1792
1793 let _ = mgr
1795 .insert(
1796 TestItem::new("penguin"),
1797 &TestKeySpecifier3,
1798 KeystoreSelector::Id(&keystore3id),
1799 true,
1800 )
1801 .unwrap();
1802
1803 let assert_key = |path, ty, expected_path: &ArtiPath, expected_type| {
1804 assert_eq!(ty, expected_type);
1805 assert_eq!(path, &KeyPath::Arti(expected_path.clone()));
1806 };
1807 let item_type = TestItem::new("axolotl").item.item_type().unwrap();
1808 let unrecognized_entry_id = RawEntryId::Path(PathBuf::from("unrecognized_entry0"));
1809
1810 let entries = mgr.list().unwrap();
1812
1813 let expected_items = [
1814 (ks_unrec1id, TestKeySpecifier1.arti_path().unwrap()),
1815 (keystore2id, TestKeySpecifier2.arti_path().unwrap()),
1816 (keystore3id, TestKeySpecifier3.arti_path().unwrap()),
1817 ];
1818
1819 let mut recognized_entries = 0;
1821 let mut unrecognized_entries = 0;
1822 for entry in entries.iter() {
1823 match entry {
1824 Ok(e) => {
1825 if let Some((_, expected_arti_path)) = expected_items
1826 .iter()
1827 .find(|(keystore_id, _)| keystore_id == e.keystore_id())
1828 {
1829 assert_key(e.key_path(), e.key_type(), expected_arti_path, &item_type);
1830 recognized_entries += 1;
1831 continue;
1832 }
1833
1834 panic!("Unexpected key encountered {:?}", e);
1835 }
1836 Err(u) => {
1837 assert_eq!(u.entry().raw_id(), &unrecognized_entry_id);
1838 unrecognized_entries += 1;
1839 }
1840 }
1841 }
1842 assert_eq!(recognized_entries, 3);
1843 assert_eq!(unrecognized_entries, 1);
1844
1845 let keystores = mgr.list_keystores().iter().len();
1847
1848 assert_eq!(keystores, 3);
1849
1850 let primary_keystore_id = KeystoreId::from_str("keystore_unrec1").unwrap();
1852 let entries = mgr.list_by_id(&primary_keystore_id).unwrap();
1853
1854 let mut recognized_entries = 0;
1856 let mut unrecognized_entries = 0;
1857 let mut all_entries = vec![];
1859 for entry in entries.iter() {
1860 match entry {
1861 Ok(entry) => {
1862 assert_key(
1863 entry.key_path(),
1864 entry.key_type(),
1865 &TestKeySpecifier1.arti_path().unwrap(),
1866 &item_type,
1867 );
1868 recognized_entries += 1;
1869 all_entries.push(RawKeystoreEntry::new(
1870 build_raw_id_path(entry.key_path(), entry.key_type()),
1871 primary_keystore_id.clone(),
1872 ));
1873 }
1874 Err(u) => {
1875 assert_eq!(u.entry().raw_id(), &unrecognized_entry_id);
1876 unrecognized_entries += 1;
1877 all_entries.push(u.entry().into());
1878 }
1879 }
1880 }
1881 assert_eq!(recognized_entries, 1);
1882 assert_eq!(unrecognized_entries, 1);
1883
1884 for entry in all_entries {
1886 mgr.remove_unchecked(&entry.raw_id().to_string(), entry.keystore_id())
1887 .unwrap();
1888 }
1889
1890 let entries = mgr.list_by_id(&primary_keystore_id).unwrap();
1892 assert_eq!(entries.len(), 0);
1893 }
1894
1895 #[cfg(feature = "experimental-api")]
1897 #[derive(Clone, Copy, Debug, PartialEq)]
1898 enum GenerateItem {
1899 Yes,
1900 No,
1901 }
1902
1903 #[cfg(feature = "experimental-api")]
1904 macro_rules! run_certificate_test {
1905 (
1906 generate_subject_key = $generate_subject_key:expr,
1907 generate_signing_key = $generate_signing_key:expr,
1908 $($expected_err:tt)?
1909 ) => {{
1910 use GenerateItem::*;
1911
1912 let mut rng = FakeEntropicRng(testing_rng());
1913 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1914
1915 builder
1916 .secondary_stores()
1917 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1918
1919 let mgr = builder.build().unwrap();
1920
1921 let spec = crate::test_utils::TestCertSpecifier {
1922 subject_key_spec: TestKeySpecifier1,
1923 signing_key_spec: TestKeySpecifier2,
1924 denotator: vec!["foo".into()],
1925 };
1926
1927 if $generate_subject_key == Yes {
1928 let _ = mgr
1929 .generate::<TestItem>(
1930 &TestKeySpecifier1,
1931 KeystoreSelector::Primary,
1932 &mut rng,
1933 false,
1934 )
1935 .unwrap();
1936 }
1937
1938 if $generate_signing_key == Yes {
1939 let _ = mgr
1940 .generate::<TestItem>(
1941 &TestKeySpecifier2,
1942 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1943 &mut rng,
1944 false,
1945 )
1946 .unwrap();
1947 }
1948
1949 let make_certificate = move |subject_key: &TestItem, signed_with: &TestItem| {
1950 let subject_id = subject_key.meta.as_key().unwrap().item_id.clone();
1951 let signing_id = signed_with.meta.as_key().unwrap().item_id.clone();
1952
1953 let meta = ItemMetadata::Cert(CertMetadata {
1954 subject_key_id: subject_id,
1955 signing_key_id: signing_id,
1956 retrieved_from: None,
1957 is_generated: true,
1958 });
1959
1960 let mut rng = FakeEntropicRng(testing_rng());
1966 let keypair = ed25519::Keypair::generate(&mut rng);
1967 let encoded_cert = Ed25519Cert::constructor()
1968 .cert_type(tor_cert::CertType::IDENTITY_V_SIGNING)
1969 .expiration(SystemTime::now() + Duration::from_secs(180))
1970 .signing_key(keypair.public_key().into())
1971 .cert_key(CertifiedKey::Ed25519(keypair.public_key().into()))
1972 .encode_and_sign(&keypair)
1973 .unwrap();
1974 let test_cert = CertData::TorEd25519Cert(encoded_cert);
1975 AlwaysValidCert(TestItem {
1976 item: KeystoreItem::Cert(test_cert),
1977 meta,
1978 })
1979 };
1980
1981 let res = mgr
1982 .get_or_generate_key_and_cert::<TestItem, AlwaysValidCert>(
1983 &spec,
1984 &make_certificate,
1985 KeystoreSelector::Primary,
1986 &mut rng,
1987 );
1988
1989 #[allow(unused_assignments)]
1990 #[allow(unused_mut)]
1991 let mut has_error = false;
1992 $(
1993 has_error = true;
1994 let err = res.clone().unwrap_err();
1995 assert!(
1996 matches!(
1997 err,
1998 crate::Error::Corruption(KeystoreCorruptionError::$expected_err)
1999 ),
2000 "unexpected error: {err:?}",
2001 );
2002 )?
2003
2004 if !has_error {
2005 let (key, cert) = res.unwrap();
2006
2007 let expected_subj_key_id = if $generate_subject_key == Yes {
2008 "generated_test_key"
2009 } else {
2010 "generated_test_key"
2011 };
2012
2013 assert_eq!(key.meta.item_id(), expected_subj_key_id);
2014 assert_eq!(
2015 cert.0.meta.as_cert().unwrap().subject_key_id,
2016 expected_subj_key_id
2017 );
2018 assert_eq!(
2019 cert.0.meta.as_cert().unwrap().signing_key_id,
2020 "generated_test_key"
2021 );
2022 assert_eq!(cert.0.meta.is_generated(), true);
2023 }
2024 }}
2025 }
2026
2027 #[test]
2028 #[cfg(feature = "experimental-api")]
2029 #[rustfmt::skip] #[allow(clippy::cognitive_complexity)] fn get_certificate() {
2032 run_certificate_test!(
2033 generate_subject_key = No,
2034 generate_signing_key = No,
2035 MissingSigningKey
2036 );
2037
2038 run_certificate_test!(
2039 generate_subject_key = Yes,
2040 generate_signing_key = No,
2041 MissingSigningKey
2042 );
2043
2044 run_certificate_test!(
2045 generate_subject_key = No,
2046 generate_signing_key = Yes,
2047 );
2048
2049 run_certificate_test!(
2050 generate_subject_key = Yes,
2051 generate_signing_key = Yes,
2052 );
2053 }
2054}