diff --git a/Cargo.lock b/Cargo.lock index 466dd942..01e4277f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1774,9 +1774,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.23.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bafc859c6815fbaffbbbf4229ecb767ac913fecb27f9ad4343662e9ef099ea" +checksum = "81b9228215d82c7b61490fec1de287136b5de6f5700f6e58ea9ad61a7964ca51" dependencies = [ "memchr", ] @@ -1960,16 +1960,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" -[[package]] -name = "routecore" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8e2f02d8dd21010b44bf2ca4502cca2fbb2a8ddfd982a18feff149279dc236c" -dependencies = [ - "bcder", - "serde", -] - [[package]] name = "rpassword" version = "5.0.1" @@ -1982,18 +1972,17 @@ dependencies = [ [[package]] name = "rpki" -version = "0.16.1" +version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "207f773b99ae73e14f8e8ab0f789a5892fc46548b1b79caccec8f33e2d303c40" +checksum = "98a05b958a41ba8c923cf14bd2ad5f1aca3f3509c8ffd147c36e094346a0290b" dependencies = [ - "base64 0.13.1", + "base64 0.21.0", "bcder", "bytes", "chrono", "log", "quick-xml", "ring", - "routecore", "serde", "untrusted", "uuid", diff --git a/Cargo.toml b/Cargo.toml index 76f553dc..79053520 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,7 @@ regex = { version = "1.5.5", optional = true, default_features = false, features ] } reqwest = { version = "0.11", features = ["json"] } rpassword = { version = "^5.0", optional = true } -rpki = { version = "0.16.1", features = ["ca", "compat", "rrdp"] } +rpki = { version = "0.17.2", features = ["ca", "compat", "rrdp"] } # rpki = { version = "0.16.0-dev", git = "https://github.com/nLnetLabs/rpki-rs", branch = "csr-ca-repo-trailing-slash", features = [ "ca", "compat", "rrdp" ] } scrypt = { version = "^0.6", optional = true, default-features = false } serde = { version = "^1.0", features = ["derive", "rc"] } diff --git a/src/cli/options.rs b/src/cli/options.rs index c9938e6f..8f41f985 100644 --- a/src/cli/options.rs +++ b/src/cli/options.rs @@ -19,7 +19,7 @@ use rpki::{ }, crypto::KeyIdentifier, repository::{ - aspa::{DuplicateProviderAs, ProviderAs}, + aspa::DuplicateProviderAs, resources::{Asn, ResourceSet}, x509::Time, }, @@ -30,8 +30,8 @@ use crate::{ cli::report::{ReportError, ReportFormat}, commons::{ api::{ - self, import::ImportChild, AddChildRequest, AspaCustomer, AspaDefinition, AspaDefinitionFormatError, - AspaProvidersUpdate, AuthorizationFmtError, BgpSecAsnKey, BgpSecDefinition, CertAuthInit, ParentCaReq, + self, import::ImportChild, AddChildRequest, AspaDefinition, AspaDefinitionFormatError, AspaProvidersUpdate, + AuthorizationFmtError, BgpSecAsnKey, BgpSecDefinition, CertAuthInit, CustomerAsn, ParentCaReq, ProviderAsn, PublicationServerUris, RepoFileDeleteCriteria, RoaConfiguration, RoaConfigurationUpdates, RoaPayload, RtaName, Token, UpdateChildRequest, }, @@ -823,7 +823,7 @@ impl Options { sub = sub.arg( Arg::with_name("aspa") .long("aspa") - .help("ASPA formatted like: 65000 => 65001, 65002(v4), 65003(v6)") + .help("ASPA formatted like: 65000 => 65001, 65002, 65003") .value_name("definition") .required(true), ); @@ -1979,8 +1979,6 @@ impl Options { Err(Error::general("Customer AS may not be used as provider.")) } else if aspa.contains_duplicate_providers() { Err(Error::general("ASPA may not have duplicate providers.")) - } else if !aspa.providers_has_both_afis() { - Err(Error::general("Definition has providers for one address family only. Please include an explicit AS0 provider for the missing address family if this is intentional.")) } else if aspa.providers().is_empty() { Err(Error::general("At least one provider MUST be specified.")) } else { @@ -1993,7 +1991,7 @@ impl Options { let general_args = GeneralArgs::from_matches(matches)?; let my_ca = Self::parse_my_ca(matches)?; let customer_str = matches.value_of("customer").unwrap(); - let customer = AspaCustomer::from_str(customer_str).map_err(|_| Error::invalid_asn(customer_str))?; + let customer = CustomerAsn::from_str(customer_str).map_err(|_| Error::invalid_asn(customer_str))?; let command = Command::CertAuth(CaCommand::AspasRemove(my_ca, customer)); @@ -2008,13 +2006,13 @@ impl Options { let mut removed = vec![]; let customer_str = matches.value_of("customer").unwrap(); - let customer = AspaCustomer::from_str(customer_str).map_err(|_| Error::invalid_asn(customer_str))?; + let customer = CustomerAsn::from_str(customer_str).map_err(|_| Error::invalid_asn(customer_str))?; if let Some(add) = matches.values_of("add") { for provider_str in add { - let provider = ProviderAs::from_str(provider_str).map_err(|_| Error::invalid_asn(provider_str))?; + let provider = ProviderAsn::from_str(provider_str).map_err(|_| Error::invalid_asn(provider_str))?; - if provider.provider() == customer { + if provider == customer { return Err(Error::general("Customer AS may not be added as provider.")); } @@ -2025,9 +2023,9 @@ impl Options { if let Some(remove) = matches.values_of("remove") { for provider_as_str in remove { let provider_as = - ProviderAs::from_str(provider_as_str).map_err(|_| Error::invalid_asn(provider_as_str))?; + ProviderAsn::from_str(provider_as_str).map_err(|_| Error::invalid_asn(provider_as_str))?; - if added.iter().any(|added| added.provider() == provider_as.provider()) { + if added.iter().any(|added| *added == provider_as) { return Err(Error::general("Do not add and remove the same AS in a single update.")); } @@ -2561,8 +2559,8 @@ pub enum CaCommand { // ASPAs AspasList(CaHandle), AspasAddOrReplace(CaHandle, AspaDefinition), - AspasUpdate(CaHandle, AspaCustomer, AspaProvidersUpdate), - AspasRemove(CaHandle, AspaCustomer), + AspasUpdate(CaHandle, CustomerAsn, AspaProvidersUpdate), + AspasRemove(CaHandle, CustomerAsn), // BGPSec BgpSecList(CaHandle), diff --git a/src/commons/api/aspa.rs b/src/commons/api/aspa.rs index a49e2fdf..e4fca686 100644 --- a/src/commons/api/aspa.rs +++ b/src/commons/api/aspa.rs @@ -8,23 +8,23 @@ use std::fmt; use std::str::FromStr; -use rpki::repository::aspa::*; -use rpki::repository::resources::{AddressFamily, Asn}; +use rpki::repository::resources::Asn; -pub type AspaCustomer = Asn; +pub type CustomerAsn = Asn; +pub type ProviderAsn = Asn; //------------ AspaDefinitionUpdates ------------------------------------- #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct AspaDefinitionUpdates { add_or_replace: Vec, - remove: Vec, + remove: Vec, } impl AspaDefinitionUpdates { - pub fn new(add_or_replace: Vec, remove: Vec) -> Self { + pub fn new(add_or_replace: Vec, remove: Vec) -> Self { AspaDefinitionUpdates { add_or_replace, remove } } - pub fn unpack(self) -> (Vec, Vec) { + pub fn unpack(self) -> (Vec, Vec) { (self.add_or_replace, self.remove) } } @@ -72,24 +72,24 @@ impl fmt::Display for AspaDefinitionList { #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct AspaDefinition { - customer: AspaCustomer, - providers: Vec, + customer: CustomerAsn, + providers: Vec, } impl AspaDefinition { - pub fn new(customer: AspaCustomer, providers: Vec) -> Self { + pub fn new(customer: CustomerAsn, providers: Vec) -> Self { AspaDefinition { customer, providers } } - pub fn unpack(self) -> (AspaCustomer, Vec) { + pub fn unpack(self) -> (CustomerAsn, Vec) { (self.customer, self.providers) } - pub fn customer(&self) -> AspaCustomer { + pub fn customer(&self) -> CustomerAsn { self.customer } - pub fn providers(&self) -> &Vec { + pub fn providers(&self) -> &Vec { &self.providers } @@ -97,14 +97,14 @@ impl AspaDefinition { /// This is not allowed by spec, and these definitions should /// be rejected by Krill. pub fn customer_used_as_provider(&self) -> bool { - self.providers.iter().any(|p| p.provider() == self.customer) + self.providers.contains(&self.customer) } /// Returns true if there are duplicate provider ASNs. This /// is not allowed by spec and these definitions should be /// rejected by Krill. pub fn contains_duplicate_providers(&self) -> bool { - let mut providers: Vec = self.providers.iter().map(|p| p.provider()).collect(); + let mut providers: Vec = self.providers.clone(); let len_before_duplicates = providers.len(); @@ -114,105 +114,25 @@ impl AspaDefinition { len_before_duplicates > providers.len() } - /// Returns true if this contains both IPv4 and IPv6 providers. - /// - /// Technically,it is allowed to omit one address family entirely, - /// but this will be interpreted as though the user specified an - /// AS0 provider for the omitted AFI. This may be counterintuitive, - /// so we'd better force people to make an explicit choice. - pub fn providers_has_both_afis(&self) -> bool { - let mut v4 = false; - let mut v6 = false; - for p in &self.providers { - if !v4 { - v4 = p.includes_v4(); - } - if !v6 { - v6 = p.includes_v6(); - } - - if v4 && v6 { - break; - } - } - - v4 && v6 - } - /// Applies an update. This is a no-op in case there is no /// actual change needed (i.e. this is idempotent). pub fn apply_update(&mut self, update: &AspaProvidersUpdate) { for removed in update.removed() { - // If the operators tries to remove a provider for a specific AFI limit - // only, and we have an existing provider without limit, then we should - // keep the provider with the remaining limit. - if let Some(limit) = removed.afi_limit() { - if let Some(existing) = self - .providers - .iter() - .find(|existing| existing.provider() == removed.provider()) - { - match existing.afi_limit() { - None => { - let remaining = match limit { - AddressFamily::Ipv4 => ProviderAs::new_v6(existing.provider()), - AddressFamily::Ipv6 => ProviderAs::new_v4(existing.provider()), - }; - - self.providers.retain(|p| p.provider() != remaining.provider()); - self.providers.push(remaining); - } - Some(_) => { - // retain all other ProviderAS, this will retain - // a possible ProviderAS for the removed ASN if - // its afiLimit was different. - self.providers.retain(|p| p != removed); - } - } - } - } else { - // there is no limit in the removal, we should remove any existing - // ProviderAS for the removed provider ASN regardless of limit. - self.providers - .retain(|provider| provider.provider() != removed.provider()); - } + self.providers.retain(|provider| provider != removed); } for added in update.added() { - if let Some(existing) = self - .providers - .iter() - .find(|e| e.provider() == added.provider()) - .copied() - { - // If there is any existing provider for the added, and if - // that was using an afiLimit which was different, then we - // need to merge this into an entry without a limit. - // - // In other words, if we hade provider listed for IPv4 and - // the operator now adds the same provider for IPv6, then - // we need to have this provider without afiLimit. - // - // And, if we hade provider listed for IPv4 and the operator - // now adds the same provider without afiLimit, then we need - // to have this provider without afiLimit. - if existing.afi_limit().is_some() && existing.afi_limit() != added.afi_limit() { - // remove the existing entry, then add a new entry without limit - self.providers.retain(|p| p != &existing); - self.providers.push(ProviderAs::new(added.provider())); - } - } else { - // no entry for this new provider ASN, add it as-is + if !self.providers.contains(added) { self.providers.push(*added); } } - self.providers.sort_by_key(|p| p.provider()); + self.providers.sort(); } } impl fmt::Display for AspaDefinition { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // example: 65000 => 65001, 65002(v4), 65003(v6) + // example: 65000 => 65001, 65002, 65003 write!(f, "{} => ", self.customer)?; if self.providers.is_empty() { write!(f, "")?; @@ -238,7 +158,7 @@ impl FromStr for AspaDefinition { let customer = { let customer_str = parts.next().ok_or(AspaDefinitionFormatError::CustomerAsMissing)?; - AspaCustomer::from_str(customer_str.trim()) + CustomerAsn::from_str(customer_str.trim()) .map_err(|_| AspaDefinitionFormatError::CustomerAsInvalid(customer_str.trim().to_string()))? }; @@ -249,7 +169,7 @@ impl FromStr for AspaDefinition { if providers_str.trim() != "" { let provider_parts = providers_str.split(','); for provider_part in provider_parts { - let provider = ProviderAs::from_str(provider_part.trim()) + let provider = ProviderAsn::from_str(provider_part.trim()) .map_err(|_| AspaDefinitionFormatError::ProviderAsInvalid(provider_part.trim().to_string()))?; providers.push(provider); } @@ -263,12 +183,9 @@ impl FromStr for AspaDefinition { Err(AspaDefinitionFormatError::ExtraParts) } else { // Ensure that the providers are sorted, and there are no duplicates - providers.sort_by_key(|p| p.provider()); + providers.sort(); - match providers - .windows(2) - .find(|pair| pair[0].provider() == pair[1].provider()) - { + match providers.windows(2).find(|pair| pair[0] == pair[1]) { Some(dup) => Err(AspaDefinitionFormatError::ProviderAsDuplicate(dup[0], dup[1])), None => Ok(AspaDefinition::new(customer, providers)), } @@ -283,7 +200,7 @@ pub enum AspaDefinitionFormatError { CustomerAsMissing, CustomerAsInvalid(String), ProviderAsInvalid(String), - ProviderAsDuplicate(ProviderAs, ProviderAs), + ProviderAsDuplicate(ProviderAsn, ProviderAsn), ExtraParts, } @@ -310,12 +227,12 @@ impl std::error::Error for AspaDefinitionFormatError {} /// AspaDefinition. #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct AspaProvidersUpdate { - added: Vec, - removed: Vec, + added: Vec, + removed: Vec, } impl AspaProvidersUpdate { - pub fn new(added: Vec, removed: Vec) -> Self { + pub fn new(added: Vec, removed: Vec) -> Self { AspaProvidersUpdate { added, removed } } pub fn empty() -> Self { @@ -334,19 +251,19 @@ impl AspaProvidersUpdate { } // Add a provider for both v4 and v6 - pub fn add(&mut self, provider: ProviderAs) { + pub fn add(&mut self, provider: ProviderAsn) { self.added.push(provider); } - pub fn remove(&mut self, provider: ProviderAs) { + pub fn remove(&mut self, provider: ProviderAsn) { self.removed.push(provider); } - pub fn added(&self) -> &Vec { + pub fn added(&self) -> &Vec { &self.added } - pub fn removed(&self) -> &Vec { + pub fn removed(&self) -> &Vec { &self.removed } } @@ -379,17 +296,17 @@ mod tests { Asn::from_str(s).unwrap() } - fn provider(s: &str) -> ProviderAs { - ProviderAs::from_str(s).unwrap() + fn provider(s: &str) -> ProviderAsn { + ProviderAsn::from_str(s).unwrap() } #[test] fn aspa_configuration_to_from_str() { let config = AspaDefinition::new( customer("AS65000"), - vec![provider("AS65001"), provider("AS65002(v4)"), provider("AS65003(v6)")], + vec![provider("AS65001"), provider("AS65002"), provider("AS65003")], ); - let config_str = "AS65000 => AS65001, AS65002(v4), AS65003(v6)"; + let config_str = "AS65000 => AS65001, AS65002, AS65003"; let to_str = config.to_string(); assert_eq!(config_str, to_str.as_str()); diff --git a/src/commons/api/history.rs b/src/commons/api/history.rs index e29f1e58..8289285e 100644 --- a/src/commons/api/history.rs +++ b/src/commons/api/history.rs @@ -15,7 +15,7 @@ use rpki::{ use crate::{ commons::{ api::{ - ArgKey, ArgVal, AspaCustomer, AspaProvidersUpdate, Message, RoaConfigurationUpdates, RtaName, + ArgKey, ArgVal, AspaProvidersUpdate, CustomerAsn, Message, RoaConfigurationUpdates, RtaName, StorableParentContact, }, eventsourcing::{Event, InitEvent, StoredCommand, StoredEffect, WithStorableDetails}, @@ -445,11 +445,11 @@ pub enum CertAuthStorableCommand { updates: AspaDefinitionUpdates, }, AspasUpdateExisting { - customer: AspaCustomer, + customer: CustomerAsn, update: AspaProvidersUpdate, }, AspaRemove { - customer: AspaCustomer, + customer: CustomerAsn, }, BgpSecDefinitionUpdates, // details in events RepoUpdate { diff --git a/src/commons/error.rs b/src/commons/error.rs index 998ba6be..1a2d8360 100644 --- a/src/commons/error.rs +++ b/src/commons/error.rs @@ -18,7 +18,7 @@ use rpki::{ use crate::{ commons::{ - api::{rrdp::PublicationDeltaError, AspaCustomer, ErrorResponse, RoaPayload}, + api::{rrdp::PublicationDeltaError, CustomerAsn, ErrorResponse, RoaPayload}, crypto::SignerError, eventsourcing::{AggregateStoreError, KeyValueError}, util::httpclient, @@ -288,13 +288,12 @@ pub enum Error { //----------------------------------------------------------------- // Autonomous System Provider Authorization - ASPA //----------------------------------------------------------------- - AspaCustomerAsNotEntitled(CaHandle, AspaCustomer), - AspaCustomerAlreadyPresent(CaHandle, AspaCustomer), - AspaCustomerUnknown(CaHandle, AspaCustomer), - AspaCustomerAsProvider(CaHandle, AspaCustomer), - AspaProvidersDuplicates(CaHandle, AspaCustomer), - AspaProvidersEmpty(CaHandle, AspaCustomer), - AspaProvidersSingleAfi(CaHandle, AspaCustomer), + AspaCustomerAsNotEntitled(CaHandle, CustomerAsn), + AspaCustomerAlreadyPresent(CaHandle, CustomerAsn), + AspaCustomerUnknown(CaHandle, CustomerAsn), + AspaCustomerAsProvider(CaHandle, CustomerAsn), + AspaProvidersDuplicates(CaHandle, CustomerAsn), + AspaProvidersEmpty(CaHandle, CustomerAsn), //----------------------------------------------------------------- // BGP Sec @@ -485,7 +484,6 @@ impl fmt::Display for Error { Error::AspaCustomerAsProvider(_ca, asn) => write!(f, "ASPA for customer AS '{}' cannot have that AS as provider", asn), Error::AspaProvidersDuplicates(_ca, asn) => write!(f, "ASPA for customer AS '{}' cannot have duplicate providers", asn), Error::AspaCustomerUnknown(_ca, asn) => write!(f, "No current ASPA exists for customer AS '{}'", asn), - Error::AspaProvidersSingleAfi(_ca, asn) => write!(f, "ASPA for customer AS '{}' only has providers for one address family. Please include an explicit AS0 provider for the missing address family if this is intentional.", asn), //----------------------------------------------------------------- // BGPSec @@ -914,9 +912,6 @@ impl Error { Error::AspaCustomerUnknown(ca, asn) => ErrorResponse::new("ca-aspa-unknown-customer-as", self) .with_ca(ca) .with_asn(*asn), - Error::AspaProvidersSingleAfi(ca, asn) => ErrorResponse::new("ca-aspa-providers-single-afi", self) - .with_ca(ca) - .with_asn(*asn), //----------------------------------------------------------------- // BGP Sec diff --git a/src/daemon/ca/aspa.rs b/src/daemon/ca/aspa.rs index 111f1ae2..5fc6320a 100644 --- a/src/daemon/ca/aspa.rs +++ b/src/daemon/ca/aspa.rs @@ -21,7 +21,7 @@ use rpki::{ use crate::{ commons::{ - api::{AspaCustomer, AspaDefinition, AspaProvidersUpdate, ObjectName}, + api::{AspaDefinition, AspaProvidersUpdate, CustomerAsn, ObjectName}, crypto::KrillSigner, error::Error, KrillResult, @@ -71,7 +71,7 @@ pub fn make_aspa_object( /// holds the ASN. #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] pub struct AspaDefinitions { - attestations: HashMap, + attestations: HashMap, } impl AspaDefinitions { @@ -82,12 +82,12 @@ impl AspaDefinitions { } // Remove an existing definition (if it is present) - pub fn remove(&mut self, customer: AspaCustomer) { + pub fn remove(&mut self, customer: CustomerAsn) { self.attestations.remove(&customer); } // Applies an update. This assumes that the update was verified beforehand. - pub fn apply_update(&mut self, customer: AspaCustomer, update: &AspaProvidersUpdate) { + pub fn apply_update(&mut self, customer: CustomerAsn, update: &AspaProvidersUpdate) { if let Some(current) = self.attestations.get_mut(&customer) { current.apply_update(update); @@ -114,11 +114,11 @@ impl AspaDefinitions { /// # Set operations /// impl AspaDefinitions { - pub fn get(&self, customer: AspaCustomer) -> Option<&AspaDefinition> { + pub fn get(&self, customer: CustomerAsn) -> Option<&AspaDefinition> { self.attestations.get(&customer) } - pub fn has(&self, customer: AspaCustomer) -> bool { + pub fn has(&self, customer: CustomerAsn) -> bool { self.attestations.contains_key(&customer) } @@ -135,7 +135,7 @@ impl AspaDefinitions { /// ASPA objects held by a resource class in a CA. #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] -pub struct AspaObjects(HashMap); +pub struct AspaObjects(HashMap); impl AspaObjects { pub fn make_aspa( @@ -292,7 +292,7 @@ impl AspaInfo { &self.definition } - pub fn customer(&self) -> AspaCustomer { + pub fn customer(&self) -> CustomerAsn { self.definition.customer() } diff --git a/src/daemon/ca/certauth.rs b/src/daemon/ca/certauth.rs index 9b42e787..fac304f7 100644 --- a/src/daemon/ca/certauth.rs +++ b/src/daemon/ca/certauth.rs @@ -32,10 +32,11 @@ use crate::{ commons::{ api::{ import::{ExportChild, ImportChild, ImportChildCertificate}, - AspaCustomer, AspaDefinition, AspaDefinitionList, AspaDefinitionUpdates, AspaProvidersUpdate, BgpSecAsnKey, + AspaDefinition, AspaDefinitionList, AspaDefinitionUpdates, AspaProvidersUpdate, BgpSecAsnKey, BgpSecCsrInfoList, BgpSecDefinitionUpdates, CertAuthInfo, CertAuthStorableCommand, ConfiguredRoa, - IdCertInfo, ObjectName, ParentCaContact, ReceivedCert, RepositoryContact, ResourceClassNameMapping, - Revocation, RoaConfiguration, RoaConfigurationUpdates, RtaList, RtaName, RtaPrepResponse, + CustomerAsn, IdCertInfo, ObjectName, ParentCaContact, ReceivedCert, RepositoryContact, + ResourceClassNameMapping, Revocation, RoaConfiguration, RoaConfigurationUpdates, RtaList, RtaName, + RtaPrepResponse, }, crypto::{CsrInfo, KrillSigner}, error::{Error, RoaDeltaError}, @@ -1877,10 +1878,6 @@ impl CertAuth { return Err(Error::AspaCustomerAsProvider(self.handle.clone(), customer)); } - if !aspa_config.providers_has_both_afis() { - return Err(Error::AspaProvidersSingleAfi(self.handle.clone(), customer)); - } - if aspa_config.contains_duplicate_providers() { return Err(Error::AspaProvidersDuplicates(self.handle.clone(), customer)); } @@ -1926,7 +1923,7 @@ impl CertAuth { pub fn aspas_update( &self, - customer: AspaCustomer, + customer: CustomerAsn, update: AspaProvidersUpdate, config: &Config, signer: &KrillSigner, @@ -1992,7 +1989,7 @@ impl CertAuth { /// the configured AspaDefinition. I.e. this gives us idempotence and e.g. allows /// an operator just issue a command to add a provider for a customer ASN, and /// if it was already authorised then no work is needed. - fn updated_allowed_and_needed(&self, customer: AspaCustomer, update: &AspaProvidersUpdate) -> KrillResult { + fn updated_allowed_and_needed(&self, customer: CustomerAsn, update: &AspaProvidersUpdate) -> KrillResult { // The easiest way to check this is by getting the existing definition, // or a default empty one if we did not have one, then apply the update // on a copy and verify if it's actually changed, and if so if the @@ -2018,8 +2015,6 @@ impl CertAuth { Err(Error::AspaCustomerAsNotEntitled(self.handle().clone(), customer)) } else if updated.customer_used_as_provider() { Err(Error::AspaCustomerAsProvider(self.handle().clone(), customer)) - } else if !updated.providers_has_both_afis() { - Err(Error::AspaProvidersSingleAfi(self.handle().clone(), customer)) } else { Ok(true) } diff --git a/src/daemon/ca/commands.rs b/src/daemon/ca/commands.rs index 33202ab6..df9146db 100644 --- a/src/daemon/ca/commands.rs +++ b/src/daemon/ca/commands.rs @@ -17,8 +17,8 @@ use crate::{ commons::{ actor::Actor, api::{ - import::ImportChild, AspaCustomer, AspaDefinitionUpdates, AspaProvidersUpdate, BgpSecDefinitionUpdates, - CertAuthStorableCommand, IdCertInfo, ParentCaContact, ReceivedCert, RepositoryContact, + import::ImportChild, AspaDefinitionUpdates, AspaProvidersUpdate, BgpSecDefinitionUpdates, + CertAuthStorableCommand, CustomerAsn, IdCertInfo, ParentCaContact, ReceivedCert, RepositoryContact, ResourceClassNameMapping, RoaConfigurationUpdates, RtaName, StorableRcEntitlement, }, crypto::KrillSigner, @@ -199,7 +199,7 @@ pub enum CertAuthCommandDetails { AspasUpdate(AspaDefinitionUpdates, Arc, Arc), // Updates an existing AspaProviders for the given AspaCustomer - AspasUpdateExisting(AspaCustomer, AspaProvidersUpdate, Arc, Arc), + AspasUpdateExisting(CustomerAsn, AspaProvidersUpdate, Arc, Arc), // Re-issue any and all ASPA objects which would otherwise expire in // some time (default 4 weeks, configurable). Note that this command @@ -690,7 +690,7 @@ impl CertAuthCommandDetails { pub fn aspas_update_aspa( ca: &CaHandle, - customer: AspaCustomer, + customer: CustomerAsn, update: AspaProvidersUpdate, config: Arc, signer: Arc, diff --git a/src/daemon/ca/events.rs b/src/daemon/ca/events.rs index 02754710..4aff4c7c 100644 --- a/src/daemon/ca/events.rs +++ b/src/daemon/ca/events.rs @@ -12,7 +12,7 @@ use rpki::{ use crate::{ commons::{ api::{ - AspaCustomer, AspaDefinition, AspaProvidersUpdate, BgpSecAsnKey, IdCertInfo, IssuedCertificate, ObjectName, + AspaDefinition, AspaProvidersUpdate, BgpSecAsnKey, CustomerAsn, IdCertInfo, IssuedCertificate, ObjectName, ParentCaContact, ReceivedCert, RepositoryContact, ResourceClassNameMapping, RoaAggregateKey, RtaName, SuspendedCert, UnsuspendedCert, }, @@ -236,11 +236,11 @@ pub struct AspaObjectsUpdates { updated: Vec, #[serde(skip_serializing_if = "Vec::is_empty", default)] - removed: Vec, + removed: Vec, } impl AspaObjectsUpdates { - pub fn new(updated: Vec, removed: Vec) -> Self { + pub fn new(updated: Vec, removed: Vec) -> Self { AspaObjectsUpdates { updated, removed } } @@ -255,7 +255,7 @@ impl AspaObjectsUpdates { self.updated.push(update) } - pub fn add_removed(&mut self, customer: AspaCustomer) { + pub fn add_removed(&mut self, customer: CustomerAsn) { self.removed.push(customer) } @@ -267,7 +267,7 @@ impl AspaObjectsUpdates { !self.is_empty() } - pub fn unpack(self) -> (Vec, Vec) { + pub fn unpack(self) -> (Vec, Vec) { (self.updated, self.removed) } @@ -275,7 +275,7 @@ impl AspaObjectsUpdates { &self.updated } - pub fn removed(&self) -> &Vec { + pub fn removed(&self) -> &Vec { &self.removed } } @@ -588,11 +588,11 @@ pub enum CertAuthEvent { aspa_config: AspaDefinition, }, AspaConfigUpdated { - customer: AspaCustomer, + customer: CustomerAsn, update: AspaProvidersUpdate, }, AspaConfigRemoved { - customer: AspaCustomer, + customer: CustomerAsn, }, AspaObjectsUpdated { // Tracks ASPA *object* which are (re-)issued in a resource class. diff --git a/src/daemon/ca/manager.rs b/src/daemon/ca/manager.rs index 110d1758..6c6a50fb 100644 --- a/src/daemon/ca/manager.rs +++ b/src/daemon/ca/manager.rs @@ -30,8 +30,8 @@ use crate::{ RoaConfigurationUpdates, Timestamp, }, api::{ - AddChildRequest, AspaCustomer, AspaDefinitionList, AspaDefinitionUpdates, AspaProvidersUpdate, - CaCommandDetails, CertAuthList, CertAuthSummary, ChildCaInfo, CommandHistory, CommandHistoryCriteria, + AddChildRequest, AspaDefinitionList, AspaDefinitionUpdates, AspaProvidersUpdate, CaCommandDetails, + CertAuthList, CertAuthSummary, ChildCaInfo, CommandHistory, CommandHistoryCriteria, CustomerAsn, ParentCaContact, ParentCaReq, ReceivedCert, RepositoryContact, RtaName, UpdateChildRequest, }, crypto::KrillSigner, @@ -2294,7 +2294,7 @@ impl CaManager { pub async fn ca_aspas_update_aspa( &self, ca: CaHandle, - customer: AspaCustomer, + customer: CustomerAsn, update: AspaProvidersUpdate, actor: &Actor, ) -> KrillResult<()> { diff --git a/src/daemon/krillserver.rs b/src/daemon/krillserver.rs index 2c13854e..15bc5505 100644 --- a/src/daemon/krillserver.rs +++ b/src/daemon/krillserver.rs @@ -21,13 +21,13 @@ use crate::{ api::{ self, import::{ExportChild, ImportChild}, - AddChildRequest, AllCertAuthIssues, AspaCustomer, AspaDefinitionList, AspaDefinitionUpdates, - AspaProvidersUpdate, BgpSecCsrInfoList, BgpSecDefinitionUpdates, CaCommandDetails, CaRepoDetails, - CertAuthInfo, CertAuthInit, CertAuthIssues, CertAuthList, CertAuthStats, ChildCaInfo, - ChildrenConnectionStats, CommandHistory, CommandHistoryCriteria, ConfiguredRoa, IdCertInfo, - ParentCaContact, ParentCaReq, PublicationServerUris, PublisherDetails, ReceivedCert, - RepoFileDeleteCriteria, RepositoryContact, RoaConfiguration, RoaConfigurationUpdates, RoaPayload, RtaList, - RtaName, RtaPrepResponse, ServerInfo, Timestamp, UpdateChildRequest, + AddChildRequest, AllCertAuthIssues, AspaDefinitionList, AspaDefinitionUpdates, AspaProvidersUpdate, + BgpSecCsrInfoList, BgpSecDefinitionUpdates, CaCommandDetails, CaRepoDetails, CertAuthInfo, CertAuthInit, + CertAuthIssues, CertAuthList, CertAuthStats, ChildCaInfo, ChildrenConnectionStats, CommandHistory, + CommandHistoryCriteria, ConfiguredRoa, CustomerAsn, IdCertInfo, ParentCaContact, ParentCaReq, + PublicationServerUris, PublisherDetails, ReceivedCert, RepoFileDeleteCriteria, RepositoryContact, + RoaConfiguration, RoaConfigurationUpdates, RoaPayload, RtaList, RtaName, RtaPrepResponse, ServerInfo, + Timestamp, UpdateChildRequest, }, bgp::{BgpAnalyser, BgpAnalysisReport, BgpAnalysisSuggestion}, crypto::KrillSignerBuilder, @@ -930,7 +930,7 @@ impl KrillServer { pub async fn ca_aspas_update_aspa( &self, ca: CaHandle, - customer: AspaCustomer, + customer: CustomerAsn, update: AspaProvidersUpdate, actor: &Actor, ) -> KrillEmptyResult { diff --git a/src/test.rs b/src/test.rs index 30132ac7..57745c09 100644 --- a/src/test.rs +++ b/src/test.rs @@ -32,11 +32,11 @@ use crate::{ }, commons::{ api::{ - self, AddChildRequest, AspaCustomer, AspaDefinition, AspaDefinitionList, AspaProvidersUpdate, BgpSecAsnKey, + self, AddChildRequest, AspaDefinition, AspaDefinitionList, AspaProvidersUpdate, BgpSecAsnKey, BgpSecCsrInfoList, BgpSecDefinition, CertAuthInfo, CertAuthInit, CertifiedKeyInfo, ConfiguredRoa, - ConfiguredRoas, ObjectName, ParentCaContact, ParentCaReq, ParentStatuses, PublicationServerUris, - PublisherDetails, PublisherList, ResourceClassKeysInfo, RoaConfiguration, RoaConfigurationUpdates, - RoaPayload, RtaList, RtaName, RtaPrepResponse, TypedPrefix, UpdateChildRequest, + ConfiguredRoas, CustomerAsn, ObjectName, ParentCaContact, ParentCaReq, ParentStatuses, + PublicationServerUris, PublisherDetails, PublisherList, ResourceClassKeysInfo, RoaConfiguration, + RoaConfigurationUpdates, RoaPayload, RtaList, RtaName, RtaPrepResponse, TypedPrefix, UpdateChildRequest, }, bgp::{Announcement, BgpAnalysisReport, BgpAnalysisSuggestion}, crypto::SignSupport, @@ -612,15 +612,15 @@ pub async fn expect_aspa_definitions(ca: &CaHandle, expected_aspas: AspaDefiniti } } -pub async fn ca_aspas_update(ca: &CaHandle, customer: AspaCustomer, update: AspaProvidersUpdate) { +pub async fn ca_aspas_update(ca: &CaHandle, customer: CustomerAsn, update: AspaProvidersUpdate) { krill_admin(Command::CertAuth(CaCommand::AspasUpdate(ca.clone(), customer, update))).await; } -pub async fn ca_aspas_update_expect_error(ca: &CaHandle, customer: AspaCustomer, update: AspaProvidersUpdate) { +pub async fn ca_aspas_update_expect_error(ca: &CaHandle, customer: CustomerAsn, update: AspaProvidersUpdate) { krill_admin_expect_error(Command::CertAuth(CaCommand::AspasUpdate(ca.clone(), customer, update))).await; } -pub async fn ca_aspas_remove(ca: &CaHandle, customer: AspaCustomer) { +pub async fn ca_aspas_remove(ca: &CaHandle, customer: CustomerAsn) { krill_admin(Command::CertAuth(CaCommand::AspasRemove(ca.clone(), customer))).await; } diff --git a/tests/functional_aspa.rs b/tests/functional_aspa.rs index 79c31ac7..faf12ef8 100644 --- a/tests/functional_aspa.rs +++ b/tests/functional_aspa.rs @@ -8,10 +8,9 @@ use rpki::{ }; use krill::{ - commons::api::{AspaCustomer, AspaDefinition, AspaDefinitionList, AspaProvidersUpdate, ObjectName}, + commons::api::{AspaDefinition, AspaDefinitionList, AspaProvidersUpdate, CustomerAsn, ObjectName, ProviderAsn}, test::*, }; -use rpki::repository::aspa::ProviderAs; #[tokio::test] async fn functional_aspa() { @@ -96,7 +95,7 @@ async fn functional_aspa() { info("##################################################################"); info(""); - let aspa_65000 = AspaDefinition::from_str("AS65000 => AS65000, AS65003(v4), AS65005(v6)").unwrap(); + let aspa_65000 = AspaDefinition::from_str("AS65000 => AS65000, AS65003, AS65005").unwrap(); ca_aspas_add_expect_error(&ca, aspa_65000.clone()).await; @@ -105,23 +104,6 @@ async fn functional_aspa() { expect_aspa_definitions(&ca, AspaDefinitionList::new(aspas)).await; } - { - info("##################################################################"); - info("# #"); - info("# Reject ASPA using one provider AFI only #"); - info("# #"); - info("##################################################################"); - info(""); - - let aspa_one_afi = AspaDefinition::from_str("AS65000 => AS65003(v4), AS65005(v4)").unwrap(); - - ca_aspas_add_expect_error(&ca, aspa_one_afi.clone()).await; - - let aspas = vec![]; - expect_aspa_objects(&ca, &aspas).await; - expect_aspa_definitions(&ca, AspaDefinitionList::new(aspas)).await; - } - { info("##################################################################"); info("# #"); @@ -130,7 +112,7 @@ async fn functional_aspa() { info("##################################################################"); info(""); - let aspa_65000 = AspaDefinition::from_str("AS65000 => AS65002, AS65003(v4), AS65005(v6)").unwrap(); + let aspa_65000 = AspaDefinition::from_str("AS65000 => AS65002, AS65003, AS65005").unwrap(); ca_aspas_add(&ca, aspa_65000.clone()).await; @@ -147,15 +129,15 @@ async fn functional_aspa() { info("##################################################################"); info(""); - let customer = AspaCustomer::from_str("AS65000").unwrap(); + let customer = CustomerAsn::from_str("AS65000").unwrap(); let aspa_update = AspaProvidersUpdate::new( - vec![ProviderAs::from_str("AS65006").unwrap()], - vec![ProviderAs::from_str("AS65002").unwrap()], + vec![ProviderAsn::from_str("AS65006").unwrap()], + vec![ProviderAsn::from_str("AS65002").unwrap()], ); ca_aspas_update(&ca, customer, aspa_update).await; - let updated_aspa = AspaDefinition::from_str("AS65000 => AS65003(v4), AS65005(v6), AS65006").unwrap(); + let updated_aspa = AspaDefinition::from_str("AS65000 => AS65003, AS65005, AS65006").unwrap(); let aspas = vec![updated_aspa.clone()]; expect_aspa_objects(&ca, &aspas).await; @@ -170,12 +152,12 @@ async fn functional_aspa() { info("##################################################################"); info(""); - let customer = AspaCustomer::from_str("AS65000").unwrap(); - let aspa_update = AspaProvidersUpdate::new(vec![ProviderAs::from_str("AS65000").unwrap()], vec![]); + let customer = CustomerAsn::from_str("AS65000").unwrap(); + let aspa_update = AspaProvidersUpdate::new(vec![ProviderAsn::from_str("AS65000").unwrap()], vec![]); ca_aspas_update_expect_error(&ca, customer, aspa_update).await; - let unmodified_aspa = AspaDefinition::from_str("AS65000 => AS65003(v4), AS65005(v6), AS65006").unwrap(); + let unmodified_aspa = AspaDefinition::from_str("AS65000 => AS65003, AS65005, AS65006").unwrap(); let aspas = vec![unmodified_aspa.clone()]; expect_aspa_objects(&ca, &aspas).await; @@ -185,43 +167,17 @@ async fn functional_aspa() { { info("##################################################################"); info("# #"); - info("# Reject update that removes one AFI from providers #"); + info("# Update ASPA and remove all providers, should amount to delete #"); info("# #"); info("##################################################################"); - info(""); - let customer = AspaCustomer::from_str("AS65000").unwrap(); + let customer = CustomerAsn::from_str("AS65000").unwrap(); let aspa_update = AspaProvidersUpdate::new( vec![], vec![ - ProviderAs::from_str("AS65003(v4)").unwrap(), - ProviderAs::from_str("AS65006(v4)").unwrap(), - ], - ); - - ca_aspas_update_expect_error(&ca, customer, aspa_update).await; - - let unmodified_aspa = AspaDefinition::from_str("AS65000 => AS65003(v4), AS65005(v6), AS65006").unwrap(); - let aspas = vec![unmodified_aspa.clone()]; - - expect_aspa_objects(&ca, &aspas).await; - expect_aspa_definitions(&ca, AspaDefinitionList::new(aspas)).await; - } - - { - info("##################################################################"); - info("# #"); - info("# Update ASPA to have no providers #"); - info("# #"); - info("##################################################################"); - - let customer = AspaCustomer::from_str("AS65000").unwrap(); - let aspa_update = AspaProvidersUpdate::new( - vec![], - vec![ - ProviderAs::from_str("AS65003(v4)").unwrap(), - ProviderAs::from_str("AS65005(v6)").unwrap(), - ProviderAs::from_str("AS65006").unwrap(), + ProviderAsn::from_str("AS65003").unwrap(), + ProviderAsn::from_str("AS65005").unwrap(), + ProviderAsn::from_str("AS65006").unwrap(), ], ); @@ -247,19 +203,19 @@ async fn functional_aspa() { info("# #"); info("##################################################################"); - let customer = AspaCustomer::from_str("AS65000").unwrap(); + let customer = CustomerAsn::from_str("AS65000").unwrap(); let aspa_update = AspaProvidersUpdate::new( vec![ - ProviderAs::from_str("AS65003(v4)").unwrap(), - ProviderAs::from_str("AS65005(v6)").unwrap(), - ProviderAs::from_str("AS65006").unwrap(), + ProviderAsn::from_str("AS65003").unwrap(), + ProviderAsn::from_str("AS65005").unwrap(), + ProviderAsn::from_str("AS65006").unwrap(), ], vec![], ); ca_aspas_update(&ca, customer, aspa_update).await; - let updated_aspa = AspaDefinition::from_str("AS65000 => AS65003(v4), AS65005(v6), AS65006").unwrap(); + let updated_aspa = AspaDefinition::from_str("AS65000 => AS65003, AS65005, AS65006").unwrap(); let aspas = vec![updated_aspa.clone()]; expect_aspa_objects(&ca, &aspas).await; @@ -274,21 +230,21 @@ async fn functional_aspa() { info("# #"); info("##################################################################"); - let customer = AspaCustomer::from_str("AS65000").unwrap(); + let customer = CustomerAsn::from_str("AS65000").unwrap(); let aspa_update = AspaProvidersUpdate::new( vec![ - ProviderAs::from_str("AS65003(v6)").unwrap(), // should add v6 to existing v4 - ProviderAs::from_str("AS65005(v6)").unwrap(), // adding, but was already present + ProviderAsn::from_str("AS65002").unwrap(), // add + ProviderAsn::from_str("AS65005").unwrap(), // add, but was already present, so ignored ], vec![ - ProviderAs::from_str("AS65006(v4)").unwrap(), // removing v4, should retain v6 - ProviderAs::from_str("AS65007").unwrap(), // removing, but was not present + ProviderAsn::from_str("AS65006").unwrap(), // remove + ProviderAsn::from_str("AS65007").unwrap(), // remove, but was not present, so ignored ], ); ca_aspas_update(&ca, customer, aspa_update).await; - let updated_aspa = AspaDefinition::from_str("AS65000 => AS65003, AS65005(v6), AS65006(v6)").unwrap(); + let updated_aspa = AspaDefinition::from_str("AS65000 => AS65002, AS65003, AS65005").unwrap(); let aspas = vec![updated_aspa.clone()]; expect_aspa_objects(&ca, &aspas).await; @@ -303,7 +259,7 @@ async fn functional_aspa() { info("##################################################################"); info(""); - let customer = AspaCustomer::from_str("AS65000").unwrap(); + let customer = CustomerAsn::from_str("AS65000").unwrap(); ca_aspas_remove(&ca, customer).await; expect_aspa_objects(&ca, &[]).await; diff --git a/tests/functional_keyroll.rs b/tests/functional_keyroll.rs index 0aa7f8d5..f06bbd92 100644 --- a/tests/functional_keyroll.rs +++ b/tests/functional_keyroll.rs @@ -53,7 +53,7 @@ async fn functional_keyroll() { // be re-issued during the roll. let roa_payload = RoaPayload::from_str("10.0.0.0/16-16 => 64496").unwrap(); let roa_configuration = RoaConfiguration::from(roa_payload); - let aspa_def = AspaDefinition::from_str("AS65000 => AS65002, AS65003(v4), AS65005(v6)").unwrap(); + let aspa_def = AspaDefinition::from_str("AS65000 => AS65002, AS65003, AS65005").unwrap(); let bgpsec_def = { let csr_bytes = include_bytes!("../test-resources/bgpsec/router-csr.der"); let csr_bytes = Bytes::copy_from_slice(csr_bytes);