From ca82ee0e594284d0c105b04881ebf88cf0696ee8 Mon Sep 17 00:00:00 2001 From: Martin Hoffmann Date: Mon, 20 Jan 2025 17:03:20 +0100 Subject: [PATCH] Add limits to provider ASN set in both repository and rtr. (#316) This PR limits the lengths of the ASPA provider set to 16380 entries both in ASPA object parsing and in RTR payload sending. Limiting in ASPA object creation and RTR payload receiving is not covered yet. --- src/repository/aspa.rs | 37 +++++++++++++++++++++++++++++++++++++ src/rtr/pdu.rs | 18 +++++++++++------- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/repository/aspa.rs b/src/repository/aspa.rs index 59eb327..b445e1e 100644 --- a/src/repository/aspa.rs +++ b/src/repository/aspa.rs @@ -202,6 +202,9 @@ impl AsProviderAttestation { /// This type contains the provider AS set in encoded form. It guarantees that /// the AS in this set are ordered, free of duplicates and there is at least /// one AS. +/// +/// It does not, at this point, enforce the maximum allowed number of 16380 +/// ASNs. This will be added with the next breaking change. #[derive(Clone, Debug)] pub struct ProviderAsSet { captured: Captured, @@ -209,6 +212,9 @@ pub struct ProviderAsSet { } impl ProviderAsSet { + /// The maximum number of ASNs allowed in the set. + const MAX_LEN: usize = 16380; + #[allow(clippy::len_without_is_empty)] // never empty pub fn len(&self) -> usize { self.len @@ -226,6 +232,9 @@ impl ProviderAsSet { ProviderAsIter(self.captured.as_slice().into_source()) } + /// Takes the provider ASN sequence from an encoded source. + /// + /// Enforces a maxium size of 16380 ASNs. fn take_from( cons: &mut decode::Constructed, customer_as: Asn, @@ -237,6 +246,11 @@ impl ProviderAsSet { while let Some(asn) = Asn::take_opt_from( cons )? { + if len >= Self::MAX_LEN { + return Err(cons.content_err( + "too many provider ASNs" + )); + } if asn == customer_as { return Err(cons.content_err( "customer AS in provider AS set" @@ -541,6 +555,29 @@ mod signer_test { make_aspa(customer_as, providers); } + #[test] + fn provider_asn_size() { + fn make_aspa(len: usize) -> Captured { + let mut builder = AspaBuilder::empty(0.into()); + for i in 0..(len as u32) { + builder.add_provider(Asn::from(i + 1)).unwrap(); + } + builder.into_attestation().encode_ref().to_captured(Mode::Der) + } + + make_aspa( + ProviderAsSet::MAX_LEN - 1 + ).decode(AsProviderAttestation::take_from).unwrap(); + make_aspa( + ProviderAsSet::MAX_LEN + ).decode(AsProviderAttestation::take_from).unwrap(); + assert!( + make_aspa( + ProviderAsSet::MAX_LEN + 1 + ).decode(AsProviderAttestation::take_from).is_err() + ); + } + #[test] #[cfg(feature = "serde")] fn serde_aspa() { diff --git a/src/rtr/pdu.rs b/src/rtr/pdu.rs index 0d38bec..3e52f69 100644 --- a/src/rtr/pdu.rs +++ b/src/rtr/pdu.rs @@ -799,7 +799,8 @@ impl Aspa { /// # Panics /// /// This function panics if the length of the resulting PDU doesn’t fit - /// in a `u32`. + /// in a `u32`. Because `ProviderAsns` is now limited in size, this can’t + /// happen. pub fn new( version: u8, flags: u8, @@ -948,6 +949,9 @@ impl AsMut<[u8]> for AspaFixed { pub struct ProviderAsns(Bytes); impl ProviderAsns { + /// The maximum number of provider ASNs. + pub const MAX_COUNT: usize = 16380; + /// Returns an empty value. pub fn empty() -> Self { Self(Bytes::new()) @@ -963,7 +967,7 @@ impl ProviderAsns { let iter = iter.into_iter(); let mut providers = Vec::with_capacity(iter.size_hint().0); iter.enumerate().try_for_each(|(idx, item)| { - if idx >= usize::from(u16::MAX) { + if idx >= Self::MAX_COUNT { return Err(ProviderAsnsError(())) } providers.extend_from_slice(&item.into_u32().to_be_bytes()); @@ -1836,19 +1840,19 @@ mod test { fn provider_count() { assert_eq!( ProviderAsns::try_from_iter( - iter::repeat(Asn::from(0)).take(usize::from(u16::MAX - 1)) + iter::repeat(Asn::from(0)).take(ProviderAsns::MAX_COUNT - 1) ).unwrap().asn_count(), - u16::MAX - 1 + (ProviderAsns::MAX_COUNT - 1) as u16, ); assert_eq!( ProviderAsns::try_from_iter( - iter::repeat(Asn::from(0)).take(usize::from(u16::MAX)) + iter::repeat(Asn::from(0)).take(ProviderAsns::MAX_COUNT) ).unwrap().asn_count(), - u16::MAX + ProviderAsns::MAX_COUNT as u16, ); assert!( ProviderAsns::try_from_iter( - iter::repeat(Asn::from(0)).take(usize::from(u16::MAX) + 1) + iter::repeat(Asn::from(0)).take(ProviderAsns::MAX_COUNT + 1) ).is_err() ); }