Support (great-) grandchildren under multiple lineages. Closes: #25

This commit is contained in:
Tim Bruijnzeels
2019-08-20 14:01:48 +02:00
parent fc98944d66
commit 86ea370e8f
17 changed files with 675 additions and 242 deletions
+29 -13
View File
@@ -1,6 +1,6 @@
use rpki::uri;
use std::io;
use rpki::uri;
use serde::de::DeserializeOwned;
use krill_commons::api::admin::{
@@ -81,7 +81,7 @@ impl KrillClient {
let uri = self.resolve_uri("api/v1/trustanchor/children");
let info: ParentCaContact =
httpclient::post_json_with_response(&uri, req, Some(&self.token))?;
Ok(ApiResponse::ParentCaInfo(info))
Ok(ApiResponse::ParentCaContact(info))
}
TrustAnchorCommand::UpdateChild(child, req) => {
let uri = format!("api/v1/trustanchor/children/{}", child);
@@ -94,10 +94,9 @@ impl KrillClient {
fn certauth(&self, command: CaCommand) -> Result<ApiResponse, Error> {
match command {
CaCommand::AddParent(handle, parent) => {
let uri = format!("api/v1/cas/{}/parents", handle);
let uri = self.resolve_uri(&uri);
httpclient::post_json(&uri, parent, Some(&self.token))?;
CaCommand::Init(init) => {
let uri = self.resolve_uri("api/v1/cas");
httpclient::post_json(&uri, init, Some(&self.token))?;
Ok(ApiResponse::Empty)
}
CaCommand::ChildRequest(handle) => {
@@ -108,16 +107,28 @@ impl KrillClient {
let req = rfc8183::ChildRequest::validate(xml.as_bytes())?;
Ok(ApiResponse::Rfc8183ChildRequest(req))
}
CaCommand::Init(init) => {
let uri = self.resolve_uri("api/v1/cas");
httpclient::post_json(&uri, init, Some(&self.token))?;
CaCommand::AddParent(handle, parent) => {
let uri = format!("api/v1/cas/{}/parents", handle);
let uri = self.resolve_uri(&uri);
httpclient::post_json(&uri, parent, Some(&self.token))?;
Ok(ApiResponse::Empty)
}
CaCommand::List => {
let uri = self.resolve_uri("api/v1/cas");
let cas = self.get_json(&uri)?;
Ok(ApiResponse::CertAuths(cas))
CaCommand::AddChild(handle, req) => {
let uri = format!("api/v1/cas/{}/children", handle);
let uri = self.resolve_uri(&uri);
let info: ParentCaContact =
httpclient::post_json_with_response(&uri, req, Some(&self.token))?;
Ok(ApiResponse::ParentCaContact(info))
}
CaCommand::UpdateChild(handle, child, req) => {
let uri = format!("api/v1/cas/{}/children/{}", handle, child);
let uri = self.resolve_uri(&uri);
httpclient::post_json(&uri, req, Some(&self.token))?;
Ok(ApiResponse::Empty)
}
CaCommand::KeyRollInit(handle) => {
let uri = format!("api/v1/cas/{}/keys/roll_init", handle);
let uri = self.resolve_uri(&uri);
@@ -137,6 +148,11 @@ impl KrillClient {
Ok(ApiResponse::CertAuthInfo(ca_info))
}
CaCommand::List => {
let uri = self.resolve_uri("api/v1/cas");
let cas = self.get_json(&uri)?;
Ok(ApiResponse::CertAuths(cas))
}
}
}
+205 -4
View File
@@ -285,8 +285,119 @@ impl Options {
)
)
.subcommand(SubCommand::with_name("children")
.about("Manage children of this CA")
.arg(Arg::with_name("handle")
.short("h")
.long("handle")
.value_name("ca handle")
.help("The handle (name) for the CA")
.required(true)
)
.subcommand(SubCommand::with_name("add")
.about("Add a child to the embedded CA")
.arg(Arg::with_name("asn")
.short("a")
.long("asn")
.value_name("AS resources")
.help("The delegated AS resources: e.g. AS1, AS3-4")
.required(false)
)
.arg(Arg::with_name("ipv4")
.short("4")
.long("ipv4")
.value_name("IPv4 resources")
.help("The delegated IPv4 resources: e.g. 192.168.0.0/16")
.required(false)
)
.arg(Arg::with_name("ipv6")
.short("6")
.long("ipv6")
.value_name("IPv6 resources")
.help("The delegated IPv6 resources: e.g. 2001:db8::/32")
.required(false)
)
.subcommand(SubCommand::with_name("embedded")
.about("Add an embedded child")
.arg(Arg::with_name("handle")
.short("h")
.long("handle")
.value_name("child-handle")
.help("The handle of the child")
.required(true)
)
)
.subcommand(SubCommand::with_name("rfc6492")
.about("Add an RFC 6492 child")
.arg(Arg::with_name("handle")
.short("h")
.long("handle")
.value_name("child-handle")
.help("Override the handle in the XML")
.required(false)
)
.arg(Arg::with_name("xml")
.short("x")
.long("xml")
.value_name("FILE")
.help("RFC 8183 Child Request XML")
.required(true)
)
)
)
.subcommand(SubCommand::with_name("update")
.about("Update details for a child")
.arg(Arg::with_name("handle")
.short("h")
.long("handle")
.value_name("child-handle")
.help("Override the handle in the XML")
.required(false)
)
.arg(Arg::with_name("xml")
.short("x")
.long("xml")
.value_name("FILE")
.help("Update child certificate from RFC 8183 Child Request XML")
.required(false)
)
.arg(Arg::with_name("asn")
.short("a")
.long("asn")
.value_name("AS resources")
.help("Update the delegated AS resources: e.g. AS1, AS3-4")
.required(false)
)
.arg(Arg::with_name("ipv4")
.short("4")
.long("ipv4")
.value_name("IPv4 resources")
.help("Update the delegated IPv4 resources: e.g. 192.168.0.0/16")
.required(false)
)
.arg(Arg::with_name("ipv6")
.short("6")
.long("ipv6")
.value_name("IPv6 resources")
.help("Update the delegated IPv6 resources: e.g. 2001:db8::/32")
.required(false)
)
.arg(Arg::with_name("force")
.short("f")
.long("force")
.takes_value(false)
.help("Force resource shrink now.")
.required(false)
)
)
)
)
.subcommand(SubCommand::with_name("publishers")
@@ -486,6 +597,79 @@ impl Options {
let handle = Handle::from(m.value_of("handle").unwrap());
command = Command::CertAuth(CaCommand::Show(handle));
}
if let Some(m) = m.subcommand_matches("children") {
let ca = Handle::from(m.value_of("handle").unwrap());
if let Some(m) = m.subcommand_matches("add") {
let asn = m.value_of("asn").unwrap_or("");
let ipv4 = m.value_of("ipv4").unwrap_or("");
let ipv6 = m.value_of("ipv6").unwrap_or("");
if let Some(m) = m.subcommand_matches("embedded") {
let handle = Handle::from(m.value_of("handle").unwrap());
let res = ResourceSet::from_strs(asn, ipv4, ipv6).unwrap();
let auth = ChildAuthRequest::Embedded;
let req = AddChildRequest::new(handle, res, auth);
command = Command::TrustAnchor(TrustAnchorCommand::AddChild(req))
}
if let Some(m) = m.subcommand_matches("rfc6492") {
let xml_path = m.value_of("xml").unwrap();
let xml = PathBuf::from(xml_path);
let bytes = file::read(&xml)?;
let cr = rfc8183::ChildRequest::validate(bytes.as_ref())?;
let handle = {
if let Some(handle) = m.value_of("handle") {
Handle::from(handle)
} else {
cr.child_handle().clone()
}
};
let res = ResourceSet::from_strs(asn, ipv4, ipv6)?;
let auth = ChildAuthRequest::Rfc8183(cr);
let req = AddChildRequest::new(handle, res, auth);
command = Command::CertAuth(CaCommand::AddChild(ca, req))
}
} else if let Some(m) = m.subcommand_matches("update") {
let handle = Handle::from(m.value_of("handle").unwrap());
let cert = match m.value_of("xml") {
Some(xml_path) => {
let xml = PathBuf::from(xml_path);
let bytes = file::read(&xml)?;
let cr = rfc8183::ChildRequest::validate(bytes.as_ref())?;
let (_, _, cert) = cr.unwrap();
Some(cert)
}
None => None,
};
let asn = m.value_of("asn").unwrap_or("");
let ipv4 = m.value_of("ipv4").unwrap_or("");
let ipv6 = m.value_of("ipv6").unwrap_or("");
let resources = ResourceSet::from_strs(asn, ipv4, ipv6)?;
let resources = if resources.is_empty() {
None
} else {
Some(resources)
};
let req = if m.is_present("force") {
UpdateChildRequest::force(cert, resources)
} else {
UpdateChildRequest::graceful(cert, resources)
};
command = Command::CertAuth(CaCommand::UpdateChild(ca, handle, req))
}
}
if let Some(m) = m.subcommand_matches("update") {
let handle = Handle::from(m.value_of("handle").unwrap());
@@ -598,13 +782,30 @@ pub enum TrustAnchorCommand {
#[derive(Clone, Debug, Eq, PartialEq)]
#[allow(clippy::large_enum_variant)]
pub enum CaCommand {
AddParent(Handle, AddParentRequest),
ChildRequest(Handle),
// Initialise a CA
Init(CertAuthInit),
// Get the RFC8183 child request
ChildRequest(Handle),
// Add a parent to this CA
AddParent(Handle, AddParentRequest),
// Add a child to this CA
AddChild(Handle, AddChildRequest),
UpdateChild(Handle, Handle, UpdateChildRequest),
// Initialise a manual key-roll now
KeyRollInit(Handle),
// Activate all new keys now (finish keyroll, provided new key was certified)
KeyRollActivate(Handle),
List,
// Show details for this CA
Show(Handle),
// List all CAs
List,
}
#[derive(Clone, Debug, Eq, PartialEq)]
+2 -2
View File
@@ -19,7 +19,7 @@ pub enum ApiResponse {
CertAuthInfo(CertAuthInfo),
CertAuths(CertAuthList),
ParentCaInfo(ParentCaContact),
ParentCaContact(ParentCaContact),
PublisherDetails(PublisherDetails),
PublisherList(PublisherList),
@@ -48,7 +48,7 @@ impl ApiResponse {
ApiResponse::TrustAnchorInfo(ta) => Ok(Some(ta.report(fmt)?)),
ApiResponse::CertAuths(list) => Ok(Some(list.report(fmt)?)),
ApiResponse::CertAuthInfo(info) => Ok(Some(info.report(fmt)?)),
ApiResponse::ParentCaInfo(info) => Ok(Some(info.report(fmt)?)),
ApiResponse::ParentCaContact(contact) => Ok(Some(contact.report(fmt)?)),
ApiResponse::PublisherList(list) => Ok(Some(list.report(fmt)?)),
ApiResponse::PublisherDetails(details) => Ok(Some(details.report(fmt)?)),
ApiResponse::Rfc8181ClientList(list) => Ok(Some(list.report(fmt)?)),
+1 -1
View File
@@ -327,7 +327,7 @@ impl AddParentRequest {
#[derive(Clone, Debug, Deserialize, Display, Eq, PartialEq, Serialize)]
#[allow(clippy::large_enum_variant)]
pub enum ParentCaContact {
#[display(fmt = "In this context this CA is a self-signed TA")]
#[display(fmt = "This CA is a TA with TAL:\n{}", _0)]
Ta(TrustAnchorLocator),
#[display(fmt = "Embedded parent")]
+36 -28
View File
@@ -251,7 +251,7 @@ impl<S: Signer> Aggregate for CertAuth<S> {
// Key rolls
CmdDet::KeyRollInitiate(duration, signer) => self.keyroll_initiate(duration, signer),
CmdDet::KeyRollActivate(duration, signer) => self.keyroll_activate(duration, signer),
CmdDet::KeyRollFinish(parent, response) => self.keyroll_finish(&parent, response),
CmdDet::KeyRollFinish(rcn, response) => self.keyroll_finish(rcn, response),
// Republish
CmdDet::Republish(signer) => self.republish(signer),
@@ -351,13 +351,13 @@ impl<S: Signer> CertAuth<S> {
/// List entitlements (section 3.3.2 of RFC6492). Return an error if
/// the child is not authorized -- or unknown etc.
///
/// Only supported in TAs until issue #25 is implemented.
pub fn list(&self, child_handle: &Handle) -> Result<api::Entitlements> {
// TODO: Support arbitrary resource classes. See issue #25.
let mut classes = vec![];
if let Some(class) = self.entitlement_class(child_handle, &ResourceClassName::default()) {
classes.push(class);
for rcn in self.resources.keys() {
if let Some(class) = self.entitlement_class(child_handle, rcn) {
classes.push(class);
}
}
Ok(Entitlements::new(classes))
@@ -498,8 +498,6 @@ impl<S: Signer> CertAuth<S> {
/// = the csr is invalid,
/// = the limit exceeds the child allocation,
/// = the signer throws up..
///
/// This CA is not a TA (until #25)
fn certify_child(
&self,
child: Handle,
@@ -1018,12 +1016,15 @@ impl<S: Signer> CertAuth<S> {
/// Get all the current open certificate requests for a parent.
/// Returns an empty list if the parent is not found.
pub fn cert_requests(&self, parent_handle: &ParentHandle) -> Vec<IssuanceRequest> {
let mut res = vec![];
pub fn cert_requests(
&self,
parent_handle: &ParentHandle,
) -> HashMap<ResourceClassName, Vec<IssuanceRequest>> {
let mut res = HashMap::new();
for rc in self.resources.values() {
for (name, rc) in self.resources.iter() {
if rc.parent_handle() == parent_handle {
res.append(&mut rc.cert_requests())
res.insert(name.clone(), rc.cert_requests());
}
}
@@ -1049,14 +1050,19 @@ impl<S: Signer> CertAuth<S> {
}
/// Returns the open revocation requests for the given parent.
pub fn revoke_requests(&self, parent: &ParentHandle) -> Vec<&RevocationRequest> {
let mut res = vec![];
for rc in self.resources.values() {
pub fn revoke_requests(
&self,
parent: &ParentHandle,
) -> HashMap<ResourceClassName, Vec<RevocationRequest>> {
let mut res = HashMap::new();
for (name, rc) in self.resources.iter() {
let mut revokes = vec![];
if let Some(req) = rc.revoke_request() {
if rc.parent_handle() == parent {
res.push(req)
revokes.push(req.clone())
}
}
res.insert(name.clone(), revokes);
}
res
}
@@ -1089,10 +1095,13 @@ impl<S: Signer> CertAuth<S> {
.iter()
.map(|c| c.class_name())
.collect();
for (name, class) in current_resource_classes
.iter()
.filter(|(name, _class)| !entitled_classes.contains(name))
{
for (name, class) in current_resource_classes.iter().filter(|(_name, class)| {
// Find the classes for this parent, not included
// in the entitlements now received.
class.parent_handle() == &parent_handle
&& !entitled_classes.contains(&class.parent_rc_name())
}) {
let signer = signer.read().unwrap();
let delta = class.withdraw(&self.base_repo);
@@ -1261,19 +1270,18 @@ impl<S: Signer> CertAuth<S> {
fn keyroll_finish(
&self,
parent_h: &ParentHandle,
response: RevocationResponse,
rcn: ResourceClassName,
_response: RevocationResponse,
) -> ca::Result<Vec<Evt>> {
if self.is_ta() {
return Ok(vec![]);
}
let (parent_rc_name, _key_id) = response.unpack();
let my_rc = self
.resources
.get(&rcn)
.ok_or_else(|| Error::unknown_resource_class(&rcn))?;
let (my_name, my_rc) = self
.find_parent_rc(parent_h, &parent_rc_name)
.ok_or_else(|| Error::unknown_resource_class(&parent_rc_name))?;
let finish_details = my_rc.keyroll_finish(my_name.clone(), &self.base_repo)?;
let finish_details = my_rc.keyroll_finish(rcn, &self.base_repo)?;
Ok(vec![StoredEvent::new(
self.handle(),
+4 -5
View File
@@ -67,7 +67,7 @@ pub enum CmdDet<S: Signer> {
// Finish the keyroll after the parent confirmed that a key for a parent and resource
// class has been revoked. I.e. remove the old key, and withdraw the crl and mft for it.
KeyRollFinish(ParentHandle, RevocationResponse),
KeyRollFinish(ResourceClassName, RevocationResponse),
// ------------------------------------------------------------
// Publishing
@@ -81,8 +81,7 @@ impl<S: Signer> eventsourcing::CommandDetails for CmdDet<S> {
impl<S: Signer> CmdDet<S> {
/// Adds a child to this CA. Will return an error in case you try
/// to give the child resources not held by the CA. And until issue
/// #25 is implemented, returns an error when the CA is not a TA.
/// to give the child resources not held by the CA.
pub fn child_add(
handle: &Handle,
child_handle: Handle,
@@ -190,10 +189,10 @@ impl<S: Signer> CmdDet<S> {
pub fn key_roll_finish(
handle: &Handle,
parent: ParentHandle,
rcn: ResourceClassName,
res: RevocationResponse,
) -> Cmd<S> {
eventsourcing::SentCommand::new(handle, None, CmdDet::KeyRollFinish(parent, res))
eventsourcing::SentCommand::new(handle, None, CmdDet::KeyRollFinish(rcn, res))
}
pub fn publish(handle: &Handle, signer: Arc<RwLock<S>>) -> Cmd<S> {
+164 -146
View File
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::ops::Deref;
use std::path::PathBuf;
use std::sync::{Arc, RwLock};
@@ -110,41 +111,41 @@ impl<S: Signer> CaServer<S> {
Ok(())
}
/// Adds a child under the embedded TA
pub fn ta_add_child(
/// Adds a child under an embedded CA
pub fn ca_add_child(
&self,
parent: &ParentHandle,
req: AddChildRequest,
service_uri: &uri::Https,
) -> ServerResult<ParentCaContact, S> {
let (handle, resources, auth) = req.unwrap();
let (child_handle, child_res, child_auth) = req.unwrap();
debug!("Adding child {} to TA", &handle);
info!("Adding child {} to CA {}", &child_handle, &parent);
let ta = self.get_trust_anchor()?;
let ta_handle = ca::ta_handle();
let ca = self.get_ca(parent)?;
let id_cert = match &auth {
let id_cert = match &child_auth {
ChildAuthRequest::Embedded => None,
ChildAuthRequest::Rfc8183(req) => Some(req.id_cert().clone()),
};
let add_child = CmdDet::child_add(&ta_handle, handle.clone(), id_cert, resources);
let add_child = CmdDet::child_add(&parent, child_handle.clone(), id_cert, child_res);
let events = ta.process_command(add_child)?;
let ta = self.ca_store.update(&ta_handle, ta, events)?;
let events = ca.process_command(add_child)?;
let ca = self.ca_store.update(&parent, ca, events)?;
match auth {
match child_auth {
ChildAuthRequest::Embedded => Ok(ParentCaContact::Embedded),
ChildAuthRequest::Rfc8183(req) => {
let service_uri = format!("{}rfc6492/{}", service_uri.to_string(), ta.handle());
let service_uri = format!("{}rfc6492/{}", service_uri.to_string(), ca.handle());
let service_uri = uri::Https::from_string(service_uri).unwrap();
let service_uri = rfc8183::ServiceUri::Https(service_uri);
let response = rfc8183::ParentResponse::new(
req.tag().cloned(),
ta.id_cert().clone(),
ta.handle().clone(),
handle,
ca.id_cert().clone(),
ca.handle().clone(),
child_handle,
service_uri,
);
Ok(ParentCaContact::for_rfc6492(response))
@@ -154,11 +155,15 @@ impl<S: Signer> CaServer<S> {
/// Show details for a child under the TA. Returns Ok(None) if the TA is present,
/// but the child is not known.
pub fn ta_show_child(&self, child: &ChildHandle) -> ServerResult<Option<ChildCaInfo>, S> {
debug!("Finding details for {} under TA", child);
pub fn ca_show_child(
&self,
parent: &ParentHandle,
child: &ChildHandle,
) -> ServerResult<Option<ChildCaInfo>, S> {
debug!("Finding details for CA: {} under parent: {}", child, parent);
let ta = self.get_trust_anchor()?;
let child_opt = match ta.get_child(child) {
let ca = self.get_ca(parent)?;
let child_opt = match ca.get_child(child) {
Err(_) => None,
Ok(child_details) => Some(child_details.clone().into()),
};
@@ -166,30 +171,34 @@ impl<S: Signer> CaServer<S> {
Ok(child_opt)
}
pub fn ta_update_child(
/// Update a child under this CA.
pub fn ca_update_child(
&self,
parent: &ParentHandle,
child: ChildHandle,
req: UpdateChildRequest,
) -> ServerResult<(), S> {
debug!("Updating details for {} under TA", child);
let mut ta = self.get_trust_anchor()?;
let ta_handle = ca::ta_handle();
debug!(
"Updating details for CA: {} under parent: {}",
child, parent
);
let mut ca = self.get_ca(parent)?;
let force = req.is_force();
let events = ta.process_command(CmdDet::child_update(&ta_handle, child.clone(), req))?;
let events = ca.process_command(CmdDet::child_update(parent, child.clone(), req))?;
if !events.is_empty() {
ta = self.ca_store.update(&ta_handle, ta, events)?;
ca = self.ca_store.update(parent, ca, events)?;
if force {
let events = ta.process_command(CmdDet::child_shrink(
&ta_handle,
let events = ca.process_command(CmdDet::child_shrink(
parent,
child,
Duration::seconds(0),
self.signer.clone(),
))?;
if !events.is_empty() {
self.ca_store.update(&ta_handle, ta, events)?;
self.ca_store.update(parent, ca, events)?;
}
}
}
@@ -250,22 +259,15 @@ impl<S: Signer> CaServer<S> {
msg: rfc6492::Message,
) -> ServerResult<Bytes, S> {
debug!("RFC6492 Response wrapping for {}", handle);
let ca = self.ca_store.get_latest(handle)?;
let res = ca
self.get_ca(handle)?
.sign_rfc6492_response(msg, self.signer.read().unwrap().deref())
.map_err(ServerError::<S>::CertAuth);
debug!("RFC6492 Response wrapped for {}", handle);
res
.map_err(ServerError::<S>::CertAuth)
}
/// List the entitlements for a child: 3.3.2 of RFC6492
pub fn list(&self, parent: &Handle, child: &Handle) -> ServerResult<Entitlements, S> {
if parent != &ca::ta_handle() {
unimplemented!("https://github.com/NLnetLabs/krill/issues/25");
} else {
let ta = self.get_trust_anchor()?;
Ok(ta.list(child)?)
}
let ca = self.get_ca(parent)?;
Ok(ca.list(child)?)
}
/// Issue a Certificate in response to a Certificate Issuance request
@@ -277,34 +279,25 @@ impl<S: Signer> CaServer<S> {
child: &ChildHandle,
issue_req: IssuanceRequest,
) -> ServerResult<IssuanceResponse, S> {
if parent != &ca::ta_handle() {
unimplemented!("https://github.com/NLnetLabs/krill/issues/25");
} else {
let ta = self.get_trust_anchor()?;
let ca = self.get_ca(parent)?;
let class_name = issue_req.class_name();
let pub_key = issue_req.csr().public_key();
let class_name = issue_req.class_name();
let pub_key = issue_req.csr().public_key();
if class_name != &ResourceClassName::default() {
unimplemented!("Issue for multiple classes from CAs, issue #25")
}
let cmd = CmdDet::child_certify(
parent,
child.clone(),
issue_req.clone(),
self.signer.clone(),
);
let cmd = CmdDet::child_certify(
parent,
child.clone(),
issue_req.clone(),
self.signer.clone(),
);
let events = ca.process_command(cmd)?;
let ca = self.ca_store.update(parent, ca, events)?;
let events = ta.process_command(cmd)?;
let ta = self.ca_store.update(parent, ta, events)?;
// The updated CA will now include the newly issued certificate.
let response = ca.issuance_response(child, &class_name, &pub_key)?;
// New entitlements will include this resource class, and
// the newly issued certificate.
let response = ta.issuance_response(child, &class_name, &pub_key)?;
Ok(response)
}
Ok(response)
}
/// See: https://tools.ietf.org/html/rfc6492#section3.5.1-2
@@ -480,10 +473,12 @@ impl<S: Signer> CaServer<S> {
let revoke_responses = self.send_revoke_requests(handle, parent, requests)?;
for response in revoke_responses.into_iter() {
let cmd = CmdDet::key_roll_finish(handle, parent.clone(), response);
let events = child.process_command(cmd)?;
child = self.ca_store.update(handle, child, events)?;
for (rcn, revoke_responses) in revoke_responses.into_iter() {
for response in revoke_responses.into_iter() {
let cmd = CmdDet::key_roll_finish(handle, rcn.clone(), response);
let events = child.process_command(cmd)?;
child = self.ca_store.update(handle, child, events)?;
}
}
Ok(())
@@ -493,77 +488,82 @@ impl<S: Signer> CaServer<S> {
&self,
handle: &Handle,
parent: &ParentHandle,
requests: Vec<&RevocationRequest>,
) -> ServerResult<Vec<RevocationResponse>, S> {
revoke_requests: HashMap<ResourceClassName, Vec<RevocationRequest>>,
) -> ServerResult<HashMap<ResourceClassName, Vec<RevocationResponse>>, S> {
let child = self.ca_store.get_latest(handle)?;
match child.parent(parent)? {
ParentCaContact::Ta(_) => {
Err(ca::Error::NotAllowedForTa).map_err(ServerError::CertAuth)
}
ParentCaContact::Embedded => {
self.send_revoke_requests_embedded(requests, handle, parent)
self.send_revoke_requests_embedded(revoke_requests, handle, parent)
}
ParentCaContact::Rfc6492(parent_res) => {
self.send_revoke_requests_rfc6492(requests, child.id_key(), parent_res)
self.send_revoke_requests_rfc6492(revoke_requests, child.id_key(), parent_res)
}
}
}
fn send_revoke_requests_embedded(
&self,
revoke_requests: Vec<&RevocationRequest>,
revoke_requests: HashMap<ResourceClassName, Vec<RevocationRequest>>,
handle: &Handle,
parent_h: &ParentHandle,
) -> ServerResult<Vec<RevocationResponse>, S> {
) -> ServerResult<HashMap<ResourceClassName, Vec<RevocationResponse>>, S> {
let mut parent = self.ca_store.get_latest(parent_h)?;
let mut revocation_responses = vec![];
let mut revoke_map = HashMap::new();
for req in revoke_requests.into_iter() {
let cmd = CmdDet::child_revoke_key(
parent_h,
handle.clone(),
req.clone(),
self.signer.clone(),
);
for (rcn, revoke_requests) in revoke_requests.into_iter() {
let mut revocations = vec![];
for req in revoke_requests.into_iter() {
revocations.push((&req).into());
let events = parent.process_command(cmd)?;
parent = self.ca_store.update(parent_h, parent, events)?;
let cmd =
CmdDet::child_revoke_key(parent_h, handle.clone(), req, self.signer.clone());
revocation_responses.push(req.into());
let events = parent.process_command(cmd)?;
parent = self.ca_store.update(parent_h, parent, events)?;
}
revoke_map.insert(rcn, revocations);
}
Ok(revocation_responses)
Ok(revoke_map)
}
fn send_revoke_requests_rfc6492(
&self,
revoke_requests: Vec<&RevocationRequest>,
revoke_requests: HashMap<ResourceClassName, Vec<RevocationRequest>>,
signing_key: &KeyId,
parent_res: &rfc8183::ParentResponse,
) -> ServerResult<Vec<RevocationResponse>, S> {
let mut res = vec![];
) -> ServerResult<HashMap<ResourceClassName, Vec<RevocationResponse>>, S> {
let mut revoke_map = HashMap::new();
for req in revoke_requests.into_iter() {
let sender = parent_res.child_handle().to_string();
let recipient = parent_res.parent_handle().to_string();
let revoke = rfc6492::Message::revoke(sender, recipient, req.clone());
for (rcn, revoke_requests) in revoke_requests.into_iter() {
let mut revocations = vec![];
for req in revoke_requests.into_iter() {
let sender = parent_res.child_handle().to_string();
let recipient = parent_res.parent_handle().to_string();
let revoke = rfc6492::Message::revoke(sender, recipient, req.clone());
match self.send_rfc6492_and_validate_response(
signing_key,
parent_res,
revoke.into_bytes(),
) {
Err(e) => error!("Could not send/validate revoke: {}", e),
Ok(response) => match response {
rfc6492::Res::Revoke(revoke_response) => res.push(revoke_response),
rfc6492::Res::NotPerformed(e) => error!("We got an error response: {}", e),
rfc6492::Res::List(_) => error!("List response to revoke request??"),
rfc6492::Res::Issue(_) => error!("Issue response to revoke request??"),
},
match self.send_rfc6492_and_validate_response(
signing_key,
parent_res,
revoke.into_bytes(),
) {
Err(e) => error!("Could not send/validate revoke: {}", e),
Ok(response) => match response {
rfc6492::Res::Revoke(revoke_response) => revocations.push(revoke_response),
rfc6492::Res::NotPerformed(e) => error!("We got an error response: {}", e),
rfc6492::Res::List(_) => error!("List response to revoke request??"),
rfc6492::Res::Issue(_) => error!("Issue response to revoke request??"),
},
}
}
revoke_map.insert(rcn, revocations);
}
Ok(res)
Ok(revoke_map)
}
fn send_cert_requests_handle_responses(
@@ -586,14 +586,20 @@ impl<S: Signer> CaServer<S> {
}
}?;
for (class_name, issued) in issued_certs.into_iter() {
let received = RcvdCert::from(issued);
for (class_name, issued_certs) in issued_certs.into_iter() {
for issued in issued_certs.into_iter() {
let received = RcvdCert::from(issued);
let upd_rcvd_cmd =
CmdDet::upd_received_cert(handle, class_name, received, self.signer.clone());
let upd_rcvd_cmd = CmdDet::upd_received_cert(
handle,
class_name.clone(),
received,
self.signer.clone(),
);
let evts = child.process_command(upd_rcvd_cmd)?;
child = self.ca_store.update(handle, child, evts)?;
let evts = child.process_command(upd_rcvd_cmd)?;
child = self.ca_store.update(handle, child, evts)?;
}
}
Ok(())
@@ -601,64 +607,76 @@ impl<S: Signer> CaServer<S> {
fn send_cert_requests_embedded(
&self,
requests: Vec<IssuanceRequest>,
requests: HashMap<ResourceClassName, Vec<IssuanceRequest>>,
handle: &Handle,
parent_h: &ParentHandle,
) -> ServerResult<Vec<(ResourceClassName, IssuedCert)>, S> {
) -> ServerResult<HashMap<ResourceClassName, Vec<IssuedCert>>, S> {
let mut parent = self.ca_store.get_latest(parent_h)?;
let mut issued_certs: Vec<(ResourceClassName, IssuedCert)> = vec![];
let mut issued_map = HashMap::new();
for req in requests.into_iter() {
let class_name = req.class_name().clone();
let pub_key = req.csr().public_key().clone();
for (rcn, requests) in requests.into_iter() {
let mut issued_certs = vec![];
for req in requests.into_iter() {
let pub_key = req.csr().public_key().clone();
let parent_class = req.class_name().clone();
let cmd = CmdDet::child_certify(parent_h, handle.clone(), req, self.signer.clone());
let cmd = CmdDet::child_certify(parent_h, handle.clone(), req, self.signer.clone());
let events = parent.process_command(cmd)?;
parent = self.ca_store.update(parent_h, parent, events)?;
let events = parent.process_command(cmd)?;
parent = self.ca_store.update(parent_h, parent, events)?;
let response = parent.issuance_response(handle, &class_name, &pub_key)?;
let response = parent.issuance_response(handle, &parent_class, &pub_key)?;
let (_, _, _, issued) = response.unwrap();
let (_, _, _, issued) = response.unwrap();
issued_certs.push((class_name, issued));
issued_certs.push(issued);
}
issued_map.insert(rcn, issued_certs);
}
Ok(issued_certs)
Ok(issued_map)
}
fn send_cert_requests_rfc6492(
&self,
requests: Vec<IssuanceRequest>,
requests: HashMap<ResourceClassName, Vec<IssuanceRequest>>,
signing_key: &KeyId,
parent_res: &rfc8183::ParentResponse,
) -> ServerResult<Vec<(ResourceClassName, IssuedCert)>, S> {
let mut res = vec![];
) -> ServerResult<HashMap<ResourceClassName, Vec<IssuedCert>>, S> {
let mut issued_map = HashMap::new();
for req in requests.into_iter() {
let sender = parent_res.child_handle().to_string();
let recipient = parent_res.parent_handle().to_string();
let issue = rfc6492::Message::issue(sender, recipient, req);
for (rcn, requests) in requests.into_iter() {
let mut issued_certs = vec![];
match self.send_rfc6492_and_validate_response(
signing_key,
parent_res,
issue.into_bytes(),
) {
Err(e) => error!("Could not send/validate csr: {}", e),
Ok(response) => match response {
rfc6492::Res::NotPerformed(e) => error!("We got an error response: {}", e),
rfc6492::Res::Issue(issue_response) => {
let (class_name, _, _, issued) = issue_response.unwrap();
res.push((class_name, issued));
}
rfc6492::Res::List(_) => error!("List reply to issue request??"),
rfc6492::Res::Revoke(_) => error!("Revoke reply to issue request??"),
},
for req in requests.into_iter() {
let sender = parent_res.child_handle().to_string();
let recipient = parent_res.parent_handle().to_string();
let issue = rfc6492::Message::issue(sender, recipient, req);
match self.send_rfc6492_and_validate_response(
signing_key,
parent_res,
issue.into_bytes(),
) {
Err(e) => error!("Could not send/validate csr: {}", e),
Ok(response) => match response {
rfc6492::Res::NotPerformed(e) => error!("We got an error response: {}", e),
rfc6492::Res::Issue(issue_response) => {
let (_, _, _, issued) = issue_response.unwrap();
issued_certs.push(issued);
}
rfc6492::Res::List(_) => error!("List reply to issue request??"),
rfc6492::Res::Revoke(_) => error!("Revoke reply to issue request??"),
},
}
}
issued_map.insert(rcn, issued_certs);
}
Ok(res)
Ok(issued_map)
}
/// Updates the CA if entitlements are different from what the CA
+65 -9
View File
@@ -18,8 +18,7 @@ use krill_pubd::publishers::PublisherError;
use krill_pubd::repo::RrdpServerError;
use crate::auth::Auth;
use crate::ca;
use crate::ca::ParentHandle;
use crate::ca::{self, ta_handle, ParentHandle};
use crate::http::server::AppServer;
use crate::krillserver;
@@ -278,19 +277,38 @@ pub fn ta_cer(server: web::Data<AppServer>) -> HttpResponse {
}
}
// TODO: Deprecate!
pub fn ta_add_child(
server: web::Data<AppServer>,
req: Json<AddChildRequest>,
auth: Auth,
) -> HttpResponse {
if_api_allowed(&server, &auth, || {
match server.read().ta_add_child(req.into_inner()) {
match server.read().ca_add_child(&ta_handle(), req.into_inner()) {
Ok(info) => render_json(info),
Err(e) => server_error(&Error::ServerError(e)),
}
})
}
pub fn ca_add_child(
server: web::Data<AppServer>,
parent: Path<ParentHandle>,
req: Json<AddChildRequest>,
auth: Auth,
) -> HttpResponse {
if_api_allowed(&server, &auth, || {
match server
.read()
.ca_add_child(&parent.into_inner(), req.into_inner())
{
Ok(info) => render_json(info),
Err(e) => server_error(&Error::ServerError(e)),
}
})
}
// TODO: Deprecate
pub fn ta_update_child(
server: web::Data<AppServer>,
child: Path<Handle>,
@@ -298,21 +316,59 @@ pub fn ta_update_child(
auth: Auth,
) -> HttpResponse {
if_api_allowed(&server, &auth, || {
render_empty_res(
server
.read()
.ta_update_child(child.into_inner(), req.into_inner()),
)
render_empty_res(server.read().ca_update_child(
&ta_handle(),
child.into_inner(),
req.into_inner(),
))
})
}
pub fn ca_update_child(
server: web::Data<AppServer>,
parent: Path<Handle>,
child: Path<Handle>,
req: Json<UpdateChildRequest>,
auth: Auth,
) -> HttpResponse {
if_api_allowed(&server, &auth, || {
render_empty_res(server.read().ca_update_child(
&parent.into_inner(),
child.into_inner(),
req.into_inner(),
))
})
}
// TODO: Deprecate
pub fn ta_show_child(
server: web::Data<AppServer>,
child: Path<Handle>,
auth: Auth,
) -> HttpResponse {
if_api_allowed(&server, &auth, || {
match server.read().ta_show_child(&child.into_inner()) {
match server
.read()
.ca_show_child(&ta_handle(), &child.into_inner())
{
Ok(Some(child)) => render_json(child),
Ok(None) => api_not_found(),
Err(e) => server_error(&Error::ServerError(e)),
}
})
}
pub fn ca_show_child(
server: web::Data<AppServer>,
parent: Path<Handle>,
child: Path<Handle>,
auth: Auth,
) -> HttpResponse {
if_api_allowed(&server, &auth, || {
match server
.read()
.ca_show_child(&parent.into_inner(), &child.into_inner())
{
Ok(Some(child)) => render_json(child),
Ok(None) => api_not_found(),
Err(e) => server_error(&Error::ServerError(e)),
+8 -5
View File
@@ -82,12 +82,15 @@ pub fn start(config: &Config) -> Result<(), Error> {
.route("/trustanchor/children/{handle}", post().to(ta_update_child))
.route("/cas", post().to(ca_init))
.route("/cas", get().to(cas))
.route("/cas/{handle}", get().to(ca_info))
.route("/cas/{handle}/child_request", get().to(ca_child_req))
.route("/cas/{handle}/parents", post().to(ca_add_parent))
.route("/cas/{handle}/keys/roll_init", post().to(ca_keyroll_init))
.route("/cas/{ca}", get().to(ca_info))
.route("/cas/{ca}/child_request", get().to(ca_child_req))
.route("/cas/{ca}/parents", post().to(ca_add_parent))
.route("/cas/{ca}/children", post().to(ca_add_child))
.route("/cas/{ca}/children/{child}", get().to(ca_show_child))
.route("/cas/{ca}/children/{child}", post().to(ca_update_child))
.route("/cas/{ca}/keys/roll_init", post().to(ca_keyroll_init))
.route(
"/cas/{handle}/keys/roll_activate",
"/cas/{ca}/keys/roll_activate",
post().to(ca_keyroll_activate),
)
.route("/republish", post().to(republish_all)),
+23 -10
View File
@@ -27,8 +27,7 @@ use krill_pubd::publishers::Publisher;
use krill_pubd::PubServer;
use crate::auth::{Auth, Authorizer};
use crate::ca::ChildHandle;
use crate::ca::{self, ta_handle};
use crate::ca::{self, ta_handle, ChildHandle, ParentHandle};
use crate::config::Config;
use crate::mq::EventQueueListener;
use crate::scheduler::Scheduler;
@@ -310,21 +309,35 @@ impl KrillServer {
Ok(())
}
/// Adds a child to the TA and returns the ParentCaInfo that the child
/// will to contact this TA for resource requests.
pub fn ta_add_child(&self, req: AddChildRequest) -> KrillRes<ParentCaContact> {
let contact = self.caserver.ta_add_child(req, &self.service_uri)?;
/// Adds a child to a CA and returns the ParentCaInfo that the child
/// will need to contact this CA for resource requests.
pub fn ca_add_child(
&self,
parent: &ParentHandle,
req: AddChildRequest,
) -> KrillRes<ParentCaContact> {
let contact = self.caserver.ca_add_child(parent, req, &self.service_uri)?;
Ok(contact)
}
pub fn ta_update_child(&self, child: ChildHandle, req: UpdateChildRequest) -> EmptyRes {
self.caserver.ta_update_child(child, req)?;
/// Update IdCert or resources of a child.
pub fn ca_update_child(
&self,
parent: &ParentHandle,
child: ChildHandle,
req: UpdateChildRequest,
) -> EmptyRes {
self.caserver.ca_update_child(parent, child, req)?;
Ok(())
}
/// Show details for a child under the TA.
pub fn ta_show_child(&self, child: &ChildHandle) -> KrillRes<Option<ChildCaInfo>> {
let child = self.caserver.ta_show_child(child)?;
pub fn ca_show_child(
&self,
parent: &ParentHandle,
child: &ChildHandle,
) -> KrillRes<Option<ChildCaInfo>> {
let child = self.caserver.ca_show_child(parent, child)?;
Ok(child)
}
+13 -4
View File
@@ -3,11 +3,12 @@
//! signed material, or asking a newly added parent for resource
//! entitlements.
use std::collections::VecDeque;
use std::collections::{HashMap, VecDeque};
use std::fmt;
use std::sync::RwLock;
use krill_commons::api::admin::Handle;
use krill_commons::api::ca::ResourceClassName;
use krill_commons::api::publication::PublishDelta;
use krill_commons::api::RevocationRequest;
use krill_commons::eventsourcing;
@@ -24,7 +25,11 @@ pub enum QueueEvent {
Delta(Handle, PublishDelta),
ParentAdded(Handle, ParentHandle),
RequestsPending(Handle),
ResourceClassRemoved(Handle, ParentHandle, Vec<RevocationRequest>),
ResourceClassRemoved(
Handle,
ParentHandle,
HashMap<ResourceClassName, Vec<RevocationRequest>>,
),
}
#[derive(Debug)]
@@ -72,12 +77,16 @@ impl<S: Signer> eventsourcing::EventListener<CertAuth<S>> for EventQueueListener
let evt = QueueEvent::Delta(handle.clone(), publish_delta);
self.push_back(evt);
}
EvtDet::ResourceClassRemoved(_class_name, delta, parent, revocations) => {
EvtDet::ResourceClassRemoved(class_name, delta, parent, revocations) => {
self.push_back(QueueEvent::Delta(handle.clone(), delta.clone().into()));
let mut revocations_map = HashMap::new();
revocations_map.insert(class_name.clone(), revocations.clone());
self.push_back(QueueEvent::ResourceClassRemoved(
handle.clone(),
parent.clone(),
revocations.clone(),
revocations_map,
))
}
EvtDet::KeyRollFinished(_class_name, delta) => {
-1
View File
@@ -64,7 +64,6 @@ fn make_event_sh(
publish(&handle, delta, &pubserver);
}
QueueEvent::ResourceClassRemoved(handle, parent, revocations) => {
let revocations = revocations.iter().collect();
if caserver
.send_revoke_requests(&handle, &parent, revocations)
.is_err()
+25 -7
View File
@@ -15,7 +15,7 @@ use krill_commons::api::ca::{CertAuthInfo, ResourceClassKeysInfo, ResourceClassN
use krill_commons::remote::rfc8183;
use krill_commons::util::test;
use crate::ca::ta_handle;
use crate::ca::{ta_handle, ChildHandle, ParentHandle};
use crate::config::Config;
use crate::http::server;
@@ -101,7 +101,7 @@ pub fn add_child_to_ta_embedded(handle: &Handle, resources: ResourceSet) -> Pare
let res = krill_admin(Command::TrustAnchor(TrustAnchorCommand::AddChild(req)));
match res {
ApiResponse::ParentCaInfo(info) => info,
ApiResponse::ParentCaContact(info) => info,
_ => panic!("Expected ParentCaInfo response"),
}
}
@@ -116,7 +116,23 @@ pub fn add_child_to_ta_rfc6492(
let res = krill_admin(Command::TrustAnchor(TrustAnchorCommand::AddChild(req)));
match res {
ApiResponse::ParentCaInfo(info) => info,
ApiResponse::ParentCaContact(info) => info,
_ => panic!("Expected ParentCaInfo response"),
}
}
pub fn add_child_rfc6492(
parent: &ParentHandle,
child: &ChildHandle,
req: rfc8183::ChildRequest,
resources: ResourceSet,
) -> ParentCaContact {
let auth = ChildAuthRequest::Rfc8183(req);
let req = AddChildRequest::new(child.clone(), resources, auth);
let res = krill_admin(Command::CertAuth(CaCommand::AddChild(parent.clone(), req)));
match res {
ApiResponse::ParentCaContact(info) => info,
_ => panic!("Expected ParentCaInfo response"),
}
}
@@ -180,7 +196,7 @@ where
panic!(error_msg);
}
pub fn wait_for_resources_on_current_key(handle: &Handle, resources: &ResourceSet) {
pub fn wait_for_current_resources(handle: &Handle, resources: &ResourceSet) {
wait_for(
30,
"cms child did not get its resource certificate",
@@ -249,17 +265,19 @@ pub fn ta_issued_resources(child: &Handle) -> ResourceSet {
pub fn ca_current_resources(handle: &Handle) -> ResourceSet {
let ca = ca_details(handle);
if let Some(rc) = ca.resources().get(&ResourceClassName::default()) {
let mut res = ResourceSet::default();
for rc in ca.resources().values() {
match rc.keys() {
ResourceClassKeysInfo::Active(current)
| ResourceClassKeysInfo::RollPending(_, current)
| ResourceClassKeysInfo::RollNew(_, current)
| ResourceClassKeysInfo::RollOld(current, _) => {
return current.incoming_cert().resources().clone()
res = res.union(current.incoming_cert().resources());
}
_ => {}
}
}
ResourceSet::default()
res
}
+1 -1
View File
@@ -28,7 +28,7 @@ fn ca_keyroll_under_rfc6492_ta() {
};
add_parent_to_ca(&child, parent);
wait_for_resources_on_current_key(&child, &child_resources);
wait_for_current_resources(&child, &child_resources);
wait_for_ta_to_have_number_of_issued_certs(1);
ca_roll_init(&child);
+3 -3
View File
@@ -28,7 +28,7 @@ fn ca_under_embedded_ta() {
// When the parent is added, a child CA will immediately request a certificate.
add_parent_to_ca(&child, parent);
wait_for_resources_on_current_key(&child, &child_resources);
wait_for_current_resources(&child, &child_resources);
wait_for_ta_to_have_number_of_issued_certs(1);
// When the parent adds resources to a CA, it will allocate them only when the child
@@ -36,7 +36,7 @@ fn ca_under_embedded_ta() {
let new_child_resources = ResourceSet::from_strs("AS65000", "10.0.0.0/16", "").unwrap();
force_update_child(&child, &new_child_resources);
assert_eq!(ta_issued_resources(&child), child_resources);
wait_for_resources_on_current_key(&child, &new_child_resources);
wait_for_current_resources(&child, &new_child_resources);
wait_for_ta_to_have_number_of_issued_certs(1);
assert_eq!(ta_issued_resources(&child), new_child_resources);
@@ -45,7 +45,7 @@ fn ca_under_embedded_ta() {
let child_resources = ResourceSet::from_strs("", "10.0.0.0/24", "").unwrap();
force_update_child(&child, &child_resources);
assert_eq!(ta_issued_resources(&child), child_resources);
wait_for_resources_on_current_key(&child, &child_resources);
wait_for_current_resources(&child, &child_resources);
// When all resources are removed, the child still gets a chance to clean up if force
// is not used.. The child will request that its certificate is revoked, and remove
+3 -3
View File
@@ -29,7 +29,7 @@ fn ca_under_rfc6492_ta() {
// When the parent is added, a child CA will immediately request a certificate.
add_parent_to_ca(&child, parent);
wait_for_resources_on_current_key(&child, &child_resources);
wait_for_current_resources(&child, &child_resources);
wait_for_ta_to_have_number_of_issued_certs(1);
// When the parent adds resources to a CA, it will allocate them only when the child
@@ -37,7 +37,7 @@ fn ca_under_rfc6492_ta() {
let new_child_resources = ResourceSet::from_strs("AS65000", "10.0.0.0/16", "").unwrap();
force_update_child(&child, &new_child_resources);
assert_eq!(ta_issued_resources(&child), child_resources);
wait_for_resources_on_current_key(&child, &new_child_resources);
wait_for_current_resources(&child, &new_child_resources);
wait_for_ta_to_have_number_of_issued_certs(1);
assert_eq!(ta_issued_resources(&child), new_child_resources);
@@ -46,7 +46,7 @@ fn ca_under_rfc6492_ta() {
let child_resources = ResourceSet::from_strs("", "10.0.0.0/24", "").unwrap();
force_update_child(&child, &child_resources);
assert_eq!(ta_issued_resources(&child), child_resources);
wait_for_resources_on_current_key(&child, &child_resources);
wait_for_current_resources(&child, &child_resources);
// When all resources are removed, the child still gets a chance to clean up if force
// is not used.. The child will request that its certificate is revoked, and remove
+93
View File
@@ -0,0 +1,93 @@
extern crate krill_client;
extern crate krill_commons;
extern crate krill_daemon;
extern crate krill_pubc;
use krill_commons::api::admin::{AddParentRequest, Handle, Token};
use krill_commons::api::ca::ResourceSet;
use krill_daemon::ca::ta_handle;
use krill_daemon::test::*;
#[test]
fn grand_children() {
test_with_krill_server(|_d| {
// Test that we can delegate from normal CAs to child CAs, and that these child CAs
// can have multiple parents.
//
// TA
// / \
// CA1 CA2
// \ /
// CA3 (two resource classes)
// | |
// CA4 (two resource classes)
//
// -------------------- TA -----------------------------------------------
let ta_handle = ta_handle();
init_ta();
// -------------------- CA1 -----------------------------------------------
let ca1 = Handle::from("CA1");
let ca1_res = ResourceSet::from_strs("", "10.0.0.0/16", "").unwrap();
init_child(&ca1, &Token::from("CA1"));
let req = child_request(&ca1);
let parent = {
let contact = add_child_to_ta_rfc6492(&ca1, req, ca1_res.clone());
AddParentRequest::new(ta_handle.clone(), contact)
};
add_parent_to_ca(&ca1, parent);
wait_for_current_resources(&ca1, &ca1_res);
// -------------------- CA2 -----------------------------------------------
let ca2 = Handle::from("CA2");
let ca2_res = ResourceSet::from_strs("", "10.1.0.0/16", "").unwrap();
init_child(&ca2, &Token::from("CA2"));
let req = child_request(&ca2);
let parent = {
let contact = add_child_to_ta_rfc6492(&ca2, req, ca2_res.clone());
AddParentRequest::new(ta_handle.clone(), contact)
};
add_parent_to_ca(&ca2, parent);
wait_for_current_resources(&ca2, &ca2_res);
// -------------------- CA3 -----------------------------------------------
let ca3 = Handle::from("CA3");
let ca_3_res_under_ca_1 = ResourceSet::from_strs("", "10.0.0.0/16", "").unwrap();
init_child(&ca3, &Token::from("CA3"));
let req = child_request(&ca3);
let parent = {
let contact = add_child_rfc6492(&ca1, &ca3, req, ca_3_res_under_ca_1.clone());
AddParentRequest::new(ca1.clone(), contact)
};
add_parent_to_ca(&ca3, parent);
wait_for_current_resources(&ca3, &ca_3_res_under_ca_1);
let ca_3_res_under_ca_2 = ResourceSet::from_strs("", "10.1.0.0/24", "").unwrap();
let ca_3_res = ca_3_res_under_ca_1.union(&ca_3_res_under_ca_2);
let req = child_request(&ca3);
let parent = {
let contact = add_child_rfc6492(&ca2, &ca3, req, ca_3_res_under_ca_2.clone());
AddParentRequest::new(ca2.clone(), contact)
};
add_parent_to_ca(&ca3, parent);
wait_for_current_resources(&ca3, &ca_3_res);
// -------------------- CA4 -----------------------------------------------
let ca4 = Handle::from("CA4");
let ca_4_res_under_ca_3 = ResourceSet::from_strs("", "10.0.0.0-10.1.0.255", "").unwrap();
init_child(&ca4, &Token::from("CA4"));
let req = child_request(&ca4);
let parent = {
let contact = add_child_rfc6492(&ca3, &ca4, req, ca_4_res_under_ca_3.clone());
AddParentRequest::new(ca3.clone(), contact)
};
add_parent_to_ca(&ca4, parent);
wait_for_current_resources(&ca4, &ca_4_res_under_ca_3);
});
}