From 7925e72e88fbbbb1492a8cb479a896fa8f3ec609 Mon Sep 17 00:00:00 2001 From: Tim Bruijnzeels Date: Mon, 19 Aug 2019 11:18:00 +0200 Subject: [PATCH] Create real type for ResourceClassName. --- commons/src/api/ca.rs | 110 ++++++++++++++++++++++++++------ commons/src/api/provisioning.rs | 62 +++++++++++------- commons/src/remote/rfc6492.rs | 40 +++++++----- daemon/src/ca/certauth.rs | 60 +++++++++-------- daemon/src/ca/commands.rs | 4 +- daemon/src/ca/error.rs | 4 ++ daemon/src/ca/events.rs | 8 +-- daemon/src/ca/mod.rs | 1 - daemon/src/ca/rc.rs | 31 ++++----- daemon/src/ca/server.rs | 23 ++++--- daemon/src/test.rs | 15 +++-- 11 files changed, 230 insertions(+), 128 deletions(-) diff --git a/commons/src/api/ca.rs b/commons/src/api/ca.rs index 0a4a262a..dd56a93a 100644 --- a/commons/src/api/ca.rs +++ b/commons/src/api/ca.rs @@ -4,9 +4,8 @@ use std::collections::HashMap; use std::convert::TryFrom; use std::ops::{Deref, DerefMut}; -use std::str; -use std::str::FromStr; -use std::{fmt, ops}; +use std::str::{from_utf8_unchecked, FromStr}; +use std::{fmt, ops, str}; use bytes::Bytes; use chrono::Duration; @@ -32,6 +31,75 @@ use crate::rpki::manifest::{FileAndHash, Manifest}; use crate::util::ext_serde; use crate::util::softsigner::KeyId; +//------------ ResourceClassName ------------------------------------------- + +/// This type represents a resource class name, as used in RFC6492. The protocol +/// allows for any arbitrary set of utf8 characters to be used as the name, though +/// in practice names can be expected to be short and plain ascii or even numbers. +/// +/// We store the name in a Bytes for cheap cloning, as these names need to be passed +/// around quite a bit and end up being stored as owned values in events. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct ResourceClassName { + name: Bytes, +} + +impl Default for ResourceClassName { + fn default() -> ResourceClassName { + ResourceClassName::from(0) + } +} + +impl From for ResourceClassName { + fn from(nr: u32) -> ResourceClassName { + ResourceClassName { + name: Bytes::from(format!("{}", nr)), + } + } +} + +impl From<&str> for ResourceClassName { + fn from(s: &str) -> ResourceClassName { + ResourceClassName { + name: Bytes::from(s), + } + } +} + +impl From for ResourceClassName { + fn from(s: String) -> ResourceClassName { + ResourceClassName { + name: Bytes::from(s), + } + } +} + +impl fmt::Display for ResourceClassName { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = unsafe { from_utf8_unchecked(self.name.as_ref()) }; + write!(f, "{}", s) + } +} + +impl Serialize for ResourceClassName { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: Serializer, + { + self.to_string().serialize(serializer) + } +} + +impl<'de> Deserialize<'de> for ResourceClassName { + fn deserialize(deserializer: D) -> std::result::Result + where + D: Deserializer<'de>, + { + let string = String::deserialize(deserializer)?; + Ok(ResourceClassName::from(string)) + } +} + //------------ ChildCaInfo --------------------------------------------------- /// This type represents information about a child CA that is safe to share @@ -40,7 +108,7 @@ use crate::util::softsigner::KeyId; #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct ChildCaInfo { id_cert: Option, - resources: HashMap, + resources: HashMap, } impl ChildCaInfo { @@ -48,11 +116,11 @@ impl ChildCaInfo { self.id_cert.as_ref() } - pub fn resources(&self) -> &HashMap { + pub fn resources(&self) -> &HashMap { &self.resources } - pub fn resources_for_class(&self, class: &str) -> Option<&ChildResources> { + pub fn resources_for_class(&self, class: &ResourceClassName) -> Option<&ChildResources> { self.resources.get(class) } } @@ -71,7 +139,7 @@ impl From for ChildCaInfo { #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct ChildCaDetails { id_cert: Option, - resources: HashMap, + resources: HashMap, } impl ChildCaDetails { @@ -90,20 +158,20 @@ impl ChildCaDetails { self.id_cert = Some(id_cert); } - pub fn resources(&self) -> &HashMap { + pub fn resources(&self) -> &HashMap { &self.resources } - pub fn remove_resource(&mut self, class_name: &str) { + pub fn remove_resource(&mut self, class_name: &ResourceClassName) { self.resources.remove(class_name); } /// This function will update the resource entitlements for an existing class /// or create a new class if needed - pub fn set_resources_for_class(&mut self, class: &str, resources: ResourceSet) { - if self.resources.contains_key(class) { + pub fn set_resources_for_class(&mut self, class: ResourceClassName, resources: ResourceSet) { + if self.resources.contains_key(&class) { self.resources - .get_mut(class) + .get_mut(&class) .unwrap() .set_resources(resources); } else { @@ -111,16 +179,15 @@ impl ChildCaDetails { } } - pub fn resources_for_class(&self, class: &str) -> Option<&ChildResources> { + pub fn resources_for_class(&self, class: &ResourceClassName) -> Option<&ChildResources> { self.resources.get(class) } - pub fn add_new_resource_class(&mut self, name: &str, resources: ResourceSet) { - self.resources - .insert(name.to_string(), ChildResources::new(resources)); + pub fn add_new_resource_class(&mut self, name: ResourceClassName, resources: ResourceSet) { + self.resources.insert(name, ChildResources::new(resources)); } - pub fn add_cert(&mut self, class_name: &str, cert: IssuedCert) { + pub fn add_cert(&mut self, class_name: &ResourceClassName, cert: IssuedCert) { // Note the resource class MUST exist, or no cert would have // been issued to it. So, it's safe to unwrap here. self.resources.get_mut(class_name).unwrap().add_cert(cert) @@ -1568,18 +1635,21 @@ impl CertAuthInfo { #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct ParentCaInfo { contact: ParentCaContact, - resources: HashMap, + resources: HashMap, } impl ParentCaInfo { - pub fn new(contact: ParentCaContact, resources: HashMap) -> Self { + pub fn new( + contact: ParentCaContact, + resources: HashMap, + ) -> Self { ParentCaInfo { contact, resources } } pub fn contact(&self) -> &ParentCaContact { &self.contact } - pub fn resources(&self) -> &HashMap { + pub fn resources(&self) -> &HashMap { &self.resources } } diff --git a/commons/src/api/provisioning.rs b/commons/src/api/provisioning.rs index 7c1789f4..10cabde9 100644 --- a/commons/src/api/provisioning.rs +++ b/commons/src/api/provisioning.rs @@ -5,11 +5,9 @@ use rpki::resources::{AsBlocks, IpBlocks}; use rpki::uri; use rpki::x509::Time; -use crate::api::ca::{IssuedCert, RcvdCert, ResourceSet}; +use crate::api::ca::{IssuedCert, RcvdCert, ResourceClassName, ResourceSet}; use crate::util::ext_serde; -pub const DFLT_CLASS: &str = "all"; - //------------ ProvisioningRequest ------------------------------------------- #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] @@ -51,10 +49,9 @@ impl Entitlements { not_after: Time, issued: Vec, ) -> Self { - let name = DFLT_CLASS.to_string(); Entitlements { classes: vec![EntitlementClass { - class_name: name, + class_name: ResourceClassName::default(), issuer, resource_set, not_after, @@ -75,7 +72,7 @@ impl Entitlements { #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct EntitlementClass { - class_name: String, + class_name: ResourceClassName, issuer: SigningCert, resource_set: ResourceSet, not_after: Time, @@ -84,7 +81,7 @@ pub struct EntitlementClass { impl EntitlementClass { pub fn new( - class_name: String, + class_name: ResourceClassName, issuer: SigningCert, resource_set: ResourceSet, not_after: Time, @@ -99,7 +96,15 @@ impl EntitlementClass { } } - fn unwrap(self) -> (String, SigningCert, ResourceSet, Time, Vec) { + fn unwrap( + self, + ) -> ( + ResourceClassName, + SigningCert, + ResourceSet, + Time, + Vec, + ) { ( self.class_name, self.issuer, @@ -108,18 +113,23 @@ impl EntitlementClass { self.issued, ) } - pub fn class_name(&self) -> &str { + + pub fn class_name(&self) -> &ResourceClassName { &self.class_name } + pub fn issuer(&self) -> &SigningCert { &self.issuer } + pub fn resource_set(&self) -> &ResourceSet { &self.resource_set } + pub fn not_after(&self) -> Time { self.not_after } + pub fn issued(&self) -> &Vec { &self.issued } @@ -184,13 +194,13 @@ impl From<&RcvdCert> for SigningCert { /// defined in section 3.4.1 of RFC6492. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct IssuanceRequest { - class_name: String, + class_name: ResourceClassName, limit: RequestResourceLimit, csr: Csr, } impl IssuanceRequest { - pub fn new(class_name: String, limit: RequestResourceLimit, csr: Csr) -> Self { + pub fn new(class_name: ResourceClassName, limit: RequestResourceLimit, csr: Csr) -> Self { IssuanceRequest { class_name, limit, @@ -198,11 +208,11 @@ impl IssuanceRequest { } } - pub fn unwrap(self) -> (String, RequestResourceLimit, Csr) { + pub fn unwrap(self) -> (ResourceClassName, RequestResourceLimit, Csr) { (self.class_name, self.limit, self.csr) } - pub fn class_name(&self) -> &str { + pub fn class_name(&self) -> &ResourceClassName { &self.class_name } pub fn limit(&self) -> &RequestResourceLimit { @@ -232,7 +242,7 @@ impl Eq for IssuanceRequest {} /// it includes the one certificate which has just been issued only. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct IssuanceResponse { - class_name: String, + class_name: ResourceClassName, issuer: SigningCert, resource_set: ResourceSet, // resources allowed on a cert not_after: Time, @@ -241,7 +251,7 @@ pub struct IssuanceResponse { impl IssuanceResponse { pub fn new( - class_name: String, + class_name: ResourceClassName, issuer: SigningCert, resource_set: ResourceSet, // resources allowed on a cert not_after: Time, @@ -256,22 +266,26 @@ impl IssuanceResponse { } } - pub fn unwrap(self) -> (String, SigningCert, ResourceSet, IssuedCert) { + pub fn unwrap(self) -> (ResourceClassName, SigningCert, ResourceSet, IssuedCert) { (self.class_name, self.issuer, self.resource_set, self.issued) } - pub fn class_name(&self) -> &str { + pub fn class_name(&self) -> &ResourceClassName { &self.class_name } + pub fn issuer(&self) -> &SigningCert { &self.issuer } + pub fn resource_set(&self) -> &ResourceSet { &self.resource_set } + pub fn not_after(&self) -> Time { self.not_after } + pub fn issued(&self) -> &IssuedCert { &self.issued } @@ -354,16 +368,16 @@ impl Default for RequestResourceLimit { /// defined in section 3.5.1 of RFC6492. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct RevocationRequest { - class_name: String, + class_name: ResourceClassName, key: KeyIdentifier, } impl RevocationRequest { - pub fn new(class_name: String, key: KeyIdentifier) -> Self { + pub fn new(class_name: ResourceClassName, key: KeyIdentifier) -> Self { RevocationRequest { class_name, key } } - pub fn class_name(&self) -> &str { + pub fn class_name(&self) -> &ResourceClassName { &self.class_name } pub fn key(&self) -> &KeyIdentifier { @@ -377,20 +391,20 @@ impl RevocationRequest { /// defined in section 3.5.2 of RFC6492. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct RevocationResponse { - class_name: String, + class_name: ResourceClassName, key: KeyIdentifier, } impl RevocationResponse { - pub fn new(class_name: String, key: KeyIdentifier) -> Self { + pub fn new(class_name: ResourceClassName, key: KeyIdentifier) -> Self { RevocationResponse { class_name, key } } - pub fn unpack(self) -> (String, KeyIdentifier) { + pub fn unpack(self) -> (ResourceClassName, KeyIdentifier) { (self.class_name, self.key) } - pub fn class_name(&self) -> &str { + pub fn class_name(&self) -> &ResourceClassName { &self.class_name } pub fn key(&self) -> &KeyIdentifier { diff --git a/commons/src/remote/rfc6492.rs b/commons/src/remote/rfc6492.rs index 0e37fe38..182acdaf 100644 --- a/commons/src/remote/rfc6492.rs +++ b/commons/src/remote/rfc6492.rs @@ -13,7 +13,7 @@ use rpki::uri; use rpki::x509::Time; use crate::api::admin::Handle; -use crate::api::ca::{IssuedCert, ResSetErr, ResourceSet}; +use crate::api::ca::{IssuedCert, ResSetErr, ResourceClassName, ResourceSet}; use crate::api::{ EntitlementClass, Entitlements, IssuanceRequest, IssuanceResponse, RequestResourceLimit, RevocationRequest, RevocationResponse, SigningCert, @@ -296,7 +296,7 @@ impl Qry { R: io::Read, { r.take_named_element("key", |mut a, _r| { - let class_name = a.take_req("class_name")?; + let class_name = ResourceClassName::from(a.take_req("class_name")?); let ski = a.take_req("ski")?; let ski_bytes = base64::decode_config(&ski, base64::URL_SAFE_NO_PAD) .map_err(|_| Error::InvalidSki)?; @@ -305,7 +305,7 @@ impl Qry { let ski = KeyIdentifier::try_from(ski_bytes.as_slice()).map_err(|_| Error::InvalidSki)?; - Ok(RevocationRequest::new(class_name.to_string(), ski)) + Ok(RevocationRequest::new(class_name, ski)) }) } @@ -314,7 +314,7 @@ impl Qry { R: io::Read, { r.take_named_element("request", |mut a, r| { - let class_name = a.take_req("class_name")?; + let class_name = ResourceClassName::from(a.take_req("class_name")?); let mut limit = RequestResourceLimit::default(); if let Some(asn) = a.take_opt("req_resource_set_as") { @@ -335,7 +335,7 @@ impl Qry { let csr_bytes = r.take_bytes_std()?; let csr = Csr::decode(csr_bytes).map_err(|_| Error::InvalidCsr)?; - Ok(IssuanceRequest::new(class_name.to_string(), limit, csr)) + Ok(IssuanceRequest::new(class_name, limit, csr)) }) } } @@ -372,9 +372,9 @@ impl Qry { if let Some(v6) = limit.v6() { attrs_strings.push(("req_resource_set_ipv6", v6.as_v6().to_string())); } + attrs_strings.push(("class_name", class_name.to_string())); - let mut attrs_str = vec![]; - attrs_str.push(("class_name", class_name)); + let mut attrs_str: Vec<(&str, &str)> = vec![]; for (k, v) in &attrs_strings { attrs_str.push((k, v.as_str())); } @@ -388,9 +388,13 @@ impl Qry { rev: &RevocationRequest, w: &mut XmlWriter, ) -> Result<(), io::Error> { + let class_name = rev.class_name().to_string(); let bytes = rev.key().as_slice(); let encoded = base64::encode_config(bytes, base64::URL_SAFE_NO_PAD); - let att = [("class_name", rev.class_name()), ("ski", encoded.as_str())]; + let att = [ + ("class_name", class_name.as_str()), + ("ski", encoded.as_str()), + ]; w.put_element("key", Some(&att), |w| w.empty()) } } @@ -453,7 +457,7 @@ impl Res { R: io::Read, { r.take_named_element("class", |mut a, r| { - let name = a.take_req("class_name")?; + let name = ResourceClassName::from(a.take_req("class_name")?); let cert_url = uri::Rsync::from_str(&a.take_req("cert_url")?)?; let asn = a.take_req("resource_set_as")?; @@ -503,7 +507,7 @@ impl Res { { r.take_opt_element(|t, mut a, r| match t.name.as_ref() { "class" => { - let name = a.take_req("class_name")?; + let name = ResourceClassName::from(a.take_req("class_name")?); let cert_url = uri::Rsync::from_str(&a.take_req("cert_url")?)?; let asn = a.take_req("resource_set_as")?; @@ -666,7 +670,7 @@ impl Res { } fn encode_class<'a, W: io::Write>( - class_name: &str, + class_name: &ResourceClassName, cert_url: &uri::Rsync, not_after: Time, inrs: &ResourceSet, @@ -675,6 +679,7 @@ impl Res { w: &mut XmlWriter, ) -> Result<(), io::Error> { let cert_url = cert_url.to_string(); + let class_name = class_name.to_string(); let not_after = not_after.to_rfc3339_opts(SecondsFormat::Secs, true); let asn = inrs.asn().to_string(); @@ -684,7 +689,7 @@ impl Res { let mut attrs = vec![]; attrs.push(("cert_url", cert_url.as_str())); - attrs.push(("class_name", class_name)); + attrs.push(("class_name", class_name.as_str())); attrs.push(("resource_set_as", asn.as_str())); attrs.push(("resource_set_ipv4", v4.as_str())); attrs.push(("resource_set_ipv6", v6.as_str())); @@ -749,9 +754,13 @@ impl Res { res: &RevocationResponse, w: &mut XmlWriter, ) -> Result<(), io::Error> { + let class_name = res.class_name().to_string(); let bytes = res.key().as_slice(); let encoded = base64::encode_config(bytes, base64::URL_SAFE_NO_PAD); - let att = [("class_name", res.class_name()), ("ski", encoded.as_str())]; + let att = [ + ("class_name", class_name.as_str()), + ("ski", encoded.as_str()), + ]; w.put_element("key", Some(&att), |w| w.empty()) } } @@ -818,6 +827,7 @@ impl NotPerformedResponse { 2001, "Internal Server Error - Request not performed", )), + _ => Err(Error::InvalidErrorCode(code.to_string())), } } @@ -1043,7 +1053,7 @@ mod tests { let sender = "child".to_string(); let rcpt = "parent".to_string(); - let class = "all".to_string(); + let class = ResourceClassName::default(); let ski = cert.subject_public_key_info().key_identifier(); let revocation = RevocationRequest::new(class, ski); @@ -1063,7 +1073,7 @@ mod tests { let sender = "child".to_string(); let rcpt = "parent".to_string(); - let class = "all".to_string(); + let class = ResourceClassName::default(); let ski = cert.subject_public_key_info().key_identifier(); let revocation = RevocationResponse::new(class, ski); diff --git a/daemon/src/ca/certauth.rs b/daemon/src/ca/certauth.rs index dbac689c..7cf07021 100644 --- a/daemon/src/ca/certauth.rs +++ b/daemon/src/ca/certauth.rs @@ -15,12 +15,12 @@ use krill_commons::api::admin::{ }; use krill_commons::api::ca::{ AddedObject, CertAuthInfo, ChildCaDetails, CurrentObject, IssuedCert, ObjectName, ObjectsDelta, - ParentCaInfo, PublicationDelta, RcvdCert, ReplacedObject, RepoInfo, ResourceSet, Revocation, - TrustAnchorInfo, UpdatedObject, WithdrawnObject, + ParentCaInfo, PublicationDelta, RcvdCert, ReplacedObject, RepoInfo, ResourceClassName, + ResourceSet, Revocation, TrustAnchorInfo, UpdatedObject, WithdrawnObject, }; use krill_commons::api::{ self, EntitlementClass, Entitlements, IssuanceRequest, IssuanceResponse, RequestResourceLimit, - RevocationRequest, RevocationResponse, SigningCert, DFLT_CLASS, + RevocationRequest, RevocationResponse, SigningCert, }; use krill_commons::eventsourcing::{Aggregate, StoredEvent}; use krill_commons::remote::builder::{IdCertBuilder, SignedMessageBuilder}; @@ -33,7 +33,7 @@ use krill_commons::util::softsigner::KeyId; use crate::ca::signing::CertSiaInfo; use crate::ca::{ self, ta_handle, ChildHandle, Cmd, CmdDet, Error, Evt, EvtDet, Ini, ParentHandle, - ResourceClass, ResourceClassName, Result, SignSupport, Signer, Ta, + ResourceClass, Result, SignSupport, Signer, Ta, }; //------------ Rfc8183Id --------------------------------------------------- @@ -138,11 +138,11 @@ impl Aggregate for CertAuth { } EvtDet::ChildUpdatedResourceClass(child, class, resources) => { let child = self.children.get_mut(&child).unwrap(); - child.set_resources_for_class(&class, resources) + child.set_resources_for_class(class, resources) } EvtDet::ChildRemovedResourceClass(child, name) => { let child = self.children.get_mut(&child).unwrap(); - child.remove_resource(name.as_str()); + child.remove_resource(&name); } //----------------------------------------------------------------------- @@ -260,7 +260,10 @@ impl CertAuth { } .ok_or_else(|| Error::NotTa)?; - let rc = ta.resources().get("all").ok_or_else(|| Error::NotTa)?; + let rc = ta + .resources() + .get(&ResourceClassName::default()) + .ok_or_else(|| Error::NotTa)?; let cert = rc.current_certificate().ok_or_else(|| Error::NotTa)?; let resources = cert.resources().clone(); @@ -309,7 +312,7 @@ impl CertAuth { /// Gets the resource class by name, if it exists, under any parent // TODO: Ensure that we have unique resource class names internally - fn resource_class(&self, class_name: &str) -> Option<&ResourceClass> { + fn resource_class(&self, class_name: &ResourceClassName) -> Option<&ResourceClass> { for parent in self.parents.values() { if let Some(rc) = parent.resources().get(class_name) { return Some(rc); @@ -318,7 +321,7 @@ impl CertAuth { None } - fn resource_class_mut(&mut self, class_name: &str) -> Option<&mut ResourceClass> { + fn resource_class_mut(&mut self, class_name: &ResourceClassName) -> Option<&mut ResourceClass> { for parent in self.parents.values_mut() { if let Ok(rc) = parent.class_mut(class_name) { return Some(rc); @@ -327,7 +330,7 @@ impl CertAuth { None } - fn get_resource_class(&self, class_name: &str) -> Result<&ResourceClass> { + fn get_resource_class(&self, class_name: &ResourceClassName) -> Result<&ResourceClass> { self.resource_class(class_name) .ok_or_else(|| Error::MissingResourceClass) } @@ -365,7 +368,7 @@ impl CertAuth { pub fn list(&self, child_handle: &Handle) -> Result { // TODO: Support arbitrary resource classes. See issue #25. let mut classes = vec![]; - if let Some(class) = self.entitlement_class(child_handle, DFLT_CLASS) { + if let Some(class) = self.entitlement_class(child_handle, &ResourceClassName::default()) { classes.push(class); } @@ -377,7 +380,7 @@ impl CertAuth { pub fn issuance_response( &self, child_handle: &Handle, - class_name: &str, + class_name: &ResourceClassName, pub_key: &PublicKey, ) -> Result { let entitlement_class = self @@ -393,7 +396,7 @@ impl CertAuth { fn entitlement_class( &self, child_handle: &Handle, - class_name: &str, + class_name: &ResourceClassName, ) -> Option { let child = match self.get_child(child_handle) { Ok(child) => child, @@ -424,7 +427,7 @@ impl CertAuth { let cert = SigningCert::new(my_rcvd_cert.uri().clone(), my_rcvd_cert.cert().clone()); Some(EntitlementClass::new( - class_name.to_string(), + class_name.clone(), cert, child_resources.resources().clone(), until, @@ -480,7 +483,7 @@ impl CertAuth { fn child_resource_classes_entitlements( &self, child_resources: ResourceSet, - ) -> Result> { + ) -> Result> { let mut map = HashMap::new(); let mut matched_resources = ResourceSet::default(); @@ -490,7 +493,7 @@ impl CertAuth { let resources = rcvd_cert.resources().intersection(&child_resources); if !resources.is_empty() { matched_resources = matched_resources.union(&resources); - map.insert(name, resources); + map.insert(name.clone(), resources); } } } @@ -577,7 +580,7 @@ impl CertAuth { limit: RequestResourceLimit, signer: &S, ) -> Result { - let my_rc = self.get_resource_class(class_name.as_str())?; + let my_rc = self.get_resource_class(&class_name)?; let issuing_key = my_rc.get_current_key()?; let issuing_cert = issuing_key.incoming_cert(); @@ -664,7 +667,7 @@ impl CertAuth { /// for updating child certificates. pub fn update_published_child_certificates( &self, - class_name: &str, + class_name: &ResourceClassName, issued_certs: Vec<&IssuedCert>, removed_certs: Vec<&Cert>, signer: Arc>, @@ -860,7 +863,7 @@ impl CertAuth { // Determine for each entitlement whether the current is changed, or a new // resource class can be added. for (class_name, entitled_resource_set) in child_entitlements.into_iter() { - if match child_resources.remove(class_name) { + if match child_resources.remove(&class_name) { None => true, Some(current_resources) => current_resources != &entitled_resource_set, } { @@ -868,7 +871,7 @@ impl CertAuth { &self.handle, version, child_handle.clone(), - class_name.clone(), + class_name, entitled_resource_set, )); version += 1; @@ -902,7 +905,8 @@ impl CertAuth { signer: Arc>, ) -> ca::Result> { // verify child and resources - let class_name = request.class_name().to_string(); + let class_name = request.class_name().clone(); + let child_resources = self .get_child(&child)? .resources_for_class(&class_name) @@ -1075,14 +1079,14 @@ impl CertAuth { // from the entitlements. In which case we will have to clean them // up and un-publish everything there was. let current_resource_classes = &parent.resources; - let entitled_classes: Vec<&str> = entitlements + let entitled_classes: Vec<&ResourceClassName> = entitlements .classes() .iter() .map(|c| c.class_name()) .collect(); for (name, class) in current_resource_classes .iter() - .filter(|(name, _class)| !entitled_classes.contains(&name.as_str())) + .filter(|(name, _class)| !entitled_classes.contains(name)) { let signer = signer.read().unwrap(); @@ -1140,7 +1144,7 @@ impl CertAuth { &self.handle, rc_add_version, parent_handle.clone(), - name.to_string(), + name.clone(), rc, ); @@ -1272,7 +1276,7 @@ impl CertAuth { let rc = parent .resources() .get(&class_name) - .ok_or_else(|| Error::UnknownResourceClass(class_name.clone()))?; + .ok_or_else(|| Error::unknown_resource_class(&class_name))?; let finish_details = rc.keyroll_finish(parent_h, class_name, &self.base_repo)?; @@ -1337,7 +1341,7 @@ impl ParentCa { let (key, tal) = ta.unpack(); let contact = ParentCaContact::Ta(tal); let mut resources = HashMap::new(); - resources.insert("all".to_string(), ResourceClass::for_ta(key)); + resources.insert(ResourceClassName::default(), ResourceClass::for_ta(key)); ParentCa { contact, resources } } @@ -1360,13 +1364,13 @@ impl ParentCa { &self.contact } - fn class(&self, class_name: &str) -> Result<&ResourceClass> { + fn class(&self, class_name: &ResourceClassName) -> Result<&ResourceClass> { self.resources .get(class_name) .ok_or_else(|| Error::UnknownResourceClass(class_name.to_string())) } - fn class_mut(&mut self, class_name: &str) -> Result<&mut ResourceClass> { + fn class_mut(&mut self, class_name: &ResourceClassName) -> Result<&mut ResourceClass> { self.resources .get_mut(class_name) .ok_or_else(|| Error::UnknownResourceClass(class_name.to_string())) diff --git a/daemon/src/ca/commands.rs b/daemon/src/ca/commands.rs index f3bb3ec3..2848dc01 100644 --- a/daemon/src/ca/commands.rs +++ b/daemon/src/ca/commands.rs @@ -3,12 +3,12 @@ use std::sync::{Arc, RwLock}; use chrono::Duration; use krill_commons::api::admin::{Handle, ParentCaContact, UpdateChildRequest}; -use krill_commons::api::ca::{RcvdCert, ResourceSet}; +use krill_commons::api::ca::{RcvdCert, ResourceClassName, ResourceSet}; use krill_commons::api::{Entitlements, IssuanceRequest, RevocationRequest, RevocationResponse}; use krill_commons::eventsourcing; use krill_commons::remote::id::IdCert; -use crate::ca::{ChildHandle, Evt, ParentHandle, ResourceClassName, Signer}; +use crate::ca::{ChildHandle, Evt, ParentHandle, Signer}; //------------ Command ----------------------------------------------------- diff --git a/daemon/src/ca/error.rs b/daemon/src/ca/error.rs index 94ae4e3c..2c90393f 100644 --- a/daemon/src/ca/error.rs +++ b/daemon/src/ca/error.rs @@ -89,6 +89,10 @@ impl Error { pub fn invalid_csr(handle: &Handle, msg: &str) -> Self { Error::InvalidCsr(handle.clone(), msg.to_string()) } + + pub fn unknown_resource_class(class: impl Display) -> Self { + Error::UnknownResourceClass(class.to_string()) + } } impl std::error::Error for Error {} diff --git a/daemon/src/ca/events.rs b/daemon/src/ca/events.rs index 2a5b288b..ceb681d2 100644 --- a/daemon/src/ca/events.rs +++ b/daemon/src/ca/events.rs @@ -10,8 +10,8 @@ use rpki::x509::{Serial, Time, Validity}; use krill_commons::api::admin::{Handle, ParentCaContact, Token}; use krill_commons::api::ca::{ - CertifiedKey, ChildCaDetails, ObjectsDelta, PublicationDelta, RcvdCert, RepoInfo, ResourceSet, - TrustAnchorLocator, + CertifiedKey, ChildCaDetails, ObjectsDelta, PublicationDelta, RcvdCert, RepoInfo, + ResourceClassName, ResourceSet, TrustAnchorLocator, }; use krill_commons::api::{ IssuanceRequest, IssuanceResponse, RevocationRequest, RevocationResponse, @@ -21,9 +21,7 @@ use krill_commons::remote::id::IdCert; use krill_commons::util::softsigner::KeyId; use crate::ca::signing::Signer; -use crate::ca::{ - ChildHandle, Error, ParentHandle, ResourceClass, ResourceClassName, Result, Rfc8183Id, -}; +use crate::ca::{ChildHandle, Error, ParentHandle, ResourceClass, Result, Rfc8183Id}; //------------ TaIniDetails -------------------------------------------------- diff --git a/daemon/src/ca/mod.rs b/daemon/src/ca/mod.rs index cf4f3b20..6b52914e 100644 --- a/daemon/src/ca/mod.rs +++ b/daemon/src/ca/mod.rs @@ -35,7 +35,6 @@ pub type Result = std::result::Result; pub type ServerResult = std::result::Result>; pub type ParentHandle = Handle; pub type ChildHandle = Handle; -pub type ResourceClassName = String; pub const TA_NAME: &str = "ta"; // reserved for TA diff --git a/daemon/src/ca/rc.rs b/daemon/src/ca/rc.rs index b3953fdf..82debcb8 100644 --- a/daemon/src/ca/rc.rs +++ b/daemon/src/ca/rc.rs @@ -3,6 +3,7 @@ use std::ops::Deref; use std::sync::{Arc, RwLock}; use chrono::Duration; +use serde::{Deserialize, Serialize}; use rpki::crypto::PublicKeyFormat; use rpki::csr::Csr; @@ -11,17 +12,16 @@ use rpki::x509::Time; use krill_commons::api::ca::{ CertifiedKey, CurrentObjects, KeyRef, ObjectsDelta, OldKey, PendingKey, PublicationDelta, - RcvdCert, RepoInfo, ResourceClassInfo, ResourceClassKeysInfo, + RcvdCert, RepoInfo, ResourceClassInfo, ResourceClassKeysInfo, ResourceClassName, }; use krill_commons::api::{ EntitlementClass, IssuanceRequest, RequestResourceLimit, RevocationRequest, }; use krill_commons::util::softsigner::KeyId; -use crate::ca::{ - self, Error, EvtDet, ParentHandle, ResourceClassName, Result, SignSupport, Signer, -}; -use ca::TA_NAME; +use crate::ca::{self, Error, EvtDet, ParentHandle, Result, SignSupport, Signer, TA_NAME}; + +//------------ ResourceClass ----------------------------------------------- /// A CA may have multiple parents, e.g. two RIRs, and it may not get all its /// resource entitlements in one set, but in a number of so-called "resource @@ -650,7 +650,7 @@ impl ResourceClassKeys { let req = self.create_issuance_req( base_repo, name_space, - entitlement.class_name(), + entitlement.class_name().clone(), key_id, signer, )?; @@ -715,7 +715,7 @@ impl ResourceClassKeys { &self, base_repo: &RepoInfo, name_space: &str, - class_name: &str, + class_name: ResourceClassName, key: &KeyId, signer: &S, ) -> Result { @@ -733,7 +733,7 @@ impl ResourceClassKeys { let csr = Csr::decode(enc.as_slice()).map_err(Error::signer)?; Ok(IssuanceRequest::new( - class_name.to_string(), + class_name, RequestResourceLimit::default(), csr, )) @@ -779,15 +779,16 @@ impl ResourceClassKeys { .map_err(Error::signer)? }; - let issuance_req = - self.create_issuance_req(base_repo, name_space, &class_name, &key_id, signer)?; + let issuance_req = self.create_issuance_req( + base_repo, + name_space, + class_name.clone(), + &key_id, + signer, + )?; Ok(vec![ - EvtDet::KeyRollPendingKeyAdded( - parent.clone(), - class_name.clone(), - key_id.clone(), - ), + EvtDet::KeyRollPendingKeyAdded(parent.clone(), class_name, key_id.clone()), EvtDet::CertificateRequested(parent, issuance_req, key_id), ]) } diff --git a/daemon/src/ca/server.rs b/daemon/src/ca/server.rs index ef1be887..2fc68a34 100644 --- a/daemon/src/ca/server.rs +++ b/daemon/src/ca/server.rs @@ -13,11 +13,10 @@ use krill_commons::api::admin::{ UpdateChildRequest, }; use krill_commons::api::ca::{ - CertAuthList, CertAuthSummary, ChildCaInfo, IssuedCert, RcvdCert, RepoInfo, + CertAuthList, CertAuthSummary, ChildCaInfo, IssuedCert, RcvdCert, RepoInfo, ResourceClassName, }; use krill_commons::api::{ Entitlements, IssuanceRequest, IssuanceResponse, RevocationRequest, RevocationResponse, - DFLT_CLASS, }; use krill_commons::eventsourcing::{Aggregate, AggregateStore, DiskAggregateStore}; use krill_commons::remote::builder::SignedMessageBuilder; @@ -27,8 +26,8 @@ use krill_commons::util::httpclient; use krill_commons::util::softsigner::KeyId; use crate::ca::{ - self, ta_handle, CertAuth, ChildHandle, CmdDet, IniDet, ParentHandle, ResourceClassName, - ServerError, ServerResult, Signer, + self, ta_handle, CertAuth, ChildHandle, CmdDet, IniDet, ParentHandle, ServerError, + ServerResult, Signer, }; use crate::mq::EventQueueListener; @@ -286,7 +285,7 @@ impl CaServer { let class_name = issue_req.class_name(); let pub_key = issue_req.csr().public_key(); - if class_name != DFLT_CLASS { + if class_name != &ResourceClassName::default() { unimplemented!("Issue for multiple classes from CAs, issue #25") } @@ -603,10 +602,10 @@ impl CaServer { ) -> ServerResult, S> { let mut parent = self.ca_store.get_latest(parent_h)?; - let mut issued_certs: Vec<(String, IssuedCert)> = vec![]; + let mut issued_certs: Vec<(ResourceClassName, IssuedCert)> = vec![]; for req in requests.into_iter() { - let class_name = req.class_name().to_string(); + let class_name = req.class_name().clone(); let pub_key = req.csr().public_key().clone(); let cmd = CmdDet::child_certify(parent_h, handle.clone(), req, self.signer.clone()); @@ -787,7 +786,7 @@ mod tests { use ca::EvtDet; use krill_commons::api::admin::{Handle, ParentCaContact, Token}; use krill_commons::api::ca::{RcvdCert, RepoInfo, ResourceSet}; - use krill_commons::api::{IssuanceRequest, DFLT_CLASS}; + use krill_commons::api::IssuanceRequest; use krill_commons::eventsourcing::{Aggregate, AggregateStore, DiskAggregateStore}; use krill_commons::util::softsigner::OpenSslSigner; use krill_commons::util::test; @@ -943,7 +942,7 @@ mod tests { }; let (class_name, limit, csr) = issuance_req.unwrap(); - assert_eq!("all", &class_name); + assert_eq!(ResourceClassName::default(), class_name); assert!(limit.is_empty()); // @@ -954,7 +953,7 @@ mod tests { // - Publication // - let request = IssuanceRequest::new(DFLT_CLASS.to_string(), limit, csr); + let request = IssuanceRequest::new(ResourceClassName::default(), limit, csr); let ta_cmd = CmdDet::child_certify(&ta_handle, child_handle.clone(), request, signer.clone()); @@ -970,7 +969,7 @@ mod tests { let (class_name, _, _, issued) = issuance_res.unwrap(); assert_eq!(child_handle, handle); - assert_eq!(DFLT_CLASS, class_name); + assert_eq!(ResourceClassName::default(), class_name); // // --- Return issued certificate to child CA @@ -984,7 +983,7 @@ mod tests { let upd_rcvd = CmdDet::upd_received_cert( &child_handle, ta_handle, - DFLT_CLASS.to_string(), + ResourceClassName::default(), rcvd_cert, signer.clone(), ); diff --git a/daemon/src/test.rs b/daemon/src/test.rs index 9db4718f..7dc7fb64 100644 --- a/daemon/src/test.rs +++ b/daemon/src/test.rs @@ -11,7 +11,7 @@ use krill_commons::api::admin::{ AddChildRequest, AddParentRequest, CertAuthInit, CertAuthPubMode, ChildAuthRequest, Handle, ParentCaContact, Token, UpdateChildRequest, }; -use krill_commons::api::ca::{CertAuthInfo, ResourceClassKeysInfo, ResourceSet}; +use krill_commons::api::ca::{CertAuthInfo, ResourceClassKeysInfo, ResourceClassName, ResourceSet}; use krill_commons::remote::rfc8183; use krill_commons::util::test; @@ -192,7 +192,7 @@ pub fn wait_for_new_key(handle: &Handle) { wait_for(30, "No new key received", move || { let ca = ca_details(handle); if let Some(parent) = ca.parent(&ta_handle()) { - if let Some(rc) = parent.resources().get("all") { + if let Some(rc) = parent.resources().get(&ResourceClassName::default()) { match rc.keys() { ResourceClassKeysInfo::RollNew(new, _) => { return new.current_set().number() == 2 @@ -211,7 +211,7 @@ pub fn wait_for_key_roll_complete(handle: &Handle) { let ca = ca_details(handle); if let Some(parent) = ca.parent(&ta_handle()) { - if let Some(rc) = parent.resources().get("all") { + if let Some(rc) = parent.resources().get(&ResourceClassName::default()) { match rc.keys() { ResourceClassKeysInfo::Active(_) => return true, _ => return false, @@ -228,7 +228,10 @@ pub fn wait_for_resource_class_to_disappear(handle: &Handle) { let ca = ca_details(handle); if let Some(parent) = ca.parent(&ta_handle()) { - return parent.resources().get("all").is_none(); + return parent + .resources() + .get(&ResourceClassName::default()) + .is_none(); } false @@ -249,7 +252,7 @@ pub fn ta_issued_certs() -> usize { pub fn ta_issued_resources(child: &Handle) -> ResourceSet { let ta = ca_details(&ta_handle()); let child = ta.children().get(child).unwrap(); - if let Some(resources) = child.resources().get("all") { + if let Some(resources) = child.resources().get(&ResourceClassName::default()) { if let Some(cert) = resources.certs_iter().next() { return cert.resource_set().clone(); // for our testing the first will do } @@ -261,7 +264,7 @@ pub fn ca_current_resources(handle: &Handle) -> ResourceSet { let ca = ca_details(handle); if let Some(parent) = ca.parent(&ta_handle()) { - if let Some(rc) = parent.resources().get("all") { + if let Some(rc) = parent.resources().get(&ResourceClassName::default()) { match rc.keys() { ResourceClassKeysInfo::Active(current) | ResourceClassKeysInfo::RollPending(_, current)