1use crate::{
6 ArtiPath, BoxedKeystore, KeyCertificateSpecifier, KeyPath, KeyPathError, KeyPathInfo,
7 KeyPathInfoExtractor, KeyPathPattern, KeySpecifier, KeystoreCorruptionError, KeystoreId,
8 KeystoreSelector, Result,
9};
10
11use itertools::Itertools;
12use std::iter;
13use std::result::Result as StdResult;
14use tor_error::{bad_api_usage, internal, into_bad_api_usage};
15use tor_key_forge::{
16 ItemType, Keygen, KeygenRng, KeystoreItemType, ToEncodableCert, ToEncodableKey,
17};
18
19#[derive(derive_builder::Builder)]
43#[builder(pattern = "owned", build_fn(private, name = "build_unvalidated"))]
44pub struct KeyMgr {
45 primary_store: BoxedKeystore,
47 #[builder(default, setter(custom))]
49 secondary_stores: Vec<BoxedKeystore>,
50 #[builder(default, setter(skip))]
55 key_info_extractors: Vec<&'static dyn KeyPathInfoExtractor>,
56}
57
58#[derive(Clone, Debug, PartialEq, amplify::Getters)]
66pub struct KeystoreEntry<'a> {
67 key_path: KeyPath,
69 key_type: KeystoreItemType,
71 #[getter(as_copy)]
73 keystore_id: &'a KeystoreId,
74}
75
76impl KeyMgrBuilder {
77 pub fn build(self) -> StdResult<KeyMgr, KeyMgrBuilderError> {
79 use itertools::Itertools as _;
80
81 let mut keymgr = self.build_unvalidated()?;
82
83 if !keymgr.all_stores().map(|s| s.id()).all_unique() {
84 return Err(KeyMgrBuilderError::ValidationError(
85 "the keystore IDs are not pairwise unique".into(),
86 ));
87 }
88
89 keymgr.key_info_extractors = inventory::iter::<&'static dyn KeyPathInfoExtractor>
90 .into_iter()
91 .copied()
92 .collect();
93
94 Ok(keymgr)
95 }
96}
97
98impl KeyMgrBuilder {
103 pub fn secondary_stores(&mut self) -> &mut Vec<BoxedKeystore> {
109 self.secondary_stores.get_or_insert(Default::default())
110 }
111
112 pub fn set_secondary_stores(mut self, list: Vec<BoxedKeystore>) -> Self {
114 self.secondary_stores = Some(list);
115 self
116 }
117
118 pub fn opt_secondary_stores(&self) -> &Option<Vec<BoxedKeystore>> {
122 &self.secondary_stores
123 }
124
125 pub fn opt_secondary_stores_mut(&mut self) -> &mut Option<Vec<BoxedKeystore>> {
129 &mut self.secondary_stores
130 }
131}
132
133inventory::collect!(&'static dyn crate::KeyPathInfoExtractor);
134
135impl KeyMgr {
136 pub fn get<K: ToEncodableKey>(&self, key_spec: &dyn KeySpecifier) -> Result<Option<K>> {
143 let result = self.get_from_store(key_spec, &K::Key::item_type(), self.all_stores())?;
144 if result.is_none() {
145 if let Some(key_pair_spec) = key_spec.keypair_specifier() {
148 return Ok(self.get::<K::KeyPair>(&*key_pair_spec)?.map(|k| k.into()));
149 }
150 }
151 Ok(result)
152 }
153
154 pub fn get_entry<K: ToEncodableKey>(&self, entry: &KeystoreEntry) -> Result<Option<K>> {
162 let selector = entry.keystore_id().into();
163 let store = self.select_keystore(&selector)?;
164 self.get_from_store(entry.key_path(), entry.key_type(), [store].into_iter())
165 }
166
167 pub fn get_or_generate<K>(
179 &self,
180 key_spec: &dyn KeySpecifier,
181 selector: KeystoreSelector,
182 rng: &mut dyn KeygenRng,
183 ) -> Result<K>
184 where
185 K: ToEncodableKey,
186 K::Key: Keygen,
187 {
188 match self.get(key_spec)? {
189 Some(k) => Ok(k),
190 None => self.generate(key_spec, selector, rng, false),
191 }
192 }
193
194 pub fn generate<K>(
215 &self,
216 key_spec: &dyn KeySpecifier,
217 selector: KeystoreSelector,
218 rng: &mut dyn KeygenRng,
219 overwrite: bool,
220 ) -> Result<K>
221 where
222 K: ToEncodableKey,
223 K::Key: Keygen,
224 {
225 let store = self.select_keystore(&selector)?;
226
227 if overwrite || !store.contains(key_spec, &K::Key::item_type())? {
228 let key = K::Key::generate(rng)?;
229 store.insert(&key, key_spec)?;
230
231 Ok(K::from_encodable_key(key))
232 } else {
233 Err(crate::Error::KeyAlreadyExists)
234 }
235 }
236
237 pub fn insert<K: ToEncodableKey>(
250 &self,
251 key: K,
252 key_spec: &dyn KeySpecifier,
253 selector: KeystoreSelector,
254 overwrite: bool,
255 ) -> Result<Option<K>> {
256 let key = key.to_encodable_key();
257 let store = self.select_keystore(&selector)?;
258 let key_type = K::Key::item_type();
259 let old_key: Option<K> = self.get_from_store(key_spec, &key_type, [store].into_iter())?;
260
261 if old_key.is_some() && !overwrite {
262 Err(crate::Error::KeyAlreadyExists)
263 } else {
264 let () = store.insert(&key, key_spec)?;
265 Ok(old_key)
266 }
267 }
268
269 pub fn remove<K: ToEncodableKey>(
280 &self,
281 key_spec: &dyn KeySpecifier,
282 selector: KeystoreSelector,
283 ) -> Result<Option<K>> {
284 let store = self.select_keystore(&selector)?;
285 let key_type = K::Key::item_type();
286 let old_key: Option<K> = self.get_from_store(key_spec, &key_type, [store].into_iter())?;
287
288 store.remove(key_spec, &key_type)?;
289
290 Ok(old_key)
291 }
292
293 pub fn remove_entry(&self, entry: &KeystoreEntry) -> Result<Option<()>> {
305 let selector = entry.keystore_id().into();
306 let store = self.select_keystore(&selector)?;
307
308 store.remove(entry.key_path(), entry.key_type())
309 }
310
311 pub fn list_matching(&self, pat: &KeyPathPattern) -> Result<Vec<KeystoreEntry>> {
319 self.all_stores()
320 .map(|store| -> Result<Vec<_>> {
321 Ok(store
322 .list()?
323 .into_iter()
324 .filter_map(|entry| entry.ok())
325 .filter(|(key_path, _): &(KeyPath, KeystoreItemType)| key_path.matches(pat))
326 .map(|(path, key_type)| KeystoreEntry {
327 key_path: path.clone(),
328 key_type,
329 keystore_id: store.id(),
330 })
331 .collect::<Vec<_>>())
332 })
333 .flatten_ok()
334 .collect::<Result<Vec<_>>>()
335 }
336
337 pub fn describe(&self, path: &KeyPath) -> StdResult<KeyPathInfo, KeyPathError> {
346 for info_extractor in &self.key_info_extractors {
347 if let Ok(info) = info_extractor.describe(path) {
348 return Ok(info);
349 }
350 }
351
352 Err(KeyPathError::Unrecognized(path.clone()))
353 }
354
355 fn get_from_store_raw<'a, K: ItemType>(
361 &self,
362 key_spec: &dyn KeySpecifier,
363 key_type: &KeystoreItemType,
364 stores: impl Iterator<Item = &'a BoxedKeystore>,
365 ) -> Result<Option<K>> {
366 let static_key_type = K::item_type();
367 if key_type != &static_key_type {
368 return Err(internal!(
369 "key type {:?} does not match the key type {:?} of requested key K::Key",
370 key_type,
371 static_key_type
372 )
373 .into());
374 }
375
376 for store in stores {
377 let key = match store.get(key_spec, &K::item_type()) {
378 Ok(None) => {
379 continue;
381 }
382 Ok(Some(k)) => k,
383 Err(e) => {
384 return Err(e);
386 }
387 };
388
389 let key: K = key
391 .downcast::<K>()
392 .map(|k| *k)
393 .map_err(|_| internal!("failed to downcast key to requested type"))?;
394
395 return Ok(Some(key));
396 }
397
398 Ok(None)
399 }
400
401 fn get_from_store<'a, K: ToEncodableKey>(
405 &self,
406 key_spec: &dyn KeySpecifier,
407 key_type: &KeystoreItemType,
408 stores: impl Iterator<Item = &'a BoxedKeystore>,
409 ) -> Result<Option<K>> {
410 let Some(key) = self.get_from_store_raw::<K::Key>(key_spec, key_type, stores)? else {
411 return Ok(None);
412 };
413
414 Ok(Some(K::from_encodable_key(key)))
415 }
416
417 #[cfg(feature = "experimental-api")]
433 pub fn get_key_and_cert<K, C>(
434 &self,
435 spec: &dyn KeyCertificateSpecifier,
436 ) -> Result<Option<(K, C)>>
437 where
438 K: ToEncodableKey,
439 C: ToEncodableCert<K>,
440 {
441 let subject_key_spec = spec.subject_key_specifier();
442 let Some(key) =
444 self.get_from_store::<K>(subject_key_spec, &K::Key::item_type(), self.all_stores())?
445 else {
446 return Ok(None);
447 };
448
449 let subject_key_arti_path = subject_key_spec
450 .arti_path()
451 .map_err(|_| bad_api_usage!("subject key does not have an ArtiPath?!"))?;
452 let cert_spec =
453 ArtiPath::from_path_and_denotators(subject_key_arti_path, &spec.cert_denotators())
454 .map_err(into_bad_api_usage!("invalid certificate specifier"))?;
455
456 let Some(cert) = self.get_from_store_raw::<C::ParsedCert>(
457 &cert_spec,
458 &<C::ParsedCert as ItemType>::item_type(),
459 self.all_stores(),
460 )?
461 else {
462 return Err(KeystoreCorruptionError::MissingCertificate.into());
463 };
464
465 let signed_with = self.get_cert_signing_key::<K, C>(spec)?;
467 let cert = C::validate(cert, &key, &signed_with)?;
468
469 Ok(Some((key, cert)))
470 }
471
472 #[cfg(feature = "experimental-api")]
508 pub fn get_or_generate_key_and_cert<K, C>(
509 &self,
510 spec: &dyn KeyCertificateSpecifier,
511 make_certificate: impl FnOnce(&K, &<C as ToEncodableCert<K>>::SigningKey) -> C,
512 selector: KeystoreSelector,
513 rng: &mut dyn KeygenRng,
514 ) -> Result<(K, C)>
515 where
516 K: ToEncodableKey,
517 K::Key: Keygen,
518 C: ToEncodableCert<K>,
519 {
520 let subject_key_spec = spec.subject_key_specifier();
521 let subject_key_arti_path = subject_key_spec
522 .arti_path()
523 .map_err(|_| bad_api_usage!("subject key does not have an ArtiPath?!"))?;
524
525 let cert_specifier =
526 ArtiPath::from_path_and_denotators(subject_key_arti_path, &spec.cert_denotators())
527 .map_err(into_bad_api_usage!("invalid certificate specifier"))?;
528
529 let maybe_cert = self.get_from_store_raw::<C::ParsedCert>(
530 &cert_specifier,
531 &C::ParsedCert::item_type(),
532 self.all_stores(),
533 )?;
534
535 let maybe_subject_key = self.get::<K>(subject_key_spec)?;
536
537 match (&maybe_cert, &maybe_subject_key) {
538 (Some(_), None) => {
539 return Err(KeystoreCorruptionError::MissingSubjectKey.into());
540 }
541 _ => {
542 }
544 }
545 let subject_key = match maybe_subject_key {
546 Some(key) => key,
547 _ => self.generate(subject_key_spec, selector, rng, false)?,
548 };
549
550 let signed_with = self.get_cert_signing_key::<K, C>(spec)?;
551 let cert = match maybe_cert {
552 Some(cert) => C::validate(cert, &subject_key, &signed_with)?,
553 None => {
554 let cert = make_certificate(&subject_key, &signed_with);
555
556 let () = self.insert_cert(cert.clone(), &cert_specifier, selector)?;
557
558 cert
559 }
560 };
561
562 Ok((subject_key, cert))
563 }
564
565 fn all_stores(&self) -> impl Iterator<Item = &BoxedKeystore> {
567 iter::once(&self.primary_store).chain(self.secondary_stores.iter())
568 }
569
570 fn select_keystore(&self, selector: &KeystoreSelector) -> Result<&BoxedKeystore> {
575 match selector {
576 KeystoreSelector::Id(keystore_id) => self.find_keystore(keystore_id),
577 KeystoreSelector::Primary => Ok(&self.primary_store),
578 }
579 }
580
581 fn find_keystore(&self, id: &KeystoreId) -> Result<&BoxedKeystore> {
586 self.all_stores()
587 .find(|keystore| keystore.id() == id)
588 .ok_or_else(|| bad_api_usage!("could not find keystore with ID {id}").into())
589 }
590
591 #[cfg(feature = "experimental-api")]
596 fn get_cert_signing_key<K, C>(
597 &self,
598 spec: &dyn KeyCertificateSpecifier,
599 ) -> Result<C::SigningKey>
600 where
601 K: ToEncodableKey,
602 C: ToEncodableCert<K>,
603 {
604 let Some(signing_key_spec) = spec.signing_key_specifier() else {
605 return Err(bad_api_usage!(
606 "signing key specifier is None, but external signing key was not provided?"
607 )
608 .into());
609 };
610
611 let Some(signing_key) = self.get_from_store::<C::SigningKey>(
612 signing_key_spec,
613 &<C::SigningKey as ToEncodableKey>::Key::item_type(),
614 self.all_stores(),
615 )?
616 else {
617 return Err(KeystoreCorruptionError::MissingSigningKey.into());
618 };
619
620 Ok(signing_key)
621 }
622
623 fn insert_cert<K, C>(
630 &self,
631 cert: C,
632 cert_spec: &dyn KeySpecifier,
633 selector: KeystoreSelector,
634 ) -> Result<()>
635 where
636 K: ToEncodableKey,
637 K::Key: Keygen,
638 C: ToEncodableCert<K>,
639 {
640 let cert = cert.to_encodable_cert();
641 let store = self.select_keystore(&selector)?;
642
643 let () = store.insert(&cert, cert_spec)?;
644 Ok(())
645 }
646}
647
648#[cfg(test)]
649mod tests {
650 #![allow(clippy::bool_assert_comparison)]
652 #![allow(clippy::clone_on_copy)]
653 #![allow(clippy::dbg_macro)]
654 #![allow(clippy::mixed_attributes_style)]
655 #![allow(clippy::print_stderr)]
656 #![allow(clippy::print_stdout)]
657 #![allow(clippy::single_char_pattern)]
658 #![allow(clippy::unwrap_used)]
659 #![allow(clippy::unchecked_duration_subtraction)]
660 #![allow(clippy::useless_vec)]
661 #![allow(clippy::needless_pass_by_value)]
662 use super::*;
664 use crate::keystore::arti::err::{ArtiNativeKeystoreError, MalformedPathError};
665 use crate::{
666 ArtiPath, ArtiPathUnavailableError, Error, KeyPath, Keystore, KeystoreEntryResult,
667 KeystoreError, UnrecognizedEntryError, UnrecognizedEntryId,
668 };
669 use std::collections::HashMap;
670 use std::path::PathBuf;
671 use std::result::Result as StdResult;
672 use std::str::FromStr;
673 use std::sync::{Arc, RwLock};
674 use std::time::{Duration, SystemTime};
675 use tor_basic_utils::test_rng::testing_rng;
676 use tor_cert::CertifiedKey;
677 use tor_cert::Ed25519Cert;
678 use tor_error::{ErrorKind, HasKind};
679 use tor_key_forge::{
680 CertData, EncodableItem, ErasedKey, InvalidCertError, KeyType, KeystoreItem,
681 };
682 use tor_llcrypto::pk::ed25519::{self, Ed25519PublicKey as _};
683 use tor_llcrypto::rng::FakeEntropicRng;
684
685 #[derive(Clone, Debug, PartialEq)]
687 struct KeyMetadata {
688 item_id: String,
690 retrieved_from: Option<KeystoreId>,
694 is_generated: bool,
696 }
697
698 #[derive(Clone, Debug, PartialEq)]
700 struct CertMetadata {
701 subject_key_id: String,
703 signing_key_id: String,
705 retrieved_from: Option<KeystoreId>,
709 is_generated: bool,
712 }
713
714 #[derive(Clone, Debug, PartialEq, derive_more::From)]
716 enum ItemMetadata {
717 Key(KeyMetadata),
719 Cert(CertMetadata),
721 }
722
723 impl ItemMetadata {
724 fn item_id(&self) -> &str {
729 match self {
730 ItemMetadata::Key(k) => &k.item_id,
731 ItemMetadata::Cert(c) => &c.subject_key_id,
732 }
733 }
734
735 fn retrieved_from(&self) -> Option<&KeystoreId> {
737 match self {
738 ItemMetadata::Key(k) => k.retrieved_from.as_ref(),
739 ItemMetadata::Cert(c) => c.retrieved_from.as_ref(),
740 }
741 }
742
743 fn is_generated(&self) -> bool {
745 match self {
746 ItemMetadata::Key(k) => k.is_generated,
747 ItemMetadata::Cert(c) => c.is_generated,
748 }
749 }
750
751 fn set_retrieved_from(&mut self, id: KeystoreId) {
753 match self {
754 ItemMetadata::Key(meta) => meta.retrieved_from = Some(id),
755 ItemMetadata::Cert(meta) => meta.retrieved_from = Some(id),
756 }
757 }
758
759 fn as_key(&self) -> Option<&KeyMetadata> {
761 match self {
762 ItemMetadata::Key(meta) => Some(meta),
763 _ => None,
764 }
765 }
766
767 fn as_cert(&self) -> Option<&CertMetadata> {
769 match self {
770 ItemMetadata::Cert(meta) => Some(meta),
771 _ => None,
772 }
773 }
774 }
775
776 #[derive(Clone, Debug)]
778 struct TestItem {
779 item: KeystoreItem,
781 meta: ItemMetadata,
783 }
784
785 #[derive(Clone, Debug)]
787 struct AlwaysValidCert(TestItem);
788
789 #[derive(Clone, Debug)]
791 struct TestPublicKey {
792 key: KeystoreItem,
794 }
795
796 impl From<TestItem> for TestPublicKey {
797 fn from(tk: TestItem) -> TestPublicKey {
798 TestPublicKey { key: tk.item }
799 }
800 }
801
802 impl TestItem {
803 fn new(item_id: &str) -> Self {
805 let mut rng = testing_rng();
806 TestItem {
807 item: ed25519::Keypair::generate(&mut rng)
808 .as_keystore_item()
809 .unwrap(),
810 meta: ItemMetadata::Key(KeyMetadata {
811 item_id: item_id.to_string(),
812 retrieved_from: None,
813 is_generated: false,
814 }),
815 }
816 }
817 }
818
819 impl Keygen for TestItem {
820 fn generate(mut rng: &mut dyn KeygenRng) -> tor_key_forge::Result<Self>
821 where
822 Self: Sized,
823 {
824 Ok(TestItem {
825 item: ed25519::Keypair::generate(&mut rng).as_keystore_item()?,
826 meta: ItemMetadata::Key(KeyMetadata {
827 item_id: "generated_test_key".to_string(),
828 retrieved_from: None,
829 is_generated: true,
830 }),
831 })
832 }
833 }
834
835 impl ItemType for TestItem {
836 fn item_type() -> KeystoreItemType
837 where
838 Self: Sized,
839 {
840 KeyType::Ed25519Keypair.into()
842 }
843 }
844
845 impl EncodableItem for TestItem {
846 fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
847 Ok(self.item.clone())
848 }
849 }
850
851 impl ToEncodableKey for TestItem {
852 type Key = Self;
853 type KeyPair = Self;
854
855 fn to_encodable_key(self) -> Self::Key {
856 self
857 }
858
859 fn from_encodable_key(key: Self::Key) -> Self {
860 key
861 }
862 }
863
864 impl ItemType for TestPublicKey {
865 fn item_type() -> KeystoreItemType
866 where
867 Self: Sized,
868 {
869 KeyType::Ed25519PublicKey.into()
870 }
871 }
872
873 impl EncodableItem for TestPublicKey {
874 fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
875 Ok(self.key.clone())
876 }
877 }
878
879 impl ToEncodableKey for TestPublicKey {
880 type Key = Self;
881 type KeyPair = TestItem;
882
883 fn to_encodable_key(self) -> Self::Key {
884 self
885 }
886
887 fn from_encodable_key(key: Self::Key) -> Self {
888 key
889 }
890 }
891
892 impl ToEncodableCert<TestItem> for AlwaysValidCert {
893 type ParsedCert = TestItem;
894 type EncodableCert = TestItem;
895 type SigningKey = TestItem;
896
897 fn validate(
898 cert: Self::ParsedCert,
899 _subject: &TestItem,
900 _signed_with: &Self::SigningKey,
901 ) -> StdResult<Self, InvalidCertError> {
902 Ok(Self(cert))
904 }
905
906 fn to_encodable_cert(self) -> Self::EncodableCert {
908 self.0
909 }
910 }
911
912 struct KeystoreListMock {
913 id: KeystoreId,
914 valid_key_path: KeyPath,
915 invalid_key_path: PathBuf,
916 }
917
918 impl Default for KeystoreListMock {
919 fn default() -> Self {
920 Self {
921 id: KeystoreId::from_str("keystore_list_mock").unwrap(),
922 valid_key_path: KeyPath::Arti(
923 ArtiPath::new("recognized_entry".to_owned()).unwrap(),
924 ),
925 invalid_key_path: PathBuf::from_str("unrecognized_entry").unwrap(),
926 }
927 }
928 }
929
930 impl Keystore for KeystoreListMock {
931 fn id(&self) -> &KeystoreId {
932 &self.id
933 }
934
935 fn get(
936 &self,
937 _key_spec: &dyn KeySpecifier,
938 _item_type: &KeystoreItemType,
939 ) -> Result<Option<ErasedKey>> {
940 Err(Error::Keystore(Arc::new(
941 KeystoreListMockError::MethodNotSuppored,
942 )))
943 }
944
945 fn list(&self) -> Result<Vec<KeystoreEntryResult<(KeyPath, KeystoreItemType)>>> {
946 Ok(vec![
948 Ok((
949 self.valid_key_path.clone(),
950 KeystoreItemType::Key(KeyType::Ed25519PublicKey),
951 )),
952 Err(UnrecognizedEntryError::new(
953 UnrecognizedEntryId::Path(self.invalid_key_path.clone()),
954 Arc::new(ArtiNativeKeystoreError::MalformedPath {
955 path: self.invalid_key_path.clone(),
956 err: MalformedPathError::NoExtension,
957 }),
958 )),
959 ])
960 }
961
962 fn insert(&self, _key: &dyn EncodableItem, _key_spec: &dyn KeySpecifier) -> Result<()> {
963 Err(Error::Keystore(Arc::new(
964 KeystoreListMockError::MethodNotSuppored,
965 )))
966 }
967
968 fn remove(
969 &self,
970 _key_spec: &dyn KeySpecifier,
971 _item_type: &KeystoreItemType,
972 ) -> Result<Option<()>> {
973 Err(Error::Keystore(Arc::new(
974 KeystoreListMockError::MethodNotSuppored,
975 )))
976 }
977
978 fn contains(
979 &self,
980 _key_spec: &dyn KeySpecifier,
981 _item_type: &KeystoreItemType,
982 ) -> Result<bool> {
983 Err(Error::Keystore(Arc::new(
984 KeystoreListMockError::MethodNotSuppored,
985 )))
986 }
987 }
988
989 #[derive(thiserror::Error, Debug, Clone, derive_more::Display)]
990 enum KeystoreListMockError {
991 MethodNotSuppored,
992 }
993
994 impl KeystoreError for KeystoreListMockError {}
995
996 impl HasKind for KeystoreListMockError {
997 fn kind(&self) -> ErrorKind {
998 ErrorKind::BadApiUsage
999 }
1000 }
1001
1002 macro_rules! impl_keystore {
1003 ($name:tt, $id:expr) => {
1004 struct $name {
1005 inner: RwLock<HashMap<(ArtiPath, KeystoreItemType), TestItem>>,
1006 id: KeystoreId,
1007 }
1008
1009 impl Default for $name {
1010 fn default() -> Self {
1011 Self {
1012 inner: Default::default(),
1013 id: KeystoreId::from_str($id).unwrap(),
1014 }
1015 }
1016 }
1017
1018 #[allow(dead_code)] impl $name {
1020 fn new_boxed() -> BoxedKeystore {
1021 Box::<Self>::default()
1022 }
1023 }
1024
1025 impl crate::Keystore for $name {
1026 fn contains(
1027 &self,
1028 key_spec: &dyn KeySpecifier,
1029 item_type: &KeystoreItemType,
1030 ) -> Result<bool> {
1031 Ok(self
1032 .inner
1033 .read()
1034 .unwrap()
1035 .contains_key(&(key_spec.arti_path().unwrap(), item_type.clone())))
1036 }
1037
1038 fn id(&self) -> &KeystoreId {
1039 &self.id
1040 }
1041
1042 fn get(
1043 &self,
1044 key_spec: &dyn KeySpecifier,
1045 item_type: &KeystoreItemType,
1046 ) -> Result<Option<ErasedKey>> {
1047 Ok(self
1048 .inner
1049 .read()
1050 .unwrap()
1051 .get(&(key_spec.arti_path().unwrap(), item_type.clone()))
1052 .map(|k| {
1053 let mut k = k.clone();
1054 k.meta.set_retrieved_from(self.id().clone());
1055 Box::new(k) as Box<dyn ItemType>
1056 }))
1057 }
1058
1059 fn insert(
1060 &self,
1061 key: &dyn EncodableItem,
1062 key_spec: &dyn KeySpecifier,
1063 ) -> Result<()> {
1064 let key = key.downcast_ref::<TestItem>().unwrap();
1065
1066 let item = key.as_keystore_item()?;
1067 let meta = key.meta.clone();
1068
1069 let item_type = item.item_type()?;
1070 let key = TestItem { item, meta };
1071
1072 self.inner
1073 .write()
1074 .unwrap()
1075 .insert((key_spec.arti_path().unwrap(), item_type), key);
1076
1077 Ok(())
1078 }
1079
1080 fn remove(
1081 &self,
1082 key_spec: &dyn KeySpecifier,
1083 item_type: &KeystoreItemType,
1084 ) -> Result<Option<()>> {
1085 Ok(self
1086 .inner
1087 .write()
1088 .unwrap()
1089 .remove(&(key_spec.arti_path().unwrap(), item_type.clone()))
1090 .map(|_| ()))
1091 }
1092
1093 fn list(&self) -> Result<Vec<KeystoreEntryResult<(KeyPath, KeystoreItemType)>>> {
1094 Ok(self
1095 .inner
1096 .read()
1097 .unwrap()
1098 .iter()
1099 .map(|((arti_path, item_type), _)| {
1100 Ok((KeyPath::Arti(arti_path.clone()), item_type.clone()))
1101 })
1102 .collect())
1103 }
1104 }
1105 };
1106 }
1107
1108 macro_rules! impl_specifier {
1109 ($name:tt, $id:expr) => {
1110 struct $name;
1111
1112 impl KeySpecifier for $name {
1113 fn arti_path(&self) -> StdResult<ArtiPath, ArtiPathUnavailableError> {
1114 Ok(ArtiPath::new($id.into()).map_err(|e| tor_error::internal!("{e}"))?)
1115 }
1116
1117 fn ctor_path(&self) -> Option<crate::CTorPath> {
1118 None
1119 }
1120
1121 fn keypair_specifier(&self) -> Option<Box<dyn KeySpecifier>> {
1122 None
1123 }
1124 }
1125 };
1126 }
1127
1128 impl_keystore!(Keystore1, "keystore1");
1129 impl_keystore!(Keystore2, "keystore2");
1130 impl_keystore!(Keystore3, "keystore3");
1131
1132 impl_specifier!(TestKeySpecifier1, "spec1");
1133 impl_specifier!(TestKeySpecifier2, "spec2");
1134 impl_specifier!(TestKeySpecifier3, "spec3");
1135 impl_specifier!(TestKeySpecifier4, "spec4");
1136
1137 impl_specifier!(TestPublicKeySpecifier1, "pub-spec1");
1138
1139 fn entry_descriptor(specifier: impl KeySpecifier, keystore_id: &KeystoreId) -> KeystoreEntry {
1141 KeystoreEntry {
1142 key_path: specifier.arti_path().unwrap().into(),
1143 key_type: TestItem::item_type(),
1144 keystore_id,
1145 }
1146 }
1147
1148 #[test]
1149 #[allow(clippy::cognitive_complexity)]
1150 fn insert_and_get() {
1151 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1152
1153 builder
1154 .secondary_stores()
1155 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1156
1157 let mgr = builder.build().unwrap();
1158
1159 let old_key = mgr
1161 .insert(
1162 TestItem::new("coot"),
1163 &TestKeySpecifier1,
1164 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1165 true,
1166 )
1167 .unwrap();
1168
1169 assert!(old_key.is_none());
1170 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1171 assert_eq!(key.meta.item_id(), "coot");
1172 assert_eq!(
1173 key.meta.retrieved_from(),
1174 Some(&KeystoreId::from_str("keystore2").unwrap())
1175 );
1176 assert_eq!(key.meta.is_generated(), false);
1177
1178 let old_key = mgr
1180 .insert(
1181 TestItem::new("gull"),
1182 &TestKeySpecifier1,
1183 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1184 true,
1185 )
1186 .unwrap()
1187 .unwrap();
1188 assert_eq!(old_key.meta.item_id(), "coot");
1189 assert_eq!(
1190 old_key.meta.retrieved_from(),
1191 Some(&KeystoreId::from_str("keystore2").unwrap())
1192 );
1193 assert_eq!(old_key.meta.is_generated(), false);
1194 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1196 assert_eq!(key.meta.item_id(), "gull");
1197 assert_eq!(
1198 key.meta.retrieved_from(),
1199 Some(&KeystoreId::from_str("keystore2").unwrap())
1200 );
1201 assert_eq!(key.meta.is_generated(), false);
1202
1203 let err = mgr
1205 .insert(
1206 TestItem::new("gull"),
1207 &TestKeySpecifier1,
1208 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1209 false,
1210 )
1211 .unwrap_err();
1212 assert!(matches!(err, crate::Error::KeyAlreadyExists));
1213
1214 let old_key = mgr
1216 .insert(
1217 TestItem::new("penguin"),
1218 &TestKeySpecifier2,
1219 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1220 false,
1221 )
1222 .unwrap();
1223 assert!(old_key.is_none());
1224
1225 let old_key = mgr
1227 .insert(
1228 TestItem::new("moorhen"),
1229 &TestKeySpecifier3,
1230 KeystoreSelector::Primary,
1231 true,
1232 )
1233 .unwrap();
1234 assert!(old_key.is_none());
1235 let key = mgr.get::<TestItem>(&TestKeySpecifier3).unwrap().unwrap();
1236 assert_eq!(key.meta.item_id(), "moorhen");
1237 assert_eq!(
1238 key.meta.retrieved_from(),
1239 Some(&KeystoreId::from_str("keystore1").unwrap())
1240 );
1241 assert_eq!(key.meta.is_generated(), false);
1242
1243 assert!(mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().is_none());
1245
1246 for store in ["keystore3", "keystore2", "keystore1"] {
1250 let old_key = mgr
1251 .insert(
1252 TestItem::new("cormorant"),
1253 &TestKeySpecifier4,
1254 KeystoreSelector::Id(&KeystoreId::from_str(store).unwrap()),
1255 true,
1256 )
1257 .unwrap();
1258 assert!(old_key.is_none());
1259
1260 let key = mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().unwrap();
1262 assert_eq!(key.meta.item_id(), "cormorant");
1263 assert_eq!(
1264 key.meta.retrieved_from(),
1265 Some(&KeystoreId::from_str(store).unwrap())
1266 );
1267 assert_eq!(key.meta.is_generated(), false);
1268 }
1269
1270 let key = mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().unwrap();
1273 assert_eq!(key.meta.item_id(), "cormorant");
1274 assert_eq!(
1275 key.meta.retrieved_from(),
1276 Some(&KeystoreId::from_str("keystore1").unwrap())
1277 );
1278 assert_eq!(key.meta.is_generated(), false);
1279 }
1280
1281 #[test]
1282 fn remove() {
1283 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1284
1285 builder
1286 .secondary_stores()
1287 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1288
1289 let mgr = builder.build().unwrap();
1290
1291 assert!(!mgr.secondary_stores[0]
1292 .contains(&TestKeySpecifier1, &TestItem::item_type())
1293 .unwrap());
1294
1295 mgr.insert(
1297 TestItem::new("coot"),
1298 &TestKeySpecifier1,
1299 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1300 true,
1301 )
1302 .unwrap();
1303 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1304 assert_eq!(key.meta.item_id(), "coot");
1305 assert_eq!(
1306 key.meta.retrieved_from(),
1307 Some(&KeystoreId::from_str("keystore2").unwrap())
1308 );
1309 assert_eq!(key.meta.is_generated(), false);
1310
1311 assert!(mgr
1313 .remove::<TestItem>(
1314 &TestKeySpecifier1,
1315 KeystoreSelector::Id(&KeystoreId::from_str("not_an_id_we_know_of").unwrap())
1316 )
1317 .is_err());
1318 assert!(mgr.secondary_stores[0]
1320 .contains(&TestKeySpecifier1, &TestItem::item_type())
1321 .unwrap());
1322
1323 assert!(mgr
1325 .remove::<TestItem>(&TestKeySpecifier1, KeystoreSelector::Primary)
1326 .unwrap()
1327 .is_none());
1328
1329 assert!(mgr.secondary_stores[0]
1331 .contains(&TestKeySpecifier1, &TestItem::item_type())
1332 .unwrap());
1333
1334 let removed_key = mgr
1336 .remove::<TestItem>(
1337 &TestKeySpecifier1,
1338 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1339 )
1340 .unwrap()
1341 .unwrap();
1342 assert_eq!(removed_key.meta.item_id(), "coot");
1343 assert_eq!(
1344 removed_key.meta.retrieved_from(),
1345 Some(&KeystoreId::from_str("keystore2").unwrap())
1346 );
1347 assert_eq!(removed_key.meta.is_generated(), false);
1348
1349 assert!(!mgr.secondary_stores[0]
1351 .contains(&TestKeySpecifier1, &TestItem::item_type())
1352 .unwrap());
1353 }
1354
1355 #[test]
1356 fn keygen() {
1357 let mut rng = FakeEntropicRng(testing_rng());
1358 let mgr = KeyMgrBuilder::default()
1359 .primary_store(Box::<Keystore1>::default())
1360 .build()
1361 .unwrap();
1362
1363 mgr.insert(
1364 TestItem::new("coot"),
1365 &TestKeySpecifier1,
1366 KeystoreSelector::Primary,
1367 true,
1368 )
1369 .unwrap();
1370
1371 assert!(mgr
1373 .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1374 .unwrap()
1375 .is_none());
1376
1377 let err = mgr
1379 .generate::<TestItem>(
1380 &TestKeySpecifier1,
1381 KeystoreSelector::Primary,
1382 &mut rng,
1383 false,
1384 )
1385 .unwrap_err();
1386
1387 assert!(matches!(err, crate::Error::KeyAlreadyExists));
1388
1389 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1391 assert_eq!(key.meta.item_id(), "coot");
1392 assert_eq!(
1393 key.meta.retrieved_from(),
1394 Some(&KeystoreId::from_str("keystore1").unwrap())
1395 );
1396 assert_eq!(key.meta.is_generated(), false);
1397
1398 assert!(mgr
1400 .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1401 .unwrap()
1402 .is_none());
1403
1404 let generated_key = mgr
1406 .generate::<TestItem>(
1407 &TestKeySpecifier1,
1408 KeystoreSelector::Primary,
1409 &mut rng,
1410 true,
1411 )
1412 .unwrap();
1413
1414 assert_eq!(generated_key.meta.item_id(), "generated_test_key");
1415 assert_eq!(generated_key.meta.retrieved_from(), None);
1418 assert_eq!(generated_key.meta.is_generated(), true);
1419
1420 let retrieved_key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1422 assert_eq!(retrieved_key.meta.item_id(), "generated_test_key");
1423 assert_eq!(
1424 retrieved_key.meta.retrieved_from(),
1425 Some(&KeystoreId::from_str("keystore1").unwrap())
1426 );
1427 assert_eq!(retrieved_key.meta.is_generated(), true);
1428
1429 assert!(mgr
1431 .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1432 .unwrap()
1433 .is_none());
1434 }
1435
1436 #[test]
1437 fn get_or_generate() {
1438 let mut rng = FakeEntropicRng(testing_rng());
1439 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1440
1441 builder
1442 .secondary_stores()
1443 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1444
1445 let mgr = builder.build().unwrap();
1446
1447 let keystore2 = KeystoreId::from_str("keystore2").unwrap();
1448 let entry_desc1 = entry_descriptor(TestKeySpecifier1, &keystore2);
1449 assert!(mgr.get_entry::<TestItem>(&entry_desc1).unwrap().is_none());
1450
1451 mgr.insert(
1452 TestItem::new("coot"),
1453 &TestKeySpecifier1,
1454 KeystoreSelector::Id(&keystore2),
1455 true,
1456 )
1457 .unwrap();
1458
1459 let key = mgr
1461 .get_or_generate::<TestItem>(&TestKeySpecifier1, KeystoreSelector::Primary, &mut rng)
1462 .unwrap();
1463 assert_eq!(key.meta.item_id(), "coot");
1464 assert_eq!(
1465 key.meta.retrieved_from(),
1466 Some(&KeystoreId::from_str("keystore2").unwrap())
1467 );
1468 assert_eq!(key.meta.is_generated(), false);
1469
1470 assert_eq!(
1471 mgr.get_entry::<TestItem>(&entry_desc1)
1472 .unwrap()
1473 .map(|k| k.meta),
1474 Some(ItemMetadata::Key(KeyMetadata {
1475 item_id: "coot".to_string(),
1476 retrieved_from: Some(keystore2.clone()),
1477 is_generated: false,
1478 }))
1479 );
1480
1481 let keystore3 = KeystoreId::from_str("keystore3").unwrap();
1484 let generated_key = mgr
1485 .get_or_generate::<TestItem>(
1486 &TestKeySpecifier2,
1487 KeystoreSelector::Id(&keystore3),
1488 &mut rng,
1489 )
1490 .unwrap();
1491 assert_eq!(generated_key.meta.item_id(), "generated_test_key");
1492 assert_eq!(generated_key.meta.retrieved_from(), None);
1495 assert_eq!(generated_key.meta.is_generated(), true);
1496
1497 let retrieved_key = mgr.get::<TestItem>(&TestKeySpecifier2).unwrap().unwrap();
1499 assert_eq!(retrieved_key.meta.item_id(), "generated_test_key");
1500 assert_eq!(
1501 retrieved_key.meta.retrieved_from(),
1502 Some(&KeystoreId::from_str("keystore3").unwrap())
1503 );
1504 assert_eq!(retrieved_key.meta.is_generated(), true);
1505
1506 let entry_desc2 = entry_descriptor(TestKeySpecifier2, &keystore3);
1507 assert_eq!(
1508 mgr.get_entry::<TestItem>(&entry_desc2)
1509 .unwrap()
1510 .map(|k| k.meta),
1511 Some(ItemMetadata::Key(KeyMetadata {
1512 item_id: "generated_test_key".to_string(),
1513 retrieved_from: Some(keystore3.clone()),
1514 is_generated: true,
1515 }))
1516 );
1517
1518 let arti_pat = KeyPathPattern::Arti("*".to_string());
1519 let matching = mgr.list_matching(&arti_pat).unwrap();
1520
1521 assert_eq!(matching.len(), 2);
1522 assert!(matching.contains(&entry_desc1));
1523 assert!(matching.contains(&entry_desc2));
1524
1525 assert_eq!(mgr.remove_entry(&entry_desc2).unwrap(), Some(()));
1526 assert!(mgr.get_entry::<TestItem>(&entry_desc2).unwrap().is_none());
1527 assert!(mgr.remove_entry(&entry_desc2).unwrap().is_none());
1528 }
1529
1530 #[test]
1531 fn list_matching_ignores_unrecognized_keys() {
1532 let builder = KeyMgrBuilder::default().primary_store(Box::new(KeystoreListMock::default()));
1533
1534 let mgr = builder.build().unwrap();
1535
1536 let arti_pat = KeyPathPattern::Arti("*".to_string());
1537 let matching = mgr.list_matching(&arti_pat).unwrap();
1538 assert_eq!(matching.len(), 1);
1540 assert_eq!(
1541 matching.first().unwrap().key_path(),
1542 &KeystoreListMock::default().valid_key_path
1543 );
1544 }
1545
1546 #[cfg(feature = "experimental-api")]
1548 #[derive(Clone, Copy, Debug, PartialEq)]
1549 enum GenerateItem {
1550 Yes,
1551 No,
1552 }
1553
1554 #[cfg(feature = "experimental-api")]
1555 macro_rules! run_certificate_test {
1556 (
1557 generate_subject_key = $generate_subject_key:expr,
1558 generate_signing_key = $generate_signing_key:expr,
1559 $($expected_err:tt)?
1560 ) => {{
1561 use GenerateItem::*;
1562
1563 let mut rng = FakeEntropicRng(testing_rng());
1564 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1565
1566 builder
1567 .secondary_stores()
1568 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1569
1570 let mgr = builder.build().unwrap();
1571
1572 let spec = crate::test_utils::TestCertSpecifier {
1573 subject_key_spec: TestKeySpecifier1,
1574 signing_key_spec: TestKeySpecifier2,
1575 denotator: vec!["foo".into()],
1576 };
1577
1578 if $generate_subject_key == Yes {
1579 let _ = mgr
1580 .generate::<TestItem>(
1581 &TestKeySpecifier1,
1582 KeystoreSelector::Primary,
1583 &mut rng,
1584 false,
1585 )
1586 .unwrap();
1587 }
1588
1589 if $generate_signing_key == Yes {
1590 let _ = mgr
1591 .generate::<TestItem>(
1592 &TestKeySpecifier2,
1593 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1594 &mut rng,
1595 false,
1596 )
1597 .unwrap();
1598 }
1599
1600 let make_certificate = move |subject_key: &TestItem, signed_with: &TestItem| {
1601 let subject_id = subject_key.meta.as_key().unwrap().item_id.clone();
1602 let signing_id = signed_with.meta.as_key().unwrap().item_id.clone();
1603
1604 let meta = ItemMetadata::Cert(CertMetadata {
1605 subject_key_id: subject_id,
1606 signing_key_id: signing_id,
1607 retrieved_from: None,
1608 is_generated: true,
1609 });
1610
1611 let mut rng = FakeEntropicRng(testing_rng());
1617 let keypair = ed25519::Keypair::generate(&mut rng);
1618 let encoded_cert = Ed25519Cert::constructor()
1619 .cert_type(tor_cert::CertType::IDENTITY_V_SIGNING)
1620 .expiration(SystemTime::now() + Duration::from_secs(180))
1621 .signing_key(keypair.public_key().into())
1622 .cert_key(CertifiedKey::Ed25519(keypair.public_key().into()))
1623 .encode_and_sign(&keypair)
1624 .unwrap();
1625 let test_cert = CertData::TorEd25519Cert(encoded_cert);
1626 AlwaysValidCert(TestItem {
1627 item: KeystoreItem::Cert(test_cert),
1628 meta,
1629 })
1630 };
1631
1632 let res = mgr
1633 .get_or_generate_key_and_cert::<TestItem, AlwaysValidCert>(
1634 &spec,
1635 &make_certificate,
1636 KeystoreSelector::Primary,
1637 &mut rng,
1638 );
1639
1640 #[allow(unused_assignments)]
1641 #[allow(unused_mut)]
1642 let mut has_error = false;
1643 $(
1644 has_error = true;
1645 let err = res.clone().unwrap_err();
1646 assert!(
1647 matches!(
1648 err,
1649 crate::Error::Corruption(KeystoreCorruptionError::$expected_err)
1650 ),
1651 "unexpected error: {err:?}",
1652 );
1653 )?
1654
1655 if !has_error {
1656 let (key, cert) = res.unwrap();
1657
1658 let expected_subj_key_id = if $generate_subject_key == Yes {
1659 "generated_test_key"
1660 } else {
1661 "generated_test_key"
1662 };
1663
1664 assert_eq!(key.meta.item_id(), expected_subj_key_id);
1665 assert_eq!(
1666 cert.0.meta.as_cert().unwrap().subject_key_id,
1667 expected_subj_key_id
1668 );
1669 assert_eq!(
1670 cert.0.meta.as_cert().unwrap().signing_key_id,
1671 "generated_test_key"
1672 );
1673 assert_eq!(cert.0.meta.is_generated(), true);
1674 }
1675 }}
1676 }
1677
1678 #[test]
1679 #[cfg(feature = "experimental-api")]
1680 #[rustfmt::skip] #[allow(clippy::cognitive_complexity)] fn get_certificate() {
1683 run_certificate_test!(
1684 generate_subject_key = No,
1685 generate_signing_key = No,
1686 MissingSigningKey
1687 );
1688
1689 run_certificate_test!(
1690 generate_subject_key = Yes,
1691 generate_signing_key = No,
1692 MissingSigningKey
1693 );
1694
1695 run_certificate_test!(
1696 generate_subject_key = No,
1697 generate_signing_key = Yes,
1698 );
1699
1700 run_certificate_test!(
1701 generate_subject_key = Yes,
1702 generate_signing_key = Yes,
1703 );
1704 }
1705}