1use std::collections::HashMap;
4use std::str::FromStr;
5use std::sync::Arc;
6use chrono::Duration;
7use log::debug;
8use rpki::{rrdp, uri};
9use rpki::ca::idexchange::CaHandle;
10use rpki::ca::provisioning::ResourceClassName;
11use rpki::ca::publication::Base64;
12use rpki::crypto::{DigestAlgorithm, KeyIdentifier};
13use rpki::repository::crl::{Crl, TbsCertList};
14use rpki::repository::manifest::{FileAndHash, Manifest, ManifestContent};
15use rpki::repository::sigobj::SignedObjectBuilder;
16use rpki::repository::x509::{Name, Serial, Time, Validity};
17use serde::{Deserialize, Serialize};
18use url::Url;
19use crate::api::admin::{PublishedFile, RepositoryContact};
20use crate::api::ca::{
21 CertInfo, IssuedCertificate, ObjectName, ReceivedCert, Revocation,
22 Revocations,
23};
24use crate::api::roa::RoaInfo;
25use crate::commons::KrillResult;
26use crate::commons::crypto::KrillSigner;
27use crate::commons::error::Error;
28use crate::commons::eventsourcing::PreSaveEventListener;
29use crate::commons::storage::{Ident, KeyValueStore};
30use crate::constants::CA_OBJECTS_NS;
31use crate::config::IssuanceTimingConfig;
32use super::aspa::{AspaInfo, AspaObjectsUpdates};
33use super::bgpsec::{BgpSecCertInfo, BgpSecCertificateUpdates};
34use super::certauth::CertAuth;
35use super::child::ChildCertificateUpdates;
36use super::events::CertAuthEvent;
37use super::keys::CertifiedKey;
38use super::roa::RoaUpdates;
39
40
41#[derive(Debug)]
63pub struct CaObjectsStore {
64 store: KeyValueStore,
66
67 signer: Arc<KrillSigner>,
69
70 issuance_timing: IssuanceTimingConfig,
72}
73
74impl CaObjectsStore {
75 pub fn create(
77 storage_uri: &Url,
78 issuance_timing: IssuanceTimingConfig,
79 signer: Arc<KrillSigner>,
80 ) -> KrillResult<Self> {
81 let store = KeyValueStore::create(storage_uri, CA_OBJECTS_NS)?;
82 Ok(CaObjectsStore {
83 store,
84 signer,
85 issuance_timing,
86 })
87 }
88}
89
90impl PreSaveEventListener<CertAuth> for CaObjectsStore {
92 fn listen(
93 &self,
94 ca: &CertAuth,
95 events: &[CertAuthEvent],
96 ) -> KrillResult<()> {
97 self.with_ca_objects(ca.handle(), |objects| {
101 let mut force_reissue = false;
102
103 for event in events {
104 match event {
105 CertAuthEvent::RoasUpdated {
106 resource_class_name,
107 updates,
108 } => {
109 objects.update_roas(resource_class_name, updates)?;
110 force_reissue = true;
111 }
112 CertAuthEvent::AspaObjectsUpdated {
113 resource_class_name,
114 updates,
115 } => {
116 objects.update_aspas(resource_class_name, updates)?;
117 force_reissue = true;
118 }
119 CertAuthEvent::BgpSecCertificatesUpdated {
120 resource_class_name,
121 updates,
122 } => {
123 objects.update_bgpsec_certs(
124 resource_class_name,
125 updates,
126 )?;
127 force_reissue = true;
128 }
129 CertAuthEvent::ChildCertificatesUpdated {
130 resource_class_name,
131 updates,
132 } => {
133 objects.update_certs(resource_class_name, updates)?;
134 force_reissue = true;
135 }
136 CertAuthEvent::KeyPendingToActive {
137 resource_class_name,
138 current_key,
139 } => {
140 objects.add_class(
141 resource_class_name,
142 current_key,
143 &self.issuance_timing,
144 &self.signer,
145 )?;
146 }
147 CertAuthEvent::KeyPendingToNew {
148 resource_class_name,
149 new_key,
150 } => {
151 objects.keyroll_stage(
152 resource_class_name,
153 new_key,
154 &self.issuance_timing,
155 &self.signer,
156 )?;
157 }
158 CertAuthEvent::KeyRollActivated {
159 resource_class_name,
160 ..
161 } => {
162 objects.keyroll_activate(resource_class_name)?;
163 force_reissue = true;
164 }
165 CertAuthEvent::KeyRollFinished {
166 resource_class_name,
167 } => {
168 objects.keyroll_finish(resource_class_name)?;
169 }
170 CertAuthEvent::CertificateReceived {
171 resource_class_name,
172 rcvd_cert,
173 ..
174 } => {
175 objects.update_received_cert(
176 resource_class_name,
177 rcvd_cert,
178 )?;
179 }
187 CertAuthEvent::ResourceClassRemoved {
188 resource_class_name,
189 ..
190 } => {
191 objects.remove_class(resource_class_name);
192 force_reissue = true;
193 }
194 CertAuthEvent::RepoUpdated { contact } => {
195 objects.update_repo(contact);
196 force_reissue = true;
197 }
198 _ => {}
199 }
200 }
201 objects.re_issue(
202 force_reissue, &self.issuance_timing, &self.signer
203 )?;
204 Ok(())
205 })
206 }
207}
208
209impl CaObjectsStore {
210 fn key(ca: &CaHandle) -> Box<Ident> {
212 Ident::builder(
217 Ident::from_handle(ca).into_owned()
218 ).finish_with_extension(
219 const { Ident::make("json") }
220 )
221 }
222
223 pub fn cas(&self) -> KrillResult<Vec<CaHandle>> {
225 Ok(
231 self.store.keys(None, ".json")?.iter().filter_map(|k| {
232 let name = k.as_str().strip_suffix(".json")?;
233 CaHandle::from_str(name).ok()
234 }).collect()
235 )
236 }
237
238 pub fn remove_ca(&self, ca: &CaHandle) -> KrillResult<()> {
240 let ca_key = Self::key(ca);
241 self.store.execute(None, |kv| {
242 if kv.has(None, &ca_key)? {
243 kv.delete(None, &ca_key)
244 } else {
245 Ok(())
246 }
247 }).map_err(Error::KeyValueError)
248 }
249
250 pub fn ca_objects(&self, ca: &CaHandle) -> KrillResult<CaObjects> {
255 match self.store.get(
256 None, &Self::key(ca)
257 ).map_err(Error::KeyValueError)? {
258 None => Ok(CaObjects::new(ca.clone())),
259 Some(objects) => Ok(objects),
260 }
261 }
262
263 pub fn with_ca_objects<F, T>(
268 &self,
269 ca: &CaHandle,
270 op: F,
271 ) -> KrillResult<T>
272 where
273 F: Fn(&mut CaObjects) -> KrillResult<T>,
274 {
275 self.store.execute(None, |kv| {
276 let key = Self::key(ca);
277
278 let mut objects: CaObjects = match kv.get(None, &key)? {
279 Some(value) => value,
280 None => CaObjects::new(ca.clone()),
281 };
282
283 match op(&mut objects) {
284 Err(e) => Ok(Err(e)),
285 Ok(t) => {
286 kv.store(None, &key, &objects)?;
287 Ok(Ok(t))
288 }
289 }
290 }).map_err(Error::KeyValueError)?
291 }
292
293 pub fn reissue_if_needed(
298 &self,
299 force: bool,
300 ca_handle: &CaHandle,
301 ) -> KrillResult<bool> {
302 debug!("Re-issue for CA {ca_handle} using force: {force}");
303 self.with_ca_objects(ca_handle, |objects| {
304 objects.re_issue(
305 force,
306 &self.issuance_timing,
307 &self.signer,
308 )
309 })
310 }
311}
312
313
314#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
320pub struct CaObjects {
321 ca: CaHandle,
323
324 repo: Option<RepositoryContact>,
328
329 classes: HashMap<ResourceClassName, ResourceClassObjects>,
331
332 #[serde(skip_serializing_if = "Vec::is_empty", default)]
334 deprecated_repos: Vec<DeprecatedRepository>,
335}
336
337impl CaObjects {
338 pub fn new(
340 ca: CaHandle,
341 ) -> Self {
342 CaObjects {
343 ca,
344 repo: None,
345 classes: HashMap::new(),
346 deprecated_repos: Vec::new(),
347 }
348 }
349
350 pub fn from_parts(
354 ca: CaHandle,
355 repo: Option<RepositoryContact>,
356 classes: HashMap<ResourceClassName, ResourceClassObjects>,
357 deprecated_repos: Vec<DeprecatedRepository>,
358 ) -> Self {
359 CaObjects {
360 ca,
361 repo,
362 classes,
363 deprecated_repos,
364 }
365 }
366
367 #[allow(clippy::mutable_key_type)]
372 pub fn repo_elements_map(
373 &self,
374 ) -> HashMap<RepositoryContact, Vec<PublishedFile>> {
375 let mut res = HashMap::new();
376
377 if let Some(repo) = &self.repo {
378 res.insert(repo.clone(), vec![]);
379
380 for resource_class_objects in self.classes.values() {
381 resource_class_objects.add_elements(&mut res, repo);
385 }
386 }
387
388 res
389 }
390
391 pub fn all_publish_elements(&self) -> Vec<PublishedFile> {
393 let mut all_elements = vec![];
394
395 for elements in self.repo_elements_map().values_mut() {
398 all_elements.append(elements);
399 }
400
401 all_elements
402 }
403
404 pub fn deprecated_repos(
406 &self
407 ) -> impl Iterator<Item = &DeprecatedRepository> + '_ {
408 self.deprecated_repos.iter()
409 }
410
411 pub fn deprecated_repo_remove(&mut self, to_remove: &RepositoryContact) {
413 self.deprecated_repos.retain(|current| current.contact() != to_remove)
414 }
415
416 pub fn deprecated_repo_inc_clean_attempts(
418 &mut self,
419 contact: &RepositoryContact,
420 ) {
421 for current in self.deprecated_repos.iter_mut() {
422 if current.contact() == contact {
423 current.inc_clean_attempts()
424 }
425 }
426 }
427}
428
429impl CaObjects {
436 fn add_class(
440 &mut self,
441 class_name: &ResourceClassName,
442 key: &CertifiedKey,
443 timing: &IssuanceTimingConfig,
444 signer: &KrillSigner,
445 ) -> KrillResult<()> {
446 if self.classes.contains_key(class_name) {
447 return Err(Error::publishing("Duplicate resource class"))
448 }
449
450 self.classes.insert(
451 class_name.clone(),
452 ResourceClassObjects::create(key, timing, signer)?,
453 );
454 Ok(())
455 }
456
457 fn remove_class(&mut self, class_name: &ResourceClassName) {
459 let old_repo_opt = self.classes.get(class_name).and_then(|rco| {
460 rco.old_repo()
461 }).cloned();
462
463 self.classes.remove(class_name);
464
465 if let Some(old_repo) = old_repo_opt {
466 self.deprecate_repo_if_no_longer_used(old_repo);
467 }
468 }
469
470 fn get_class_mut(
474 &mut self,
475 rcn: &ResourceClassName,
476 ) -> KrillResult<&mut ResourceClassObjects> {
477 self.classes.get_mut(rcn).ok_or_else(|| {
478 Error::publishing("Missing resource class")
479 })
480 }
481
482 fn keyroll_stage(
487 &mut self,
488 rcn: &ResourceClassName,
489 key: &CertifiedKey,
490 timing: &IssuanceTimingConfig,
491 signer: &KrillSigner,
492 ) -> KrillResult<()> {
493 self.get_class_mut(rcn)?.keyroll_stage(key, timing, signer)
494 }
495
496 fn keyroll_activate(
500 &mut self,
501 rcn: &ResourceClassName,
502 ) -> KrillResult<()> {
503 self.get_class_mut(rcn)?.keyroll_activate()
504 }
505
506 fn keyroll_finish(&mut self, rcn: &ResourceClassName) -> KrillResult<()> {
508 let resource_class_objects = self.get_class_mut(rcn)?;
509
510 if let Some(old_repo) = resource_class_objects.keyroll_finish()? {
514 self.deprecate_repo_if_no_longer_used(old_repo);
515 }
516
517 Ok(())
518 }
519
520 fn update_roas(
522 &mut self,
523 rcn: &ResourceClassName,
524 roa_updates: &RoaUpdates,
525 ) -> KrillResult<()> {
526 self.get_class_mut(rcn)
527 .map(|rco| rco.update_roas(roa_updates))
528 }
529
530 fn update_aspas(
532 &mut self,
533 rcn: &ResourceClassName,
534 updates: &AspaObjectsUpdates,
535 ) -> KrillResult<()> {
536 self.get_class_mut(rcn).map(|rco| rco.update_aspas(updates))
537 }
538
539 fn update_bgpsec_certs(
541 &mut self,
542 rcn: &ResourceClassName,
543 updates: &BgpSecCertificateUpdates,
544 ) -> KrillResult<()> {
545 self.get_class_mut(rcn).map(|rco| rco.update_bgpsec_certs(updates))
546 }
547
548 fn update_certs(
550 &mut self,
551 rcn: &ResourceClassName,
552 cert_updates: &ChildCertificateUpdates,
553 ) -> KrillResult<()> {
554 self.get_class_mut(rcn).map(|rco| rco.update_certs(cert_updates))
555 }
556
557 fn update_received_cert(
559 &mut self,
560 rcn: &ResourceClassName,
561 cert: &ReceivedCert,
562 ) -> KrillResult<()> {
563 self.get_class_mut(rcn)?.update_received_cert(cert)
564 }
565
566 fn re_issue(
574 &mut self,
575 force: bool,
576 timing: &IssuanceTimingConfig,
577 signer: &KrillSigner,
578 ) -> KrillResult<bool> {
579 let hours = timing.publish_hours_before_next();
580 let mut required = false;
581
582 for (_, resource_class_objects) in self.classes.iter_mut() {
583 if force || resource_class_objects.requires_re_issuance(hours) {
584 required = true;
585 resource_class_objects.reissue(timing, signer)?;
586 }
587 }
588
589 Ok(required)
590 }
591
592 fn update_repo(&mut self, repo: &RepositoryContact) {
598 if let Some(old) = &self.repo {
599 for resource_class_objects in self.classes.values_mut() {
600 resource_class_objects.set_old_repo(old);
601 }
602 }
603 self.repo = Some(repo.clone());
604 }
605
606 fn deprecate_repo_if_no_longer_used(
608 &mut self,
609 old_repo: RepositoryContact,
610 ) {
611 if !self.has_old_repo(&old_repo) {
612 self.deprecated_repos
613 .push(DeprecatedRepository::new(old_repo, 0));
614 }
615 }
616
617 fn has_old_repo(&self, old_repo: &RepositoryContact) -> bool {
618 self.classes.values().any(|rco| rco.has_old_repo(old_repo))
619 }
620}
621
622
623#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
629pub struct DeprecatedRepository {
630 contact: RepositoryContact,
632
633 clean_attempts: usize,
635}
636
637impl DeprecatedRepository {
638 pub fn new(contact: RepositoryContact, clean_attempts: usize) -> Self {
640 DeprecatedRepository {
641 contact,
642 clean_attempts,
643 }
644 }
645
646 pub fn contact(&self) -> &RepositoryContact {
648 &self.contact
649 }
650
651 pub fn into_contact(self) -> RepositoryContact {
653 self.contact
654 }
655
656 pub fn clean_attempts(&self) -> usize {
658 self.clean_attempts
659 }
660
661 pub fn inc_clean_attempts(&mut self) {
663 self.clean_attempts += 1;
664 }
665}
666
667
668#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
674pub struct ResourceClassObjects {
675 keys: ResourceClassKeyState,
676}
677
678impl ResourceClassObjects {
679 pub fn new(keys: ResourceClassKeyState) -> Self {
683 ResourceClassObjects { keys }
684 }
685
686 fn create(
688 key: &CertifiedKey,
689 timing: &IssuanceTimingConfig,
690 signer: &KrillSigner,
691 ) -> KrillResult<Self> {
692 let current_set = KeyObjectSet::create(key, timing, signer)?;
693
694 Ok(ResourceClassObjects {
695 keys: ResourceClassKeyState::Current(CurrentKeyState {
696 current_set,
697 }),
698 })
699 }
700
701 #[allow(clippy::mutable_key_type)]
707 fn add_elements(
708 &self,
709 map: &mut HashMap<RepositoryContact, Vec<PublishedFile>>,
710 dflt_repo: &RepositoryContact,
711 ) {
712 match &self.keys {
713 ResourceClassKeyState::Current(state) => {
714 state.current_set.add_elements(map, dflt_repo)
715 }
716 ResourceClassKeyState::Staging(state) => {
717 state.current_set.add_elements(map, dflt_repo);
718 state.staging_set.add_elements(map, dflt_repo);
719 }
720 ResourceClassKeyState::Old(state) => {
721 state.current_set.add_elements(map, dflt_repo);
722 state.old_set.add_elements(map, dflt_repo);
723 }
724 }
725 }
726
727 fn keyroll_stage(
728 &mut self,
729 key: &CertifiedKey,
730 timing: &IssuanceTimingConfig,
731 signer: &KrillSigner,
732 ) -> KrillResult<()> {
733 let current_set = match &self.keys {
734 ResourceClassKeyState::Current(state) => {
735 state.current_set.clone()
736 }
737 _ => {
738 return Err(Error::publishing(
739 "published resource class in the wrong key state",
740 ))
741 }
742 };
743
744 let staging_set = KeyObjectSet::create(key, timing, signer)?;
745
746 self.keys = ResourceClassKeyState::Staging(StagingKeyState {
747 staging_set,
748 current_set,
749 });
750
751 Ok(())
752 }
753
754 fn keyroll_activate(&mut self) -> KrillResult<()> {
755 self.keys = match &self.keys {
756 ResourceClassKeyState::Staging(state) => {
757 let old_set = state.current_set.retire()?;
758 let current_set = state.staging_set.clone();
759
760 ResourceClassKeyState::Old(OldKeyState {
761 current_set,
762 old_set,
763 })
764 }
765 _ => {
766 return Err(Error::publishing(
767 "published resource class in the wrong key state",
768 ))
769 }
770 };
771
772 Ok(())
773 }
774
775 fn keyroll_finish(&mut self) -> KrillResult<Option<RepositoryContact>> {
776 match self.keys.clone() {
777 ResourceClassKeyState::Old(old) => {
778 let current_set = old.current_set;
779 self.keys = ResourceClassKeyState::current(current_set);
780 Ok(old.old_set.old_repo)
781 }
782 _ => Err(Error::publishing(
783 "published resource class in the wrong key state",
784 )),
785 }
786 }
787
788 fn update_received_cert(
789 &mut self,
790 updated_cert: &ReceivedCert,
791 ) -> KrillResult<()> {
792 self.keys.update_received_cert(updated_cert)
793 }
794
795 fn update_roas(&mut self, roa_updates: &RoaUpdates) {
796 match &mut self.keys {
797 ResourceClassKeyState::Current(state) => {
798 state.current_set.update_roas(roa_updates)
799 }
800 ResourceClassKeyState::Staging(state) => {
801 state.current_set.update_roas(roa_updates)
802 }
803 ResourceClassKeyState::Old(state) => {
804 state.current_set.update_roas(roa_updates)
805 }
806 }
807 }
808
809 fn update_aspas(&mut self, updates: &AspaObjectsUpdates) {
810 match &mut self.keys {
811 ResourceClassKeyState::Current(state) => {
812 state.current_set.update_aspas(updates)
813 }
814 ResourceClassKeyState::Staging(state) => {
815 state.current_set.update_aspas(updates)
816 }
817 ResourceClassKeyState::Old(state) => {
818 state.current_set.update_aspas(updates)
819 }
820 }
821 }
822
823 fn update_bgpsec_certs(&mut self, updates: &BgpSecCertificateUpdates) {
824 match &mut self.keys {
825 ResourceClassKeyState::Current(state) => {
826 state.current_set.update_bgpsec_certs(updates)
827 }
828 ResourceClassKeyState::Staging(state) => {
829 state.current_set.update_bgpsec_certs(updates)
830 }
831 ResourceClassKeyState::Old(state) => {
832 state.current_set.update_bgpsec_certs(updates)
833 }
834 }
835 }
836
837 fn update_certs(&mut self, cert_updates: &ChildCertificateUpdates) {
838 match &mut self.keys {
839 ResourceClassKeyState::Current(state) => {
840 state.current_set.update_certs(cert_updates)
841 }
842 ResourceClassKeyState::Staging(state) => {
843 state.current_set.update_certs(cert_updates)
844 }
845 ResourceClassKeyState::Old(state) => {
846 state.current_set.update_certs(cert_updates)
847 }
848 }
849 }
850
851 fn requires_re_issuance(&self, hours: i64) -> bool {
852 match &self.keys {
853 ResourceClassKeyState::Current(state) => {
854 state.current_set.requires_reissuance(hours)
855 }
856 ResourceClassKeyState::Old(state) => {
857 state.old_set.requires_reissuance(hours)
858 || state.current_set.requires_reissuance(hours)
859 }
860 ResourceClassKeyState::Staging(state) => {
861 state.staging_set.requires_reissuance(hours)
862 || state.current_set.requires_reissuance(hours)
863 }
864 }
865 }
866
867 fn reissue(
868 &mut self,
869 timing: &IssuanceTimingConfig,
870 signer: &KrillSigner,
871 ) -> KrillResult<()> {
872 match &mut self.keys {
873 ResourceClassKeyState::Current(state) => {
874 state.current_set.reissue(timing, signer)
875 }
876 ResourceClassKeyState::Staging(state) => {
877 state.staging_set.reissue(timing, signer)?;
878 state.current_set.reissue(timing, signer)
879 }
880 ResourceClassKeyState::Old(state) => {
881 state.old_set.reissue(timing, signer)?;
882 state.current_set.reissue(timing, signer)
883 }
884 }
885 }
886
887 fn set_old_repo(&mut self, repo: &RepositoryContact) {
888 match &mut self.keys {
889 ResourceClassKeyState::Current(state) => {
890 state.current_set.set_old_repo(repo)
891 }
892 ResourceClassKeyState::Staging(state) => {
893 state.staging_set.set_old_repo(repo);
894 state.current_set.set_old_repo(repo);
895 }
896 ResourceClassKeyState::Old(state) => {
897 state.old_set.set_old_repo(repo);
898 state.current_set.set_old_repo(repo);
899 }
900 }
901 }
902
903 fn has_old_repo(&self, repo: &RepositoryContact) -> bool {
904 match &self.keys {
905 ResourceClassKeyState::Current(state) => {
906 state.current_set.old_repo() == Some(repo)
907 }
908 ResourceClassKeyState::Staging(state) => {
909 state.staging_set.old_repo() == Some(repo)
910 || state.current_set.old_repo() == Some(repo)
911 }
912 ResourceClassKeyState::Old(state) => {
913 state.old_set.old_repo() == Some(repo)
914 || state.current_set.old_repo() == Some(repo)
915 }
916 }
917 }
918
919 fn old_repo(&self) -> Option<&RepositoryContact> {
920 match &self.keys {
925 ResourceClassKeyState::Current(state) => {
926 state.current_set.old_repo()
927 }
928 ResourceClassKeyState::Staging(state) => state
929 .staging_set
930 .old_repo()
931 .or_else(|| state.current_set.old_repo()),
932 ResourceClassKeyState::Old(state) => state
933 .old_set
934 .old_repo()
935 .or_else(|| state.current_set.old_repo()),
936 }
937 }
938}
939
940
941#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
945#[serde(tag = "type", rename_all = "snake_case")]
946pub enum ResourceClassKeyState {
947 Current(CurrentKeyState),
948 Staging(StagingKeyState),
949 Old(OldKeyState),
950}
951
952impl ResourceClassKeyState {
953 pub fn current(current_set: KeyObjectSet) -> Self {
954 ResourceClassKeyState::Current(CurrentKeyState { current_set })
955 }
956
957 pub fn staging(
958 staging_set: KeyObjectSet,
959 current_set: KeyObjectSet,
960 ) -> Self {
961 ResourceClassKeyState::Staging(StagingKeyState {
962 staging_set,
963 current_set,
964 })
965 }
966
967 pub fn old(current_set: KeyObjectSet, old_set: KeyObjectSet) -> Self {
968 ResourceClassKeyState::Old(OldKeyState {
969 current_set,
970 old_set,
971 })
972 }
973
974 fn update_received_cert(
975 &mut self,
976 cert: &ReceivedCert,
977 ) -> KrillResult<()> {
978 match self {
979 ResourceClassKeyState::Current(state) => {
980 state.current_set.update_signing_cert(cert)
981 }
982 ResourceClassKeyState::Staging(state) => {
983 if state.staging_set.update_signing_cert(cert).is_ok() {
984 Ok(())
985 } else {
986 state.current_set.update_signing_cert(cert)
987 }
988 }
989 ResourceClassKeyState::Old(state) => {
990 if state.old_set.update_signing_cert(cert).is_ok() {
991 Ok(())
992 } else {
993 state.current_set.update_signing_cert(cert)
994 }
995 }
996 }
997 }
998}
999
1000
1001#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1005pub struct CurrentKeyState {
1006 current_set: KeyObjectSet,
1007}
1008
1009impl CurrentKeyState {
1010 pub fn new(current_set: KeyObjectSet) -> Self {
1011 CurrentKeyState { current_set }
1012 }
1013}
1014
1015#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1019pub struct StagingKeyState {
1020 staging_set: KeyObjectSet,
1021 current_set: KeyObjectSet,
1022}
1023
1024impl StagingKeyState {
1025 pub fn new(staging_set: KeyObjectSet, current_set: KeyObjectSet) -> Self {
1026 StagingKeyState {
1027 staging_set,
1028 current_set,
1029 }
1030 }
1031}
1032
1033
1034#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1038pub struct OldKeyState {
1039 current_set: KeyObjectSet,
1040 old_set: KeyObjectSet,
1041}
1042
1043impl OldKeyState {
1044 pub fn new(current_set: KeyObjectSet, old_set: KeyObjectSet) -> Self {
1045 OldKeyState {
1046 current_set,
1047 old_set,
1048 }
1049 }
1050}
1051
1052#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1058pub struct KeyObjectSet {
1059 signing_cert: ReceivedCert,
1063
1064 revision: ObjectSetRevision,
1069
1070 revocations: Revocations,
1079
1080 manifest: PublishedManifest,
1089
1090 crl: PublishedCrl,
1101
1102 #[serde(skip_serializing_if = "HashMap::is_empty", default)]
1115 published_objects: HashMap<ObjectName, PublishedObject>,
1116
1117 #[serde(skip_serializing_if = "Option::is_none")]
1126 old_repo: Option<RepositoryContact>,
1127}
1128
1129impl KeyObjectSet {
1130 pub fn new(
1134 signing_cert: ReceivedCert,
1135 revision: ObjectSetRevision,
1136 revocations: Revocations,
1137 manifest: PublishedManifest,
1138 crl: PublishedCrl,
1139 published_objects: HashMap<ObjectName, PublishedObject>,
1140 old_repo: Option<RepositoryContact>,
1141 ) -> Self {
1142 KeyObjectSet {
1143 signing_cert,
1144 revision,
1145 revocations,
1146 manifest,
1147 crl,
1148 published_objects,
1149 old_repo,
1150 }
1151 }
1152
1153 fn create(
1158 key: &CertifiedKey,
1159 timing: &IssuanceTimingConfig,
1160 signer: &KrillSigner,
1161 ) -> KrillResult<Self> {
1162 let signing_cert = key.incoming_cert().clone();
1163
1164 let signing_key = signing_cert.key_identifier();
1165 let issuer = signing_cert.subject.clone();
1166 let revocations = Revocations::default();
1167 let revision = ObjectSetRevision::create(timing.publish_next());
1168 let published_objects = HashMap::new();
1169
1170 let crl = PublishedCrl::build(
1171 signing_key,
1172 issuer,
1173 &revocations,
1174 revision,
1175 signer,
1176 )?;
1177 let manifest = ManifestBuilder::new(revision)
1178 .with_objects(&crl, &published_objects)
1179 .build_new_mft(&signing_cert, signer)
1180 .map(|m| m.into())?;
1181
1182
1183 Ok(KeyObjectSet {
1184 signing_cert,
1185 revision,
1186 revocations,
1187 manifest,
1188 crl,
1189 published_objects,
1190 old_repo: None,
1191 })
1192 }
1193
1194 #[allow(clippy::mutable_key_type)]
1199 fn add_elements(
1200 &self,
1201 map: &mut HashMap<RepositoryContact, Vec<PublishedFile>>,
1202 dflt_repo: &RepositoryContact,
1203 ) {
1204 let repo = self.old_repo.as_ref().unwrap_or(dflt_repo);
1205
1206 let crl_uri = self.signing_cert.crl_uri();
1207 let mft_uri = self.signing_cert.mft_uri();
1208
1209 let elements = map.entry(repo.clone()).or_default();
1210
1211 elements.push(self.manifest.published_file(mft_uri));
1212 elements.push(self.crl.published_file(crl_uri));
1213
1214 for (name, object) in &self.published_objects {
1215 elements.push(PublishedFile {
1216 uri: self.signing_cert.uri_for_name(name),
1217 base64: object.base64.clone(),
1218 });
1219 }
1220 }
1221
1222 pub fn requires_reissuance(&self, hours: i64) -> bool {
1224 Time::now() > self.next_update() - Duration::hours(hours)
1225 }
1226
1227 pub fn next_update(&self) -> Time {
1229 self.revision.next_update
1230 }
1231
1232 fn update_signing_cert(
1236 &mut self,
1237 cert: &ReceivedCert,
1238 ) -> KrillResult<()> {
1239 if self.signing_cert.key_identifier() == cert.key_identifier() {
1240 self.signing_cert = cert.clone();
1241 Ok(())
1242 }
1243 else {
1244 Err(Error::PublishingObjects(format!(
1245 "received new cert for unknown key id: {}",
1246 cert.key_identifier()
1247 )))
1248 }
1249 }
1250
1251 fn update_roas(&mut self, roa_updates: &RoaUpdates) {
1253 for (name, roa_info) in roa_updates.added_roas() {
1254 let published_object = PublishedObject::for_roa(
1255 name.clone(), roa_info
1256 );
1257 if let Some(old) = self.published_objects.insert(
1258 name, published_object
1259 ) {
1260 self.revocations.add(old.revoke());
1261 }
1262 }
1263 for name in roa_updates.removed_roas() {
1264 if let Some(old) = self.published_objects.remove(&name) {
1265 self.revocations.add(old.revoke());
1266 }
1267 }
1268 }
1269
1270 fn update_aspas(&mut self, updates: &AspaObjectsUpdates) {
1272 for aspa_info in updates.updated() {
1273 let name = ObjectName::aspa_from_customer(aspa_info.customer());
1274 let published_object =
1275 PublishedObject::for_aspa(name.clone(), aspa_info);
1276 if let Some(old) =
1277 self.published_objects.insert(name, published_object)
1278 {
1279 self.revocations.add(old.revoke());
1280 }
1281 }
1282 for removed in updates.removed() {
1283 let name = ObjectName::aspa_from_customer(*removed);
1284 if let Some(old) = self.published_objects.remove(&name) {
1285 self.revocations.add(old.revoke());
1286 }
1287 }
1288 }
1289
1290 fn update_bgpsec_certs(&mut self, updates: &BgpSecCertificateUpdates) {
1292 for bgpsec_cert_info in updates.updated() {
1293 let published_object =
1294 PublishedObject::for_bgpsec_cert_info(bgpsec_cert_info);
1295 if let Some(old) = self
1296 .published_objects
1297 .insert(bgpsec_cert_info.name(), published_object)
1298 {
1299 self.revocations.add(old.revoke());
1300 }
1301 }
1302
1303 for removed in updates.removed() {
1304 let name = ObjectName::from(removed);
1305 if let Some(old) = self.published_objects.remove(&name) {
1306 self.revocations.add(old.revoke());
1307 }
1308 }
1309 }
1310
1311 fn update_certs(&mut self, cert_updates: &ChildCertificateUpdates) {
1313 for removed in &cert_updates.removed {
1314 let name = ObjectName::from_key(removed, "cer");
1315 if let Some(old) = self.published_objects.remove(&name) {
1316 self.revocations.add(old.revoke());
1317 }
1318 }
1319
1320 for issued in &cert_updates.issued {
1321 let published_object = PublishedObject::for_cert_info(issued);
1322 if let Some(old) = self
1323 .published_objects
1324 .insert(issued.name.clone(), published_object)
1325 {
1326 self.revocations.add(old.revoke());
1327 }
1328 }
1329
1330 for cert in &cert_updates.unsuspended {
1333 let published_object = PublishedObject::for_cert_info(cert);
1334 self
1335 .published_objects
1336 .insert(cert.name.clone(), published_object);
1337 }
1338
1339 for suspended in &cert_updates.suspended {
1340 if let Some(old) = self.published_objects.remove(&suspended.name)
1341 {
1342 self.revocations.add(old.revoke());
1343 }
1344 }
1345 }
1346
1347 fn reissue(
1349 &mut self,
1350 timing: &IssuanceTimingConfig,
1351 signer: &KrillSigner,
1352 ) -> KrillResult<()> {
1353 debug!(
1354 "Will re-issue for key: {}. Current revision: {} and next \
1355 update: {}",
1356 self.signing_cert.key_identifier(),
1357 self.revision.number,
1358 self.revision.next_update.to_rfc3339()
1359 );
1360
1361 self.revision.next(timing.publish_next(), None);
1362
1363 self.revocations.remove_expired();
1364 let signing_key = self.signing_cert.key_identifier();
1365 let issuer = self.signing_cert.subject.clone();
1366
1367 self.crl = PublishedCrl::build(
1368 signing_key,
1369 issuer,
1370 &self.revocations,
1371 self.revision,
1372 signer,
1373 )?;
1374
1375 self.manifest = ManifestBuilder::new(self.revision)
1376 .with_objects(&self.crl, &self.published_objects)
1377 .build_new_mft(&self.signing_cert, signer)
1378 .map(|m| m.into())?;
1379
1380 Ok(())
1381 }
1382
1383 fn retire(&self) -> KrillResult<KeyObjectSet> {
1387 let mut revocations = self.revocations.clone();
1388 for object in self.published_objects.values() {
1389 revocations.add(object.revoke());
1390 }
1391 revocations.remove_expired();
1392
1393 let retired_set = KeyObjectSet {
1394 signing_cert: self.signing_cert.clone(),
1395 revision: self.revision,
1396 revocations,
1397 manifest: self.manifest.clone(),
1398 crl: self.crl.clone(),
1399 published_objects: HashMap::new(),
1400 old_repo: self.old_repo.clone(),
1401 };
1402
1403 Ok(retired_set)
1404 }
1405
1406 fn set_old_repo(&mut self, repo: &RepositoryContact) {
1408 self.old_repo = Some(repo.clone())
1409 }
1410
1411 fn old_repo(&self) -> Option<&RepositoryContact> {
1413 self.old_repo.as_ref()
1414 }
1415}
1416
1417
1418#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
1424pub struct ObjectSetRevision {
1425 number: u64,
1427
1428 this_update: Time,
1432
1433 next_update: Time,
1435}
1436
1437impl ObjectSetRevision {
1438 pub fn new(number: u64, this_update: Time, next_update: Time) -> Self {
1440 ObjectSetRevision {
1441 number,
1442 this_update,
1443 next_update,
1444 }
1445 }
1446
1447 fn create(next_update: Time) -> Self {
1449 ObjectSetRevision {
1450 number: 1,
1451 this_update: Time::five_minutes_ago(),
1452 next_update,
1453 }
1454 }
1455
1456 pub fn number(&self) -> u64 {
1457 self.number
1458 }
1459
1460 pub fn this_update(&self) -> Time {
1461 self.this_update
1462 }
1463
1464 pub fn next_update(&self) -> Time {
1465 self.next_update
1466 }
1467
1468 pub fn next(
1470 &mut self,
1471 next_update: Time,
1472 mft_number_override: Option<u64>,
1473 ) {
1474 if let Some(forced_next) = mft_number_override {
1475 self.number = forced_next;
1476 } else {
1477 self.number += 1;
1478 }
1479 self.this_update = Time::five_minutes_ago();
1480 self.next_update = next_update;
1481 }
1482}
1483
1484pub type PublishedCert = IssuedCertificate;
1488
1489
1490#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1499pub struct PublishedItem<T> {
1500 name: ObjectName,
1502
1503 base64: Base64,
1505
1506 hash: rrdp::Hash,
1510
1511 serial: Serial,
1513
1514 expires: Time,
1516
1517 marker: std::marker::PhantomData<T>,
1519}
1520
1521impl<T> PublishedItem<T> {
1522 pub fn new(
1524 name: ObjectName,
1525 base64: Base64,
1526 serial: Serial,
1527 expires: Time,
1528 ) -> Self {
1529 let hash = base64.to_hash();
1530
1531 PublishedItem {
1532 name,
1533 base64,
1534 hash,
1535 serial,
1536 expires,
1537 marker: std::marker::PhantomData,
1538 }
1539 }
1540
1541 pub fn published_file(&self, uri: uri::Rsync) -> PublishedFile {
1543 PublishedFile { uri, base64: self.base64.clone() }
1544 }
1545
1546 pub fn revoke(&self) -> Revocation {
1548 Revocation::new(self.serial, self.expires)
1549 }
1550}
1551
1552
1553pub type PublishedManifest = PublishedItem<PublishedItemManifest>;
1559
1560#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1561pub struct PublishedItemManifest;
1562
1563impl From<Manifest> for PublishedManifest {
1564 fn from(mft: Manifest) -> Self {
1565 PublishedItem::new(
1566 ObjectName::from(&mft),
1567 Base64::from(&mft),
1568 mft.cert().serial_number(),
1569 mft.next_update(),
1570 )
1571 }
1572}
1573
1574
1575pub type PublishedCrl = PublishedItem<PublishedItemCrl>;
1581
1582#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1583pub struct PublishedItemCrl;
1584
1585impl PublishedCrl {
1586 pub fn build(
1587 aki: KeyIdentifier,
1588 issuer: Name,
1589 revocations: &Revocations,
1590 revision: ObjectSetRevision,
1591 signer: &KrillSigner,
1592 ) -> KrillResult<Self> {
1593 let serial_number = Serial::from(revision.number);
1594
1595 let crl = TbsCertList::new(
1596 Default::default(),
1597 issuer,
1598 revision.this_update,
1599 revision.next_update,
1600 revocations.to_crl_entries(),
1601 aki,
1602 serial_number,
1603 );
1604
1605 let crl = signer.sign_crl(crl, &aki)?;
1606
1607 Ok(crl.into())
1608 }
1609}
1610
1611impl From<Crl> for PublishedCrl {
1612 fn from(crl: Crl) -> Self {
1613 PublishedItem::new(
1614 ObjectName::from(&crl),
1615 Base64::from(&crl),
1616 crl.crl_number(), crl.next_update(),
1618 )
1619 }
1620}
1621
1622pub type PublishedObject = PublishedItem<PublishedItemOther>;
1628
1629#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
1630pub struct PublishedItemOther;
1631
1632impl PublishedObject {
1633 pub fn for_roa(name: ObjectName, roa_info: &RoaInfo) -> Self {
1635 PublishedObject::new(
1636 name,
1637 roa_info.base64.clone(),
1638 roa_info.serial,
1639 roa_info.expires(),
1640 )
1641 }
1642
1643 pub fn for_aspa(name: ObjectName, aspa_info: &AspaInfo) -> Self {
1645 PublishedObject::new(
1646 name,
1647 aspa_info.base64.clone(),
1648 aspa_info.serial,
1649 aspa_info.expires(),
1650 )
1651 }
1652
1653 pub fn for_cert_info<T>(cert: &CertInfo<T>) -> Self {
1655 PublishedObject::new(
1656 cert.name.clone(),
1657 cert.base64.clone(),
1658 cert.serial,
1659 cert.expires(),
1660 )
1661 }
1662
1663 pub fn for_bgpsec_cert_info(cert: &BgpSecCertInfo) -> Self {
1665 PublishedObject::new(
1666 cert.name(),
1667 cert.base64.clone(),
1668 cert.serial,
1669 cert.expires,
1670 )
1671 }
1672}
1673
1674
1675#[allow(clippy::mutable_key_type)]
1679pub struct ManifestBuilder {
1680 revision: ObjectSetRevision,
1682
1683 entries: HashMap<ObjectName, rrdp::Hash>,
1685}
1686
1687impl ManifestBuilder {
1688 pub fn new(revision: ObjectSetRevision) -> Self {
1690 ManifestBuilder {
1691 revision,
1692 entries: HashMap::new(),
1693 }
1694 }
1695
1696 #[allow(clippy::mutable_key_type)]
1698 pub fn with_objects(
1699 mut self,
1700 crl: &PublishedCrl,
1701 published_objects: &HashMap<ObjectName, PublishedObject>,
1702 ) -> Self {
1703 self.entries.insert(crl.name.clone(), crl.hash);
1705
1706 for (name, object) in published_objects {
1708 self.entries.insert(name.clone(), object.hash);
1709 }
1710
1711 self
1712 }
1713
1714 pub fn build_new_mft(
1716 self,
1717 signing_cert: &ReceivedCert,
1718 signer: &KrillSigner,
1719 ) -> KrillResult<Manifest> {
1720 let mft_uri = signing_cert.mft_uri();
1721 let crl_uri = signing_cert.crl_uri();
1722
1723 let aia = &signing_cert.uri;
1724 let aki = signing_cert.key_identifier();
1725 let serial_number = Serial::from(self.revision.number);
1726
1727 let entries =
1728 self.entries.iter().map(|(k, v)| FileAndHash::new(k, v));
1729
1730 let manifest: Manifest = {
1731 let mft_content = ManifestContent::new(
1732 serial_number,
1733 self.revision.this_update,
1734 self.revision.next_update,
1735 DigestAlgorithm::default(),
1736 entries,
1737 );
1738 let mut object_builder = SignedObjectBuilder::new(
1739 signer.random_serial()?,
1740 Validity::new(
1741 self.revision.this_update,
1742 self.revision.next_update,
1743 ),
1744 crl_uri,
1745 aia.clone(),
1746 mft_uri,
1747 );
1748 object_builder.set_issuer(Some(signing_cert.subject.clone()));
1749 object_builder.set_signing_time(Time::now());
1750
1751 signer.sign_manifest(mft_content, object_builder, &aki)?
1752 };
1753
1754 Ok(manifest)
1755 }
1756}