Depend on latest rpki-rs with ASPA v1.

This commit is contained in:
Tim Bruijnzeels
2023-10-23 12:00:46 +02:00
parent f29d490652
commit 04cbfdadea
15 changed files with 134 additions and 284 deletions
Generated
+5 -16
View File
@@ -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",
+1 -1
View File
@@ -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"] }
+12 -14
View File
@@ -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),
+34 -117
View File
@@ -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<AspaDefinition>,
remove: Vec<AspaCustomer>,
remove: Vec<CustomerAsn>,
}
impl AspaDefinitionUpdates {
pub fn new(add_or_replace: Vec<AspaDefinition>, remove: Vec<AspaCustomer>) -> Self {
pub fn new(add_or_replace: Vec<AspaDefinition>, remove: Vec<CustomerAsn>) -> Self {
AspaDefinitionUpdates { add_or_replace, remove }
}
pub fn unpack(self) -> (Vec<AspaDefinition>, Vec<AspaCustomer>) {
pub fn unpack(self) -> (Vec<AspaDefinition>, Vec<CustomerAsn>) {
(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<ProviderAs>,
customer: CustomerAsn,
providers: Vec<ProviderAsn>,
}
impl AspaDefinition {
pub fn new(customer: AspaCustomer, providers: Vec<ProviderAs>) -> Self {
pub fn new(customer: CustomerAsn, providers: Vec<ProviderAsn>) -> Self {
AspaDefinition { customer, providers }
}
pub fn unpack(self) -> (AspaCustomer, Vec<ProviderAs>) {
pub fn unpack(self) -> (CustomerAsn, Vec<ProviderAsn>) {
(self.customer, self.providers)
}
pub fn customer(&self) -> AspaCustomer {
pub fn customer(&self) -> CustomerAsn {
self.customer
}
pub fn providers(&self) -> &Vec<ProviderAs> {
pub fn providers(&self) -> &Vec<ProviderAsn> {
&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<Asn> = self.providers.iter().map(|p| p.provider()).collect();
let mut providers: Vec<Asn> = 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, "<none>")?;
@@ -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() != "<none>" {
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<ProviderAs>,
removed: Vec<ProviderAs>,
added: Vec<ProviderAsn>,
removed: Vec<ProviderAsn>,
}
impl AspaProvidersUpdate {
pub fn new(added: Vec<ProviderAs>, removed: Vec<ProviderAs>) -> Self {
pub fn new(added: Vec<ProviderAsn>, removed: Vec<ProviderAsn>) -> 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<ProviderAs> {
pub fn added(&self) -> &Vec<ProviderAsn> {
&self.added
}
pub fn removed(&self) -> &Vec<ProviderAs> {
pub fn removed(&self) -> &Vec<ProviderAsn> {
&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());
+3 -3
View File
@@ -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 {
+7 -12
View File
@@ -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
+8 -8
View File
@@ -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<AspaCustomer, AspaDefinition>,
attestations: HashMap<CustomerAsn, AspaDefinition>,
}
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<AspaCustomer, AspaInfo>);
pub struct AspaObjects(HashMap<CustomerAsn, AspaInfo>);
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()
}
+6 -11
View File
@@ -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<bool> {
fn updated_allowed_and_needed(&self, customer: CustomerAsn, update: &AspaProvidersUpdate) -> KrillResult<bool> {
// 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)
}
+4 -4
View File
@@ -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<Config>, Arc<KrillSigner>),
// Updates an existing AspaProviders for the given AspaCustomer
AspasUpdateExisting(AspaCustomer, AspaProvidersUpdate, Arc<Config>, Arc<KrillSigner>),
AspasUpdateExisting(CustomerAsn, AspaProvidersUpdate, Arc<Config>, Arc<KrillSigner>),
// 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<Config>,
signer: Arc<KrillSigner>,
+8 -8
View File
@@ -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<AspaInfo>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
removed: Vec<AspaCustomer>,
removed: Vec<CustomerAsn>,
}
impl AspaObjectsUpdates {
pub fn new(updated: Vec<AspaInfo>, removed: Vec<AspaCustomer>) -> Self {
pub fn new(updated: Vec<AspaInfo>, removed: Vec<CustomerAsn>) -> 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<AspaInfo>, Vec<AspaCustomer>) {
pub fn unpack(self) -> (Vec<AspaInfo>, Vec<CustomerAsn>) {
(self.updated, self.removed)
}
@@ -275,7 +275,7 @@ impl AspaObjectsUpdates {
&self.updated
}
pub fn removed(&self) -> &Vec<AspaCustomer> {
pub fn removed(&self) -> &Vec<CustomerAsn> {
&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.
+3 -3
View File
@@ -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<()> {
+8 -8
View File
@@ -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 {
+7 -7
View File
@@ -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;
}
+27 -71
View File
@@ -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;
+1 -1
View File
@@ -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);