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() ); }