Skip to content

Commit

Permalink
Add limits to provider ASN set in both repository and rtr. (#316)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
partim authored Jan 20, 2025
1 parent 2d28cde commit ca82ee0
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 7 deletions.
37 changes: 37 additions & 0 deletions src/repository/aspa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,13 +202,19 @@ 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,
len: usize,
}

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
Expand All @@ -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<S: decode::Source>(
cons: &mut decode::Constructed<S>,
customer_as: Asn,
Expand All @@ -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"
Expand Down Expand Up @@ -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() {
Expand Down
18 changes: 11 additions & 7 deletions src/rtr/pdu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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())
Expand All @@ -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());
Expand Down Expand Up @@ -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()
);
}
Expand Down

0 comments on commit ca82ee0

Please sign in to comment.