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>> {
315 self.all_stores()
316 .map(|store| -> Result<Vec<_>> {
317 Ok(store
318 .list()?
319 .into_iter()
320 .filter(|(key_path, _): &(KeyPath, KeystoreItemType)| key_path.matches(pat))
321 .map(|(path, key_type)| KeystoreEntry {
322 key_path: path.clone(),
323 key_type,
324 keystore_id: store.id(),
325 })
326 .collect::<Vec<_>>())
327 })
328 .flatten_ok()
329 .collect::<Result<Vec<_>>>()
330 }
331
332 pub fn describe(&self, path: &KeyPath) -> StdResult<KeyPathInfo, KeyPathError> {
341 for info_extractor in &self.key_info_extractors {
342 if let Ok(info) = info_extractor.describe(path) {
343 return Ok(info);
344 }
345 }
346
347 Err(KeyPathError::Unrecognized(path.clone()))
348 }
349
350 fn get_from_store_raw<'a, K: ItemType>(
356 &self,
357 key_spec: &dyn KeySpecifier,
358 key_type: &KeystoreItemType,
359 stores: impl Iterator<Item = &'a BoxedKeystore>,
360 ) -> Result<Option<K>> {
361 let static_key_type = K::item_type();
362 if key_type != &static_key_type {
363 return Err(internal!(
364 "key type {:?} does not match the key type {:?} of requested key K::Key",
365 key_type,
366 static_key_type
367 )
368 .into());
369 }
370
371 for store in stores {
372 let key = match store.get(key_spec, &K::item_type()) {
373 Ok(None) => {
374 continue;
376 }
377 Ok(Some(k)) => k,
378 Err(e) => {
379 return Err(e);
381 }
382 };
383
384 let key: K = key
386 .downcast::<K>()
387 .map(|k| *k)
388 .map_err(|_| internal!("failed to downcast key to requested type"))?;
389
390 return Ok(Some(key));
391 }
392
393 Ok(None)
394 }
395
396 fn get_from_store<'a, K: ToEncodableKey>(
400 &self,
401 key_spec: &dyn KeySpecifier,
402 key_type: &KeystoreItemType,
403 stores: impl Iterator<Item = &'a BoxedKeystore>,
404 ) -> Result<Option<K>> {
405 let Some(key) = self.get_from_store_raw::<K::Key>(key_spec, key_type, stores)? else {
406 return Ok(None);
407 };
408
409 Ok(Some(K::from_encodable_key(key)))
410 }
411
412 #[cfg(feature = "experimental-api")]
428 pub fn get_key_and_cert<K, C>(
429 &self,
430 spec: &dyn KeyCertificateSpecifier,
431 ) -> Result<Option<(K, C)>>
432 where
433 K: ToEncodableKey,
434 C: ToEncodableCert<K>,
435 {
436 let subject_key_spec = spec.subject_key_specifier();
437 let Some(key) =
439 self.get_from_store::<K>(subject_key_spec, &K::Key::item_type(), self.all_stores())?
440 else {
441 return Ok(None);
442 };
443
444 let subject_key_arti_path = subject_key_spec
445 .arti_path()
446 .map_err(|_| bad_api_usage!("subject key does not have an ArtiPath?!"))?;
447 let cert_spec =
448 ArtiPath::from_path_and_denotators(subject_key_arti_path, &spec.cert_denotators())
449 .map_err(into_bad_api_usage!("invalid certificate specifier"))?;
450
451 let Some(cert) = self.get_from_store_raw::<C::ParsedCert>(
452 &cert_spec,
453 &<C::ParsedCert as ItemType>::item_type(),
454 self.all_stores(),
455 )?
456 else {
457 return Err(KeystoreCorruptionError::MissingCertificate.into());
458 };
459
460 let signed_with = self.get_cert_signing_key::<K, C>(spec)?;
462 let cert = C::validate(cert, &key, &signed_with)?;
463
464 Ok(Some((key, cert)))
465 }
466
467 #[cfg(feature = "experimental-api")]
503 pub fn get_or_generate_key_and_cert<K, C>(
504 &self,
505 spec: &dyn KeyCertificateSpecifier,
506 make_certificate: impl FnOnce(&K, &<C as ToEncodableCert<K>>::SigningKey) -> C,
507 selector: KeystoreSelector,
508 rng: &mut dyn KeygenRng,
509 ) -> Result<(K, C)>
510 where
511 K: ToEncodableKey,
512 K::Key: Keygen,
513 C: ToEncodableCert<K>,
514 {
515 let subject_key_spec = spec.subject_key_specifier();
516 let subject_key_arti_path = subject_key_spec
517 .arti_path()
518 .map_err(|_| bad_api_usage!("subject key does not have an ArtiPath?!"))?;
519
520 let cert_specifier =
521 ArtiPath::from_path_and_denotators(subject_key_arti_path, &spec.cert_denotators())
522 .map_err(into_bad_api_usage!("invalid certificate specifier"))?;
523
524 let maybe_cert = self.get_from_store_raw::<C::ParsedCert>(
525 &cert_specifier,
526 &C::ParsedCert::item_type(),
527 self.all_stores(),
528 )?;
529
530 let maybe_subject_key = self.get::<K>(subject_key_spec)?;
531
532 match (&maybe_cert, &maybe_subject_key) {
533 (Some(_), None) => {
534 return Err(KeystoreCorruptionError::MissingSubjectKey.into());
535 }
536 _ => {
537 }
539 }
540 let subject_key = match maybe_subject_key {
541 Some(key) => key,
542 _ => self.generate(subject_key_spec, selector, rng, false)?,
543 };
544
545 let signed_with = self.get_cert_signing_key::<K, C>(spec)?;
546 let cert = match maybe_cert {
547 Some(cert) => C::validate(cert, &subject_key, &signed_with)?,
548 None => {
549 let cert = make_certificate(&subject_key, &signed_with);
550
551 let () = self.insert_cert(cert.clone(), &cert_specifier, selector)?;
552
553 cert
554 }
555 };
556
557 Ok((subject_key, cert))
558 }
559
560 fn all_stores(&self) -> impl Iterator<Item = &BoxedKeystore> {
562 iter::once(&self.primary_store).chain(self.secondary_stores.iter())
563 }
564
565 fn select_keystore(&self, selector: &KeystoreSelector) -> Result<&BoxedKeystore> {
570 match selector {
571 KeystoreSelector::Id(keystore_id) => self.find_keystore(keystore_id),
572 KeystoreSelector::Primary => Ok(&self.primary_store),
573 }
574 }
575
576 fn find_keystore(&self, id: &KeystoreId) -> Result<&BoxedKeystore> {
581 self.all_stores()
582 .find(|keystore| keystore.id() == id)
583 .ok_or_else(|| bad_api_usage!("could not find keystore with ID {id}").into())
584 }
585
586 #[cfg(feature = "experimental-api")]
591 fn get_cert_signing_key<K, C>(
592 &self,
593 spec: &dyn KeyCertificateSpecifier,
594 ) -> Result<C::SigningKey>
595 where
596 K: ToEncodableKey,
597 C: ToEncodableCert<K>,
598 {
599 let Some(signing_key_spec) = spec.signing_key_specifier() else {
600 return Err(bad_api_usage!(
601 "signing key specifier is None, but external signing key was not provided?"
602 )
603 .into());
604 };
605
606 let Some(signing_key) = self.get_from_store::<C::SigningKey>(
607 signing_key_spec,
608 &<C::SigningKey as ToEncodableKey>::Key::item_type(),
609 self.all_stores(),
610 )?
611 else {
612 return Err(KeystoreCorruptionError::MissingSigningKey.into());
613 };
614
615 Ok(signing_key)
616 }
617
618 fn insert_cert<K, C>(
625 &self,
626 cert: C,
627 cert_spec: &dyn KeySpecifier,
628 selector: KeystoreSelector,
629 ) -> Result<()>
630 where
631 K: ToEncodableKey,
632 K::Key: Keygen,
633 C: ToEncodableCert<K>,
634 {
635 let cert = cert.to_encodable_cert();
636 let store = self.select_keystore(&selector)?;
637
638 let () = store.insert(&cert, cert_spec)?;
639 Ok(())
640 }
641}
642
643#[cfg(test)]
644mod tests {
645 #![allow(clippy::bool_assert_comparison)]
647 #![allow(clippy::clone_on_copy)]
648 #![allow(clippy::dbg_macro)]
649 #![allow(clippy::mixed_attributes_style)]
650 #![allow(clippy::print_stderr)]
651 #![allow(clippy::print_stdout)]
652 #![allow(clippy::single_char_pattern)]
653 #![allow(clippy::unwrap_used)]
654 #![allow(clippy::unchecked_duration_subtraction)]
655 #![allow(clippy::useless_vec)]
656 #![allow(clippy::needless_pass_by_value)]
657 use super::*;
659 use crate::{ArtiPath, ArtiPathUnavailableError, KeyPath};
660 use std::collections::HashMap;
661 use std::result::Result as StdResult;
662 use std::str::FromStr;
663 use std::sync::RwLock;
664 use std::time::{Duration, SystemTime};
665 use tor_basic_utils::test_rng::testing_rng;
666 use tor_cert::CertifiedKey;
667 use tor_cert::Ed25519Cert;
668 use tor_key_forge::{
669 CertData, EncodableItem, ErasedKey, InvalidCertError, KeyType, KeystoreItem,
670 };
671 use tor_llcrypto::pk::ed25519::{self, Ed25519PublicKey as _};
672 use tor_llcrypto::rng::FakeEntropicRng;
673
674 #[derive(Clone, Debug, PartialEq)]
676 struct KeyMetadata {
677 item_id: String,
679 retrieved_from: Option<KeystoreId>,
683 is_generated: bool,
685 }
686
687 #[derive(Clone, Debug, PartialEq)]
689 struct CertMetadata {
690 subject_key_id: String,
692 signing_key_id: String,
694 retrieved_from: Option<KeystoreId>,
698 is_generated: bool,
701 }
702
703 #[derive(Clone, Debug, PartialEq, derive_more::From)]
705 enum ItemMetadata {
706 Key(KeyMetadata),
708 Cert(CertMetadata),
710 }
711
712 impl ItemMetadata {
713 fn item_id(&self) -> &str {
718 match self {
719 ItemMetadata::Key(k) => &k.item_id,
720 ItemMetadata::Cert(c) => &c.subject_key_id,
721 }
722 }
723
724 fn retrieved_from(&self) -> Option<&KeystoreId> {
726 match self {
727 ItemMetadata::Key(k) => k.retrieved_from.as_ref(),
728 ItemMetadata::Cert(c) => c.retrieved_from.as_ref(),
729 }
730 }
731
732 fn is_generated(&self) -> bool {
734 match self {
735 ItemMetadata::Key(k) => k.is_generated,
736 ItemMetadata::Cert(c) => c.is_generated,
737 }
738 }
739
740 fn set_retrieved_from(&mut self, id: KeystoreId) {
742 match self {
743 ItemMetadata::Key(meta) => meta.retrieved_from = Some(id),
744 ItemMetadata::Cert(meta) => meta.retrieved_from = Some(id),
745 }
746 }
747
748 fn as_key(&self) -> Option<&KeyMetadata> {
750 match self {
751 ItemMetadata::Key(meta) => Some(meta),
752 _ => None,
753 }
754 }
755
756 fn as_cert(&self) -> Option<&CertMetadata> {
758 match self {
759 ItemMetadata::Cert(meta) => Some(meta),
760 _ => None,
761 }
762 }
763 }
764
765 #[derive(Clone, Debug)]
767 struct TestItem {
768 item: KeystoreItem,
770 meta: ItemMetadata,
772 }
773
774 #[derive(Clone, Debug)]
776 struct AlwaysValidCert(TestItem);
777
778 #[derive(Clone, Debug)]
780 struct TestPublicKey {
781 key: KeystoreItem,
783 }
784
785 impl From<TestItem> for TestPublicKey {
786 fn from(tk: TestItem) -> TestPublicKey {
787 TestPublicKey { key: tk.item }
788 }
789 }
790
791 impl TestItem {
792 fn new(item_id: &str) -> Self {
794 let mut rng = testing_rng();
795 TestItem {
796 item: ed25519::Keypair::generate(&mut rng)
797 .as_keystore_item()
798 .unwrap(),
799 meta: ItemMetadata::Key(KeyMetadata {
800 item_id: item_id.to_string(),
801 retrieved_from: None,
802 is_generated: false,
803 }),
804 }
805 }
806 }
807
808 impl Keygen for TestItem {
809 fn generate(mut rng: &mut dyn KeygenRng) -> tor_key_forge::Result<Self>
810 where
811 Self: Sized,
812 {
813 Ok(TestItem {
814 item: ed25519::Keypair::generate(&mut rng).as_keystore_item()?,
815 meta: ItemMetadata::Key(KeyMetadata {
816 item_id: "generated_test_key".to_string(),
817 retrieved_from: None,
818 is_generated: true,
819 }),
820 })
821 }
822 }
823
824 impl ItemType for TestItem {
825 fn item_type() -> KeystoreItemType
826 where
827 Self: Sized,
828 {
829 KeyType::Ed25519Keypair.into()
831 }
832 }
833
834 impl EncodableItem for TestItem {
835 fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
836 Ok(self.item.clone())
837 }
838 }
839
840 impl ToEncodableKey for TestItem {
841 type Key = Self;
842 type KeyPair = Self;
843
844 fn to_encodable_key(self) -> Self::Key {
845 self
846 }
847
848 fn from_encodable_key(key: Self::Key) -> Self {
849 key
850 }
851 }
852
853 impl ItemType for TestPublicKey {
854 fn item_type() -> KeystoreItemType
855 where
856 Self: Sized,
857 {
858 KeyType::Ed25519PublicKey.into()
859 }
860 }
861
862 impl EncodableItem for TestPublicKey {
863 fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
864 Ok(self.key.clone())
865 }
866 }
867
868 impl ToEncodableKey for TestPublicKey {
869 type Key = Self;
870 type KeyPair = TestItem;
871
872 fn to_encodable_key(self) -> Self::Key {
873 self
874 }
875
876 fn from_encodable_key(key: Self::Key) -> Self {
877 key
878 }
879 }
880
881 impl ToEncodableCert<TestItem> for AlwaysValidCert {
882 type ParsedCert = TestItem;
883 type EncodableCert = TestItem;
884 type SigningKey = TestItem;
885
886 fn validate(
887 cert: Self::ParsedCert,
888 _subject: &TestItem,
889 _signed_with: &Self::SigningKey,
890 ) -> StdResult<Self, InvalidCertError> {
891 Ok(Self(cert))
893 }
894
895 fn to_encodable_cert(self) -> Self::EncodableCert {
897 self.0
898 }
899 }
900
901 macro_rules! impl_keystore {
902 ($name:tt, $id:expr) => {
903 struct $name {
904 inner: RwLock<HashMap<(ArtiPath, KeystoreItemType), TestItem>>,
905 id: KeystoreId,
906 }
907
908 impl Default for $name {
909 fn default() -> Self {
910 Self {
911 inner: Default::default(),
912 id: KeystoreId::from_str($id).unwrap(),
913 }
914 }
915 }
916
917 #[allow(dead_code)] impl $name {
919 fn new_boxed() -> BoxedKeystore {
920 Box::<Self>::default()
921 }
922 }
923
924 impl crate::Keystore for $name {
925 fn contains(
926 &self,
927 key_spec: &dyn KeySpecifier,
928 item_type: &KeystoreItemType,
929 ) -> Result<bool> {
930 Ok(self
931 .inner
932 .read()
933 .unwrap()
934 .contains_key(&(key_spec.arti_path().unwrap(), item_type.clone())))
935 }
936
937 fn id(&self) -> &KeystoreId {
938 &self.id
939 }
940
941 fn get(
942 &self,
943 key_spec: &dyn KeySpecifier,
944 item_type: &KeystoreItemType,
945 ) -> Result<Option<ErasedKey>> {
946 Ok(self
947 .inner
948 .read()
949 .unwrap()
950 .get(&(key_spec.arti_path().unwrap(), item_type.clone()))
951 .map(|k| {
952 let mut k = k.clone();
953 k.meta.set_retrieved_from(self.id().clone());
954 Box::new(k) as Box<dyn ItemType>
955 }))
956 }
957
958 fn insert(
959 &self,
960 key: &dyn EncodableItem,
961 key_spec: &dyn KeySpecifier,
962 ) -> Result<()> {
963 let key = key.downcast_ref::<TestItem>().unwrap();
964
965 let item = key.as_keystore_item()?;
966 let meta = key.meta.clone();
967
968 let item_type = item.item_type()?;
969 let key = TestItem { item, meta };
970
971 self.inner
972 .write()
973 .unwrap()
974 .insert((key_spec.arti_path().unwrap(), item_type), key);
975
976 Ok(())
977 }
978
979 fn remove(
980 &self,
981 key_spec: &dyn KeySpecifier,
982 item_type: &KeystoreItemType,
983 ) -> Result<Option<()>> {
984 Ok(self
985 .inner
986 .write()
987 .unwrap()
988 .remove(&(key_spec.arti_path().unwrap(), item_type.clone()))
989 .map(|_| ()))
990 }
991
992 fn list(&self) -> Result<Vec<(KeyPath, KeystoreItemType)>> {
993 Ok(self
994 .inner
995 .read()
996 .unwrap()
997 .iter()
998 .map(|((arti_path, item_type), _)| {
999 (KeyPath::Arti(arti_path.clone()), item_type.clone())
1000 })
1001 .collect())
1002 }
1003 }
1004 };
1005 }
1006
1007 macro_rules! impl_specifier {
1008 ($name:tt, $id:expr) => {
1009 struct $name;
1010
1011 impl KeySpecifier for $name {
1012 fn arti_path(&self) -> StdResult<ArtiPath, ArtiPathUnavailableError> {
1013 Ok(ArtiPath::new($id.into()).map_err(|e| tor_error::internal!("{e}"))?)
1014 }
1015
1016 fn ctor_path(&self) -> Option<crate::CTorPath> {
1017 None
1018 }
1019
1020 fn keypair_specifier(&self) -> Option<Box<dyn KeySpecifier>> {
1021 None
1022 }
1023 }
1024 };
1025 }
1026
1027 impl_keystore!(Keystore1, "keystore1");
1028 impl_keystore!(Keystore2, "keystore2");
1029 impl_keystore!(Keystore3, "keystore3");
1030
1031 impl_specifier!(TestKeySpecifier1, "spec1");
1032 impl_specifier!(TestKeySpecifier2, "spec2");
1033 impl_specifier!(TestKeySpecifier3, "spec3");
1034 impl_specifier!(TestKeySpecifier4, "spec4");
1035
1036 impl_specifier!(TestPublicKeySpecifier1, "pub-spec1");
1037
1038 fn entry_descriptor(specifier: impl KeySpecifier, keystore_id: &KeystoreId) -> KeystoreEntry {
1040 KeystoreEntry {
1041 key_path: specifier.arti_path().unwrap().into(),
1042 key_type: TestItem::item_type(),
1043 keystore_id,
1044 }
1045 }
1046
1047 #[test]
1048 #[allow(clippy::cognitive_complexity)]
1049 fn insert_and_get() {
1050 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1051
1052 builder
1053 .secondary_stores()
1054 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1055
1056 let mgr = builder.build().unwrap();
1057
1058 let old_key = mgr
1060 .insert(
1061 TestItem::new("coot"),
1062 &TestKeySpecifier1,
1063 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1064 true,
1065 )
1066 .unwrap();
1067
1068 assert!(old_key.is_none());
1069 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1070 assert_eq!(key.meta.item_id(), "coot");
1071 assert_eq!(
1072 key.meta.retrieved_from(),
1073 Some(&KeystoreId::from_str("keystore2").unwrap())
1074 );
1075 assert_eq!(key.meta.is_generated(), false);
1076
1077 let old_key = mgr
1079 .insert(
1080 TestItem::new("gull"),
1081 &TestKeySpecifier1,
1082 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1083 true,
1084 )
1085 .unwrap()
1086 .unwrap();
1087 assert_eq!(old_key.meta.item_id(), "coot");
1088 assert_eq!(
1089 old_key.meta.retrieved_from(),
1090 Some(&KeystoreId::from_str("keystore2").unwrap())
1091 );
1092 assert_eq!(old_key.meta.is_generated(), false);
1093 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1095 assert_eq!(key.meta.item_id(), "gull");
1096 assert_eq!(
1097 key.meta.retrieved_from(),
1098 Some(&KeystoreId::from_str("keystore2").unwrap())
1099 );
1100 assert_eq!(key.meta.is_generated(), false);
1101
1102 let err = mgr
1104 .insert(
1105 TestItem::new("gull"),
1106 &TestKeySpecifier1,
1107 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1108 false,
1109 )
1110 .unwrap_err();
1111 assert!(matches!(err, crate::Error::KeyAlreadyExists));
1112
1113 let old_key = mgr
1115 .insert(
1116 TestItem::new("penguin"),
1117 &TestKeySpecifier2,
1118 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1119 false,
1120 )
1121 .unwrap();
1122 assert!(old_key.is_none());
1123
1124 let old_key = mgr
1126 .insert(
1127 TestItem::new("moorhen"),
1128 &TestKeySpecifier3,
1129 KeystoreSelector::Primary,
1130 true,
1131 )
1132 .unwrap();
1133 assert!(old_key.is_none());
1134 let key = mgr.get::<TestItem>(&TestKeySpecifier3).unwrap().unwrap();
1135 assert_eq!(key.meta.item_id(), "moorhen");
1136 assert_eq!(
1137 key.meta.retrieved_from(),
1138 Some(&KeystoreId::from_str("keystore1").unwrap())
1139 );
1140 assert_eq!(key.meta.is_generated(), false);
1141
1142 assert!(mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().is_none());
1144
1145 for store in ["keystore3", "keystore2", "keystore1"] {
1149 let old_key = mgr
1150 .insert(
1151 TestItem::new("cormorant"),
1152 &TestKeySpecifier4,
1153 KeystoreSelector::Id(&KeystoreId::from_str(store).unwrap()),
1154 true,
1155 )
1156 .unwrap();
1157 assert!(old_key.is_none());
1158
1159 let key = mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().unwrap();
1161 assert_eq!(key.meta.item_id(), "cormorant");
1162 assert_eq!(
1163 key.meta.retrieved_from(),
1164 Some(&KeystoreId::from_str(store).unwrap())
1165 );
1166 assert_eq!(key.meta.is_generated(), false);
1167 }
1168
1169 let key = mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().unwrap();
1172 assert_eq!(key.meta.item_id(), "cormorant");
1173 assert_eq!(
1174 key.meta.retrieved_from(),
1175 Some(&KeystoreId::from_str("keystore1").unwrap())
1176 );
1177 assert_eq!(key.meta.is_generated(), false);
1178 }
1179
1180 #[test]
1181 fn remove() {
1182 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1183
1184 builder
1185 .secondary_stores()
1186 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1187
1188 let mgr = builder.build().unwrap();
1189
1190 assert!(!mgr.secondary_stores[0]
1191 .contains(&TestKeySpecifier1, &TestItem::item_type())
1192 .unwrap());
1193
1194 mgr.insert(
1196 TestItem::new("coot"),
1197 &TestKeySpecifier1,
1198 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1199 true,
1200 )
1201 .unwrap();
1202 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1203 assert_eq!(key.meta.item_id(), "coot");
1204 assert_eq!(
1205 key.meta.retrieved_from(),
1206 Some(&KeystoreId::from_str("keystore2").unwrap())
1207 );
1208 assert_eq!(key.meta.is_generated(), false);
1209
1210 assert!(mgr
1212 .remove::<TestItem>(
1213 &TestKeySpecifier1,
1214 KeystoreSelector::Id(&KeystoreId::from_str("not_an_id_we_know_of").unwrap())
1215 )
1216 .is_err());
1217 assert!(mgr.secondary_stores[0]
1219 .contains(&TestKeySpecifier1, &TestItem::item_type())
1220 .unwrap());
1221
1222 assert!(mgr
1224 .remove::<TestItem>(&TestKeySpecifier1, KeystoreSelector::Primary)
1225 .unwrap()
1226 .is_none());
1227
1228 assert!(mgr.secondary_stores[0]
1230 .contains(&TestKeySpecifier1, &TestItem::item_type())
1231 .unwrap());
1232
1233 let removed_key = mgr
1235 .remove::<TestItem>(
1236 &TestKeySpecifier1,
1237 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1238 )
1239 .unwrap()
1240 .unwrap();
1241 assert_eq!(removed_key.meta.item_id(), "coot");
1242 assert_eq!(
1243 removed_key.meta.retrieved_from(),
1244 Some(&KeystoreId::from_str("keystore2").unwrap())
1245 );
1246 assert_eq!(removed_key.meta.is_generated(), false);
1247
1248 assert!(!mgr.secondary_stores[0]
1250 .contains(&TestKeySpecifier1, &TestItem::item_type())
1251 .unwrap());
1252 }
1253
1254 #[test]
1255 fn keygen() {
1256 let mut rng = FakeEntropicRng(testing_rng());
1257 let mgr = KeyMgrBuilder::default()
1258 .primary_store(Box::<Keystore1>::default())
1259 .build()
1260 .unwrap();
1261
1262 mgr.insert(
1263 TestItem::new("coot"),
1264 &TestKeySpecifier1,
1265 KeystoreSelector::Primary,
1266 true,
1267 )
1268 .unwrap();
1269
1270 assert!(mgr
1272 .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1273 .unwrap()
1274 .is_none());
1275
1276 let err = mgr
1278 .generate::<TestItem>(
1279 &TestKeySpecifier1,
1280 KeystoreSelector::Primary,
1281 &mut rng,
1282 false,
1283 )
1284 .unwrap_err();
1285
1286 assert!(matches!(err, crate::Error::KeyAlreadyExists));
1287
1288 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1290 assert_eq!(key.meta.item_id(), "coot");
1291 assert_eq!(
1292 key.meta.retrieved_from(),
1293 Some(&KeystoreId::from_str("keystore1").unwrap())
1294 );
1295 assert_eq!(key.meta.is_generated(), false);
1296
1297 assert!(mgr
1299 .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1300 .unwrap()
1301 .is_none());
1302
1303 let generated_key = mgr
1305 .generate::<TestItem>(
1306 &TestKeySpecifier1,
1307 KeystoreSelector::Primary,
1308 &mut rng,
1309 true,
1310 )
1311 .unwrap();
1312
1313 assert_eq!(generated_key.meta.item_id(), "generated_test_key");
1314 assert_eq!(generated_key.meta.retrieved_from(), None);
1317 assert_eq!(generated_key.meta.is_generated(), true);
1318
1319 let retrieved_key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1321 assert_eq!(retrieved_key.meta.item_id(), "generated_test_key");
1322 assert_eq!(
1323 retrieved_key.meta.retrieved_from(),
1324 Some(&KeystoreId::from_str("keystore1").unwrap())
1325 );
1326 assert_eq!(retrieved_key.meta.is_generated(), true);
1327
1328 assert!(mgr
1330 .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1331 .unwrap()
1332 .is_none());
1333 }
1334
1335 #[test]
1336 fn get_or_generate() {
1337 let mut rng = FakeEntropicRng(testing_rng());
1338 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1339
1340 builder
1341 .secondary_stores()
1342 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1343
1344 let mgr = builder.build().unwrap();
1345
1346 let keystore2 = KeystoreId::from_str("keystore2").unwrap();
1347 let entry_desc1 = entry_descriptor(TestKeySpecifier1, &keystore2);
1348 assert!(mgr.get_entry::<TestItem>(&entry_desc1).unwrap().is_none());
1349
1350 mgr.insert(
1351 TestItem::new("coot"),
1352 &TestKeySpecifier1,
1353 KeystoreSelector::Id(&keystore2),
1354 true,
1355 )
1356 .unwrap();
1357
1358 let key = mgr
1360 .get_or_generate::<TestItem>(&TestKeySpecifier1, KeystoreSelector::Primary, &mut rng)
1361 .unwrap();
1362 assert_eq!(key.meta.item_id(), "coot");
1363 assert_eq!(
1364 key.meta.retrieved_from(),
1365 Some(&KeystoreId::from_str("keystore2").unwrap())
1366 );
1367 assert_eq!(key.meta.is_generated(), false);
1368
1369 assert_eq!(
1370 mgr.get_entry::<TestItem>(&entry_desc1)
1371 .unwrap()
1372 .map(|k| k.meta),
1373 Some(ItemMetadata::Key(KeyMetadata {
1374 item_id: "coot".to_string(),
1375 retrieved_from: Some(keystore2.clone()),
1376 is_generated: false,
1377 }))
1378 );
1379
1380 let keystore3 = KeystoreId::from_str("keystore3").unwrap();
1383 let generated_key = mgr
1384 .get_or_generate::<TestItem>(
1385 &TestKeySpecifier2,
1386 KeystoreSelector::Id(&keystore3),
1387 &mut rng,
1388 )
1389 .unwrap();
1390 assert_eq!(generated_key.meta.item_id(), "generated_test_key");
1391 assert_eq!(generated_key.meta.retrieved_from(), None);
1394 assert_eq!(generated_key.meta.is_generated(), true);
1395
1396 let retrieved_key = mgr.get::<TestItem>(&TestKeySpecifier2).unwrap().unwrap();
1398 assert_eq!(retrieved_key.meta.item_id(), "generated_test_key");
1399 assert_eq!(
1400 retrieved_key.meta.retrieved_from(),
1401 Some(&KeystoreId::from_str("keystore3").unwrap())
1402 );
1403 assert_eq!(retrieved_key.meta.is_generated(), true);
1404
1405 let entry_desc2 = entry_descriptor(TestKeySpecifier2, &keystore3);
1406 assert_eq!(
1407 mgr.get_entry::<TestItem>(&entry_desc2)
1408 .unwrap()
1409 .map(|k| k.meta),
1410 Some(ItemMetadata::Key(KeyMetadata {
1411 item_id: "generated_test_key".to_string(),
1412 retrieved_from: Some(keystore3.clone()),
1413 is_generated: true,
1414 }))
1415 );
1416
1417 let arti_pat = KeyPathPattern::Arti("*".to_string());
1418 let matching = mgr.list_matching(&arti_pat).unwrap();
1419
1420 assert_eq!(matching.len(), 2);
1421 assert!(matching.contains(&entry_desc1));
1422 assert!(matching.contains(&entry_desc2));
1423
1424 assert_eq!(mgr.remove_entry(&entry_desc2).unwrap(), Some(()));
1425 assert!(mgr.get_entry::<TestItem>(&entry_desc2).unwrap().is_none());
1426 assert!(mgr.remove_entry(&entry_desc2).unwrap().is_none());
1427 }
1428
1429 #[cfg(feature = "experimental-api")]
1431 #[derive(Clone, Copy, Debug, PartialEq)]
1432 enum GenerateItem {
1433 Yes,
1434 No,
1435 }
1436
1437 #[cfg(feature = "experimental-api")]
1438 macro_rules! run_certificate_test {
1439 (
1440 generate_subject_key = $generate_subject_key:expr,
1441 generate_signing_key = $generate_signing_key:expr,
1442 $($expected_err:tt)?
1443 ) => {{
1444 use GenerateItem::*;
1445
1446 let mut rng = FakeEntropicRng(testing_rng());
1447 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1448
1449 builder
1450 .secondary_stores()
1451 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1452
1453 let mgr = builder.build().unwrap();
1454
1455 let spec = crate::test_utils::TestCertSpecifier {
1456 subject_key_spec: TestKeySpecifier1,
1457 signing_key_spec: TestKeySpecifier2,
1458 denotator: vec!["foo".into()],
1459 };
1460
1461 if $generate_subject_key == Yes {
1462 let _ = mgr
1463 .generate::<TestItem>(
1464 &TestKeySpecifier1,
1465 KeystoreSelector::Primary,
1466 &mut rng,
1467 false,
1468 )
1469 .unwrap();
1470 }
1471
1472 if $generate_signing_key == Yes {
1473 let _ = mgr
1474 .generate::<TestItem>(
1475 &TestKeySpecifier2,
1476 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1477 &mut rng,
1478 false,
1479 )
1480 .unwrap();
1481 }
1482
1483 let make_certificate = move |subject_key: &TestItem, signed_with: &TestItem| {
1484 let subject_id = subject_key.meta.as_key().unwrap().item_id.clone();
1485 let signing_id = signed_with.meta.as_key().unwrap().item_id.clone();
1486
1487 let meta = ItemMetadata::Cert(CertMetadata {
1488 subject_key_id: subject_id,
1489 signing_key_id: signing_id,
1490 retrieved_from: None,
1491 is_generated: true,
1492 });
1493
1494 let mut rng = FakeEntropicRng(testing_rng());
1500 let keypair = ed25519::Keypair::generate(&mut rng);
1501 let encoded_cert = Ed25519Cert::constructor()
1502 .cert_type(tor_cert::CertType::IDENTITY_V_SIGNING)
1503 .expiration(SystemTime::now() + Duration::from_secs(180))
1504 .signing_key(keypair.public_key().into())
1505 .cert_key(CertifiedKey::Ed25519(keypair.public_key().into()))
1506 .encode_and_sign(&keypair)
1507 .unwrap();
1508 let test_cert = CertData::TorEd25519Cert(encoded_cert);
1509 AlwaysValidCert(TestItem {
1510 item: KeystoreItem::Cert(test_cert),
1511 meta,
1512 })
1513 };
1514
1515 let res = mgr
1516 .get_or_generate_key_and_cert::<TestItem, AlwaysValidCert>(
1517 &spec,
1518 &make_certificate,
1519 KeystoreSelector::Primary,
1520 &mut rng,
1521 );
1522
1523 #[allow(unused_assignments)]
1524 #[allow(unused_mut)]
1525 let mut has_error = false;
1526 $(
1527 has_error = true;
1528 let err = res.clone().unwrap_err();
1529 assert!(
1530 matches!(
1531 err,
1532 crate::Error::Corruption(KeystoreCorruptionError::$expected_err)
1533 ),
1534 "unexpected error: {err:?}",
1535 );
1536 )?
1537
1538 if !has_error {
1539 let (key, cert) = res.unwrap();
1540
1541 let expected_subj_key_id = if $generate_subject_key == Yes {
1542 "generated_test_key"
1543 } else {
1544 "generated_test_key"
1545 };
1546
1547 assert_eq!(key.meta.item_id(), expected_subj_key_id);
1548 assert_eq!(
1549 cert.0.meta.as_cert().unwrap().subject_key_id,
1550 expected_subj_key_id
1551 );
1552 assert_eq!(
1553 cert.0.meta.as_cert().unwrap().signing_key_id,
1554 "generated_test_key"
1555 );
1556 assert_eq!(cert.0.meta.is_generated(), true);
1557 }
1558 }}
1559 }
1560
1561 #[test]
1562 #[cfg(feature = "experimental-api")]
1563 #[rustfmt::skip] #[allow(clippy::cognitive_complexity)] fn get_certificate() {
1566 run_certificate_test!(
1567 generate_subject_key = No,
1568 generate_signing_key = No,
1569 MissingSigningKey
1570 );
1571
1572 run_certificate_test!(
1573 generate_subject_key = Yes,
1574 generate_signing_key = No,
1575 MissingSigningKey
1576 );
1577
1578 run_certificate_test!(
1579 generate_subject_key = No,
1580 generate_signing_key = Yes,
1581 );
1582
1583 run_certificate_test!(
1584 generate_subject_key = Yes,
1585 generate_signing_key = Yes,
1586 );
1587 }
1588}