Let user specify a repository before adding a parent #160

This commit is contained in:
Tim Bruijnzeels
2019-12-17 16:56:19 +01:00
parent 07069dac5b
commit 593bf7a35d
18 changed files with 312 additions and 212 deletions
+12 -7
View File
@@ -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");
+11 -7
View File
@@ -1473,7 +1473,7 @@ impl fmt::Display for ParentInfo {
pub struct CertAuthInfo {
handle: Handle,
id_cert: IdCertPem,
repo_info: RepoInfo,
repo_info: Option<RepoInfo>,
parents: Vec<ParentInfo>,
resources: ResourceSet,
resource_classes: HashMap<ResourceClassName, ResourceClassInfo>,
@@ -1484,7 +1484,7 @@ impl CertAuthInfo {
pub fn new(
handle: Handle,
id_cert: IdCertPem,
repo_info: RepoInfo,
repo_info: Option<RepoInfo>,
parents: HashMap<ParentHandle, ParentCaContact>,
resource_classes: HashMap<ResourceClassName, ResourceClassInfo>,
children: Vec<ChildHandle>,
@@ -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<ParentInfo> {
@@ -1543,10 +1543,14 @@ impl CertAuthInfo {
pub fn published_objects(&self) -> Vec<Publish> {
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
}
}
+6 -1
View File
@@ -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<usize> 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<ErrorResponse> 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)
}
+147 -43
View File
@@ -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<S: Signer> {
id: Rfc8183Id, // Used for RFC 6492 (up-down) and RFC 8181 (publication)
repository: RepositoryContact,
repository: Option<RepositoryContact>,
repository_pending_withdraw: Option<RepositoryContact>,
parents: HashMap<ParentHandle, ParentCaContact>,
@@ -94,12 +96,13 @@ impl<S: Signer> Aggregate for CertAuth<S> {
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<S: Signer> Aggregate for CertAuth<S> {
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<S: Signer> Aggregate for CertAuth<S> {
id,
repository: pubserver,
repository,
repository_pending_withdraw: None,
parents,
@@ -141,6 +143,19 @@ impl<S: Signer> Aggregate for CertAuth<S> {
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<S: Signer> Aggregate for CertAuth<S> {
}
}
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<S: Signer> Aggregate for CertAuth<S> {
);
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<S: Signer> Aggregate for CertAuth<S> {
impl<S: Signer> CertAuth<S> {
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<S: Signer> CertAuth<S> {
impl<S: Signer> CertAuth<S> {
pub fn all_objects(&self) -> Vec<PublishElement> {
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<S: Signer> CertAuth<S> {
}
}
/// # Being a trustanchor
///
impl<S: Signer> CertAuth<S> {
fn trust_anchor_make(
&self,
uris: Vec<uri::Https>,
signer: Arc<RwLock<S>>,
) -> ca::Result<Vec<Evt>> {
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<S: Signer> CertAuth<S> {
@@ -656,15 +753,12 @@ impl<S: Signer> CertAuth<S> {
removed_certs: &[&Cert],
signer: &S,
) -> Result<HashMap<KeyIdentifier, CurrentObjectSetDelta>> {
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<S: Signer> CertAuth<S> {
/// 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<Vec<Evt>> {
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<S: Signer> CertAuth<S> {
/// Removes a parent. Returns an error if it doesn't exist.
fn remove_parent(&self, parent: Handle) -> ca::Result<Vec<Evt>> {
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<S: Signer> CertAuth<S> {
.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<S: Signer> CertAuth<S> {
rc: &ResourceClass,
signer: &S,
) -> Result<Vec<Evt>> {
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<S: Signer> CertAuth<S> {
}) {
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<S: Signer> CertAuth<S> {
.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<S: Signer> CertAuth<S> {
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<S: Signer> CertAuth<S> {
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<S: Signer> CertAuth<S> {
.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<S: Signer> CertAuth<S> {
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<S: Signer> CertAuth<S> {
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<S: Signer> CertAuth<S> {
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<S: Signer> CertAuth<S> {
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<S: Signer> CertAuth<S> {
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;
+21
View File
@@ -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<S> = eventsourcing::SentCommand<CmdDet<S>>;
#[derive(Clone, Debug)]
#[allow(clippy::large_enum_variant)]
pub enum CmdDet<S: Signer> {
// ------------------------------------------------------------
// Being a TA
// ------------------------------------------------------------
MakeTrustAnchor(Vec<uri::Https>, Arc<RwLock<S>>),
// ------------------------------------------------------------
// Being a parent
// ------------------------------------------------------------
@@ -108,6 +115,11 @@ pub enum CmdDet<S: Signer> {
impl<S: Signer> fmt::Display for CmdDet<S> {
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<S: Signer> eventsourcing::CommandDetails for CmdDet<S> {
}
impl<S: Signer> CmdDet<S> {
/// Turns this CA into a TrustAnchor
pub fn make_trust_anchor(
handle: &Handle,
uris: Vec<uri::Https>,
signer: Arc<RwLock<S>>,
) -> Cmd<S> {
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(
+7
View File
@@ -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 {}
+28 -96
View File
@@ -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<IniDet>;
#[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<RepoInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
ta_details: Option<TaCertDetails>,
}
impl IniDet {
pub fn unwrap(self) -> (Rfc8183Id, RepoInfo, Option<TaCertDetails>) {
pub fn unwrap(self) -> (Rfc8183Id, Option<RepoInfo>, Option<TaCertDetails>) {
(self.id, self.info, self.ta_details)
}
}
impl IniDet {
pub fn init<S: Signer>(handle: &Handle, info: RepoInfo, signer: Arc<RwLock<S>>) -> Result<Ini> {
pub fn init<S: Signer>(handle: &Handle, signer: Arc<RwLock<S>>) -> Result<Ini> {
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<S: Signer>(
handle: &Handle,
info: RepoInfo,
ta_uris: Vec<uri::Https>,
signer: Arc<RwLock<S>>,
) -> Result<Ini> {
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<S: Signer>(
repo_info: &RepoInfo,
resources: &ResourceSet,
key: &S::KeyId,
signer: &S,
) -> Result<Cert> {
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<EvtDet>;
#[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!(
+17 -8
View File
@@ -75,21 +75,30 @@ impl<S: Signer> CaServer<S> {
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)?;
let ta = 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)?;
// 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<S: Signer> CaServer<S> {
)
}
/// 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(())
}
+1
View File
@@ -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,
}
}
+32 -32
View File
@@ -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<rfc8183::RepositoryResponse> {
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<CaRepoDetails> {
pub fn ca_repo_details(&self, handle: &Handle) -> KrillRes<Option<CaRepoDetails>> {
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<CurrentRepoState> {
pub fn ca_repo_state(&self, handle: &Handle) -> KrillRes<Option<CurrentRepoState>> {
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();
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)?)
// Add publisher
let req = rfc8183::PublisherRequest::new(None, handle.clone(), id_cert);
self.add_publisher(req)?;
}
RepositoryUpdate::Rfc8181(res) => RepositoryContact::Rfc8181(res),
};
Ok(self.caserver.update_repo(handle, contact)?)
}
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),
)));
}
RepositoryContact::Rfc8181(response)
}
};
Ok(self.caserver.update_repo(handle, contact)?)
}
fn repo_state(
+9 -4
View File
@@ -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) {
+9 -2
View File
@@ -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)?
+1 -1
View File
@@ -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 = {
+4 -4
View File
@@ -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());
+1 -1
View File
@@ -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 --------------------------------------------------------------------
+1 -1
View File
@@ -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 = {
+1 -1
View File
@@ -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 ----------------------------------------------------------------
{
+4 -4
View File
@@ -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 = {