use rpki::data_model::rc::{ Afi, AsIdOrRange, AsIdentifierChoice, AsResourceSet, IpAddressChoice, IpAddressOrRange, IpResourceSet, }; fn len_bytes(len: usize) -> Vec { if len < 128 { vec![len as u8] } else { let mut tmp = Vec::new(); let mut n = len; while n > 0 { tmp.push((n & 0xFF) as u8); n >>= 8; } tmp.reverse(); let mut out = vec![0x80 | (tmp.len() as u8)]; out.extend(tmp); out } } fn tlv(tag: u8, content: &[u8]) -> Vec { let mut out = vec![tag]; out.extend(len_bytes(content.len())); out.extend_from_slice(content); out } fn der_sequence(children: Vec>) -> Vec { let mut content = Vec::new(); for c in children { content.extend(c); } tlv(0x30, &content) } fn der_octet_string(bytes: &[u8]) -> Vec { tlv(0x04, bytes) } fn der_null() -> Vec { vec![0x05, 0x00] } fn der_integer_u64(v: u64) -> Vec { let mut bytes = Vec::new(); let mut n = v; if n == 0 { bytes.push(0); } else { while n > 0 { bytes.push((n & 0xFF) as u8); n >>= 8; } bytes.reverse(); if bytes[0] & 0x80 != 0 { bytes.insert(0, 0); } } tlv(0x02, &bytes) } fn der_bit_string(unused: u8, bytes: &[u8]) -> Vec { let mut content = vec![unused]; content.extend_from_slice(bytes); tlv(0x03, &content) } fn cs_cons(tag_no: u8, inner_der: Vec) -> Vec { tlv(0xA0 | (tag_no & 0x1F), &inner_der) } #[test] fn ip_addr_blocks_decode_handles_inherit_and_range_endpoint_fill() { // IPv6 family with one range: // - min: 240a:a000::/32 (encoded as 32 bits) // - max: 240a:a008::/31 (encoded as 31 bits, so fill-ones yields 240a:a009:ffff..) let address_family = der_octet_string(&[0x00, 0x02]); let min = der_bit_string(0, &[0x24, 0x0A, 0xA0, 0x00]); let max = der_bit_string(1, &[0x24, 0x0A, 0xA0, 0x08]); let range = der_sequence(vec![min, max]); let choice = der_sequence(vec![range]); let fam = der_sequence(vec![address_family, choice]); let ip_addr_blocks = der_sequence(vec![fam]); let decoded = IpResourceSet::decode_extn_value(&ip_addr_blocks).expect("decode ipAddrBlocks"); assert_eq!(decoded.families.len(), 1); let fam = &decoded.families[0]; assert_eq!(fam.afi, Afi::Ipv6); let IpAddressChoice::AddressesOrRanges(items) = &fam.choice else { panic!("expected AddressesOrRanges"); }; let IpAddressOrRange::Range(r) = &items[0] else { panic!("expected Range"); }; assert_eq!(r.min[..4], [0x24, 0x0A, 0xA0, 0x00]); assert_eq!(r.max[..4], [0x24, 0x0A, 0xA0, 0x09]); assert!(r.max[4..].iter().all(|&b| b == 0xFF)); // Inherit branch. let fam_inherit = der_sequence(vec![der_octet_string(&[0x00, 0x01]), der_null()]); let decoded = IpResourceSet::decode_extn_value(&der_sequence(vec![fam_inherit])).expect("decode inherit"); assert!(decoded.is_all_inherit()); } #[test] fn autonomous_sys_ids_decode_handles_inherit_ids_and_ranges() { // ASIdentifiers with: // - asnum [0] EXPLICIT asIdsOrRanges { id 64496, range 64500..64510 } let as_id_or_ranges = der_sequence(vec![ der_integer_u64(64496), der_sequence(vec![der_integer_u64(64500), der_integer_u64(64510)]), ]); let asnum = cs_cons(0, as_id_or_ranges); let as_identifiers = der_sequence(vec![asnum]); let decoded = AsResourceSet::decode_extn_value(&as_identifiers).expect("decode asIdentifiers"); assert!(decoded.rdi.is_none()); let Some(asnum) = decoded.asnum else { panic!("missing asnum"); }; let AsIdentifierChoice::AsIdsOrRanges(items) = asnum else { panic!("expected AsIdsOrRanges"); }; assert_eq!(items.len(), 2); assert!(matches!(items[0], AsIdOrRange::Id(64496))); assert!(matches!( items[1], AsIdOrRange::Range { min: 64500, max: 64510 } )); // asnum inherit. let asnum_inherit = cs_cons(0, der_null()); let decoded = AsResourceSet::decode_extn_value(&der_sequence(vec![asnum_inherit])) .expect("decode inherit"); assert!(decoded.is_asnum_inherit()); }