From 593bf7a35d1b7c2ca5dbecf033bf86e1405164e8 Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Tue, 17 Dec 2019 16:56:19 +0100 Subject: [PATCH 01/18] Let user specify a repository before adding a parent #160 --- src/cli/report.rs | 19 ++-- src/commons/api/ca.rs | 18 ++-- src/commons/api/mod.rs | 7 +- src/daemon/ca/certauth.rs | 190 ++++++++++++++++++++++++++++-------- src/daemon/ca/commands.rs | 21 ++++ src/daemon/ca/error.rs | 7 ++ src/daemon/ca/events.rs | 124 ++++++----------------- src/daemon/ca/server.rs | 25 +++-- src/daemon/endpoints.rs | 1 + src/daemon/krillserver.rs | 64 ++++++------ src/daemon/test.rs | 13 ++- src/publish/mod.rs | 11 ++- tests/ca_embedded.rs | 2 +- tests/ca_grandchildren.rs | 8 +- tests/ca_keyroll_rfc6492.rs | 2 +- tests/ca_rfc6492.rs | 2 +- tests/ca_roas.rs | 2 +- tests/remote_publication.rs | 8 +- 18 files changed, 312 insertions(+), 212 deletions(-) diff --git a/src/cli/report.rs b/src/cli/report.rs index fea61620d..4f0e7a19f 100644 --- a/src/cli/report.rs +++ b/src/cli/report.rs @@ -2,11 +2,11 @@ use std::str::{from_utf8_unchecked, FromStr}; use crate::commons::api::{ CaRepoDetails, CertAuthHistory, CertAuthInfo, CertAuthList, ChildCaInfo, CurrentObjects, - ParentCaContact, PublisherDetails, PublisherList, RepositoryContact, RoaDefinition, + CurrentRepoState, ParentCaContact, PublisherDetails, PublisherList, RepositoryContact, + RoaDefinition, }; use crate::commons::remote::api::ClientInfo; use crate::commons::remote::rfc8183; -use commons::api::CurrentRepoState; //------------ ApiResponse --------------------------------------------------- @@ -148,14 +148,19 @@ impl Report for CertAuthInfo { ReportFormat::Text => { let mut res = String::new(); - let base_uri = self.repo_repo().base_uri(); - let rrdp_uri = self.repo_repo().rpki_notify(); - res.push_str(&format!("Name: {}\n", self.handle())); res.push_str("\n"); - res.push_str(&format!("Base uri: {}\n", base_uri)); - res.push_str(&format!("RRDP uri: {}\n", rrdp_uri)); + + if let Some(repo_info) = self.repo_info() { + let base_uri = repo_info.base_uri(); + let rrdp_uri = repo_info.rpki_notify(); + res.push_str(&format!("Base uri: {}\n", base_uri)); + res.push_str(&format!("RRDP uri: {}\n", rrdp_uri)); + } else { + res.push_str("No repository configured.") + } res.push_str("\n"); + res.push_str(&format!("ID cert PEM:\n{}\n", self.id_cert().pem())); res.push_str(&format!("Hash: {}\n", self.id_cert().hash())); res.push_str("\n"); diff --git a/src/commons/api/ca.rs b/src/commons/api/ca.rs index 8351d55f0..f7a79ca57 100644 --- a/src/commons/api/ca.rs +++ b/src/commons/api/ca.rs @@ -1473,7 +1473,7 @@ impl fmt::Display for ParentInfo { pub struct CertAuthInfo { handle: Handle, id_cert: IdCertPem, - repo_info: RepoInfo, + repo_info: Option, parents: Vec, resources: ResourceSet, resource_classes: HashMap, @@ -1484,7 +1484,7 @@ impl CertAuthInfo { pub fn new( handle: Handle, id_cert: IdCertPem, - repo_info: RepoInfo, + repo_info: Option, parents: HashMap, resource_classes: HashMap, children: Vec, @@ -1521,8 +1521,8 @@ impl CertAuthInfo { &self.id_cert } - pub fn repo_repo(&self) -> &RepoInfo { - &self.repo_info + pub fn repo_info(&self) -> Option<&RepoInfo> { + self.repo_info.as_ref() } pub fn parents(&self) -> &Vec { @@ -1543,10 +1543,14 @@ impl CertAuthInfo { pub fn published_objects(&self) -> Vec { let mut res = vec![]; - for (_rc_name, rc) in self.resource_classes.iter() { - let name_space = rc.name_space(); - res.append(&mut rc.current_objects().publish(self.repo_repo(), name_space)); + + if let Some(repo_info) = &self.repo_info { + for (_rc_name, rc) in self.resource_classes.iter() { + let name_space = rc.name_space(); + res.append(&mut rc.current_objects().publish(repo_info, name_space)); + } } + res } } diff --git a/src/commons/api/mod.rs b/src/commons/api/mod.rs index 8861afb06..e56bb68fc 100644 --- a/src/commons/api/mod.rs +++ b/src/commons/api/mod.rs @@ -330,6 +330,9 @@ pub enum ErrorCode { #[display(fmt = "No known parent for handle")] UnknownParent, + #[display(fmt = "No repository configured yet for CA")] + NoRepositorySet, + #[display(fmt = "Invalid ROA delta: adding a definition which is already present")] RoaUpdateInvalidDuplicate, @@ -408,6 +411,7 @@ impl From for ErrorCode { 2304 => ErrorCode::DuplicateParent, 2305 => ErrorCode::UnknownChild, 2306 => ErrorCode::UnknownParent, + 2307 => ErrorCode::NoRepositorySet, // 2400s -> ROA issues 2401 => ErrorCode::RoaUpdateInvalidDuplicate, @@ -468,6 +472,7 @@ impl Into for ErrorCode { ErrorCode::DuplicateParent => 2304, ErrorCode::UnknownChild => 2305, ErrorCode::UnknownParent => 2306, + ErrorCode::NoRepositorySet => 2307, // roa errors ErrorCode::RoaUpdateInvalidDuplicate => 2401, @@ -525,7 +530,7 @@ mod tests { test_code(n) } - for n in 2301..2307 { + for n in 2301..2308 { test_code(n) } diff --git a/src/daemon/ca/certauth.rs b/src/daemon/ca/certauth.rs index a3bbb599e..44856d177 100644 --- a/src/daemon/ca/certauth.rs +++ b/src/daemon/ca/certauth.rs @@ -7,9 +7,9 @@ use std::sync::{Arc, RwLock}; use bytes::Bytes; use chrono::Duration; -use rpki::cert::Cert; +use rpki::cert::{Cert, KeyUsage, Overclaim, TbsCert}; use rpki::crypto::{KeyIdentifier, PublicKey, PublicKeyFormat}; -use rpki::x509::Time; +use rpki::x509::{Serial, Time, Validity}; use crate::commons::api::rrdp::PublishElement; use crate::commons::api::{ @@ -32,6 +32,8 @@ use crate::daemon::ca::{ self, ta_handle, ChildDetails, Cmd, CmdDet, CurrentObjectSetDelta, Error, Evt, EvtDet, Ini, ResourceClass, Result, RouteAuthorization, RouteAuthorizationUpdates, Routes, Signer, }; +use commons::api::{TaCertDetails, TrustAnchorLocator}; +use rpki::uri; //------------ Rfc8183Id --------------------------------------------------- @@ -69,7 +71,7 @@ pub struct CertAuth { id: Rfc8183Id, // Used for RFC 6492 (up-down) and RFC 8181 (publication) - repository: RepositoryContact, + repository: Option, repository_pending_withdraw: Option, parents: HashMap, @@ -94,12 +96,13 @@ impl Aggregate for CertAuth { let (handle, _version, details) = event.unwrap(); let (id, repo_info, ta_opt) = details.unwrap(); - let pubserver = RepositoryContact::embedded(repo_info); - let mut parents = HashMap::new(); let mut resources = HashMap::new(); let mut next_class_name = 0; + let children = HashMap::new(); + let routes = Routes::default(); + if let Some(ta_details) = ta_opt { let key_id = ta_details.cert().subject_key_identifier(); parents.insert(ta_handle(), ParentCaContact::Ta(ta_details)); @@ -109,8 +112,7 @@ impl Aggregate for CertAuth { resources.insert(rcn.clone(), ResourceClass::for_ta(rcn, key_id)); } - let children = HashMap::new(); - let routes = Routes::default(); + let repository = repo_info.map(RepositoryContact::embedded); Ok(CertAuth { handle, @@ -118,7 +120,7 @@ impl Aggregate for CertAuth { id, - repository: pubserver, + repository, repository_pending_withdraw: None, parents, @@ -141,6 +143,19 @@ impl Aggregate for CertAuth { fn apply(&mut self, event: Evt) { self.version += 1; match event.into_details() { + //----------------------------------------------------------------------- + // Being a trust anchor + //----------------------------------------------------------------------- + EvtDet::TrustAnchorMade(details) => { + let key_id = details.cert().subject_key_identifier(); + self.parents + .insert(ta_handle(), ParentCaContact::Ta(details)); + let rcn = ResourceClassName::from(self.next_class_name); + self.next_class_name += 1; + self.resources + .insert(rcn.clone(), ResourceClass::for_ta(rcn, key_id)); + } + //----------------------------------------------------------------------- // Being a parent //----------------------------------------------------------------------- @@ -288,8 +303,10 @@ impl Aggregate for CertAuth { } } EvtDet::RepoUpdated(contact) => { - self.repository_pending_withdraw = Some(self.repository.clone()); - self.repository = contact; + if let Some(current) = &self.repository { + self.repository_pending_withdraw = Some(current.clone()) + } + self.repository = Some(contact); } EvtDet::RepoCleaned(_) => { self.repository_pending_withdraw = None; @@ -304,6 +321,9 @@ impl Aggregate for CertAuth { ); match command.into_details() { + // trust anchor + CmdDet::MakeTrustAnchor(uris, signer) => self.trust_anchor_make(uris, signer), + // being a parent CmdDet::ChildAdd(child, id_cert_opt, resources) => { self.child_add(child, id_cert_opt, resources) @@ -353,7 +373,10 @@ impl Aggregate for CertAuth { impl CertAuth { pub fn as_ca_info(&self) -> CertAuthInfo { let handle = self.handle.clone(); - let repo_info = self.repository.repo_info().clone(); + let repo_info = self + .repository + .as_ref() + .map(|repo| repo.repo_info().clone()); let parents = self.parents.clone(); @@ -411,14 +434,20 @@ impl CertAuth { impl CertAuth { pub fn all_objects(&self) -> Vec { let mut res = vec![]; - for rc in self.resources.values() { - res.append(&mut rc.all_objects(self.repository.repo_info())); + if let Some(repo_info) = self.repository.as_ref().map(|r| r.repo_info()) { + for rc in self.resources.values() { + res.append(&mut rc.all_objects(repo_info)); + } } res } - pub fn repository_contact(&self) -> &RepositoryContact { - &self.repository + pub fn repository_contact(&self) -> Option<&RepositoryContact> { + self.repository.as_ref() + } + + fn get_repository_contact(&self) -> Result<&RepositoryContact> { + self.repository.as_ref().ok_or(Error::RepoNotSet) } pub fn old_repository_contact(&self) -> Option<&RepositoryContact> { @@ -426,6 +455,74 @@ impl CertAuth { } } +/// # Being a trustanchor +/// +impl CertAuth { + fn trust_anchor_make( + &self, + uris: Vec, + signer: Arc>, + ) -> ca::Result> { + let mut signer = signer.write().unwrap(); + + if !self.resources.is_empty() { + return Err(Error::custom("Cannot turn CA with resources into TA")); + } + + let repo_info = self.get_repository_contact()?.repo_info(); + + let key = signer + .create_key(PublicKeyFormat::default()) + .map_err(Error::signer)?; + + let resources = ResourceSet::all_resources(); + + let cert = { + let serial: Serial = Serial::random(signer.deref()).map_err(Error::signer)?; + + let pub_key = signer.get_key_info(&key).map_err(Error::signer)?; + let name = pub_key.to_subject_name(); + + let mut cert = TbsCert::new( + serial, + name.clone(), + Validity::new(Time::five_minutes_ago(), Time::years_from_now(100)), + Some(name), + pub_key.clone(), + KeyUsage::Ca, + Overclaim::Refuse, + ); + + cert.set_basic_ca(Some(true)); + + let ns = ResourceClassName::default().to_string(); + + cert.set_ca_repository(Some(repo_info.ca_repository(&ns))); + cert.set_rpki_manifest(Some( + repo_info.rpki_manifest(&ns, &pub_key.key_identifier()), + )); + cert.set_rpki_notify(Some(repo_info.rpki_notify())); + + cert.set_as_resources(Some(resources.to_as_resources())); + cert.set_v4_resources(Some(resources.to_ip_resources_v4())); + cert.set_v6_resources(Some(resources.to_ip_resources_v6())); + + cert.into_cert(signer.deref(), &key) + .map_err(Error::signer)? + }; + + let tal = TrustAnchorLocator::new(uris, &cert); + + let ta_details = TaCertDetails::new(cert, resources, tal); + + Ok(vec![StoredEvent::new( + &self.handle, + self.version, + EvtDet::TrustAnchorMade(ta_details), + )]) + } +} + /// # Being a parent /// impl CertAuth { @@ -656,15 +753,12 @@ impl CertAuth { removed_certs: &[&Cert], signer: &S, ) -> Result> { + let repo = self.get_repository_contact()?; + self.resources .get(&class_name) .ok_or_else(|| Error::unknown_resource_class(&class_name))? - .republish_certs( - issued_certs, - removed_certs, - self.repository.repo_info(), - signer, - ) + .republish_certs(issued_certs, removed_certs, repo.repo_info(), signer) } /// Updates child IdCert and/or Resource entitlements. @@ -855,7 +949,9 @@ impl CertAuth { /// 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) -> ca::Result> { - if self.has_parent(&parent) { + if self.repository.is_none() { + Err(Error::RepoNotSet) + } else if self.has_parent(&parent) { Err(Error::DuplicateParent(parent)) } else if self.is_ta() { Err(Error::NotAllowedForTa) @@ -872,6 +968,7 @@ impl CertAuth { /// Removes a parent. Returns an error if it doesn't exist. fn remove_parent(&self, parent: Handle) -> ca::Result> { let _parent = self.parent(&parent)?; + let repo = self.get_repository_contact()?; // remove the parent, the RCs and un-publish everything. let mut deltas = vec![]; @@ -880,7 +977,7 @@ impl CertAuth { .values() .filter(|rc| rc.parent_handle() == &parent) { - deltas.push(rc.withdraw(self.repository.repo_info())); + deltas.push(rc.withdraw(repo.repo_info())); } Ok(vec![EvtDet::parent_removed( @@ -947,9 +1044,9 @@ impl CertAuth { rc: &ResourceClass, signer: &S, ) -> Result> { + let repo = self.get_repository_contact()?; let parent_class_name = entitlement.class_name().clone(); - let req_details_list = - rc.make_request_events(entitlement, self.repository.repo_info(), signer)?; + let req_details_list = rc.make_request_events(entitlement, repo.repo_info(), signer)?; let mut res = vec![]; for details in req_details_list.into_iter() { @@ -1027,7 +1124,8 @@ impl CertAuth { }) { let signer = signer.read().unwrap(); - let delta = rc.withdraw(self.repository.repo_info()); + let repo = self.get_repository_contact()?; + let delta = rc.withdraw(repo.repo_info()); let revocations = rc.revoke(signer.deref())?; debug!( @@ -1135,8 +1233,10 @@ impl CertAuth { .resources .get(&rcn) .ok_or_else(|| Error::unknown_resource_class(&rcn))?; - let evt_details = - rc.update_received_cert(rcvd_cert, self.repository.repo_info(), signer.deref())?; + + let repo = self.get_repository_contact()?; + + let evt_details = rc.update_received_cert(rcvd_cert, repo.repo_info(), signer.deref())?; let mut res = vec![]; let mut version = self.version; @@ -1164,8 +1264,9 @@ impl CertAuth { for (rcn, rc) in self.resources.iter() { let mut started = false; + let repo = self.get_repository_contact()?; for details in rc - .keyroll_initiate(self.repository.repo_info(), duration, signer.deref_mut())? + .keyroll_initiate(repo.repo_info(), duration, signer.deref_mut())? .into_iter() { started = true; @@ -1193,8 +1294,10 @@ impl CertAuth { for (rcn, rc) in self.resources.iter() { let mut activated = false; + let repo = self.get_repository_contact()?; + for details in rc - .keyroll_activate(self.repository.repo_info(), staging, signer.deref())? + .keyroll_activate(repo.repo_info(), staging, signer.deref())? .into_iter() { activated = true; @@ -1223,7 +1326,9 @@ impl CertAuth { .get(&rcn) .ok_or_else(|| Error::unknown_resource_class(&rcn))?; - let finish_details = my_rc.keyroll_finish(self.repository.repo_info())?; + let repo = self.get_repository_contact()?; + + let finish_details = my_rc.keyroll_finish(repo.repo_info())?; info!("Finished key roll for ca: {}, rc: {}", &self.handle, rcn); @@ -1269,7 +1374,7 @@ impl CertAuth { let repo_info = if let PublishMode::NewRepo(info) = mode { info } else { - self.repository.repo_info() + self.get_repository_contact()?.repo_info() }; res.append(&mut rc.republish(auths.as_slice(), repo_info, mode, signer)?); @@ -1296,9 +1401,12 @@ impl CertAuth { let signer = signer.deref(); // check that it is indeed different - if self.repository == new_contact { - return Err(Error::NewRepoUpdateNoChange); + if let Some(contact) = &self.repository { + if contact == &new_contact { + return Err(Error::NewRepoUpdateNoChange); + } } + let info = new_contact.repo_info().clone(); let mut evt_dts = vec![]; @@ -1356,6 +1464,8 @@ impl CertAuth { let signer = signer.read().unwrap(); let mode = PublishMode::Normal; + let repo = self.get_repository_contact()?; + let mut res = vec![]; let mut version = self.version; let all_resources = self.all_resources(); @@ -1410,8 +1520,7 @@ impl CertAuth { for (rcn, rc) in self.resources.iter() { let updates = rc.update_roas(current_auths.as_slice(), &mode, signer.deref())?; if updates.contains_changes() { - let mut delta = - ObjectsDelta::new(self.repository.repo_info().ca_repository(rc.name_space())); + let mut delta = ObjectsDelta::new(repo.repo_info().ca_repository(rc.name_space())); for added in updates.added().into_iter() { delta.add(added); @@ -1440,13 +1549,8 @@ impl CertAuth { for (rcn, (delta, revocations)) in deltas.into_iter() { let rc = self.resources.get(&rcn).unwrap(); - let pub_detail = rc.publish_objects( - self.repository.repo_info(), - delta, - revocations, - &mode, - signer.deref(), - )?; + let pub_detail = + rc.publish_objects(repo.repo_info(), delta, revocations, &mode, signer.deref())?; res.push(StoredEvent::new(&self.handle, version, pub_detail)); version += 1; diff --git a/src/daemon/ca/commands.rs b/src/daemon/ca/commands.rs index a910d4813..098d0ff4f 100644 --- a/src/daemon/ca/commands.rs +++ b/src/daemon/ca/commands.rs @@ -3,6 +3,8 @@ use std::sync::{Arc, RwLock}; use chrono::Duration; +use rpki::uri; + use crate::commons::api::{ ChildHandle, Entitlements, Handle, IssuanceRequest, ParentCaContact, ParentHandle, RcvdCert, RepositoryContact, ResourceClassName, ResourceSet, RevocationRequest, RevocationResponse, @@ -21,6 +23,11 @@ pub type Cmd = eventsourcing::SentCommand>; #[derive(Clone, Debug)] #[allow(clippy::large_enum_variant)] pub enum CmdDet { + // ------------------------------------------------------------ + // Being a TA + // ------------------------------------------------------------ + MakeTrustAnchor(Vec, Arc>), + // ------------------------------------------------------------ // Being a parent // ------------------------------------------------------------ @@ -108,6 +115,11 @@ pub enum CmdDet { impl fmt::Display for CmdDet { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + // ------------------------------------------------------------ + // Becoming a trust anchor + // ------------------------------------------------------------ + CmdDet::MakeTrustAnchor(_, _) => write!(f, "Turn into Trust Anchor"), + // ------------------------------------------------------------ // Being a parent // ------------------------------------------------------------ @@ -196,6 +208,15 @@ impl eventsourcing::CommandDetails for CmdDet { } impl CmdDet { + /// Turns this CA into a TrustAnchor + pub fn make_trust_anchor( + handle: &Handle, + uris: Vec, + signer: Arc>, + ) -> Cmd { + eventsourcing::SentCommand::new(handle, None, CmdDet::MakeTrustAnchor(uris, signer)) + } + /// Adds a child to this CA. Will return an error in case you try /// to give the child resources not held by the CA. pub fn child_add( diff --git a/src/daemon/ca/error.rs b/src/daemon/ca/error.rs index e8fcb35be..ba32db41f 100644 --- a/src/daemon/ca/error.rs +++ b/src/daemon/ca/error.rs @@ -110,6 +110,9 @@ pub enum Error { #[display(fmt = "Error getting list query from new repository: {}", _0)] NewRepoUpdateNotResponsive(String), + #[display(fmt = "No repository configured.")] + RepoNotSet, + #[display(fmt = "{}", _0)] Custom(String), } @@ -138,6 +141,10 @@ impl Error { pub fn unknown_resource_class(class: impl Display) -> Self { Error::UnknownResourceClass(class.to_string()) } + + pub fn custom(msg: impl fmt::Display) -> Self { + Error::Custom(msg.to_string()) + } } impl std::error::Error for Error {} diff --git a/src/daemon/ca/events.rs b/src/daemon/ca/events.rs index 76b480633..36d091b20 100644 --- a/src/daemon/ca/events.rs +++ b/src/daemon/ca/events.rs @@ -1,25 +1,22 @@ use std::collections::HashMap; use std::fmt; -use std::ops::{Deref, DerefMut}; +use std::ops::DerefMut; use std::sync::{Arc, RwLock}; -use rpki::cert::{Cert, KeyUsage, Overclaim, TbsCert}; -use rpki::crypto::{KeyIdentifier, PublicKeyFormat}; -use rpki::uri; -use rpki::x509::{Serial, Time, Validity}; +use rpki::crypto::KeyIdentifier; use crate::commons::api::{ AddedObject, ChildHandle, Handle, IssuanceRequest, IssuedCert, ObjectName, ObjectsDelta, ParentCaContact, ParentHandle, RcvdCert, RepoInfo, RepositoryContact, ResourceClassName, - ResourceSet, Revocation, RevocationRequest, RevokedObject, TaCertDetails, TrustAnchorLocator, - UpdatedObject, WithdrawnObject, + ResourceSet, Revocation, RevocationRequest, RevokedObject, TaCertDetails, UpdatedObject, + WithdrawnObject, }; use crate::commons::eventsourcing::StoredEvent; use crate::commons::remote::id::IdCert; use crate::daemon::ca::signing::Signer; use crate::daemon::ca::{ - CertifiedKey, ChildDetails, CurrentObjectSetDelta, Error, ResourceClass, Result, Rfc8183Id, - RoaInfo, RouteAuthorization, + CertifiedKey, ChildDetails, CurrentObjectSetDelta, ResourceClass, Result, Rfc8183Id, RoaInfo, + RouteAuthorization, }; //------------ Ini ----------------------------------------------------------- @@ -31,18 +28,27 @@ pub type Ini = StoredEvent; #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct IniDet { id: Rfc8183Id, - info: RepoInfo, + + // The following two fields need to be kept to maintain data compatibility + // with Krill 0.4.2 installations. + // + // Newer versions of krill will no longer include these fields. I.e. there + // will be no default embedded repository, and trust anchors will be created + // through an explicit command and events. + #[serde(skip_serializing_if = "Option::is_none")] + info: Option, + #[serde(skip_serializing_if = "Option::is_none")] ta_details: Option, } impl IniDet { - pub fn unwrap(self) -> (Rfc8183Id, RepoInfo, Option) { + pub fn unwrap(self) -> (Rfc8183Id, Option, Option) { (self.id, self.info, self.ta_details) } } impl IniDet { - pub fn init(handle: &Handle, info: RepoInfo, signer: Arc>) -> Result { + pub fn init(handle: &Handle, signer: Arc>) -> Result { let mut signer = signer.write().unwrap(); let id = Rfc8183Id::generate(signer.deref_mut())?; Ok(Ini::new( @@ -50,98 +56,16 @@ impl IniDet { 0, IniDet { id, - info, + info: None, ta_details: None, }, )) } - - pub fn init_ta( - handle: &Handle, - info: RepoInfo, - ta_uris: Vec, - signer: Arc>, - ) -> Result { - let mut signer = signer.write().unwrap(); - let id = Rfc8183Id::generate(signer.deref_mut())?; - - let ta = { - let resources = ResourceSet::all_resources(); - let ta_cert = { - let key = signer - .create_key(PublicKeyFormat::default()) - .map_err(|e| Error::SignerError(e.to_string()))?; - - Self::mk_ta_cer(&info, &resources, &key, signer.deref())? - }; - - let tal = TrustAnchorLocator::new(ta_uris, &ta_cert); - - TaCertDetails::new(ta_cert, resources, tal) - }; - - Ok(Ini::new( - handle, - 0, - IniDet { - id, - info, - ta_details: Some(ta), - }, - )) - } - - fn mk_ta_cer( - repo_info: &RepoInfo, - resources: &ResourceSet, - key: &S::KeyId, - signer: &S, - ) -> Result { - let serial: Serial = Serial::random(signer).map_err(Error::signer)?; - - let pub_key = signer.get_key_info(&key).map_err(Error::signer)?; - let name = pub_key.to_subject_name(); - - let mut cert = TbsCert::new( - serial, - name.clone(), - Validity::new(Time::now(), Time::years_from_now(100)), - Some(name), - pub_key.clone(), - KeyUsage::Ca, - Overclaim::Refuse, - ); - - cert.set_basic_ca(Some(true)); - - let ns = ResourceClassName::default().to_string(); - - cert.set_ca_repository(Some(repo_info.ca_repository(&ns))); - cert.set_rpki_manifest(Some( - repo_info.rpki_manifest(&ns, &pub_key.key_identifier()), - )); - cert.set_rpki_notify(Some(repo_info.rpki_notify())); - - cert.set_as_resources(Some(resources.to_as_resources())); - cert.set_v4_resources(Some(resources.to_ip_resources_v4())); - cert.set_v6_resources(Some(resources.to_ip_resources_v6())); - - cert.into_cert(signer.deref(), key).map_err(Error::signer) - } } impl fmt::Display for IniDet { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "Initialised with cert (hash): {}, base_uri: {}, rpki notify: {}", - self.id.key_hash(), - self.info.base_uri(), - self.info.rpki_notify() - )?; - if self.ta_details.is_some() { - write!(f, " AS TA")?; - } + write!(f, "Initialised with ID key hash: {}", self.id.key_hash())?; Ok(()) } } @@ -288,6 +212,9 @@ pub type Evt = StoredEvent; #[allow(clippy::large_enum_variant)] #[serde(rename_all = "snake_case")] pub enum EvtDet { + // Being a Trust Anchor + TrustAnchorMade(TaCertDetails), + // Being a parent Events ChildAdded(ChildHandle, ChildDetails), ChildCertificateIssued(ChildHandle, ResourceClassName, KeyIdentifier), @@ -489,6 +416,11 @@ impl EvtDet { impl fmt::Display for EvtDet { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + // Being a Trust Anchor + EvtDet::TrustAnchorMade(details) => { + write!(f, "turn into TA with key (hash) {}", details.cert().subject_key_identifier()) + }, + // Being a parent Events EvtDet::ChildAdded(child, details) => { write!( diff --git a/src/daemon/ca/server.rs b/src/daemon/ca/server.rs index 51ec404e8..1dfa02c58 100644 --- a/src/daemon/ca/server.rs +++ b/src/daemon/ca/server.rs @@ -75,21 +75,30 @@ impl CaServer { if self.ca_store.has(&handle) { Err(ServerError::TrustAnchorInitialisedError) } else { - let init = IniDet::init_ta(&handle, info, ta_uris, self.signer.clone())?; + // init normal CA + let init = IniDet::init(&handle, self.signer.clone())?; + self.ca_store.add(init)?; + + // add embedded repo + let embedded = RepositoryContact::embedded(info); + let upd_repo_cmd = CmdDet::update_repo(&handle, embedded, self.signer.clone()); + self.ca_store.command(upd_repo_cmd)?; - let ta = self.ca_store.add(init)?; + // make trust anchor + let make_ta_cmd = CmdDet::make_trust_anchor(&handle, ta_uris, self.signer.clone()); + let ta = self.ca_store.command(make_ta_cmd)?; + // receive the self signed cert (now as child of self) let ta_cert = ta.parent(&handle).unwrap().to_ta_cert(); let rcvd_cert = RcvdCert::new(ta_cert.clone(), ta_aia, ResourceSet::all_resources()); - let command = CmdDet::upd_received_cert( + let rcv_cert = CmdDet::upd_received_cert( &handle, ResourceClassName::default(), rcvd_cert, self.signer.clone(), ); - - self.ca_store.command(command)?; + self.ca_store.command(rcv_cert)?; Ok(()) } @@ -392,12 +401,12 @@ impl CaServer { ) } - /// Initialises an embedded CA, without any parents (for now). - pub fn init_ca(&self, handle: &Handle, repo_info: RepoInfo) -> ServerResult<()> { + /// Initialises a CA without a repo, no parents, no children, no nothing + pub fn init_ca(&self, handle: &Handle) -> ServerResult<()> { if self.ca_store.has(handle) { Err(ServerError::DuplicateCa(handle.to_string())) } else { - let init = IniDet::init(handle, repo_info, self.signer.clone())?; + let init = IniDet::init(handle, self.signer.clone())?; self.ca_store.add(init)?; Ok(()) } diff --git a/src/daemon/endpoints.rs b/src/daemon/endpoints.rs index 7c1f5baf0..9c4307ed3 100644 --- a/src/daemon/endpoints.rs +++ b/src/daemon/endpoints.rs @@ -786,6 +786,7 @@ impl ToErrorCode for ca::Error { ca::Error::AuthorisationInvalidMaxlength(_, _) => ErrorCode::RoaUpdateInvalidMaxlength, ca::Error::NewRepoUpdateNoChange => ErrorCode::NewRepoNoChange, ca::Error::NewRepoUpdateNotResponsive(_) => ErrorCode::NewRepoNoResponse, + ca::Error::RepoNotSet => ErrorCode::NoRepositorySet, _ => ErrorCode::CaServerError, } } diff --git a/src/daemon/krillserver.rs b/src/daemon/krillserver.rs index 6e359ead3..badd1e7ad 100644 --- a/src/daemon/krillserver.rs +++ b/src/daemon/krillserver.rs @@ -168,7 +168,7 @@ impl KrillServer { /// Adds the publishers, blows up if it already existed. pub fn add_publisher( - &mut self, + &self, req: rfc8183::PublisherRequest, ) -> KrillRes { let publisher_handle = req.publisher_handle().clone(); @@ -381,64 +381,64 @@ impl KrillServer { pub fn ca_init(&mut self, init: CertAuthInit) -> EmptyRes { let handle = init.unpack(); - let repo_info = self.pubserver.repo_info_for(&handle)?; - // Create CA - self.caserver.init_ca(&handle, repo_info)?; - - let ca = self.caserver.get_ca(&handle)?; - let id_cert = ca.id_cert().clone(); - - // Add publisher - let req = rfc8183::PublisherRequest::new(None, handle.clone(), id_cert); - self.add_publisher(req)?; + self.caserver.init_ca(&handle)?; Ok(()) } /// Return the info about the configured repository server for a given Ca. /// and the actual objects published there, as reported by a list reply. - pub fn ca_repo_details(&self, handle: &Handle) -> KrillRes { + pub fn ca_repo_details(&self, handle: &Handle) -> KrillRes> { self.caserver .get_ca(handle) .map(|ca| { - let contact = ca.repository_contact().clone(); - CaRepoDetails::new(contact) + ca.repository_contact() + .map(|repo| CaRepoDetails::new(repo.clone())) }) .map_err(Error::CaServerError) } /// Returns the state of the current configured repo for a ca - pub fn ca_repo_state(&self, handle: &Handle) -> KrillRes { + pub fn ca_repo_state(&self, handle: &Handle) -> KrillRes> { self.caserver .get_ca(handle) .map(|ca| { - let contact = ca.repository_contact().clone(); - let repo_opt = contact.as_reponse_opt(); - self.repo_state(handle, repo_opt) + ca.repository_contact() + .map(|repo| self.repo_state(handle, repo.as_reponse_opt())) }) .map_err(Error::CaServerError) } /// Update the repository for a CA, or return an error. (see `CertAuth::repo_update`) pub fn ca_update_repo(&self, handle: Handle, update: RepositoryUpdate) -> EmptyRes { - // first check that the new repo can be contacted - let repo = update.as_response_opt(); + let contact = match update { + RepositoryUpdate::Embedded => { + // Add to embedded publication server if not present + if self.pubserver.get_publisher_details(&handle).is_err() { + let ca = self.caserver.get_ca(&handle)?; + let id_cert = ca.id_cert().clone(); + + // Add publisher + let req = rfc8183::PublisherRequest::new(None, handle.clone(), id_cert); + self.add_publisher(req)?; + } - if let CurrentRepoState::Error(msg) = self.repo_state(&handle, repo) { - Err(Error::CaServerError(ca::ServerError::CertAuth( - ca::Error::NewRepoUpdateNotResponsive(msg), - ))) - } else { - let contact = match update { - RepositoryUpdate::Embedded => { - RepositoryContact::embedded(self.pubserver.repo_info_for(&handle)?) + RepositoryContact::embedded(self.pubserver.repo_info_for(&handle)?) + } + RepositoryUpdate::Rfc8181(response) => { + // first check that the new repo can be contacted + if let CurrentRepoState::Error(msg) = self.repo_state(&handle, Some(&response)) { + return Err(Error::CaServerError(ca::ServerError::CertAuth( + ca::Error::NewRepoUpdateNotResponsive(msg), + ))); } - RepositoryUpdate::Rfc8181(res) => RepositoryContact::Rfc8181(res), - }; - Ok(self.caserver.update_repo(handle, contact)?) - } + RepositoryContact::Rfc8181(response) + } + }; + + Ok(self.caserver.update_repo(handle, contact)?) } fn repo_state( diff --git a/src/daemon/test.rs b/src/daemon/test.rs index 8c82aa3a0..62107fba7 100644 --- a/src/daemon/test.rs +++ b/src/daemon/test.rs @@ -11,7 +11,7 @@ use crate::cli::{Error, KrillClient}; use crate::commons::api::{ AddChildRequest, CertAuthInfo, CertAuthInit, CertifiedKeyInfo, ChildAuthRequest, ChildHandle, Handle, ParentCaContact, ParentCaReq, ParentHandle, Publish, PublisherDetails, PublisherHandle, - ResourceClassKeysInfo, ResourceClassName, ResourceSet, RoaDefinitionUpdates, + RepositoryUpdate, ResourceClassKeysInfo, ResourceClassName, ResourceSet, RoaDefinitionUpdates, UpdateChildRequest, }; use crate::commons::remote::rfc8183; @@ -155,9 +155,14 @@ fn refresh_all() { krill_admin(Command::Bulk(BulkCaCommand::Refresh)); } -pub fn init_child(handle: &Handle) { - let init = CertAuthInit::new(handle.clone()); - krill_admin(Command::CertAuth(CaCommand::Init(init))); +pub fn init_child_with_embedded_repo(handle: &Handle) { + krill_admin(Command::CertAuth(CaCommand::Init(CertAuthInit::new( + handle.clone(), + )))); + krill_admin(Command::CertAuth(CaCommand::RepoUpdate( + handle.clone(), + RepositoryUpdate::Embedded, + ))); } pub fn generate_new_id(handle: &Handle) { diff --git a/src/publish/mod.rs b/src/publish/mod.rs index e15451d68..7abdff031 100644 --- a/src/publish/mod.rs +++ b/src/publish/mod.rs @@ -34,7 +34,14 @@ impl CaPublisher { pub fn publish(&self, ca_handle: &Handle) -> Result<(), Error> { let ca = self.caserver.get_ca(ca_handle)?; - let list_reply = match ca.repository_contact() { + // Since this is called by the schedular, this should act as a no-op for + // new CAs which do not yet have any repository configured. + let repo_contact = match ca.repository_contact() { + Some(repo) => repo, + None => return Ok(()), + }; + + let list_reply = match &repo_contact { RepositoryContact::Embedded(_) => self.pubserver.list(ca_handle)?, RepositoryContact::Rfc8181(repo) => self.caserver.send_rfc8181_list(ca_handle, repo)?, }; @@ -69,7 +76,7 @@ impl CaPublisher { PublishDelta::new(publishes, updates, withdraws) }; - match ca.repository_contact() { + match &repo_contact { RepositoryContact::Embedded(_) => self.pubserver.publish(ca_handle.clone(), delta)?, RepositoryContact::Rfc8181(repo) => { self.caserver.send_rfc8181_delta(ca_handle, repo, delta)? diff --git a/tests/ca_embedded.rs b/tests/ca_embedded.rs index 56103d776..5a00876fe 100644 --- a/tests/ca_embedded.rs +++ b/tests/ca_embedded.rs @@ -12,7 +12,7 @@ fn ca_embedded() { let child = Handle::from_str_unsafe("child"); let child_resources = ResourceSet::from_strs("", "10.0.0.0/16", "").unwrap(); - init_child(&child); + init_child_with_embedded_repo(&child); // Embedded parent -------------------------------------------------------------------- let parent = { diff --git a/tests/ca_grandchildren.rs b/tests/ca_grandchildren.rs index e4b27670a..1c95e6453 100644 --- a/tests/ca_grandchildren.rs +++ b/tests/ca_grandchildren.rs @@ -36,7 +36,7 @@ fn ca_grandchildren() { let ca1 = Handle::from_str_unsafe("CA1"); let ca1_res = ResourceSet::from_strs("", "10.0.0.0/16", "").unwrap(); - init_child(&ca1); + init_child_with_embedded_repo(&ca1); let req = child_request(&ca1); let parent = { let contact = add_child_to_ta_rfc6492(&ca1, req, ca1_res.clone()); @@ -60,7 +60,7 @@ fn ca_grandchildren() { let ca2 = Handle::from_str_unsafe("CA2"); let ca2_res = ResourceSet::from_strs("", "10.1.0.0/16", "").unwrap(); - init_child(&ca2); + init_child_with_embedded_repo(&ca2); let req = child_request(&ca2); let parent = { let contact = add_child_to_ta_rfc6492(&ca2, req, ca2_res.clone()); @@ -87,7 +87,7 @@ fn ca_grandchildren() { let ca3 = Handle::from_str_unsafe("CA3"); let ca_3_res_under_ca_1 = ResourceSet::from_strs("", "10.0.0.0/16", "").unwrap(); - init_child(&ca3); + init_child_with_embedded_repo(&ca3); let req = child_request(&ca3); let parent = { let contact = add_child_rfc6492(&ca1, &ca3, req, ca_3_res_under_ca_1.clone()); @@ -132,7 +132,7 @@ fn ca_grandchildren() { let ca4 = Handle::from_str_unsafe("CA4"); let ca_4_res_under_ca_3 = ResourceSet::from_strs("", "10.0.0.0-10.1.0.255", "").unwrap(); - init_child(&ca4); + init_child_with_embedded_repo(&ca4); let req = child_request(&ca4); let parent = { let contact = add_child_rfc6492(&ca3, &ca4, req, ca_4_res_under_ca_3.clone()); diff --git a/tests/ca_keyroll_rfc6492.rs b/tests/ca_keyroll_rfc6492.rs index b51ee1edb..360fa7539 100644 --- a/tests/ca_keyroll_rfc6492.rs +++ b/tests/ca_keyroll_rfc6492.rs @@ -12,7 +12,7 @@ fn ca_keyroll_rfc6492() { let child = Handle::from_str_unsafe("rfc6492"); let child_resources = ResourceSet::from_strs("", "10.0.0.0/16", "").unwrap(); - init_child(&child); + init_child_with_embedded_repo(&child); let req = child_request(&child); // RFC6492 parent -------------------------------------------------------------------- diff --git a/tests/ca_rfc6492.rs b/tests/ca_rfc6492.rs index 7972ef938..e160e25a8 100644 --- a/tests/ca_rfc6492.rs +++ b/tests/ca_rfc6492.rs @@ -12,7 +12,7 @@ fn ca_rfc6492() { let child = Handle::from_str_unsafe("rfc6492"); let child_resources = ResourceSet::from_strs("", "10.0.0.0/16", "").unwrap(); - init_child(&child); + init_child_with_embedded_repo(&child); // Add child to parent (ta) let parent = { diff --git a/tests/ca_roas.rs b/tests/ca_roas.rs index ae3df480f..c04efccd0 100644 --- a/tests/ca_roas.rs +++ b/tests/ca_roas.rs @@ -18,7 +18,7 @@ fn ca_roas() { let child = Handle::from_str_unsafe("child"); let child_resources = ResourceSet::from_strs("", "10.0.0.0/16", "2001:DB8::/32").unwrap(); - init_child(&child); + init_child_with_embedded_repo(&child); // Set up under parent ---------------------------------------------------------------- { diff --git a/tests/remote_publication.rs b/tests/remote_publication.rs index 4acb430b8..46fbabc4e 100644 --- a/tests/remote_publication.rs +++ b/tests/remote_publication.rs @@ -17,9 +17,9 @@ use krill::commons::api::{ use krill::commons::remote::rfc8183; use krill::daemon::ca::ta_handle; use krill::daemon::test::{ - add_child_to_ta_embedded, add_parent_to_ca, ca_route_authorizations_update, init_child, - krill_admin, krill_pubd_admin, start_krill_pubd_server, test_with_krill_server, wait_for, - wait_for_current_resources, PubdTestContext, + add_child_to_ta_embedded, add_parent_to_ca, ca_route_authorizations_update, + init_child_with_embedded_repo, krill_admin, krill_pubd_admin, start_krill_pubd_server, + test_with_krill_server, wait_for, wait_for_current_resources, PubdTestContext, }; fn repository_response( @@ -90,7 +90,7 @@ fn remote_publication() { // Set up child as a child of the TA { - init_child(&child); + init_child_with_embedded_repo(&child); let child_resources = ResourceSet::from_strs("", "10.0.0.0/16", "").unwrap(); let parent = { From bcf4031fe1944314fc0e538b494a1ae9dac2fc4f Mon Sep 17 00:00:00 2001 From: ximon18 <3304436+ximon18@users.noreply.github.com> Date: Tue, 17 Dec 2019 17:02:18 +0100 Subject: [PATCH 02/18] Quick PoC hack to support uploading more children resources. --- src/daemon/http/server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/daemon/http/server.rs b/src/daemon/http/server.rs index 7032859f6..6dcee33ce 100644 --- a/src/daemon/http/server.rs +++ b/src/daemon/http/server.rs @@ -95,7 +95,7 @@ pub fn start(config: &Config) -> Result<(), Error> { .route("/cas/{ca}/parents/{parent}", get().to(ca_my_parent_contact)) .route("/cas/{ca}/parents/{parent}", post().to(ca_update_parent)) .route("/cas/{ca}/parents/{parent}", delete().to(ca_remove_parent)) - .route("/cas/{ca}/children", post().to(ca_add_child)) + .route("/cas/{ca}/children", post().to(ca_add_child)).data(web::JsonConfig::default().limit(1 << 25)) .route( "/cas/{ca}/children/{child}/contact", get().to(ca_parent_contact), From e64471b53f699f2fcfe6fb5ab7ad231fdb2a704e Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Tue, 17 Dec 2019 20:45:51 +0100 Subject: [PATCH 03/18] Use friendly error message when failing to start (fixes: #155) --- src/bin/krill.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/bin/krill.rs b/src/bin/krill.rs index 38fe926de..24957a68b 100644 --- a/src/bin/krill.rs +++ b/src/bin/krill.rs @@ -5,9 +5,14 @@ use krill::daemon::http::server; fn main() { match Config::create() { - Ok(config) => server::start(&config).unwrap(), + Ok(config) => { + if let Err(e) = server::start(&config) { + eprintln!("Krill failed to start: {}", e); + ::std::process::exit(1); + } + } Err(e) => { - eprintln!("{}", e); + eprintln!("Krill failed to start: {}", e); ::std::process::exit(1); } } From 9154cc81d0427c5bd23bed2bf362486638da0505 Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Tue, 17 Dec 2019 21:14:24 +0100 Subject: [PATCH 04/18] Show human readable error on CLI rather than json (when format is text) (closes #162) --- src/bin/krillc.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/bin/krillc.rs b/src/bin/krillc.rs index 0169dd929..fffbb62c4 100644 --- a/src/bin/krillc.rs +++ b/src/bin/krillc.rs @@ -2,7 +2,8 @@ extern crate krill; use krill::cli::options::Options; use krill::cli::report::ReportFormat; -use krill::cli::KrillClient; +use krill::cli::{Error, KrillClient}; +use krill::commons::util::httpclient; fn main() { match Options::from_args() { @@ -12,7 +13,21 @@ fn main() { Ok(()) => {} //, Err(e) => { if format != ReportFormat::None { - eprintln!("{}", e); + match &e { + Error::HttpClientError(httpclient::Error::ErrorWithJson( + _code, + res, + )) => { + if format == ReportFormat::Json { + eprintln!("{}", e); + } else { + eprintln!("Error {}: {}", res.code(), res.msg()); + } + } + _ => { + eprintln!("{}", e); + } + } } ::std::process::exit(1); } From 18f50f8c13d9b51d97779ff9e696364f56a0c3b3 Mon Sep 17 00:00:00 2001 From: Ximon Eighteen <3304436+ximon18@users.noreply.github.com> Date: Tue, 17 Dec 2019 21:31:41 +0100 Subject: [PATCH 05/18] FIX: Don't send large unnecessary directories to the Docker build daemon. --- .dockerignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..cf2c04e0d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +/target +.git From ae98800356472b8d66397505f3c88e29eaf9f63d Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Tue, 17 Dec 2019 22:01:16 +0100 Subject: [PATCH 06/18] Depend on version of rpki-rs with fix for RFC3779 encoding issue (#161) --- Cargo.toml | 2 +- src/commons/api/ca.rs | 4 ++-- test-resources/resources/child_resources.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e097ea4c3..a37c7278d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ openssl = { version = "^0.10", features = ["v110"] } pretty = "0.5.2" rand = "^0.5" reqwest = "^0.9.17" -rpki = "0.8.2" +rpki = { version = "0.8.3-pre", git = "https://github.com/NLnetLabs/rpki-rs.git", branch = "chain-from-iter-fix" } serde = { version = "^1.0", features = ["derive"] } serde_json = "^1.0" syslog = "^4.0" diff --git a/src/commons/api/ca.rs b/src/commons/api/ca.rs index f7a79ca57..cee083f55 100644 --- a/src/commons/api/ca.rs +++ b/src/commons/api/ca.rs @@ -1962,9 +1962,9 @@ mod test { let parent_resources_json = include_str!("../../../test-resources/resources/parent_resources.json"); - let parent_resouces: ResourceSet = serde_json::from_str(parent_resources_json).unwrap(); + let parent_resources: ResourceSet = serde_json::from_str(parent_resources_json).unwrap(); - let intersection = parent_resouces.intersection(&child_resources); + let intersection = parent_resources.intersection(&child_resources); assert_eq!(intersection, child_resources); } diff --git a/test-resources/resources/child_resources.json b/test-resources/resources/child_resources.json index a0a12b039..1b5edcee7 100644 --- a/test-resources/resources/child_resources.json +++ b/test-resources/resources/child_resources.json @@ -1,5 +1,5 @@ { "asn": "AS10906, AS11284, AS11644, AS11752, AS12136, AS14026, AS14650, AS22548, AS26162, AS53035, AS61580", - "v4": "45.6.52.0/22, 45.184.144.0/22, 45.227.0.0/22, 168.181.20.0/22, 187.16.192.0/19, 189.76.96.0/19, 200.160.0.0/20, 200.189.40.0/22, 200.192.104.0/24, 200.192.108.0/22, 200.192.232.0/22, 200.194.128.0/19, 200.219.130.0/23, 200.219.138.0-200.219.141.255, 200.219.143.0-200.219.148.255, 200.219.154.0-200.219.157.255, 200.219.158.0/23, 200.229.248.0/23", + "v4": "45.6.53.0/24, 45.6.52.0/24, 45.6.54.0/23, 45.184.144.0/22, 45.227.0.0/22, 168.181.20.0/22, 187.16.192.0/19, 189.76.96.0/19, 200.160.0.0/20, 200.189.40.0/22, 200.192.104.0/24, 200.192.108.0/22, 200.192.232.0/22, 200.194.128.0/19, 200.219.130.0/23, 200.219.138.0-200.219.141.255, 200.219.143.0-200.219.148.255, 200.219.154.0-200.219.157.255, 200.219.158.0/23, 200.229.248.0/23", "v6": "2001:12f8::/48, 2001:12f8:2::-2001:12f8:d:ffff:ffff:ffff:ffff:ffff, 2001:12fe::/31, 2801:80:1700::/40, 2801:80:1e00::/40" } \ No newline at end of file From 61472fb227c6e45dcc272a1bc49eb03792dded2a Mon Sep 17 00:00:00 2001 From: Ximon Eighteen <3304436+ximon18@users.noreply.github.com> Date: Tue, 17 Dec 2019 22:33:29 +0100 Subject: [PATCH 07/18] Added new error code 2307. --- doc/openapi.yaml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/doc/openapi.yaml b/doc/openapi.yaml index 2534d0705..77bfa90a3 100644 --- a/doc/openapi.yaml +++ b/doc/openapi.yaml @@ -607,7 +607,13 @@ paths: '403': $ref: '#/components/responses/Forbidden' '400': - $ref: '#/components/schemas/ParentWithHandleExists' + description: Bad request parameters. + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/ParentWithHandleExists' + - $ref: '#/components/schemas/NoRepositoryConfiguredYetForCA' '404': $ref: '#/components/responses/UnknownCA' '500': @@ -1460,6 +1466,18 @@ components: msg: type: string example: No known parent for handle. + NoRepositoryConfiguredYetForCA: + type: object + required: + - code + - msg + properties: + code: + type: integer + enum: [2307] + msg: + type: string + example: No repository configured yet for CA. InvalidROADeltaAddingDefinitionAlreadyPresent: type: object required: From f52ae43e911bc93951d5e12a8a6dc32f9479894d Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Wed, 18 Dec 2019 09:17:45 +0100 Subject: [PATCH 08/18] Remove logins and cookies as they are not required by Lagosta. --- Cargo.toml | 3 --- src/daemon/auth.rs | 51 ++++++--------------------------------- src/daemon/http/server.rs | 14 ++--------- src/daemon/krillserver.rs | 12 ++------- src/lib.rs | 3 --- 5 files changed, 11 insertions(+), 72 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a37c7278d..14ec16bd3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,10 +6,7 @@ description = "Resource Public Key Infrastructure (RPKI) daemon" license = "MPL-2.0" [dependencies] -actix-identity = "0.1.0" actix-web = { version = "1.0.3", features = ["ssl"] } -actix-session = "0.1.0" -actix-service = "0.4.0" base64 = "^0.10" bcder = "0.4.0" bytes = "^0.4" diff --git a/src/daemon/auth.rs b/src/daemon/auth.rs index 7fa8c2e58..7df4812d6 100644 --- a/src/daemon/auth.rs +++ b/src/daemon/auth.rs @@ -1,13 +1,8 @@ //! Authorization for the API -use actix_identity::Identity; use actix_web::dev::Payload; -use actix_web::web::{self, Json}; use actix_web::{Error, FromRequest, HttpRequest, HttpResponse, ResponseError}; use crate::commons::api::Token; -use crate::daemon::http::server::AppServer; - -pub const AUTH_COOKIE_NAME: &str = "krill_auth"; //------------ Authorizer ---------------------------------------------------- @@ -25,43 +20,14 @@ impl Authorizer { } } - pub fn is_api_allowed(&self, token: &Token) -> bool { - &self.krill_auth_token == token - } -} - -#[derive(Deserialize)] -pub struct Credentials { - token: Token, -} - -pub fn login(server: web::Data, cred: Json, id: Identity) -> HttpResponse { - if server.read().login(cred.token.clone()) { - id.remember("admin".to_string()); - HttpResponse::Ok().finish() - } else { - info!("Failed login attempt {}", cred.token.as_ref()); - HttpResponse::Forbidden().finish() - } -} - -pub fn logout(id: Identity) -> HttpResponse { - id.forget(); - HttpResponse::Ok().finish() -} - -pub fn is_logged_in(id: Identity) -> HttpResponse { - if id.identity().is_some() { - HttpResponse::Ok().finish() - } else { - HttpResponse::Forbidden().finish() + pub fn is_api_allowed(&self, auth: &Auth) -> bool { + match auth { + Auth::Bearer(token) => &self.krill_auth_token == token, + } } } -pub type UserName = String; - pub enum Auth { - User(UserName), Bearer(Token), } @@ -88,11 +54,8 @@ impl FromRequest for Auth { type Future = Result; type Config = (); - fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future { - if let Some(identity) = Identity::from_request(req, payload)?.identity() { - info!("Found user: {}", &identity); - Ok(Auth::User(identity)) - } else if let Some(header) = req.headers().get("Authorization") { + fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future { + if let Some(header) = req.headers().get("Authorization") { let token = Auth::extract_bearer_token(header.to_str().map_err(|_| AuthError::InvalidToken)?)?; @@ -105,7 +68,7 @@ impl FromRequest for Auth { #[derive(Debug, Display)] pub enum AuthError { - #[display(fmt = "Neither logged in user, nor bearer token found")] + #[display(fmt = "No bearer token found")] Unauthorised, #[display(fmt = "Invalid token")] diff --git a/src/daemon/http/server.rs b/src/daemon/http/server.rs index 6dcee33ce..eb4a8e5b0 100644 --- a/src/daemon/http/server.rs +++ b/src/daemon/http/server.rs @@ -7,7 +7,6 @@ use std::fs::File; use std::io; use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; -use actix_session::CookieSession; use actix_web::http::StatusCode; use actix_web::web::{delete, get, post, scope, Path}; use actix_web::{guard, middleware, web}; @@ -16,7 +15,6 @@ use openssl::ssl::{SslAcceptor, SslAcceptorBuilder, SslFiletype, SslMethod}; use bcder::decode; -use crate::daemon::auth::{is_logged_in, login, logout, AUTH_COOKIE_NAME}; use crate::daemon::config::Config; use crate::daemon::endpoints; use crate::daemon::endpoints::*; @@ -51,11 +49,6 @@ pub fn start(config: &Config) -> Result<(), Error> { App::new() .data(server.clone()) .wrap(middleware::Logger::default()) - .wrap( - CookieSession::signed(&[0; 32]) - .name(AUTH_COOKIE_NAME) - .secure(true), - ) .route("/health", get().to(endpoints::health)) // API end-points .service( @@ -95,7 +88,8 @@ pub fn start(config: &Config) -> Result<(), Error> { .route("/cas/{ca}/parents/{parent}", get().to(ca_my_parent_contact)) .route("/cas/{ca}/parents/{parent}", post().to(ca_update_parent)) .route("/cas/{ca}/parents/{parent}", delete().to(ca_remove_parent)) - .route("/cas/{ca}/children", post().to(ca_add_child)).data(web::JsonConfig::default().limit(1 << 25)) + .route("/cas/{ca}/children", post().to(ca_add_child)) + .data(web::JsonConfig::default().limit(1 << 25)) .route( "/cas/{ca}/children/{child}/contact", get().to(ca_parent_contact), @@ -124,10 +118,6 @@ pub fn start(config: &Config) -> Result<(), Error> { // Methods that are not found should return a bad request and some explanation .default_service(web::route().to(api_bad_request)), ) - // Logged in users for the API - .route("/ui/is_logged_in", get().to(is_logged_in)) - .route("/ui/login", post().to(login)) - .route("/ui/logout", post().to(logout)) // Identity exchanges for remote publishers .route("/rfc8181/{handle}", post().to(rfc8181)) // Provisioning for remote krill clients diff --git a/src/daemon/krillserver.rs b/src/daemon/krillserver.rs index badd1e7ad..b73e57a70 100644 --- a/src/daemon/krillserver.rs +++ b/src/daemon/krillserver.rs @@ -12,8 +12,7 @@ use crate::commons::api::{ AddChildRequest, CaRepoDetails, CertAuthHistory, CertAuthInfo, CertAuthInit, CertAuthList, ChildCaInfo, ChildHandle, CurrentRepoState, Handle, ListReply, ParentCaContact, ParentCaReq, ParentHandle, PublishDelta, PublisherDetails, PublisherHandle, RepoInfo, RepositoryContact, - RepositoryUpdate, RoaDefinition, RoaDefinitionUpdates, TaCertDetails, Token, - UpdateChildRequest, + RepositoryUpdate, RoaDefinition, RoaDefinitionUpdates, TaCertDetails, UpdateChildRequest, }; use crate::commons::remote::rfc8183; use crate::commons::util::softsigner::{OpenSslSigner, SignerError}; @@ -147,15 +146,8 @@ impl KrillServer { /// # Authentication impl KrillServer { - pub fn login(&self, token: Token) -> bool { - self.authorizer.is_api_allowed(&token) - } - pub fn is_api_allowed(&self, auth: &Auth) -> bool { - match auth { - Auth::Bearer(token) => self.authorizer.is_api_allowed(token), - Auth::User(_) => true, - } + self.authorizer.is_api_allowed(auth) } } diff --git a/src/lib.rs b/src/lib.rs index 4b6844871..cf4041fdf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,9 +13,6 @@ extern crate futures; extern crate hex; #[macro_use] extern crate log; -extern crate actix_identity; -extern crate actix_service; -extern crate actix_session; extern crate actix_web; extern crate clokwerk; extern crate openssl; From 2f5b9f9c64176080e2550da2d53b4c44aea86bf2 Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Wed, 18 Dec 2019 11:16:48 +0100 Subject: [PATCH 09/18] Add post size limit to api json (#158) --- defaults/krill.conf | 8 +++++++- src/daemon/config.rs | 13 +++++++++++-- src/daemon/http/server.rs | 6 ++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/defaults/krill.conf b/defaults/krill.conf index d53afe59e..c97cb9d02 100644 --- a/defaults/krill.conf +++ b/defaults/krill.conf @@ -93,4 +93,10 @@ # # Defaults to 10 minutes # -#ca_refresh = 600 \ No newline at end of file +#ca_refresh = 600 + +# Restrict size of messages sent to the API +# +# Default 256 kB +# +# post_limit_api = 262144 \ No newline at end of file diff --git a/src/daemon/config.rs b/src/daemon/config.rs index e10c3bac0..47beecf45 100644 --- a/src/daemon/config.rs +++ b/src/daemon/config.rs @@ -75,6 +75,10 @@ impl ConfigDefaults { fn ca_refresh() -> u32 { 600 } + + fn post_limit_api() -> usize { + 256 * 1024 // 256kB - some + } } //------------ Config -------------------------------------------------------- @@ -129,6 +133,9 @@ pub struct Config { #[serde(default = "ConfigDefaults::ca_refresh")] pub ca_refresh: u32, + + #[serde(default = "ConfigDefaults::post_limit_api")] + pub post_limit_api: usize, } /// # Accessors @@ -181,7 +188,7 @@ impl Config { let ip = ConfigDefaults::ip(); let port = ConfigDefaults::port(); let use_ta = true; - let use_ssl = HttpsMode::Generate; + let https_mode = HttpsMode::Generate; let data_dir = data_dir.clone(); let rsync_base = ConfigDefaults::rsync_base(); let service_uri = ConfigDefaults::service_uri(); @@ -193,12 +200,13 @@ impl Config { let syslog_facility = ConfigDefaults::syslog_facility(); let auth_token = Token::from("secret"); let ca_refresh = 3600; + let post_limit_api = ConfigDefaults::post_limit_api(); Config { ip, port, use_ta, - https_mode: use_ssl, + https_mode, data_dir, rsync_base, service_uri, @@ -209,6 +217,7 @@ impl Config { syslog_facility, auth_token, ca_refresh, + post_limit_api, } } diff --git a/src/daemon/http/server.rs b/src/daemon/http/server.rs index eb4a8e5b0..a721efbed 100644 --- a/src/daemon/http/server.rs +++ b/src/daemon/http/server.rs @@ -45,6 +45,8 @@ pub fn start(config: &Config) -> Result<(), Error> { let https_builder = https_builder(config)?; + let post_limit_api = config.post_limit_api; + HttpServer::new(move || { App::new() .data(server.clone()) @@ -53,7 +55,8 @@ pub fn start(config: &Config) -> Result<(), Error> { // API end-points .service( scope("/api/v1") - // Health + .data(web::JsonConfig::default().limit(post_limit_api)) + // Let the UI check if it's authorized .route("/authorized", get().to(api_authorized)) // Repositories and their publishers (both embedded and remote) .route("/publishers", get().to(list_pbl)) @@ -89,7 +92,6 @@ pub fn start(config: &Config) -> Result<(), Error> { .route("/cas/{ca}/parents/{parent}", post().to(ca_update_parent)) .route("/cas/{ca}/parents/{parent}", delete().to(ca_remove_parent)) .route("/cas/{ca}/children", post().to(ca_add_child)) - .data(web::JsonConfig::default().limit(1 << 25)) .route( "/cas/{ca}/children/{child}/contact", get().to(ca_parent_contact), From 41763d68b8eb21672487dac7f848b48e5abf650f Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Wed, 18 Dec 2019 12:20:12 +0100 Subject: [PATCH 10/18] Adding configurable limits for RFC 8181 and RFC 6492. (#158) --- defaults/krill.conf | 14 +++++++++++++- src/daemon/config.rs | 20 +++++++++++++++++++- src/daemon/http/server.rs | 20 +++++++++++++++----- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/defaults/krill.conf b/defaults/krill.conf index c97cb9d02..e637b503b 100644 --- a/defaults/krill.conf +++ b/defaults/krill.conf @@ -99,4 +99,16 @@ # # Default 256 kB # -# post_limit_api = 262144 \ No newline at end of file +# post_limit_api = 262144 + +# Restrict size of messages sent to the RFC 8181 publication protocol +# +# Default 32MB (enough for a keyroll with about 8000 issued certificates) +# +# post_limit_rfc8181 = 33554432 + +# Restrict size of messages sent to the RFC 6492 up-down protocol +# +# Default 1MB (enough for a keyroll with certs of ~400kb, the biggest known cert is 220kB) +# +# post_limit_rfc6492 = 1048576 \ No newline at end of file diff --git a/src/daemon/config.rs b/src/daemon/config.rs index 47beecf45..2ef40e779 100644 --- a/src/daemon/config.rs +++ b/src/daemon/config.rs @@ -77,7 +77,15 @@ impl ConfigDefaults { } fn post_limit_api() -> usize { - 256 * 1024 // 256kB - some + 256 * 1024 // 256kB + } + + fn post_limit_rfc8181() -> usize { + 32 * 1024 * 1024 // 32MB (roughly 8000 issued certificates, so a key roll for nicbr and 100% uptake should be okay) + } + + fn post_limit_rfc6492() -> usize { + 1024 * 1024 // 1MB (for ref. the NIC br cert is about 200kB) } } @@ -136,6 +144,12 @@ pub struct Config { #[serde(default = "ConfigDefaults::post_limit_api")] pub post_limit_api: usize, + + #[serde(default = "ConfigDefaults::post_limit_rfc8181")] + pub post_limit_rfc8181: usize, + + #[serde(default = "ConfigDefaults::post_limit_rfc6492")] + pub post_limit_rfc6492: usize, } /// # Accessors @@ -201,6 +215,8 @@ impl Config { let auth_token = Token::from("secret"); let ca_refresh = 3600; let post_limit_api = ConfigDefaults::post_limit_api(); + let post_limit_rfc8181 = ConfigDefaults::post_limit_rfc8181(); + let post_limit_rfc6492 = ConfigDefaults::post_limit_rfc6492(); Config { ip, @@ -218,6 +234,8 @@ impl Config { auth_token, ca_refresh, post_limit_api, + post_limit_rfc8181, + post_limit_rfc6492, } } diff --git a/src/daemon/http/server.rs b/src/daemon/http/server.rs index a721efbed..bfeb7a5c5 100644 --- a/src/daemon/http/server.rs +++ b/src/daemon/http/server.rs @@ -9,7 +9,7 @@ use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; use actix_web::http::StatusCode; use actix_web::web::{delete, get, post, scope, Path}; -use actix_web::{guard, middleware, web}; +use actix_web::{guard, middleware, web, Resource}; use actix_web::{App, HttpResponse, HttpServer}; use openssl::ssl::{SslAcceptor, SslAcceptorBuilder, SslFiletype, SslMethod}; @@ -46,6 +46,8 @@ pub fn start(config: &Config) -> Result<(), Error> { let https_builder = https_builder(config)?; let post_limit_api = config.post_limit_api; + let post_limit_rfc8181 = config.post_limit_rfc8181; + let post_limit_rfc6492 = config.post_limit_rfc6492; HttpServer::new(move || { App::new() @@ -120,10 +122,18 @@ pub fn start(config: &Config) -> Result<(), Error> { // Methods that are not found should return a bad request and some explanation .default_service(web::route().to(api_bad_request)), ) - // Identity exchanges for remote publishers - .route("/rfc8181/{handle}", post().to(rfc8181)) - // Provisioning for remote krill clients - .route("/rfc6492/{handle}", post().to(rfc6492)) + // Publication Protocol (RFC 8181) + .service( + Resource::new("/rfc8181/{handle}") + .data(web::PayloadConfig::default().limit(post_limit_rfc8181)) + .route(post().to(rfc8181)), + ) + // Uo-Down Protocol (RFC 6492) + .service( + Resource::new("/rfc6492/{handle}") + .data(web::PayloadConfig::default().limit(post_limit_rfc6492)) + .route(post().to(rfc6492)), + ) // Public TA related methods .route("/ta/ta.tal", get().to(tal)) .route("/ta/ta.cer", get().to(ta_cer)) From 454e648b440d0b753d359009db9c605265b08ba6 Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Wed, 18 Dec 2019 12:47:11 +0100 Subject: [PATCH 11/18] Return proper error when view the repository config or state. --- src/daemon/ca/certauth.rs | 12 ++++-------- src/daemon/krillserver.rs | 28 ++++++++++++---------------- src/publish/mod.rs | 8 ++++---- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/src/daemon/ca/certauth.rs b/src/daemon/ca/certauth.rs index 44856d177..fd7ff5917 100644 --- a/src/daemon/ca/certauth.rs +++ b/src/daemon/ca/certauth.rs @@ -9,6 +9,7 @@ use chrono::Duration; use rpki::cert::{Cert, KeyUsage, Overclaim, TbsCert}; use rpki::crypto::{KeyIdentifier, PublicKey, PublicKeyFormat}; +use rpki::uri; use rpki::x509::{Serial, Time, Validity}; use crate::commons::api::rrdp::PublishElement; @@ -16,7 +17,8 @@ use crate::commons::api::{ self, CertAuthInfo, ChildHandle, EntitlementClass, Entitlements, Handle, IdCertPem, IssuanceRequest, IssuedCert, ObjectsDelta, ParentCaContact, ParentHandle, RcvdCert, RepositoryContact, RequestResourceLimit, ResourceClassName, ResourceSet, RevocationRequest, - RevocationResponse, RoaDefinition, SigningCert, UpdateChildRequest, + RevocationResponse, RoaDefinition, SigningCert, TaCertDetails, TrustAnchorLocator, + UpdateChildRequest, }; use crate::commons::eventsourcing::{Aggregate, StoredEvent}; use crate::commons::remote::builder::{IdCertBuilder, SignedMessageBuilder}; @@ -32,8 +34,6 @@ use crate::daemon::ca::{ self, ta_handle, ChildDetails, Cmd, CmdDet, CurrentObjectSetDelta, Error, Evt, EvtDet, Ini, ResourceClass, Result, RouteAuthorization, RouteAuthorizationUpdates, Routes, Signer, }; -use commons::api::{TaCertDetails, TrustAnchorLocator}; -use rpki::uri; //------------ Rfc8183Id --------------------------------------------------- @@ -442,11 +442,7 @@ impl CertAuth { res } - pub fn repository_contact(&self) -> Option<&RepositoryContact> { - self.repository.as_ref() - } - - fn get_repository_contact(&self) -> Result<&RepositoryContact> { + pub fn get_repository_contact(&self) -> Result<&RepositoryContact> { self.repository.as_ref().ok_or(Error::RepoNotSet) } diff --git a/src/daemon/krillserver.rs b/src/daemon/krillserver.rs index b73e57a70..cca69b2a3 100644 --- a/src/daemon/krillserver.rs +++ b/src/daemon/krillserver.rs @@ -381,25 +381,21 @@ impl KrillServer { /// Return the info about the configured repository server for a given Ca. /// and the actual objects published there, as reported by a list reply. - pub fn ca_repo_details(&self, handle: &Handle) -> KrillRes> { - self.caserver - .get_ca(handle) - .map(|ca| { - ca.repository_contact() - .map(|repo| CaRepoDetails::new(repo.clone())) - }) - .map_err(Error::CaServerError) + pub fn ca_repo_details(&self, handle: &Handle) -> KrillRes { + let ca = self.caserver.get_ca(handle).map_err(Error::CaServerError)?; + let contact = ca + .get_repository_contact() + .map_err(|e| Error::CaServerError(ca::ServerError::CertAuth(e)))?; + Ok(CaRepoDetails::new(contact.clone())) } /// Returns the state of the current configured repo for a ca - pub fn ca_repo_state(&self, handle: &Handle) -> KrillRes> { - self.caserver - .get_ca(handle) - .map(|ca| { - ca.repository_contact() - .map(|repo| self.repo_state(handle, repo.as_reponse_opt())) - }) - .map_err(Error::CaServerError) + pub fn ca_repo_state(&self, handle: &Handle) -> KrillRes { + let ca = self.caserver.get_ca(handle).map_err(Error::CaServerError)?; + let contact = ca + .get_repository_contact() + .map_err(|e| Error::CaServerError(ca::ServerError::CertAuth(e)))?; + Ok(self.repo_state(handle, contact.as_reponse_opt())) } /// Update the repository for a CA, or return an error. (see `CertAuth::repo_update`) diff --git a/src/publish/mod.rs b/src/publish/mod.rs index 7abdff031..66dc8bbe7 100644 --- a/src/publish/mod.rs +++ b/src/publish/mod.rs @@ -34,11 +34,11 @@ impl CaPublisher { pub fn publish(&self, ca_handle: &Handle) -> Result<(), Error> { let ca = self.caserver.get_ca(ca_handle)?; - // Since this is called by the schedular, this should act as a no-op for + // Since this is called by the scheduler, this should act as a no-op for // new CAs which do not yet have any repository configured. - let repo_contact = match ca.repository_contact() { - Some(repo) => repo, - None => return Ok(()), + let repo_contact = match ca.get_repository_contact() { + Ok(repo) => repo, + Err(_) => return Ok(()), }; let list_reply = match &repo_contact { From 1758506b59810ca6994fcec08be44909a12cb02f Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Wed, 18 Dec 2019 15:00:04 +0100 Subject: [PATCH 12/18] Check that parent can be reached before adding or updating it. (#163) --- src/commons/api/admin.rs | 10 ++++- src/commons/api/mod.rs | 7 +++- src/daemon/ca/error.rs | 3 ++ src/daemon/ca/server.rs | 26 +++++++++++-- src/daemon/endpoints.rs | 7 ++-- src/daemon/krillserver.rs | 80 ++++++++++++++++++++++++++------------- 6 files changed, 98 insertions(+), 35 deletions(-) diff --git a/src/commons/api/admin.rs b/src/commons/api/admin.rs index e0db3ad15..5af806fdf 100644 --- a/src/commons/api/admin.rs +++ b/src/commons/api/admin.rs @@ -373,7 +373,7 @@ impl fmt::Display for RepositoryContact { /// This type defines all parent ca details needed to add a parent to a CA #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct ParentCaReq { - handle: Handle, // the local name the child gave to the parent + handle: ParentHandle, // the local name the child gave to the parent contact: ParentCaContact, // where the parent can be contacted } @@ -382,6 +382,14 @@ impl ParentCaReq { ParentCaReq { handle, contact } } + pub fn handle(&self) -> &ParentHandle { + &self.handle + } + + pub fn contact(&self) -> &ParentCaContact { + &self.contact + } + pub fn unwrap(self) -> (Handle, ParentCaContact) { (self.handle, self.contact) } diff --git a/src/commons/api/mod.rs b/src/commons/api/mod.rs index e56bb68fc..4d286b0d7 100644 --- a/src/commons/api/mod.rs +++ b/src/commons/api/mod.rs @@ -333,6 +333,9 @@ pub enum ErrorCode { #[display(fmt = "No repository configured yet for CA")] NoRepositorySet, + #[display(fmt = "No response from parent")] + ParentNoResponse, + #[display(fmt = "Invalid ROA delta: adding a definition which is already present")] RoaUpdateInvalidDuplicate, @@ -412,6 +415,7 @@ impl From for ErrorCode { 2305 => ErrorCode::UnknownChild, 2306 => ErrorCode::UnknownParent, 2307 => ErrorCode::NoRepositorySet, + 2308 => ErrorCode::ParentNoResponse, // 2400s -> ROA issues 2401 => ErrorCode::RoaUpdateInvalidDuplicate, @@ -473,6 +477,7 @@ impl Into for ErrorCode { ErrorCode::UnknownChild => 2305, ErrorCode::UnknownParent => 2306, ErrorCode::NoRepositorySet => 2307, + ErrorCode::ParentNoResponse => 2308, // roa errors ErrorCode::RoaUpdateInvalidDuplicate => 2401, @@ -530,7 +535,7 @@ mod tests { test_code(n) } - for n in 2301..2308 { + for n in 2301..2309 { test_code(n) } diff --git a/src/daemon/ca/error.rs b/src/daemon/ca/error.rs index ba32db41f..6eb48a426 100644 --- a/src/daemon/ca/error.rs +++ b/src/daemon/ca/error.rs @@ -110,6 +110,9 @@ pub enum Error { #[display(fmt = "Error getting list query from new repository: {}", _0)] NewRepoUpdateNotResponsive(String), + #[display(fmt = "Error getting entitlements from parent: {}", _0)] + ParentNotResponsive(String), + #[display(fmt = "No repository configured.")] RepoNotSet, diff --git a/src/daemon/ca/server.rs b/src/daemon/ca/server.rs index 1dfa02c58..b3c4692bc 100644 --- a/src/daemon/ca/server.rs +++ b/src/daemon/ca/server.rs @@ -418,7 +418,7 @@ impl CaServer { } /// Adds a parent to a CA - pub fn ca_add_parent(&self, handle: Handle, parent: ParentCaReq) -> ServerResult<()> { + pub fn ca_parent_add(&self, handle: Handle, parent: ParentCaReq) -> ServerResult<()> { let (parent_handle, parent_contact) = parent.unwrap(); let add = CmdDet::add_parent(&handle, parent_handle, parent_contact); @@ -426,7 +426,7 @@ impl CaServer { } /// Updates a parent of a CA - pub fn ca_update_parent( + pub fn ca_parent_update( &self, handle: Handle, parent: ParentHandle, @@ -437,7 +437,7 @@ impl CaServer { } /// Removes a parent from a CA - pub fn ca_remove_parent(&self, handle: Handle, parent: ParentHandle) -> ServerResult<()> { + pub fn ca_parent_remove(&self, handle: Handle, parent: ParentHandle) -> ServerResult<()> { let upd = CmdDet::remove_parent(&handle, parent); self.send_command(upd) } @@ -759,7 +759,25 @@ impl CaServer { handle: &Handle, parent: &ParentHandle, ) -> ServerResult { - match self.get_ca(&handle)?.parent(parent)? { + let ca = self.get_ca(&handle)?; + let contact = ca.parent(parent)?; + self.get_entitlements_from_parent_and_contact(handle, parent, contact) + // match self.get_ca(&handle)?.parent(parent)? { + // ParentCaContact::Ta(_) => { + // Err(ca::Error::NotAllowedForTa).map_err(ServerError::CertAuth) + // } + // ParentCaContact::Embedded => self.get_entitlements_embedded(handle, parent), + // ParentCaContact::Rfc6492(res) => self.get_entitlements_rfc6492(handle, res), + // } + } + + pub fn get_entitlements_from_parent_and_contact( + &self, + handle: &Handle, + parent: &ParentHandle, + contact: &ParentCaContact, + ) -> ServerResult { + match contact { ParentCaContact::Ta(_) => { Err(ca::Error::NotAllowedForTa).map_err(ServerError::CertAuth) } diff --git a/src/daemon/endpoints.rs b/src/daemon/endpoints.rs index 9c4307ed3..ddc0dface 100644 --- a/src/daemon/endpoints.rs +++ b/src/daemon/endpoints.rs @@ -498,7 +498,7 @@ pub fn ca_add_parent( render_empty_res( server .read() - .ca_add_parent(handle.into_inner(), parent.into_inner()), + .ca_parent_add(handle.into_inner(), parent.into_inner()), ) }) } @@ -514,7 +514,7 @@ pub fn ca_update_parent( render_empty_res( server .read() - .ca_update_parent(ca, parent, contact.into_inner()), + .ca_parent_update(ca, parent, contact.into_inner()), ) }) } @@ -526,7 +526,7 @@ pub fn ca_remove_parent( ) -> HttpResponse { let (ca, parent) = ca_and_parent.into_inner(); if_api_allowed(&server, &auth, || { - render_empty_res(server.read().ca_remove_parent(ca, parent)) + render_empty_res(server.read().ca_parent_remove(ca, parent)) }) } @@ -787,6 +787,7 @@ impl ToErrorCode for ca::Error { ca::Error::NewRepoUpdateNoChange => ErrorCode::NewRepoNoChange, ca::Error::NewRepoUpdateNotResponsive(_) => ErrorCode::NewRepoNoResponse, ca::Error::RepoNotSet => ErrorCode::NoRepositorySet, + ca::Error::ParentNotResponsive(_) => ErrorCode::ParentNoResponse, _ => ErrorCode::CaServerError, } } diff --git a/src/daemon/krillserver.rs b/src/daemon/krillserver.rs index cca69b2a3..fc070322f 100644 --- a/src/daemon/krillserver.rs +++ b/src/daemon/krillserver.rs @@ -215,7 +215,7 @@ impl KrillServer { } } -/// # Admin CA as parent +/// # Being a parent /// impl KrillServer { pub fn ta(&self) -> KrillRes { @@ -292,7 +292,60 @@ impl KrillServer { let child = self.caserver.ca_show_child(parent, child)?; Ok(child) } +} + +/// # Being a child +/// +impl KrillServer { + /// Returns the child request for a CA, or NONE if the CA cannot be found. + pub fn ca_child_req(&self, handle: &Handle) -> KrillRes { + self.caserver + .get_ca(handle) + .map(|ca| ca.child_request()) + .map_err(Error::CaServerError) + } + + /// Adds a parent to a CA, will check first if the parent can be reached. + pub fn ca_parent_add(&self, handle: Handle, parent: ParentCaReq) -> EmptyRes { + self.ca_parent_reachable(&handle, parent.handle(), parent.contact())?; + Ok(self.caserver.ca_parent_add(handle, parent)?) + } + + /// Updates a parent contact for a CA + pub fn ca_parent_update( + &self, + handle: Handle, + parent: ParentHandle, + contact: ParentCaContact, + ) -> EmptyRes { + self.ca_parent_reachable(&handle, &parent, &contact)?; + Ok(self.caserver.ca_parent_update(handle, parent, contact)?) + } + + fn ca_parent_reachable( + &self, + handle: &Handle, + parent: &ParentHandle, + contact: &ParentCaContact, + ) -> EmptyRes { + self.caserver + .get_entitlements_from_parent_and_contact(handle, parent, contact) + .map_err(|e| { + Error::CaServerError(ca::ServerError::CertAuth(ca::Error::ParentNotResponsive( + e.to_string(), + ))) + })?; + Ok(()) + } + pub fn ca_parent_remove(&self, handle: Handle, parent: ParentHandle) -> EmptyRes { + Ok(self.caserver.ca_parent_remove(handle, parent)?) + } +} + +/// # Bulk background operations CAS +/// +impl KrillServer { /// Republish all CAs that need it. pub fn republish_all(&self) -> EmptyRes { self.caserver.republish_all()?; @@ -354,14 +407,6 @@ impl KrillServer { self.caserver.get_ca_history(handle).ok() } - /// Returns the child request for a CA, or NONE if the CA cannot be found. - pub fn ca_child_req(&self, handle: &Handle) -> KrillRes { - self.caserver - .get_ca(handle) - .map(|ca| ca.child_request()) - .map_err(Error::CaServerError) - } - /// Returns the publisher request for a CA, or NONE of the CA cannot be found. pub fn ca_publisher_req(&self, handle: &Handle) -> Option { self.caserver @@ -450,23 +495,6 @@ impl KrillServer { Ok(self.caserver.ca_update_id(handle)?) } - pub fn ca_add_parent(&self, handle: Handle, parent: ParentCaReq) -> EmptyRes { - Ok(self.caserver.ca_add_parent(handle, parent)?) - } - - pub fn ca_update_parent( - &self, - handle: Handle, - parent: ParentHandle, - contact: ParentCaContact, - ) -> EmptyRes { - Ok(self.caserver.ca_update_parent(handle, parent, contact)?) - } - - pub fn ca_remove_parent(&self, handle: Handle, parent: ParentHandle) -> EmptyRes { - Ok(self.caserver.ca_remove_parent(handle, parent)?) - } - pub fn ca_keyroll_init(&self, handle: Handle) -> EmptyRes { Ok(self .caserver From 03ae5dab9984f1b38ca4bd3c06c37f3e379d491b Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Wed, 18 Dec 2019 16:11:15 +0100 Subject: [PATCH 13/18] Update openapi spec with new error codes and some hints. --- doc/openapi.yaml | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/doc/openapi.yaml b/doc/openapi.yaml index 77bfa90a3..643fe9363 100644 --- a/doc/openapi.yaml +++ b/doc/openapi.yaml @@ -593,6 +593,9 @@ paths: will be used. In principle CAs can also use this to talk to a local parent CA in the same krill server, but this is inefficient. Therefore it is also possible to add an 'embedded' parent in this case. + + Note that you MUST specify a repository for your CA before you are + allowed to add a parent to it. parameters: - $ref: '#/components/parameters/ca_handle' requestBody: @@ -613,6 +616,7 @@ paths: schema: oneOf: - $ref: '#/components/schemas/ParentWithHandleExists' + - $ref: '#/components/responses/ParentNoResponse' - $ref: '#/components/schemas/NoRepositoryConfiguredYetForCA' '404': $ref: '#/components/responses/UnknownCA' @@ -661,7 +665,13 @@ paths: '200': $ref: '#/components/responses/Success' '400': - $ref: '#/components/responses/UnknownParent' + description: Bad request parameters. + content: + application/json: + schema: + oneOf: + - $ref: '#/components/responses/UnknownParent' + - $ref: '#/components/responses/ParentNoResponse' '403': $ref: '#/components/responses/Forbidden' '404': @@ -725,8 +735,12 @@ paths: - Request new certificates with SIA entries pointing to the new locations. - (best effort) Clean up of the old repository. + The new repository can be embedded, or remote. To use a remote repository, the RFC 8181 Repository Response must be encoded into JSON. + + Note: for most users it's better to use a remote repository, e.g. provided + by your RIR or NIR. parameters: - $ref: '#/components/parameters/ca_handle' requestBody: @@ -1442,6 +1456,18 @@ components: msg: type: string example: Parent with handle exists. + ParentNoResponse: + type: object + required: + - code + - msg + properties: + code: + type: integer + enum: [2308] + msg: + type: string + example: No response from parent. UnknownChild: type: object required: @@ -1606,6 +1632,12 @@ components: application/json: schema: $ref: '#/components/schemas/UnknownParent' + ParentNoResponse: + description: No response from parent. + content: + application/json: + schema: + $ref: '#/components/schemas/ParentNoResponse' GeneralPublicationServerError: description: General Publication Server error. content: From 6be1f000e29bdd0d03fff27a6d740b84c5ffdc15 Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Wed, 18 Dec 2019 16:25:09 +0100 Subject: [PATCH 14/18] Update release numbers for target release 0.4.2 (#165) --- Cargo.toml | 6 +----- src/constants.rs | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 14ec16bd3..aadcddbac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "krill" -version = "0.4.2-pre" +version = "0.4.2" authors = [ "The NLnet Labs RPKI team " ] description = "Resource Public Key Infrastructure (RPKI) daemon" license = "MPL-2.0" @@ -42,7 +42,3 @@ ignore = "^0.4" [features] default = [] extra-debug = [ "rpki/extra-debug" ] - -# Used when depending on development branches of rpki-rs or bcder -#[patch.crates-io] -#rpki = { git = "https://github.com/NLnetLabs/rpki-rs.git", branch = "resource-set-fix" } diff --git a/src/constants.rs b/src/constants.rs index 372c16e51..c84ec92c5 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,4 +1,4 @@ -pub const KRILL_VERSION: &str = "0.4.1"; +pub const KRILL_VERSION: &str = "0.4.2"; pub const KRILL_SERVER_APP: &str = "Krill"; pub const KRILL_CLIENT_APP: &str = "Krill Client"; From 484dfda761cdc3a4150e9faca32bc8c56d119224 Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Wed, 18 Dec 2019 16:38:16 +0100 Subject: [PATCH 15/18] Update changelog for release 0.4.2 (#164) --- Changelog.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 645a52293..640a1cc17 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,7 +1,23 @@ # Change Log Please see [here](https://github.com/NLnetLabs/krill/projects?query=is%3Aopen+sort%3Aname-asc) -for planned releases. +for planned releases. + +## 0.4.2 'Finer Things' + +This release fixes a bug, and introduces minor usability improvements: +* Certain adjacent resources were encoded incorrectly (#161) +* Let users explicitly specify a repository before adding a parent (#160) +* Allow timezone to be set on the Docker container (#156) +* Improve error messaging when failing to start Krill (#155) +* Improve readability or CLI error responses (#162) +* Introduce configurable size limits for data submitted to Krill (#158) + +Note that contrary to previous versions a new CA is set up without a default repository. For most +users we recommend that a remote (RFC 8181) repository is used, e.g. provided by their RIR or NIR. +A repository MUST be configured before a parent can be added to a CA. + + ## 0.4.1 'Fogo de Krill' From 4bf37e22fa0ad4a20d25432c54bd710572dda591 Mon Sep 17 00:00:00 2001 From: Alex Band Date: Wed, 18 Dec 2019 16:50:01 +0100 Subject: [PATCH 16/18] Fix minor typos --- Changelog.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Changelog.md b/Changelog.md index 640a1cc17..df607ee91 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,15 +10,13 @@ This release fixes a bug, and introduces minor usability improvements: * Let users explicitly specify a repository before adding a parent (#160) * Allow timezone to be set on the Docker container (#156) * Improve error messaging when failing to start Krill (#155) -* Improve readability or CLI error responses (#162) +* Improve readability for CLI error responses (#162) * Introduce configurable size limits for data submitted to Krill (#158) Note that contrary to previous versions a new CA is set up without a default repository. For most users we recommend that a remote (RFC 8181) repository is used, e.g. provided by their RIR or NIR. A repository MUST be configured before a parent can be added to a CA. - - ## 0.4.1 'Fogo de Krill' This release fixes two issues: From 90c7fcd42e0e49524fda952bcc4d387ee641f108 Mon Sep 17 00:00:00 2001 From: Ximon Eighteen <3304436+ximon18@users.noreply.github.com> Date: Fri, 20 Dec 2019 22:59:53 +0100 Subject: [PATCH 17/18] FIX: out-dated comment. --- docker/entrypoint.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 0756c9370..e1e742765 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -61,8 +61,7 @@ if [ "$1" == "krill" ]; then # RSYNC and RRDP endpoints to the correct FQDN. We cannot know know the # FQDN which clients use to reach us so the operator must inform this # script via a "-e KRILL_FQDN=some.domain.name" argument to - # "docker run". If KRILL_FQDN is not set assume that the user is - # managing the Krill configuration themselves. + # "docker run". cat << EOF >> ${KRILL_CONF} rsync_base = "rsync://${KRILL_FQDN}/repo/" ${MAGIC} service_uri = "https://${KRILL_FQDN}/" ${MAGIC} @@ -81,4 +80,4 @@ fi # to ensure krill runs as PID 1 as required by Docker for proper signal # handling. This also allows this Docker image to be used to run krill_admin # instead of krill. -exec "$@" \ No newline at end of file +exec "$@" From 8d85dbaa49b71043a8be220932527504f757c414 Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Mon, 6 Jan 2020 13:28:31 +0100 Subject: [PATCH 18/18] Update to rpki-rs 0.8.3. (closes #166) --- Cargo.toml | 2 +- Changelog.md | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index aadcddbac..aebd32b52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ openssl = { version = "^0.10", features = ["v110"] } pretty = "0.5.2" rand = "^0.5" reqwest = "^0.9.17" -rpki = { version = "0.8.3-pre", git = "https://github.com/NLnetLabs/rpki-rs.git", branch = "chain-from-iter-fix" } +rpki = "0.8.3" serde = { version = "^1.0", features = ["derive"] } serde_json = "^1.0" syslog = "^4.0" diff --git a/Changelog.md b/Changelog.md index df607ee91..b04f1b1f5 100644 --- a/Changelog.md +++ b/Changelog.md @@ -96,7 +96,6 @@ Known issues: Work for the next release has already started. [Release 0.3](https://github.com/NLnetLabs/krill/projects/6) will focus on (remote) publication, and will also solve the out-of-sync issue. - ## 0.1.0 'A View to a Krill' This is the first version of Krill that we are testing in the real world. Please note that the