diff --git a/src/daemon/ca/certauth.rs b/src/daemon/ca/certauth.rs index 8269b103..01e7d8ad 100644 --- a/src/daemon/ca/certauth.rs +++ b/src/daemon/ca/certauth.rs @@ -286,6 +286,9 @@ impl Aggregate for CertAuth { .unwrap() .old_key_removed(); } + EvtDet::UnexpectedKeyFound(_, _) => { + // no action needed, this is marked to flag that a key may be removed + } //----------------------------------------------------------------------- // Route Authorizations @@ -955,6 +958,15 @@ impl CertAuth { .ok_or_else(|| Error::CaParentUnknown(self.handle.clone(), parent.clone())) } + /// Find the parent for a given resource class name. + pub fn parent_for_rc(&self, rcn: &ResourceClassName) -> KrillResult<&ParentHandle> { + let rc = self + .resources + .get(rcn) + .ok_or_else(|| Error::ResourceClassUnknown(rcn.clone()))?; + Ok(rc.parent_handle()) + } + /// Adds a parent. This method will return an error in case a parent /// by this name (handle) is already known. fn add_parent(&self, parent: Handle, info: ParentCaContact) -> KrillResult> { @@ -1053,7 +1065,7 @@ impl CertAuth { ) -> KrillResult> { let repo = self.get_repository_contact()?; let parent_class_name = entitlement.class_name().clone(); - let req_details_list = rc.make_request_events(entitlement, repo.repo_info(), signer)?; + let req_details_list = rc.make_entitlement_events(entitlement, repo.repo_info(), signer)?; let mut res = vec![]; for details in req_details_list.into_iter() { diff --git a/src/daemon/ca/events.rs b/src/daemon/ca/events.rs index 8e5dc943..4faa9c66 100644 --- a/src/daemon/ca/events.rs +++ b/src/daemon/ca/events.rs @@ -247,6 +247,7 @@ pub enum EvtDet { KeyPendingToActive(ResourceClassName, CertifiedKey, ObjectsDelta), KeyRollActivated(ResourceClassName, RevocationRequest), KeyRollFinished(ResourceClassName, ObjectsDelta), + UnexpectedKeyFound(ResourceClassName, RevocationRequest), // Route Authorizations RouteAuthorizationAdded(RouteAuthorization), @@ -555,6 +556,11 @@ impl fmt::Display for EvtDet { "key roll: finished for resource class '{}'", rcn ), + EvtDet::UnexpectedKeyFound(rcn, revoke) => write!( + f, + "Found unexpected key in resource class '{}', will try to revoke key id: '{}'", + rcn, revoke.key() + ), // Route Authorizations EvtDet::RouteAuthorizationAdded(route) => write!( diff --git a/src/daemon/ca/keys.rs b/src/daemon/ca/keys.rs index 61b10fd7..ec70356b 100644 --- a/src/daemon/ca/keys.rs +++ b/src/daemon/ca/keys.rs @@ -323,7 +323,7 @@ impl KeyState { } } - pub fn request_certs( + pub fn make_entitlement_events( &self, rcn: ResourceClassName, entitlement: &EntitlementClass, @@ -379,6 +379,17 @@ impl KeyState { res.push(EvtDet::CertificateRequested(rcn.clone(), req, *key_id)); } + for key in entitlement + .issued() + .iter() + .map(|c| c.subject_key_identifier()) + { + if !self.knows_key(key) { + let revocation = RevocationRequest::new(entitlement.class_name().clone(), key); + res.push(EvtDet::UnexpectedKeyFound(rcn.clone(), revocation)); + } + } + Ok(res) } @@ -572,4 +583,16 @@ impl KeyState { _ => false, } } + + fn knows_key(&self, key_id: KeyIdentifier) -> bool { + match self { + KeyState::Pending(pending) => pending.key_id == key_id, + KeyState::Active(current) => current.key_id == key_id, + KeyState::RollPending(pending, current) => { + pending.key_id == key_id || current.key_id == key_id + } + KeyState::RollNew(new, current) => new.key_id == key_id || current.key_id == key_id, + KeyState::RollOld(current, old) => current.key_id == key_id || old.key_id == key_id, + } + } } diff --git a/src/daemon/ca/rc.rs b/src/daemon/ca/rc.rs index 06703ab9..b97823a6 100644 --- a/src/daemon/ca/rc.rs +++ b/src/daemon/ca/rc.rs @@ -327,13 +327,18 @@ impl ResourceClass { } /// Request certificates for any key that needs it. - pub fn make_request_events( + /// Also, create revocation events for any unexpected keys to recover from + /// issues where the parent believes we have keys that we do not know. This + /// can happen in corner cases where re-initialisation of Krill as a child + /// is done without proper revocation at the parent, or as is the case with + /// ARIN - Krill is sometimes told to just drop all resources. + pub fn make_entitlement_events( &self, entitlement: &EntitlementClass, base_repo: &RepoInfo, signer: &S, ) -> KrillResult> { - self.key_state.request_certs( + self.key_state.make_entitlement_events( self.name.clone(), entitlement, base_repo, diff --git a/src/daemon/ca/server.rs b/src/daemon/ca/server.rs index 73be1024..59a17c26 100644 --- a/src/daemon/ca/server.rs +++ b/src/daemon/ca/server.rs @@ -578,6 +578,20 @@ impl CaServer { } } + pub fn send_revoke_unexpected_key( + &self, + handle: &Handle, + rcn: ResourceClassName, + revocation: RevocationRequest, + ) -> KrillResult>> { + let child = self.ca_store.get_latest(handle)?; + let parent = child.parent_for_rc(&rcn)?; + let mut requests = HashMap::new(); + requests.insert(rcn, vec![revocation]); + + self.send_revoke_requests(handle, parent, requests) + } + fn send_revoke_requests_embedded( &self, revoke_requests: HashMap>, diff --git a/src/daemon/endpoints.rs b/src/daemon/endpoints.rs index 95e475a5..5b8b163a 100644 --- a/src/daemon/endpoints.rs +++ b/src/daemon/endpoints.rs @@ -656,7 +656,7 @@ pub fn ca_add_parent_xml( }; let req = if string.starts_with(">, ), + #[display( + fmt = "unexpected key found for '{}' version '{}' resource class: '{}'", + _0, + _1, + _2 + )] + UnexpectedKey(Handle, u64, ResourceClassName, RevocationRequest), + #[display(fmt = "clean up old repo *if it exists* for '{}' version '{}'", _0, _1)] CleanOldRepo(Handle, u64), } diff --git a/src/daemon/scheduler.rs b/src/daemon/scheduler.rs index ce337d23..9a7568b5 100644 --- a/src/daemon/scheduler.rs +++ b/src/daemon/scheduler.rs @@ -80,6 +80,19 @@ fn make_event_sh( just before removing the resource class entitlements."); } } + QueueEvent::UnexpectedKey(handle, _, rcn, revocation) => { + trace!( + "Trigger sending revocation requests for unexpected key with id '{}' in RC '{}'", + revocation.key(), + rcn + ); + if caserver + .send_revoke_unexpected_key(&handle, rcn, revocation) + .is_err() + { + debug!("Could not revoke unexpected surplus key at parent."); + } + } QueueEvent::ParentAdded(handle, _, parent) => { trace!( "Get updates for '{}' from added parent '{}'.",