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