Register success/failure for RFC6492 messages sent to parents. (#250)

This commit is contained in:
Tim Bruijnzeels
2020-07-30 12:38:01 +02:00
parent 0a3f3a50b7
commit 7ba2af960b
3 changed files with 200 additions and 36 deletions
+118 -1
View File
@@ -20,7 +20,7 @@ use rpki::uri;
use rpki::x509::{Serial, Time};
use crate::commons::api::publication::Publish;
use crate::commons::api::{publication, RoaAggregateKey};
use crate::commons::api::{publication, Entitlements, RoaAggregateKey};
use crate::commons::api::{
Base64, ChildHandle, ErrorResponse, Handle, HexEncodedHash, IssuanceRequest, ListReply, ParentCaContact,
ParentHandle, RepositoryContact, RequestResourceLimit, RoaDefinition,
@@ -1492,6 +1492,7 @@ pub enum ParentKindInfo {
}
//------------ ParentInfo ----------------------------------------------------
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct ParentInfo {
handle: ParentHandle,
@@ -1515,6 +1516,122 @@ impl fmt::Display for ParentInfo {
}
}
//------------ ParentStatus --------------------------------------------------
pub struct AllParentStatuses(HashMap<Handle, ParentStatuses>);
impl AllParentStatuses {
pub fn set_failure(&mut self, ca: &Handle, parent: &ParentHandle, error: ErrorResponse) {
let status = self.get_mut_status(ca);
status.set_failure(parent, error);
}
pub fn set_last_updated(&mut self, ca: &Handle, parent: &ParentHandle) {
self.get_mut_status(ca).set_last_updated(parent);
}
pub fn set_entitlements(&mut self, ca: &Handle, parent: &ParentHandle, entitlements: &Entitlements) {
self.get_mut_status(ca).set_entitlements(parent, entitlements)
}
fn get_mut_status(&mut self, ca: &Handle) -> &mut ParentStatuses {
if !self.0.contains_key(ca) {
self.0.insert(ca.clone(), ParentStatuses::default());
}
self.0.get_mut(ca).unwrap()
}
}
impl Default for AllParentStatuses {
fn default() -> Self {
AllParentStatuses(HashMap::new())
}
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct ParentStatuses(HashMap<ParentHandle, ParentStatus>);
impl ParentStatuses {
fn set_failure(&mut self, parent: &ParentHandle, error: ErrorResponse) {
self.get_mut_status(parent).set_failure(error);
}
fn set_entitlements(&mut self, parent: &ParentHandle, entitlements: &Entitlements) {
self.get_mut_status(parent).set_entitlements(entitlements);
}
fn set_last_updated(&mut self, parent: &ParentHandle) {
self.get_mut_status(parent).set_last_updated();
}
fn get_mut_status(&mut self, parent: &ParentHandle) -> &mut ParentStatus {
if !self.0.contains_key(parent) {
self.0.insert(parent.clone(), ParentStatus::default());
}
self.0.get_mut(parent).unwrap()
}
}
impl Default for ParentStatuses {
fn default() -> Self {
ParentStatuses(HashMap::new())
}
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct ParentStatus {
last_exchange: Option<ParentExchange>,
resources: HashMap<ResourceClassName, ResourceSet>,
}
impl ParentStatus {
fn set_failure(&mut self, error: ErrorResponse) {
self.last_exchange = Some(ParentExchange {
time: Time::now(),
result: ParentExchangeResult::Failure(error),
})
}
fn set_entitlements(&mut self, entitlements: &Entitlements) {
self.set_last_updated();
self.resources = entitlements
.classes()
.iter()
.map(|rc| (rc.class_name().clone(), rc.resource_set().clone()))
.collect();
}
fn set_last_updated(&mut self) {
self.last_exchange = Some(ParentExchange {
time: Time::now(),
result: ParentExchangeResult::Success,
});
}
}
impl Default for ParentStatus {
fn default() -> Self {
ParentStatus {
last_exchange: None,
resources: HashMap::new(),
}
}
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct ParentExchange {
time: Time,
result: ParentExchangeResult,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum ParentExchangeResult {
Success,
Failure(ErrorResponse),
}
//------------ CertAuthInfo --------------------------------------------------
/// This type represents the details of a CertAuth that need
+5
View File
@@ -16,6 +16,7 @@ use crate::commons::api::{
};
use crate::commons::eventsourcing::AggregateStoreError;
use crate::commons::remote::rfc6492;
use crate::commons::remote::rfc6492::NotPerformedResponse;
use crate::commons::remote::rfc8181;
use crate::commons::remote::rfc8181::ReportErrorCode;
use crate::commons::util::httpclient;
@@ -288,6 +289,9 @@ pub enum Error {
#[display(fmt = "RFC 6492 Issue: {}", _0)]
Rfc6492(rfc6492::Error),
#[display(fmt = "RFC 6492 Not Performed: {}", _0)]
Rfc6492NotPerformed(NotPerformedResponse),
#[display(fmt = "Invalid CSR received: {}", _0)]
Rfc6492InvalidCsrSent(String),
@@ -592,6 +596,7 @@ impl Error {
// RFC6492 (requesting resources, not on JSON api)
//-----------------------------------------------------------------
Error::Rfc6492(e) => ErrorResponse::new("rfc6492-protocol", &self).with_cause(e),
Error::Rfc6492NotPerformed(e) => ErrorResponse::new("rfc6492-not-performed-response", &self).with_cause(e),
Error::Rfc6492InvalidCsrSent(e) => ErrorResponse::new("rfc6492-invalid-csr", &self).with_cause(e),
Error::Rfc6492SignatureInvalid => ErrorResponse::new("rfc6492-invalid-signature", &self),
+77 -35
View File
@@ -10,11 +10,11 @@ use rpki::crypto::KeyIdentifier;
use rpki::uri;
use crate::commons::api::{
self, AddChildRequest, Base64, CaCommandDetails, CaCommandResult, CertAuthList, CertAuthSummary, ChildAuthRequest,
ChildCaInfo, ChildHandle, CommandHistory, CommandHistoryCriteria, Entitlements, Handle, IssuanceRequest,
IssuanceResponse, IssuedCert, ListReply, ParentCaContact, ParentCaReq, ParentHandle, PublishDelta, RcvdCert,
RepoInfo, RepositoryContact, ResourceClassName, ResourceSet, RevocationRequest, RevocationResponse, StoredEffect,
UpdateChildRequest,
self, AddChildRequest, AllParentStatuses, Base64, CaCommandDetails, CaCommandResult, CertAuthList, CertAuthSummary,
ChildAuthRequest, ChildCaInfo, ChildHandle, CommandHistory, CommandHistoryCriteria, Entitlements, ErrorResponse,
Handle, IssuanceRequest, IssuanceResponse, IssuedCert, ListReply, ParentCaContact, ParentCaReq, ParentHandle,
PublishDelta, RcvdCert, RepoInfo, RepositoryContact, ResourceClassName, ResourceSet, RevocationRequest,
RevocationResponse, StoredEffect, UpdateChildRequest,
};
use crate::commons::error::Error;
use crate::commons::eventsourcing::{Aggregate, AggregateStore, CommandKey, DiskAggregateStore};
@@ -36,6 +36,7 @@ use crate::daemon::mq::EventQueueListener;
pub struct CaServer<S: Signer> {
signer: Arc<RwLock<S>>,
ca_store: Arc<DiskAggregateStore<CertAuth<S>>>,
parents_statuses: Arc<RwLock<AllParentStatuses>>,
rfc8181_log_dir: Option<PathBuf>,
rfc6492_log_dir: Option<PathBuf>,
}
@@ -56,6 +57,7 @@ impl<S: Signer> CaServer<S> {
Ok(CaServer {
signer,
ca_store: Arc::new(ca_store),
parents_statuses: Arc::new(RwLock::new(AllParentStatuses::default())),
rfc6492_log_dir: rfc6492_log_dir.cloned(),
rfc8181_log_dir: rfc8181_log_dir.cloned(),
})
@@ -510,13 +512,20 @@ impl<S: Signer> CaServer<S> {
// No repo set, yet. So, skip updating.
Ok(())
} else {
let entitlements = self.get_entitlements_from_parent(handle, parent).await?;
match self.get_entitlements_from_parent(handle, parent).await {
Err(e) => {
self.set_parent_status_failure(handle, parent, e.to_error_response());
Err(e)
}
Ok(entitlements) => {
self.set_parent_status_entitlements(handle, parent, &entitlements);
if !self.update_resource_classes(handle, parent.clone(), entitlements)? {
return Ok(()); // Nothing to do
}
if !self.update_resource_classes(handle, parent.clone(), entitlements)? {
return Ok(()); // Nothing to do
Ok(()) // Pending requests will be picked up by the scheduler.
}
}
Ok(()) // Pending requests will be picked up by the scheduler.
}
}
}
@@ -568,8 +577,19 @@ impl<S: Signer> CaServer<S> {
.await
}
ParentCaContact::Rfc6492(parent_res) => {
self.send_revoke_requests_rfc6492(revoke_requests, child.id_key(), parent_res)
match self
.send_revoke_requests_rfc6492(revoke_requests, child.id_key(), parent_res)
.await
{
Err(e) => {
self.set_parent_status_failure(handle, parent, e.to_error_response());
Err(e)
}
Ok(res) => {
self.set_parent_status_updated(handle, parent);
Ok(res)
}
}
}
}
}
@@ -628,17 +648,15 @@ impl<S: Signer> CaServer<S> {
let revoke = rfc6492::Message::revoke(sender, recipient, req.clone());
match self
let response = self
.send_rfc6492_and_validate_response(signing_key, parent_res, revoke.into_bytes(), Some(cms_logger))
.await
{
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??"),
},
.await?;
match response {
rfc6492::Res::Revoke(revoke_response) => revocations.push(revoke_response),
rfc6492::Res::NotPerformed(e) => return Err(Error::Rfc6492NotPerformed(e)),
rfc6492::Res::List(_) => return Err(Error::custom("Got a List response to revoke request??")),
rfc6492::Res::Issue(_) => return Err(Error::custom("Issue response to revoke request??")),
}
}
@@ -656,8 +674,19 @@ impl<S: Signer> CaServer<S> {
ParentCaContact::Ta(_) => Err(Error::TaNotAllowed),
ParentCaContact::Embedded => self.send_cert_requests_embedded(cert_requests, handle, parent),
ParentCaContact::Rfc6492(parent_res) => {
self.send_cert_requests_rfc6492(cert_requests, child.id_key(), &parent_res)
match self
.send_cert_requests_rfc6492(cert_requests, child.id_key(), &parent_res)
.await
{
Err(e) => {
self.set_parent_status_failure(handle, parent, e.to_error_response());
Err(e)
}
Ok(res) => {
self.set_parent_status_updated(handle, parent);
Ok(res)
}
}
}
}?;
@@ -724,20 +753,18 @@ impl<S: Signer> CaServer<S> {
let issue = rfc6492::Message::issue(sender, recipient, req);
match self
let response = self
.send_rfc6492_and_validate_response(signing_key, parent_res, issue.into_bytes(), Some(cms_logger))
.await
{
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??"),
},
.await?;
match response {
rfc6492::Res::NotPerformed(e) => return Err(Error::Rfc6492NotPerformed(e)),
rfc6492::Res::Issue(issue_response) => {
let (_, _, _, issued) = issue_response.unwrap();
issued_certs.push(issued);
}
rfc6492::Res::List(_) => return Err(Error::custom("List reply to issue request??")),
rfc6492::Res::Revoke(_) => return Err(Error::custom("Revoke reply to issue request??")),
}
}
@@ -843,6 +870,21 @@ impl<S: Signer> CaServer<S> {
.into_reply()
.map_err(Error::custom)
}
fn set_parent_status_failure(&self, ca: &Handle, parent: &ParentHandle, error: ErrorResponse) {
self.parents_statuses.write().unwrap().set_failure(ca, parent, error);
}
fn set_parent_status_entitlements(&self, ca: &Handle, parent: &ParentHandle, entitlements: &Entitlements) {
self.parents_statuses
.write()
.unwrap()
.set_entitlements(ca, parent, entitlements);
}
fn set_parent_status_updated(&self, ca: &Handle, parent: &ParentHandle) {
self.parents_statuses.write().unwrap().set_last_updated(ca, parent);
}
}
/// # Support sending publication messages, and verifying responses.