1use crate::{
6 ArtiPath, BoxedKeystore, KeyCertificateSpecifier, KeyPath, KeyPathError, KeyPathInfo,
7 KeyPathInfoExtractor, KeyPathPattern, KeySpecifier, KeystoreCorruptionError,
8 KeystoreEntryResult, KeystoreId, 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 #[cfg(feature = "onion-service-cli-extra")]
339 pub fn list_by_id(
340 &self,
341 id: &KeystoreId,
342 ) -> Result<Vec<KeystoreEntryResult<(KeyPath, KeystoreItemType)>>> {
343 self.find_keystore(id)?.list()
344 }
345
346 #[cfg(feature = "onion-service-cli-extra")]
348 pub fn list(&self) -> Result<Vec<KeystoreEntryResult<KeystoreEntry>>> {
349 self.all_stores()
350 .map(|store| -> Result<Vec<_>> {
351 Ok(store
352 .list()?
353 .into_iter()
354 .map(|entry| match entry {
355 Ok((key_path, key_type)) => Ok(KeystoreEntry {
356 key_path: key_path.clone(),
357 key_type,
358 keystore_id: store.id(),
359 }),
360 Err(e) => Err(e),
361 })
362 .collect::<Vec<_>>())
363 })
364 .flatten_ok()
365 .collect::<Result<Vec<_>>>()
366 }
367
368 #[cfg(feature = "onion-service-cli-extra")]
370 pub fn list_keystores(&self) -> Vec<KeystoreId> {
371 self.all_stores()
372 .map(|store| store.id().to_owned())
373 .collect()
374 }
375
376 pub fn describe(&self, path: &KeyPath) -> StdResult<KeyPathInfo, KeyPathError> {
385 for info_extractor in &self.key_info_extractors {
386 if let Ok(info) = info_extractor.describe(path) {
387 return Ok(info);
388 }
389 }
390
391 Err(KeyPathError::Unrecognized(path.clone()))
392 }
393
394 fn get_from_store_raw<'a, K: ItemType>(
400 &self,
401 key_spec: &dyn KeySpecifier,
402 key_type: &KeystoreItemType,
403 stores: impl Iterator<Item = &'a BoxedKeystore>,
404 ) -> Result<Option<K>> {
405 let static_key_type = K::item_type();
406 if key_type != &static_key_type {
407 return Err(internal!(
408 "key type {:?} does not match the key type {:?} of requested key K::Key",
409 key_type,
410 static_key_type
411 )
412 .into());
413 }
414
415 for store in stores {
416 let key = match store.get(key_spec, &K::item_type()) {
417 Ok(None) => {
418 continue;
420 }
421 Ok(Some(k)) => k,
422 Err(e) => {
423 return Err(e);
425 }
426 };
427
428 let key: K = key
430 .downcast::<K>()
431 .map(|k| *k)
432 .map_err(|_| internal!("failed to downcast key to requested type"))?;
433
434 return Ok(Some(key));
435 }
436
437 Ok(None)
438 }
439
440 fn get_from_store<'a, K: ToEncodableKey>(
444 &self,
445 key_spec: &dyn KeySpecifier,
446 key_type: &KeystoreItemType,
447 stores: impl Iterator<Item = &'a BoxedKeystore>,
448 ) -> Result<Option<K>> {
449 let Some(key) = self.get_from_store_raw::<K::Key>(key_spec, key_type, stores)? else {
450 return Ok(None);
451 };
452
453 Ok(Some(K::from_encodable_key(key)))
454 }
455
456 #[cfg(feature = "experimental-api")]
472 pub fn get_key_and_cert<K, C>(
473 &self,
474 spec: &dyn KeyCertificateSpecifier,
475 ) -> Result<Option<(K, C)>>
476 where
477 K: ToEncodableKey,
478 C: ToEncodableCert<K>,
479 {
480 let subject_key_spec = spec.subject_key_specifier();
481 let Some(key) =
483 self.get_from_store::<K>(subject_key_spec, &K::Key::item_type(), self.all_stores())?
484 else {
485 return Ok(None);
486 };
487
488 let subject_key_arti_path = subject_key_spec
489 .arti_path()
490 .map_err(|_| bad_api_usage!("subject key does not have an ArtiPath?!"))?;
491 let cert_spec =
492 ArtiPath::from_path_and_denotators(subject_key_arti_path, &spec.cert_denotators())
493 .map_err(into_bad_api_usage!("invalid certificate specifier"))?;
494
495 let Some(cert) = self.get_from_store_raw::<C::ParsedCert>(
496 &cert_spec,
497 &<C::ParsedCert as ItemType>::item_type(),
498 self.all_stores(),
499 )?
500 else {
501 return Err(KeystoreCorruptionError::MissingCertificate.into());
502 };
503
504 let signed_with = self.get_cert_signing_key::<K, C>(spec)?;
506 let cert = C::validate(cert, &key, &signed_with)?;
507
508 Ok(Some((key, cert)))
509 }
510
511 #[cfg(feature = "experimental-api")]
547 pub fn get_or_generate_key_and_cert<K, C>(
548 &self,
549 spec: &dyn KeyCertificateSpecifier,
550 make_certificate: impl FnOnce(&K, &<C as ToEncodableCert<K>>::SigningKey) -> C,
551 selector: KeystoreSelector,
552 rng: &mut dyn KeygenRng,
553 ) -> Result<(K, C)>
554 where
555 K: ToEncodableKey,
556 K::Key: Keygen,
557 C: ToEncodableCert<K>,
558 {
559 let subject_key_spec = spec.subject_key_specifier();
560 let subject_key_arti_path = subject_key_spec
561 .arti_path()
562 .map_err(|_| bad_api_usage!("subject key does not have an ArtiPath?!"))?;
563
564 let cert_specifier =
565 ArtiPath::from_path_and_denotators(subject_key_arti_path, &spec.cert_denotators())
566 .map_err(into_bad_api_usage!("invalid certificate specifier"))?;
567
568 let maybe_cert = self.get_from_store_raw::<C::ParsedCert>(
569 &cert_specifier,
570 &C::ParsedCert::item_type(),
571 self.all_stores(),
572 )?;
573
574 let maybe_subject_key = self.get::<K>(subject_key_spec)?;
575
576 match (&maybe_cert, &maybe_subject_key) {
577 (Some(_), None) => {
578 return Err(KeystoreCorruptionError::MissingSubjectKey.into());
579 }
580 _ => {
581 }
583 }
584 let subject_key = match maybe_subject_key {
585 Some(key) => key,
586 _ => self.generate(subject_key_spec, selector, rng, false)?,
587 };
588
589 let signed_with = self.get_cert_signing_key::<K, C>(spec)?;
590 let cert = match maybe_cert {
591 Some(cert) => C::validate(cert, &subject_key, &signed_with)?,
592 None => {
593 let cert = make_certificate(&subject_key, &signed_with);
594
595 let () = self.insert_cert(cert.clone(), &cert_specifier, selector)?;
596
597 cert
598 }
599 };
600
601 Ok((subject_key, cert))
602 }
603
604 fn all_stores(&self) -> impl Iterator<Item = &BoxedKeystore> {
606 iter::once(&self.primary_store).chain(self.secondary_stores.iter())
607 }
608
609 fn select_keystore(&self, selector: &KeystoreSelector) -> Result<&BoxedKeystore> {
614 match selector {
615 KeystoreSelector::Id(keystore_id) => self.find_keystore(keystore_id),
616 KeystoreSelector::Primary => Ok(&self.primary_store),
617 }
618 }
619
620 fn find_keystore(&self, id: &KeystoreId) -> Result<&BoxedKeystore> {
625 self.all_stores()
626 .find(|keystore| keystore.id() == id)
627 .ok_or_else(|| bad_api_usage!("could not find keystore with ID {id}").into())
628 }
629
630 #[cfg(feature = "experimental-api")]
635 fn get_cert_signing_key<K, C>(
636 &self,
637 spec: &dyn KeyCertificateSpecifier,
638 ) -> Result<C::SigningKey>
639 where
640 K: ToEncodableKey,
641 C: ToEncodableCert<K>,
642 {
643 let Some(signing_key_spec) = spec.signing_key_specifier() else {
644 return Err(bad_api_usage!(
645 "signing key specifier is None, but external signing key was not provided?"
646 )
647 .into());
648 };
649
650 let Some(signing_key) = self.get_from_store::<C::SigningKey>(
651 signing_key_spec,
652 &<C::SigningKey as ToEncodableKey>::Key::item_type(),
653 self.all_stores(),
654 )?
655 else {
656 return Err(KeystoreCorruptionError::MissingSigningKey.into());
657 };
658
659 Ok(signing_key)
660 }
661
662 fn insert_cert<K, C>(
669 &self,
670 cert: C,
671 cert_spec: &dyn KeySpecifier,
672 selector: KeystoreSelector,
673 ) -> Result<()>
674 where
675 K: ToEncodableKey,
676 K::Key: Keygen,
677 C: ToEncodableCert<K>,
678 {
679 let cert = cert.to_encodable_cert();
680 let store = self.select_keystore(&selector)?;
681
682 let () = store.insert(&cert, cert_spec)?;
683 Ok(())
684 }
685}
686
687#[cfg(test)]
688mod tests {
689 #![allow(clippy::bool_assert_comparison)]
691 #![allow(clippy::clone_on_copy)]
692 #![allow(clippy::dbg_macro)]
693 #![allow(clippy::mixed_attributes_style)]
694 #![allow(clippy::print_stderr)]
695 #![allow(clippy::print_stdout)]
696 #![allow(clippy::single_char_pattern)]
697 #![allow(clippy::unwrap_used)]
698 #![allow(clippy::unchecked_duration_subtraction)]
699 #![allow(clippy::useless_vec)]
700 #![allow(clippy::needless_pass_by_value)]
701 use super::*;
703 use crate::keystore::arti::err::{ArtiNativeKeystoreError, MalformedPathError};
704 use crate::{
705 ArtiPath, ArtiPathUnavailableError, Error, KeyPath, Keystore, KeystoreEntryResult,
706 KeystoreError, UnrecognizedEntryError, UnrecognizedEntryId,
707 };
708 use std::collections::HashMap;
709 use std::path::PathBuf;
710 use std::result::Result as StdResult;
711 use std::str::FromStr;
712 use std::sync::{Arc, RwLock};
713 use std::time::{Duration, SystemTime};
714 use tor_basic_utils::test_rng::testing_rng;
715 use tor_cert::CertifiedKey;
716 use tor_cert::Ed25519Cert;
717 use tor_error::{ErrorKind, HasKind};
718 use tor_key_forge::{
719 CertData, EncodableItem, ErasedKey, InvalidCertError, KeyType, KeystoreItem,
720 };
721 use tor_llcrypto::pk::ed25519::{self, Ed25519PublicKey as _};
722 use tor_llcrypto::rng::FakeEntropicRng;
723
724 #[derive(Clone, Debug, PartialEq)]
726 struct KeyMetadata {
727 item_id: String,
729 retrieved_from: Option<KeystoreId>,
733 is_generated: bool,
735 }
736
737 #[derive(Clone, Debug, PartialEq)]
739 struct CertMetadata {
740 subject_key_id: String,
742 signing_key_id: String,
744 retrieved_from: Option<KeystoreId>,
748 is_generated: bool,
751 }
752
753 #[derive(Clone, Debug, PartialEq, derive_more::From)]
755 enum ItemMetadata {
756 Key(KeyMetadata),
758 Cert(CertMetadata),
760 }
761
762 impl ItemMetadata {
763 fn item_id(&self) -> &str {
768 match self {
769 ItemMetadata::Key(k) => &k.item_id,
770 ItemMetadata::Cert(c) => &c.subject_key_id,
771 }
772 }
773
774 fn retrieved_from(&self) -> Option<&KeystoreId> {
776 match self {
777 ItemMetadata::Key(k) => k.retrieved_from.as_ref(),
778 ItemMetadata::Cert(c) => c.retrieved_from.as_ref(),
779 }
780 }
781
782 fn is_generated(&self) -> bool {
784 match self {
785 ItemMetadata::Key(k) => k.is_generated,
786 ItemMetadata::Cert(c) => c.is_generated,
787 }
788 }
789
790 fn set_retrieved_from(&mut self, id: KeystoreId) {
792 match self {
793 ItemMetadata::Key(meta) => meta.retrieved_from = Some(id),
794 ItemMetadata::Cert(meta) => meta.retrieved_from = Some(id),
795 }
796 }
797
798 fn as_key(&self) -> Option<&KeyMetadata> {
800 match self {
801 ItemMetadata::Key(meta) => Some(meta),
802 _ => None,
803 }
804 }
805
806 fn as_cert(&self) -> Option<&CertMetadata> {
808 match self {
809 ItemMetadata::Cert(meta) => Some(meta),
810 _ => None,
811 }
812 }
813 }
814
815 #[derive(Clone, Debug)]
817 struct TestItem {
818 item: KeystoreItem,
820 meta: ItemMetadata,
822 }
823
824 #[derive(Clone, Debug)]
826 struct AlwaysValidCert(TestItem);
827
828 #[derive(Clone, Debug)]
830 struct TestPublicKey {
831 key: KeystoreItem,
833 }
834
835 impl From<TestItem> for TestPublicKey {
836 fn from(tk: TestItem) -> TestPublicKey {
837 TestPublicKey { key: tk.item }
838 }
839 }
840
841 impl TestItem {
842 fn new(item_id: &str) -> Self {
844 let mut rng = testing_rng();
845 TestItem {
846 item: ed25519::Keypair::generate(&mut rng)
847 .as_keystore_item()
848 .unwrap(),
849 meta: ItemMetadata::Key(KeyMetadata {
850 item_id: item_id.to_string(),
851 retrieved_from: None,
852 is_generated: false,
853 }),
854 }
855 }
856 }
857
858 impl Keygen for TestItem {
859 fn generate(mut rng: &mut dyn KeygenRng) -> tor_key_forge::Result<Self>
860 where
861 Self: Sized,
862 {
863 Ok(TestItem {
864 item: ed25519::Keypair::generate(&mut rng).as_keystore_item()?,
865 meta: ItemMetadata::Key(KeyMetadata {
866 item_id: "generated_test_key".to_string(),
867 retrieved_from: None,
868 is_generated: true,
869 }),
870 })
871 }
872 }
873
874 impl ItemType for TestItem {
875 fn item_type() -> KeystoreItemType
876 where
877 Self: Sized,
878 {
879 KeyType::Ed25519Keypair.into()
881 }
882 }
883
884 impl EncodableItem for TestItem {
885 fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
886 Ok(self.item.clone())
887 }
888 }
889
890 impl ToEncodableKey for TestItem {
891 type Key = Self;
892 type KeyPair = Self;
893
894 fn to_encodable_key(self) -> Self::Key {
895 self
896 }
897
898 fn from_encodable_key(key: Self::Key) -> Self {
899 key
900 }
901 }
902
903 impl ItemType for TestPublicKey {
904 fn item_type() -> KeystoreItemType
905 where
906 Self: Sized,
907 {
908 KeyType::Ed25519PublicKey.into()
909 }
910 }
911
912 impl EncodableItem for TestPublicKey {
913 fn as_keystore_item(&self) -> tor_key_forge::Result<KeystoreItem> {
914 Ok(self.key.clone())
915 }
916 }
917
918 impl ToEncodableKey for TestPublicKey {
919 type Key = Self;
920 type KeyPair = TestItem;
921
922 fn to_encodable_key(self) -> Self::Key {
923 self
924 }
925
926 fn from_encodable_key(key: Self::Key) -> Self {
927 key
928 }
929 }
930
931 impl ToEncodableCert<TestItem> for AlwaysValidCert {
932 type ParsedCert = TestItem;
933 type EncodableCert = TestItem;
934 type SigningKey = TestItem;
935
936 fn validate(
937 cert: Self::ParsedCert,
938 _subject: &TestItem,
939 _signed_with: &Self::SigningKey,
940 ) -> StdResult<Self, InvalidCertError> {
941 Ok(Self(cert))
943 }
944
945 fn to_encodable_cert(self) -> Self::EncodableCert {
947 self.0
948 }
949 }
950
951 const KEYSTORE_LIST_MOCK_ID: &str = "keystore_list_mock";
952 const KEYSTORE_LIST_MOCK_UNRECOGNIZED_PATH_STR: &str = "unrecognized_entry";
953
954 struct KeystoreListMock {
955 id: KeystoreId,
956 valid_key_path: KeyPath,
957 invalid_key_path: PathBuf,
958 }
959
960 impl Default for KeystoreListMock {
961 fn default() -> Self {
962 Self {
963 id: KeystoreId::from_str(KEYSTORE_LIST_MOCK_ID).unwrap(),
964 valid_key_path: KeyPath::Arti(TestKeySpecifierListMock.arti_path().unwrap()),
965 invalid_key_path: PathBuf::from_str(KEYSTORE_LIST_MOCK_UNRECOGNIZED_PATH_STR)
966 .unwrap(),
967 }
968 }
969 }
970
971 impl Keystore for KeystoreListMock {
972 fn id(&self) -> &KeystoreId {
973 &self.id
974 }
975
976 fn get(
977 &self,
978 _key_spec: &dyn KeySpecifier,
979 _item_type: &KeystoreItemType,
980 ) -> Result<Option<ErasedKey>> {
981 Err(Error::Keystore(Arc::new(
982 KeystoreListMockError::MethodNotSuppored,
983 )))
984 }
985
986 fn list(&self) -> Result<Vec<KeystoreEntryResult<(KeyPath, KeystoreItemType)>>> {
987 Ok(vec![
989 Ok((
990 self.valid_key_path.clone(),
991 TestItem::new("capibara").item.item_type().unwrap(),
992 )),
993 Err(UnrecognizedEntryError::new(
994 UnrecognizedEntryId::Path(self.invalid_key_path.clone()),
995 Arc::new(ArtiNativeKeystoreError::MalformedPath {
996 path: self.invalid_key_path.clone(),
997 err: MalformedPathError::NoExtension,
998 }),
999 )),
1000 ])
1001 }
1002
1003 fn insert(&self, _key: &dyn EncodableItem, _key_spec: &dyn KeySpecifier) -> Result<()> {
1004 Err(Error::Keystore(Arc::new(
1005 KeystoreListMockError::MethodNotSuppored,
1006 )))
1007 }
1008
1009 fn remove(
1010 &self,
1011 _key_spec: &dyn KeySpecifier,
1012 _item_type: &KeystoreItemType,
1013 ) -> Result<Option<()>> {
1014 Err(Error::Keystore(Arc::new(
1015 KeystoreListMockError::MethodNotSuppored,
1016 )))
1017 }
1018
1019 fn contains(
1020 &self,
1021 _key_spec: &dyn KeySpecifier,
1022 _item_type: &KeystoreItemType,
1023 ) -> Result<bool> {
1024 Err(Error::Keystore(Arc::new(
1025 KeystoreListMockError::MethodNotSuppored,
1026 )))
1027 }
1028 }
1029
1030 #[derive(thiserror::Error, Debug, Clone, derive_more::Display)]
1031 enum KeystoreListMockError {
1032 MethodNotSuppored,
1033 }
1034
1035 impl KeystoreError for KeystoreListMockError {}
1036
1037 impl HasKind for KeystoreListMockError {
1038 fn kind(&self) -> ErrorKind {
1039 ErrorKind::BadApiUsage
1040 }
1041 }
1042
1043 macro_rules! impl_keystore {
1044 ($name:tt, $id:expr) => {
1045 struct $name {
1046 inner: RwLock<HashMap<(ArtiPath, KeystoreItemType), TestItem>>,
1047 id: KeystoreId,
1048 }
1049
1050 impl Default for $name {
1051 fn default() -> Self {
1052 Self {
1053 inner: Default::default(),
1054 id: KeystoreId::from_str($id).unwrap(),
1055 }
1056 }
1057 }
1058
1059 #[allow(dead_code)] impl $name {
1061 fn new_boxed() -> BoxedKeystore {
1062 Box::<Self>::default()
1063 }
1064 }
1065
1066 impl crate::Keystore for $name {
1067 fn contains(
1068 &self,
1069 key_spec: &dyn KeySpecifier,
1070 item_type: &KeystoreItemType,
1071 ) -> Result<bool> {
1072 Ok(self
1073 .inner
1074 .read()
1075 .unwrap()
1076 .contains_key(&(key_spec.arti_path().unwrap(), item_type.clone())))
1077 }
1078
1079 fn id(&self) -> &KeystoreId {
1080 &self.id
1081 }
1082
1083 fn get(
1084 &self,
1085 key_spec: &dyn KeySpecifier,
1086 item_type: &KeystoreItemType,
1087 ) -> Result<Option<ErasedKey>> {
1088 Ok(self
1089 .inner
1090 .read()
1091 .unwrap()
1092 .get(&(key_spec.arti_path().unwrap(), item_type.clone()))
1093 .map(|k| {
1094 let mut k = k.clone();
1095 k.meta.set_retrieved_from(self.id().clone());
1096 Box::new(k) as Box<dyn ItemType>
1097 }))
1098 }
1099
1100 fn insert(
1101 &self,
1102 key: &dyn EncodableItem,
1103 key_spec: &dyn KeySpecifier,
1104 ) -> Result<()> {
1105 let key = key.downcast_ref::<TestItem>().unwrap();
1106
1107 let item = key.as_keystore_item()?;
1108 let meta = key.meta.clone();
1109
1110 let item_type = item.item_type()?;
1111 let key = TestItem { item, meta };
1112
1113 self.inner
1114 .write()
1115 .unwrap()
1116 .insert((key_spec.arti_path().unwrap(), item_type), key);
1117
1118 Ok(())
1119 }
1120
1121 fn remove(
1122 &self,
1123 key_spec: &dyn KeySpecifier,
1124 item_type: &KeystoreItemType,
1125 ) -> Result<Option<()>> {
1126 Ok(self
1127 .inner
1128 .write()
1129 .unwrap()
1130 .remove(&(key_spec.arti_path().unwrap(), item_type.clone()))
1131 .map(|_| ()))
1132 }
1133
1134 fn list(&self) -> Result<Vec<KeystoreEntryResult<(KeyPath, KeystoreItemType)>>> {
1135 Ok(self
1136 .inner
1137 .read()
1138 .unwrap()
1139 .iter()
1140 .map(|((arti_path, item_type), _)| {
1141 Ok((KeyPath::Arti(arti_path.clone()), item_type.clone()))
1142 })
1143 .collect())
1144 }
1145 }
1146 };
1147 }
1148
1149 macro_rules! impl_specifier {
1150 ($name:tt, $id:expr) => {
1151 struct $name;
1152
1153 impl KeySpecifier for $name {
1154 fn arti_path(&self) -> StdResult<ArtiPath, ArtiPathUnavailableError> {
1155 Ok(ArtiPath::new($id.into()).map_err(|e| tor_error::internal!("{e}"))?)
1156 }
1157
1158 fn ctor_path(&self) -> Option<crate::CTorPath> {
1159 None
1160 }
1161
1162 fn keypair_specifier(&self) -> Option<Box<dyn KeySpecifier>> {
1163 None
1164 }
1165 }
1166 };
1167 }
1168
1169 impl_keystore!(Keystore1, "keystore1");
1170 impl_keystore!(Keystore2, "keystore2");
1171 impl_keystore!(Keystore3, "keystore3");
1172
1173 impl_specifier!(TestKeySpecifier1, "spec1");
1174 impl_specifier!(TestKeySpecifier2, "spec2");
1175 impl_specifier!(TestKeySpecifier3, "spec3");
1176 impl_specifier!(TestKeySpecifier4, "spec4");
1177 impl_specifier!(TestKeySpecifierListMock, "recognized_entry");
1178
1179 impl_specifier!(TestPublicKeySpecifier1, "pub-spec1");
1180
1181 fn entry_descriptor(specifier: impl KeySpecifier, keystore_id: &KeystoreId) -> KeystoreEntry {
1183 KeystoreEntry {
1184 key_path: specifier.arti_path().unwrap().into(),
1185 key_type: TestItem::item_type(),
1186 keystore_id,
1187 }
1188 }
1189
1190 #[test]
1191 #[allow(clippy::cognitive_complexity)]
1192 fn insert_and_get() {
1193 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1194
1195 builder
1196 .secondary_stores()
1197 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1198
1199 let mgr = builder.build().unwrap();
1200
1201 let old_key = mgr
1203 .insert(
1204 TestItem::new("coot"),
1205 &TestKeySpecifier1,
1206 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1207 true,
1208 )
1209 .unwrap();
1210
1211 assert!(old_key.is_none());
1212 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1213 assert_eq!(key.meta.item_id(), "coot");
1214 assert_eq!(
1215 key.meta.retrieved_from(),
1216 Some(&KeystoreId::from_str("keystore2").unwrap())
1217 );
1218 assert_eq!(key.meta.is_generated(), false);
1219
1220 let old_key = mgr
1222 .insert(
1223 TestItem::new("gull"),
1224 &TestKeySpecifier1,
1225 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1226 true,
1227 )
1228 .unwrap()
1229 .unwrap();
1230 assert_eq!(old_key.meta.item_id(), "coot");
1231 assert_eq!(
1232 old_key.meta.retrieved_from(),
1233 Some(&KeystoreId::from_str("keystore2").unwrap())
1234 );
1235 assert_eq!(old_key.meta.is_generated(), false);
1236 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1238 assert_eq!(key.meta.item_id(), "gull");
1239 assert_eq!(
1240 key.meta.retrieved_from(),
1241 Some(&KeystoreId::from_str("keystore2").unwrap())
1242 );
1243 assert_eq!(key.meta.is_generated(), false);
1244
1245 let err = mgr
1247 .insert(
1248 TestItem::new("gull"),
1249 &TestKeySpecifier1,
1250 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1251 false,
1252 )
1253 .unwrap_err();
1254 assert!(matches!(err, crate::Error::KeyAlreadyExists));
1255
1256 let old_key = mgr
1258 .insert(
1259 TestItem::new("penguin"),
1260 &TestKeySpecifier2,
1261 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1262 false,
1263 )
1264 .unwrap();
1265 assert!(old_key.is_none());
1266
1267 let old_key = mgr
1269 .insert(
1270 TestItem::new("moorhen"),
1271 &TestKeySpecifier3,
1272 KeystoreSelector::Primary,
1273 true,
1274 )
1275 .unwrap();
1276 assert!(old_key.is_none());
1277 let key = mgr.get::<TestItem>(&TestKeySpecifier3).unwrap().unwrap();
1278 assert_eq!(key.meta.item_id(), "moorhen");
1279 assert_eq!(
1280 key.meta.retrieved_from(),
1281 Some(&KeystoreId::from_str("keystore1").unwrap())
1282 );
1283 assert_eq!(key.meta.is_generated(), false);
1284
1285 assert!(mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().is_none());
1287
1288 for store in ["keystore3", "keystore2", "keystore1"] {
1292 let old_key = mgr
1293 .insert(
1294 TestItem::new("cormorant"),
1295 &TestKeySpecifier4,
1296 KeystoreSelector::Id(&KeystoreId::from_str(store).unwrap()),
1297 true,
1298 )
1299 .unwrap();
1300 assert!(old_key.is_none());
1301
1302 let key = mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().unwrap();
1304 assert_eq!(key.meta.item_id(), "cormorant");
1305 assert_eq!(
1306 key.meta.retrieved_from(),
1307 Some(&KeystoreId::from_str(store).unwrap())
1308 );
1309 assert_eq!(key.meta.is_generated(), false);
1310 }
1311
1312 let key = mgr.get::<TestItem>(&TestKeySpecifier4).unwrap().unwrap();
1315 assert_eq!(key.meta.item_id(), "cormorant");
1316 assert_eq!(
1317 key.meta.retrieved_from(),
1318 Some(&KeystoreId::from_str("keystore1").unwrap())
1319 );
1320 assert_eq!(key.meta.is_generated(), false);
1321 }
1322
1323 #[test]
1324 fn remove() {
1325 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1326
1327 builder
1328 .secondary_stores()
1329 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1330
1331 let mgr = builder.build().unwrap();
1332
1333 assert!(!mgr.secondary_stores[0]
1334 .contains(&TestKeySpecifier1, &TestItem::item_type())
1335 .unwrap());
1336
1337 mgr.insert(
1339 TestItem::new("coot"),
1340 &TestKeySpecifier1,
1341 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1342 true,
1343 )
1344 .unwrap();
1345 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1346 assert_eq!(key.meta.item_id(), "coot");
1347 assert_eq!(
1348 key.meta.retrieved_from(),
1349 Some(&KeystoreId::from_str("keystore2").unwrap())
1350 );
1351 assert_eq!(key.meta.is_generated(), false);
1352
1353 assert!(mgr
1355 .remove::<TestItem>(
1356 &TestKeySpecifier1,
1357 KeystoreSelector::Id(&KeystoreId::from_str("not_an_id_we_know_of").unwrap())
1358 )
1359 .is_err());
1360 assert!(mgr.secondary_stores[0]
1362 .contains(&TestKeySpecifier1, &TestItem::item_type())
1363 .unwrap());
1364
1365 assert!(mgr
1367 .remove::<TestItem>(&TestKeySpecifier1, KeystoreSelector::Primary)
1368 .unwrap()
1369 .is_none());
1370
1371 assert!(mgr.secondary_stores[0]
1373 .contains(&TestKeySpecifier1, &TestItem::item_type())
1374 .unwrap());
1375
1376 let removed_key = mgr
1378 .remove::<TestItem>(
1379 &TestKeySpecifier1,
1380 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1381 )
1382 .unwrap()
1383 .unwrap();
1384 assert_eq!(removed_key.meta.item_id(), "coot");
1385 assert_eq!(
1386 removed_key.meta.retrieved_from(),
1387 Some(&KeystoreId::from_str("keystore2").unwrap())
1388 );
1389 assert_eq!(removed_key.meta.is_generated(), false);
1390
1391 assert!(!mgr.secondary_stores[0]
1393 .contains(&TestKeySpecifier1, &TestItem::item_type())
1394 .unwrap());
1395 }
1396
1397 #[test]
1398 fn keygen() {
1399 let mut rng = FakeEntropicRng(testing_rng());
1400 let mgr = KeyMgrBuilder::default()
1401 .primary_store(Box::<Keystore1>::default())
1402 .build()
1403 .unwrap();
1404
1405 mgr.insert(
1406 TestItem::new("coot"),
1407 &TestKeySpecifier1,
1408 KeystoreSelector::Primary,
1409 true,
1410 )
1411 .unwrap();
1412
1413 assert!(mgr
1415 .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1416 .unwrap()
1417 .is_none());
1418
1419 let err = mgr
1421 .generate::<TestItem>(
1422 &TestKeySpecifier1,
1423 KeystoreSelector::Primary,
1424 &mut rng,
1425 false,
1426 )
1427 .unwrap_err();
1428
1429 assert!(matches!(err, crate::Error::KeyAlreadyExists));
1430
1431 let key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1433 assert_eq!(key.meta.item_id(), "coot");
1434 assert_eq!(
1435 key.meta.retrieved_from(),
1436 Some(&KeystoreId::from_str("keystore1").unwrap())
1437 );
1438 assert_eq!(key.meta.is_generated(), false);
1439
1440 assert!(mgr
1442 .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1443 .unwrap()
1444 .is_none());
1445
1446 let generated_key = mgr
1448 .generate::<TestItem>(
1449 &TestKeySpecifier1,
1450 KeystoreSelector::Primary,
1451 &mut rng,
1452 true,
1453 )
1454 .unwrap();
1455
1456 assert_eq!(generated_key.meta.item_id(), "generated_test_key");
1457 assert_eq!(generated_key.meta.retrieved_from(), None);
1460 assert_eq!(generated_key.meta.is_generated(), true);
1461
1462 let retrieved_key = mgr.get::<TestItem>(&TestKeySpecifier1).unwrap().unwrap();
1464 assert_eq!(retrieved_key.meta.item_id(), "generated_test_key");
1465 assert_eq!(
1466 retrieved_key.meta.retrieved_from(),
1467 Some(&KeystoreId::from_str("keystore1").unwrap())
1468 );
1469 assert_eq!(retrieved_key.meta.is_generated(), true);
1470
1471 assert!(mgr
1473 .get::<TestPublicKey>(&TestPublicKeySpecifier1)
1474 .unwrap()
1475 .is_none());
1476 }
1477
1478 #[test]
1479 fn get_or_generate() {
1480 let mut rng = FakeEntropicRng(testing_rng());
1481 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1482
1483 builder
1484 .secondary_stores()
1485 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1486
1487 let mgr = builder.build().unwrap();
1488
1489 let keystore2 = KeystoreId::from_str("keystore2").unwrap();
1490 let entry_desc1 = entry_descriptor(TestKeySpecifier1, &keystore2);
1491 assert!(mgr.get_entry::<TestItem>(&entry_desc1).unwrap().is_none());
1492
1493 mgr.insert(
1494 TestItem::new("coot"),
1495 &TestKeySpecifier1,
1496 KeystoreSelector::Id(&keystore2),
1497 true,
1498 )
1499 .unwrap();
1500
1501 let key = mgr
1503 .get_or_generate::<TestItem>(&TestKeySpecifier1, KeystoreSelector::Primary, &mut rng)
1504 .unwrap();
1505 assert_eq!(key.meta.item_id(), "coot");
1506 assert_eq!(
1507 key.meta.retrieved_from(),
1508 Some(&KeystoreId::from_str("keystore2").unwrap())
1509 );
1510 assert_eq!(key.meta.is_generated(), false);
1511
1512 assert_eq!(
1513 mgr.get_entry::<TestItem>(&entry_desc1)
1514 .unwrap()
1515 .map(|k| k.meta),
1516 Some(ItemMetadata::Key(KeyMetadata {
1517 item_id: "coot".to_string(),
1518 retrieved_from: Some(keystore2.clone()),
1519 is_generated: false,
1520 }))
1521 );
1522
1523 let keystore3 = KeystoreId::from_str("keystore3").unwrap();
1526 let generated_key = mgr
1527 .get_or_generate::<TestItem>(
1528 &TestKeySpecifier2,
1529 KeystoreSelector::Id(&keystore3),
1530 &mut rng,
1531 )
1532 .unwrap();
1533 assert_eq!(generated_key.meta.item_id(), "generated_test_key");
1534 assert_eq!(generated_key.meta.retrieved_from(), None);
1537 assert_eq!(generated_key.meta.is_generated(), true);
1538
1539 let retrieved_key = mgr.get::<TestItem>(&TestKeySpecifier2).unwrap().unwrap();
1541 assert_eq!(retrieved_key.meta.item_id(), "generated_test_key");
1542 assert_eq!(
1543 retrieved_key.meta.retrieved_from(),
1544 Some(&KeystoreId::from_str("keystore3").unwrap())
1545 );
1546 assert_eq!(retrieved_key.meta.is_generated(), true);
1547
1548 let entry_desc2 = entry_descriptor(TestKeySpecifier2, &keystore3);
1549 assert_eq!(
1550 mgr.get_entry::<TestItem>(&entry_desc2)
1551 .unwrap()
1552 .map(|k| k.meta),
1553 Some(ItemMetadata::Key(KeyMetadata {
1554 item_id: "generated_test_key".to_string(),
1555 retrieved_from: Some(keystore3.clone()),
1556 is_generated: true,
1557 }))
1558 );
1559
1560 let arti_pat = KeyPathPattern::Arti("*".to_string());
1561 let matching = mgr.list_matching(&arti_pat).unwrap();
1562
1563 assert_eq!(matching.len(), 2);
1564 assert!(matching.contains(&entry_desc1));
1565 assert!(matching.contains(&entry_desc2));
1566
1567 assert_eq!(mgr.remove_entry(&entry_desc2).unwrap(), Some(()));
1568 assert!(mgr.get_entry::<TestItem>(&entry_desc2).unwrap().is_none());
1569 assert!(mgr.remove_entry(&entry_desc2).unwrap().is_none());
1570 }
1571
1572 #[test]
1573 fn list_matching_ignores_unrecognized_keys() {
1574 let builder = KeyMgrBuilder::default().primary_store(Box::new(KeystoreListMock::default()));
1575
1576 let mgr = builder.build().unwrap();
1577
1578 let arti_pat = KeyPathPattern::Arti("*".to_string());
1579 let matching = mgr.list_matching(&arti_pat).unwrap();
1580 assert_eq!(matching.len(), 1);
1582 assert_eq!(
1583 matching.first().unwrap().key_path(),
1584 &KeystoreListMock::default().valid_key_path
1585 );
1586 }
1587
1588 #[cfg(feature = "onion-service-cli-extra")]
1589 #[test]
1590 fn lists() {
1591 let mut builder =
1592 KeyMgrBuilder::default().primary_store(Box::new(KeystoreListMock::default()));
1593 builder
1594 .secondary_stores()
1595 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1596
1597 let mgr = builder.build().unwrap();
1598 let keystore2id = KeystoreId::from_str("keystore2").unwrap();
1599 let keystore3id = KeystoreId::from_str("keystore3").unwrap();
1600
1601 let _ = mgr
1603 .insert(
1604 TestItem::new("coot"),
1605 &TestKeySpecifier2,
1606 KeystoreSelector::Id(&keystore2id),
1607 true,
1608 )
1609 .unwrap();
1610
1611 let _ = mgr
1613 .insert(
1614 TestItem::new("penguin"),
1615 &TestKeySpecifier3,
1616 KeystoreSelector::Id(&keystore3id),
1617 true,
1618 )
1619 .unwrap();
1620
1621 let entries = mgr
1623 .list_by_id(&KeystoreId::from_str(KEYSTORE_LIST_MOCK_ID).unwrap())
1624 .unwrap();
1625
1626 let assert_key = |path, ty, expected_path: &ArtiPath, expected_type| {
1627 assert_eq!(ty, expected_type);
1628 assert_eq!(path, &KeyPath::Arti(expected_path.clone()));
1629 };
1630 let item_type = TestItem::new("axolotl").item.item_type().unwrap();
1631 let unrecognized_entry_id = UnrecognizedEntryId::Path(
1632 PathBuf::from_str(KEYSTORE_LIST_MOCK_UNRECOGNIZED_PATH_STR).unwrap(),
1633 );
1634 let list_mock_key_spec = TestKeySpecifierListMock.arti_path().unwrap();
1635
1636 let mut recognized_entries = 0;
1638 let mut unrecognized_entries = 0;
1639 for entry in entries.iter() {
1640 match entry {
1641 Ok((key_path, key_type)) => {
1642 assert_key(key_path, key_type, &list_mock_key_spec, &item_type);
1643 recognized_entries += 1;
1644 }
1645 Err(u) => {
1646 assert_eq!(u.entry(), &unrecognized_entry_id);
1647 unrecognized_entries += 1;
1648 }
1649 }
1650 }
1651 assert_eq!(recognized_entries, 1);
1652 assert_eq!(unrecognized_entries, 1);
1653
1654 let entries = mgr.list().unwrap();
1656
1657 let expected_items = [
1658 (
1659 KeystoreId::from_str("keystore_list_mock").unwrap(),
1660 TestKeySpecifierListMock.arti_path().unwrap(),
1661 ),
1662 (keystore2id, TestKeySpecifier2.arti_path().unwrap()),
1663 (keystore3id, TestKeySpecifier3.arti_path().unwrap()),
1664 ];
1665
1666 let mut recognized_entries = 0;
1668 let mut unrecognized_entries = 0;
1669 for entry in entries.iter() {
1670 match entry {
1671 Ok(e) => {
1672 if let Some((_, expected_arti_path)) = expected_items
1673 .iter()
1674 .find(|(keystore_id, _)| keystore_id == e.keystore_id())
1675 {
1676 assert_key(e.key_path(), e.key_type(), expected_arti_path, &item_type);
1677 recognized_entries += 1;
1678 continue;
1679 }
1680
1681 panic!("Unexpected key encountered {:?}", e);
1682 }
1683 Err(u) => {
1684 assert_eq!(u.entry(), &unrecognized_entry_id);
1685 unrecognized_entries += 1;
1686 }
1687 }
1688 }
1689 assert_eq!(recognized_entries, 3);
1690 assert_eq!(unrecognized_entries, 1);
1691
1692 let keystores = mgr.list_keystores().iter().len();
1694
1695 assert_eq!(keystores, 3);
1696 }
1697
1698 #[cfg(feature = "experimental-api")]
1700 #[derive(Clone, Copy, Debug, PartialEq)]
1701 enum GenerateItem {
1702 Yes,
1703 No,
1704 }
1705
1706 #[cfg(feature = "experimental-api")]
1707 macro_rules! run_certificate_test {
1708 (
1709 generate_subject_key = $generate_subject_key:expr,
1710 generate_signing_key = $generate_signing_key:expr,
1711 $($expected_err:tt)?
1712 ) => {{
1713 use GenerateItem::*;
1714
1715 let mut rng = FakeEntropicRng(testing_rng());
1716 let mut builder = KeyMgrBuilder::default().primary_store(Box::<Keystore1>::default());
1717
1718 builder
1719 .secondary_stores()
1720 .extend([Keystore2::new_boxed(), Keystore3::new_boxed()]);
1721
1722 let mgr = builder.build().unwrap();
1723
1724 let spec = crate::test_utils::TestCertSpecifier {
1725 subject_key_spec: TestKeySpecifier1,
1726 signing_key_spec: TestKeySpecifier2,
1727 denotator: vec!["foo".into()],
1728 };
1729
1730 if $generate_subject_key == Yes {
1731 let _ = mgr
1732 .generate::<TestItem>(
1733 &TestKeySpecifier1,
1734 KeystoreSelector::Primary,
1735 &mut rng,
1736 false,
1737 )
1738 .unwrap();
1739 }
1740
1741 if $generate_signing_key == Yes {
1742 let _ = mgr
1743 .generate::<TestItem>(
1744 &TestKeySpecifier2,
1745 KeystoreSelector::Id(&KeystoreId::from_str("keystore2").unwrap()),
1746 &mut rng,
1747 false,
1748 )
1749 .unwrap();
1750 }
1751
1752 let make_certificate = move |subject_key: &TestItem, signed_with: &TestItem| {
1753 let subject_id = subject_key.meta.as_key().unwrap().item_id.clone();
1754 let signing_id = signed_with.meta.as_key().unwrap().item_id.clone();
1755
1756 let meta = ItemMetadata::Cert(CertMetadata {
1757 subject_key_id: subject_id,
1758 signing_key_id: signing_id,
1759 retrieved_from: None,
1760 is_generated: true,
1761 });
1762
1763 let mut rng = FakeEntropicRng(testing_rng());
1769 let keypair = ed25519::Keypair::generate(&mut rng);
1770 let encoded_cert = Ed25519Cert::constructor()
1771 .cert_type(tor_cert::CertType::IDENTITY_V_SIGNING)
1772 .expiration(SystemTime::now() + Duration::from_secs(180))
1773 .signing_key(keypair.public_key().into())
1774 .cert_key(CertifiedKey::Ed25519(keypair.public_key().into()))
1775 .encode_and_sign(&keypair)
1776 .unwrap();
1777 let test_cert = CertData::TorEd25519Cert(encoded_cert);
1778 AlwaysValidCert(TestItem {
1779 item: KeystoreItem::Cert(test_cert),
1780 meta,
1781 })
1782 };
1783
1784 let res = mgr
1785 .get_or_generate_key_and_cert::<TestItem, AlwaysValidCert>(
1786 &spec,
1787 &make_certificate,
1788 KeystoreSelector::Primary,
1789 &mut rng,
1790 );
1791
1792 #[allow(unused_assignments)]
1793 #[allow(unused_mut)]
1794 let mut has_error = false;
1795 $(
1796 has_error = true;
1797 let err = res.clone().unwrap_err();
1798 assert!(
1799 matches!(
1800 err,
1801 crate::Error::Corruption(KeystoreCorruptionError::$expected_err)
1802 ),
1803 "unexpected error: {err:?}",
1804 );
1805 )?
1806
1807 if !has_error {
1808 let (key, cert) = res.unwrap();
1809
1810 let expected_subj_key_id = if $generate_subject_key == Yes {
1811 "generated_test_key"
1812 } else {
1813 "generated_test_key"
1814 };
1815
1816 assert_eq!(key.meta.item_id(), expected_subj_key_id);
1817 assert_eq!(
1818 cert.0.meta.as_cert().unwrap().subject_key_id,
1819 expected_subj_key_id
1820 );
1821 assert_eq!(
1822 cert.0.meta.as_cert().unwrap().signing_key_id,
1823 "generated_test_key"
1824 );
1825 assert_eq!(cert.0.meta.is_generated(), true);
1826 }
1827 }}
1828 }
1829
1830 #[test]
1831 #[cfg(feature = "experimental-api")]
1832 #[rustfmt::skip] #[allow(clippy::cognitive_complexity)] fn get_certificate() {
1835 run_certificate_test!(
1836 generate_subject_key = No,
1837 generate_signing_key = No,
1838 MissingSigningKey
1839 );
1840
1841 run_certificate_test!(
1842 generate_subject_key = Yes,
1843 generate_signing_key = No,
1844 MissingSigningKey
1845 );
1846
1847 run_certificate_test!(
1848 generate_subject_key = No,
1849 generate_signing_key = Yes,
1850 );
1851
1852 run_certificate_test!(
1853 generate_subject_key = Yes,
1854 generate_signing_key = Yes,
1855 );
1856 }
1857}