1 //! Route Origin Authorizations.
2 //!
3 //! For details, see RFC 6482.
4 
5 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
6 use bcder::{decode, encode};
7 use bcder::{Captured, Mode, OctetString, Oid, Tag, xerr};
8 use bcder::encode::{PrimitiveContent, Values};
9 use super::oid;
10 use super::cert::{Cert, ResourceCert};
11 use super::crypto::{Signer, SigningError};
12 use super::resources::{Addr, AddressFamily, AsId, IpResources, Prefix};
13 use super::sigobj::{SignedObject, SignedObjectBuilder};
14 use super::x509::ValidationError;
15 
16 
17 //------------ Roa -----------------------------------------------------------
18 
19 #[derive(Clone, Debug)]
20 pub struct Roa {
21     signed: SignedObject,
22     content: RouteOriginAttestation,
23 }
24 
25 impl Roa {
decode<S: decode::Source>( source: S, strict: bool ) -> Result<Self, S::Err>26     pub fn decode<S: decode::Source>(
27         source: S,
28         strict: bool
29     ) -> Result<Self, S::Err> {
30         let signed = SignedObject::decode(source, strict)?;
31         if signed.content_type().ne(&oid::ROUTE_ORIGIN_AUTHZ) {
32             return Err(decode::Malformed.into())
33         }
34         let content = signed.decode_content(|cons| {
35             RouteOriginAttestation::take_from(cons)
36         })?;
37         Ok(Roa { signed, content })
38     }
39 
process<F>( mut self, issuer: &ResourceCert, strict: bool, check_crl: F ) -> Result<(ResourceCert, RouteOriginAttestation), ValidationError> where F: FnOnce(&Cert) -> Result<(), ValidationError>40     pub fn process<F>(
41         mut self,
42         issuer: &ResourceCert,
43         strict: bool,
44         check_crl: F
45     ) -> Result<(ResourceCert, RouteOriginAttestation), ValidationError>
46     where F: FnOnce(&Cert) -> Result<(), ValidationError> {
47         let cert = self.signed.validate(issuer, strict)?;
48         check_crl(cert.as_ref())?;
49         self.content.validate(&cert)?;
50         Ok((cert, self.content))
51     }
52 
53     /// Returns a value encoder for a reference to a ROA.
encode_ref(&self) -> impl encode::Values + '_54     pub fn encode_ref(&self) -> impl encode::Values + '_ {
55         self.signed.encode_ref()
56     }
57 
58     /// Returns a DER encoded Captured for this ROA.
to_captured(&self) -> Captured59     pub fn to_captured(&self) -> Captured {
60         self.encode_ref().to_captured(Mode::Der)
61     }
62 
63     /// Returns a reference to the EE certificate of this ROA.
cert(&self) -> &Cert64     pub fn cert(&self) -> &Cert {
65         self.signed.cert()
66     }
67 }
68 
69 
70 //--- Deserialize and Serialize
71 
72 #[cfg(feature = "serde")]
73 impl serde::Serialize for Roa {
serialize<S: serde::Serializer>( &self, serializer: S ) -> Result<S::Ok, S::Error>74     fn serialize<S: serde::Serializer>(
75         &self, serializer: S
76     ) -> Result<S::Ok, S::Error> {
77         let bytes = self.to_captured().into_bytes();
78         let b64 = base64::encode(&bytes);
79         b64.serialize(serializer)
80     }
81 }
82 
83 #[cfg(feature = "serde")]
84 impl<'de> serde::Deserialize<'de> for Roa {
deserialize<D: serde::Deserializer<'de>>( deserializer: D ) -> Result<Self, D::Error>85     fn deserialize<D: serde::Deserializer<'de>>(
86         deserializer: D
87     ) -> Result<Self, D::Error> {
88         use serde::de;
89 
90         let string = String::deserialize(deserializer)?;
91         let decoded = base64::decode(&string).map_err(de::Error::custom)?;
92         let bytes = bytes::Bytes::from(decoded);
93         Roa::decode(bytes, true).map_err(de::Error::custom)
94     }
95 }
96 
97 
98 //------------ RouteOriginAttestation ----------------------------------------
99 
100 #[derive(Clone, Debug)]
101 pub struct RouteOriginAttestation {
102     as_id: AsId,
103     v4_addrs: RoaIpAddresses,
104     v6_addrs: RoaIpAddresses,
105 }
106 
107 impl RouteOriginAttestation {
as_id(&self) -> AsId108     pub fn as_id(&self) -> AsId {
109         self.as_id
110     }
111 
v4_addrs(&self) -> &RoaIpAddresses112     pub fn v4_addrs(&self) -> &RoaIpAddresses {
113         &self.v4_addrs
114     }
115 
v6_addrs(&self) -> &RoaIpAddresses116     pub fn v6_addrs(&self) -> &RoaIpAddresses {
117         &self.v6_addrs
118     }
119 
iter( &self ) -> impl Iterator<Item=FriendlyRoaIpAddress> + '_120     pub fn iter(
121         &self
122     ) -> impl Iterator<Item=FriendlyRoaIpAddress> + '_ {
123         self.v4_addrs.iter().map(|addr| FriendlyRoaIpAddress::new(addr, true))
124             .chain(
125                 self.v6_addrs.iter()
126                     .map(|addr| FriendlyRoaIpAddress::new(addr, false))
127             )
128     }
129 }
130 
131 impl RouteOriginAttestation {
take_from<S: decode::Source>( cons: &mut decode::Constructed<S> ) -> Result<Self, S::Err>132     fn take_from<S: decode::Source>(
133         cons: &mut decode::Constructed<S>
134     ) -> Result<Self, S::Err> {
135         cons.take_sequence(|cons| {
136             // version [0] EXPLICIT INTEGER DEFAULT 0
137             cons.take_opt_constructed_if(Tag::CTX_0, |c| c.skip_u8_if(0))?;
138             let as_id = AsId::take_from(cons)?;
139             let mut v4 = None;
140             let mut v6 = None;
141             cons.take_sequence(|cons| {
142                 while let Some(()) = cons.take_opt_sequence(|cons| {
143                     match AddressFamily::take_from(cons)? {
144                         AddressFamily::Ipv4 => {
145                             if v4.is_some() {
146                                 xerr!(return Err(decode::Malformed.into()));
147                             }
148                             v4 = Some(RoaIpAddresses::take_from(
149                                 cons, AddressFamily::Ipv4
150                             )?);
151                         }
152                         AddressFamily::Ipv6 => {
153                             if v6.is_some() {
154                                 xerr!(return Err(decode::Malformed.into()));
155                             }
156                             v6 = Some(RoaIpAddresses::take_from(
157                                 cons, AddressFamily::Ipv6
158                             )?);
159                         }
160                     }
161                     Ok(())
162                 })? { }
163                 Ok(())
164             })?;
165             Ok(RouteOriginAttestation {
166                 as_id,
167                 v4_addrs: match v4 {
168                     Some(addrs) => addrs,
169                     None => RoaIpAddresses(Captured::empty(Mode::Der))
170                 },
171                 v6_addrs: match v6 {
172                     Some(addrs) => addrs,
173                     None => RoaIpAddresses(Captured::empty(Mode::Der))
174                 },
175             })
176         })
177     }
178 
validate( &mut self, cert: &ResourceCert ) -> Result<(), ValidationError>179     fn validate(
180         &mut self,
181         cert: &ResourceCert
182     ) -> Result<(), ValidationError> {
183         if !self.v4_addrs.is_empty() {
184             let blocks = cert.v4_resources();
185             if blocks.is_empty() {
186                 return Err(ValidationError)
187             }
188             for addr in self.v4_addrs.iter() {
189                 if !blocks.contains_roa(&addr) {
190                     return Err(ValidationError)
191                 }
192             }
193         }
194         if !self.v6_addrs.is_empty() {
195             let blocks = cert.v6_resources();
196             if blocks.is_empty() {
197                 return Err(ValidationError)
198             }
199             for addr in self.v6_addrs.iter() {
200                 if !blocks.contains_roa(&addr) {
201                     return Err(ValidationError)
202                 }
203             }
204         }
205         Ok(())
206     }
207 
encode_ref(&self) -> impl encode::Values + '_208     pub fn encode_ref(&self) -> impl encode::Values + '_ {
209         encode::sequence((
210             // version is DEFAULT
211             self.as_id.encode(),
212             encode::sequence((
213                 self.v4_addrs.encode_ref_family([0x00, 0x01]),
214                 self.v6_addrs.encode_ref_family([0x00, 0x02]),
215             ))
216         ))
217     }
218 
219 }
220 
221 
222 //------------ RoaIpAddresses ------------------------------------------------
223 
224 #[derive(Clone, Debug)]
225 pub struct RoaIpAddresses(Captured);
226 
227 impl RoaIpAddresses {
take_from<S: decode::Source>( cons: &mut decode::Constructed<S>, family: AddressFamily, ) -> Result<Self, S::Err>228     fn take_from<S: decode::Source>(
229         cons: &mut decode::Constructed<S>,
230         family: AddressFamily,
231     ) -> Result<Self, S::Err> {
232         cons.take_sequence(|cons| {
233             cons.capture(|cons| {
234                 while RoaIpAddress::skip_opt_in(cons, family)?.is_some() { }
235                 Ok(())
236             })
237         }).map(RoaIpAddresses)
238     }
239 
is_empty(&self) -> bool240     pub fn is_empty(&self) -> bool {
241         self.0.is_empty()
242     }
243 
iter(&self) -> RoaIpAddressIter244     pub fn iter(&self) -> RoaIpAddressIter {
245         RoaIpAddressIter(self.0.as_ref())
246     }
247 
encode_ref_family( &self, family: [u8; 2] ) -> Option<impl encode::Values + '_>248     fn encode_ref_family(
249         &self,
250         family: [u8; 2]
251     ) -> Option<impl encode::Values + '_> {
252         if self.0.is_empty() {
253             None
254         }
255         else {
256             Some(encode::sequence((
257                 OctetString::encode_slice(family),
258                 &self.0
259             )))
260         }
261     }
262 
263 }
264 
265 
266 //------------ RoaIpAddressIter ----------------------------------------------
267 
268 #[derive(Clone, Debug)]
269 pub struct RoaIpAddressIter<'a>(&'a [u8]);
270 
271 impl<'a> Iterator for RoaIpAddressIter<'a> {
272     type Item = RoaIpAddress;
273 
next(&mut self) -> Option<Self::Item>274     fn next(&mut self) -> Option<Self::Item> {
275         if self.0.is_empty() {
276             None
277         }
278         else {
279             Mode::Der.decode(&mut self.0, |cons| {
280                 RoaIpAddress::take_opt_from_unchecked(cons)
281             }).unwrap()
282         }
283     }
284 }
285 
286 
287 //------------ RoaIpAddress --------------------------------------------------
288 
289 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
290 pub struct RoaIpAddress {
291     prefix: Prefix,
292     max_length: Option<u8>
293 }
294 
295 impl RoaIpAddress {
new(prefix: Prefix, max_length: Option<u8>) -> Self296     pub fn new(prefix: Prefix, max_length: Option<u8>) -> Self {
297         RoaIpAddress { prefix, max_length }
298     }
299 
new_addr(addr: IpAddr, len: u8, max_len: Option<u8>) -> Self300     pub fn new_addr(addr: IpAddr, len: u8, max_len: Option<u8>) -> Self {
301         RoaIpAddress::new(Prefix::new(addr, len), max_len)
302     }
303 
prefix(self) -> Prefix304     pub fn prefix(self) -> Prefix {
305         self.prefix
306     }
307 
range(self) -> (Addr, Addr)308     pub fn range(self) -> (Addr, Addr) {
309         self.prefix.range()
310     }
311 }
312 
313 impl RoaIpAddress {
314     // Section 3 of RFC 6482 defines  ROAIPAddress as
315     //
316     // ```txt
317     // ROAIPAddress ::= SEQUENCE {
318     //    address       IPAddress,
319     //    maxLength     INTEGER OPTIONAL }
320     //
321     // IPAddress    ::= BIT STRING
322     // ```
323     //
324     // The address is the same as in section 2.1.1 of RFC 3779, that is, it
325     // is a bit string with all the bits of the prefix.
326 
take_opt_from_unchecked<S: decode::Source>( cons: &mut decode::Constructed<S> ) -> Result<Option<Self>, S::Err>327     fn take_opt_from_unchecked<S: decode::Source>(
328         cons: &mut decode::Constructed<S>
329     ) -> Result<Option<Self>, S::Err> {
330         cons.take_opt_sequence(|cons| {
331             Ok(RoaIpAddress {
332                 prefix: Prefix::take_from(cons)?,
333                 max_length: cons.take_opt_u8()?,
334             })
335         })
336     }
337 
338     /// Skips one address in a source.
339     ///
340     /// In order to check that the address is correctly formatted, this
341     /// function needs to know the address family of the address.
skip_opt_in<S: decode::Source>( cons: &mut decode::Constructed<S>, family: AddressFamily, ) -> Result<Option<()>, S::Err>342     fn skip_opt_in<S: decode::Source>(
343         cons: &mut decode::Constructed<S>,
344         family: AddressFamily,
345     ) -> Result<Option<()>, S::Err> {
346         let addr = match Self::take_opt_from_unchecked(cons)? {
347             Some(addr) => addr,
348             None => return Ok(None)
349         };
350 
351         // Check that the prefix length fits the address family.
352         if addr.prefix.addr_len() > family.max_addr_len() {
353             return Err(decode::Malformed.into())
354         }
355 
356         // Check that a max length fits both family and prefix length.
357         if let Some(max_length) = addr.max_length {
358             if max_length > family.max_addr_len()
359                 || max_length < addr.prefix.addr_len()
360             {
361                 return Err(decode::Malformed.into())
362             }
363         }
364 
365         Ok(Some(()))
366     }
367 
encode(&self) -> impl encode::Values368     fn encode(&self) -> impl encode::Values {
369         encode::sequence((
370             self.prefix.encode(),
371             self.max_length.map(|v| v.encode())
372         ))
373     }
374 }
375 
376 
377 //------------ FriendlyRoaIpAddress ------------------------------------------
378 
379 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
380 pub struct FriendlyRoaIpAddress {
381     addr: RoaIpAddress,
382     v4: bool
383 }
384 
385 impl FriendlyRoaIpAddress {
new(addr: RoaIpAddress, v4: bool) -> Self386     fn new(addr: RoaIpAddress, v4: bool) -> Self {
387         FriendlyRoaIpAddress { addr, v4 }
388     }
389 
prefix(self) -> Prefix390     pub fn prefix(self) -> Prefix {
391         self.addr.prefix
392     }
393 
is_v4(self) -> bool394     pub fn is_v4(self) -> bool {
395         self.v4
396     }
397 
address(self) -> IpAddr398     pub fn address(self) -> IpAddr {
399         if self.v4 {
400             self.addr.prefix.to_v4().into()
401         }
402         else {
403             self.addr.prefix.to_v6().into()
404         }
405     }
406 
address_length(self) -> u8407     pub fn address_length(self) -> u8 {
408         self.addr.prefix.addr_len()
409     }
410 
max_length(self) -> u8411     pub fn max_length(self) -> u8 {
412         self.addr.max_length.unwrap_or_else(||
413             self.addr.prefix.addr_len()
414         )
415     }
416 }
417 
418 
419 //------------ RoaBuilder ----------------------------------------------------
420 
421 pub struct RoaBuilder {
422     as_id: AsId,
423     v4: RoaIpAddressesBuilder,
424     v6: RoaIpAddressesBuilder,
425 }
426 
427 impl RoaBuilder {
new(as_id: AsId) -> Self428     pub fn new(as_id: AsId) -> Self {
429         Self::with_addresses(
430             as_id,
431             RoaIpAddressesBuilder::new(),
432             RoaIpAddressesBuilder::new(),
433         )
434     }
435 
with_addresses( as_id: AsId, v4: RoaIpAddressesBuilder, v6: RoaIpAddressesBuilder ) -> Self436     pub fn with_addresses(
437         as_id: AsId,
438         v4: RoaIpAddressesBuilder,
439         v6: RoaIpAddressesBuilder
440     ) -> Self {
441         Self { as_id, v4, v6 }
442     }
443 
as_id(&self) -> AsId444     pub fn as_id(&self) -> AsId {
445         self.as_id
446     }
447 
set_as_id(&mut self, as_id: AsId)448     pub fn set_as_id(&mut self, as_id: AsId) {
449         self.as_id = as_id
450     }
451 
v4(&self) -> &RoaIpAddressesBuilder452     pub fn v4(&self) -> &RoaIpAddressesBuilder {
453         &self.v4
454     }
455 
v4_mut(&mut self) -> &mut RoaIpAddressesBuilder456     pub fn v4_mut(&mut self) -> &mut RoaIpAddressesBuilder {
457         &mut self.v4
458     }
459 
v6(&self) -> &RoaIpAddressesBuilder460     pub fn v6(&self) -> &RoaIpAddressesBuilder {
461         &self.v6
462     }
463 
v6_mut(&mut self) -> &mut RoaIpAddressesBuilder464     pub fn v6_mut(&mut self) -> &mut RoaIpAddressesBuilder {
465         &mut self.v6
466     }
467 
push_addr( &mut self, addr: IpAddr, len: u8, max_len: Option<u8> )468     pub fn push_addr(
469         &mut self, addr: IpAddr, len: u8, max_len: Option<u8>
470     ) {
471         match addr {
472             IpAddr::V4(addr) => self.push_v4_addr(addr, len, max_len),
473             IpAddr::V6(addr) => self.push_v6_addr(addr, len, max_len)
474         }
475     }
476 
push_v4(&mut self, addr: RoaIpAddress)477     pub fn push_v4(&mut self, addr: RoaIpAddress) {
478         self.v4_mut().push(addr)
479     }
480 
push_v4_addr( &mut self, addr: Ipv4Addr, len: u8, max_len: Option<u8> )481     pub fn push_v4_addr(
482         &mut self, addr: Ipv4Addr, len: u8, max_len: Option<u8>
483     ) {
484         self.v4_mut().push_addr(IpAddr::V4(addr), len, max_len)
485     }
486 
extend_v4_from_slice(&mut self, addrs: &[RoaIpAddress])487     pub fn extend_v4_from_slice(&mut self, addrs: &[RoaIpAddress]) {
488         self.v4_mut().extend_from_slice(addrs)
489     }
490 
push_v6(&mut self, addr: RoaIpAddress)491     pub fn push_v6(&mut self, addr: RoaIpAddress) {
492         self.v6_mut().push(addr)
493     }
494 
push_v6_addr( &mut self, addr: Ipv6Addr, len: u8, max_len: Option<u8> )495     pub fn push_v6_addr(
496         &mut self, addr: Ipv6Addr, len: u8, max_len: Option<u8>
497     ) {
498         self.v6_mut().push_addr(IpAddr::V6(addr), len, max_len)
499     }
500 
extend_v6_from_slice(&mut self, addrs: &[RoaIpAddress])501     pub fn extend_v6_from_slice(&mut self, addrs: &[RoaIpAddress]) {
502         self.v6_mut().extend_from_slice(addrs)
503     }
504 
to_attestation(&self) -> RouteOriginAttestation505     pub fn to_attestation(&self) -> RouteOriginAttestation {
506         RouteOriginAttestation {
507             as_id: self.as_id,
508             v4_addrs: self.v4.to_addresses(),
509             v6_addrs: self.v6.to_addresses(),
510         }
511     }
512 
513     /// Finalizes the builder into a ROA.
514     ///
515     /// # Panic
516     ///
517     /// This method will panic if both the IPv4 and IPv6 addresses are empty
518     /// as that is not allowed and would lead to a malformed ROA.
finalize<S: Signer>( self, mut sigobj: SignedObjectBuilder, signer: &S, issuer_key: &S::KeyId, ) -> Result<Roa, SigningError<S::Error>>519     pub fn finalize<S: Signer>(
520         self,
521         mut sigobj: SignedObjectBuilder,
522         signer: &S,
523         issuer_key: &S::KeyId,
524     ) -> Result<Roa, SigningError<S::Error>> {
525         let content = self.to_attestation();
526         let v4 = self.v4.to_resources();
527         let v6 = self.v6.to_resources();
528         // There must be some resources in order to make a valid ROA.
529         assert!(v4.is_present() || v6.is_present());
530         sigobj.set_v4_resources(v4);
531         sigobj.set_v6_resources(v6);
532         let signed = sigobj.finalize(
533             Oid(oid::ROUTE_ORIGIN_AUTHZ.0.into()),
534             content.encode_ref().to_captured(Mode::Der).into_bytes(),
535             signer,
536             issuer_key,
537         )?;
538         Ok(Roa { signed, content })
539     }
540 }
541 
542 
543 //------------ RoaIpAddressesBuilder -----------------------------------------
544 
545 #[derive(Clone, Debug)]
546 pub struct RoaIpAddressesBuilder {
547     addrs: Vec<RoaIpAddress>,
548 }
549 
550 impl RoaIpAddressesBuilder {
new() -> Self551     pub fn new() -> Self {
552         RoaIpAddressesBuilder {
553             addrs: Vec::new()
554         }
555     }
556 
push(&mut self, addr: RoaIpAddress)557     pub fn push(&mut self, addr: RoaIpAddress) {
558         self.addrs.push(addr)
559     }
560 
push_addr(&mut self, addr: IpAddr, len: u8, max_len: Option<u8>)561     pub fn push_addr(&mut self, addr: IpAddr, len: u8, max_len: Option<u8>) {
562         self.push(RoaIpAddress::new_addr(addr, len, max_len))
563     }
564 
extend_from_slice(&mut self, addrs: &[RoaIpAddress])565     pub fn extend_from_slice(&mut self, addrs: &[RoaIpAddress]) {
566         self.addrs.extend_from_slice(addrs)
567     }
568 
to_addresses(&self) -> RoaIpAddresses569     pub fn to_addresses(&self) -> RoaIpAddresses {
570         RoaIpAddresses(
571             if self.addrs.is_empty() {
572                 Captured::empty(Mode::Der)
573             }
574             else {
575                 Captured::from_values(Mode::Der, self.encode_ref())
576             }
577        )
578     }
579 
to_resources(&self) -> IpResources580     pub fn to_resources(&self) -> IpResources {
581         IpResources::blocks(
582             self.addrs.iter().map(|addr| addr.prefix.into()).collect()
583         )
584     }
585 
encode_ref(&self) -> impl encode::Values + '_586     pub fn encode_ref(&self) -> impl encode::Values + '_ {
587         encode::sequence(
588             encode::slice(self.addrs.as_slice(), |v: &RoaIpAddress| v.encode())
589         )
590     }
591 }
592 
593 impl Default for RoaIpAddressesBuilder {
default() -> Self594     fn default() -> Self {
595         Self::new()
596     }
597 }
598 
599 impl Extend<RoaIpAddress> for RoaIpAddressesBuilder {
extend<T>(&mut self, iter: T) where T: IntoIterator<Item=RoaIpAddress>600     fn extend<T>(&mut self, iter: T)
601     where T: IntoIterator<Item=RoaIpAddress> {
602         self.addrs.extend(iter)
603     }
604 }
605 
606 
607 //============ Tests =========================================================
608 
609 #[cfg(test)]
610 mod test {
611     use super::*;
612 
613     #[test]
decode_roa()614     fn decode_roa() {
615         assert!(
616             Roa::decode(
617                 include_bytes!("../../test-data/example-ripe.roa").as_ref(),
618                 false
619             ).is_ok()
620         )
621     }
622 
623     #[test]
decode_illegal_roas()624     fn decode_illegal_roas() {
625         assert!(
626             Roa::decode(
627                 include_bytes!(
628                     "../../test-data/prefix-len-overflow.roa"
629                 ).as_ref(),
630                 false
631             ).is_err()
632         );
633         assert!(
634             Roa::decode(
635                 include_bytes!("../../test-data/maxlen-overflow.roa").as_ref(),
636                 false
637             ).is_err()
638         );
639         assert!(
640             Roa::decode(
641                 include_bytes!("../../test-data/maxlen-underflow.roa").as_ref(),
642                 false
643             ).is_err()
644         );
645     }
646 }
647 
648 #[cfg(all(test, feature="softkeys"))]
649 mod signer_test {
650     use std::str::FromStr;
651     use bcder::encode::Values;
652     use crate::uri;
653     use crate::repository::cert::{KeyUsage, Overclaim, TbsCert};
654     use crate::repository::crypto::{PublicKeyFormat, Signer};
655     use crate::repository::crypto::softsigner::OpenSslSigner;
656     use crate::repository::resources::{AsId, Prefix};
657     use crate::repository::tal::TalInfo;
658     use crate::repository::x509::Validity;
659     use super::*;
660 
make_roa() -> Roa661     fn make_roa() -> Roa {
662         let signer = OpenSslSigner::new();
663         let key = signer.create_key(PublicKeyFormat::Rsa).unwrap();
664         let pubkey = signer.get_key_info(&key).unwrap();
665         let uri = uri::Rsync::from_str("rsync://example.com/m/p").unwrap();
666 
667         let mut cert = TbsCert::new(
668             12u64.into(), pubkey.to_subject_name(),
669             Validity::from_secs(86400), None, pubkey, KeyUsage::Ca,
670             Overclaim::Trim
671         );
672         cert.set_basic_ca(Some(true));
673         cert.set_ca_repository(Some(uri.clone()));
674         cert.set_rpki_manifest(Some(uri.clone()));
675         cert.build_v4_resource_blocks(|b| b.push(Prefix::new(0, 0)));
676         cert.build_v6_resource_blocks(|b| b.push(Prefix::new(0, 0)));
677         cert.build_as_resource_blocks(|b| b.push((AsId::MIN, AsId::MAX)));
678         let cert = cert.into_cert(&signer, &key).unwrap();
679 
680         let mut roa = RoaBuilder::new(64496.into());
681         roa.push_v4_addr(Ipv4Addr::new(192, 0, 2, 0), 24, None);
682 
683         let roa = roa.finalize(
684             SignedObjectBuilder::new(
685                 12u64.into(), Validity::from_secs(86400), uri.clone(),
686                 uri.clone(), uri
687             ),
688             &signer, &key
689         ).unwrap();
690         let roa = roa.encode_ref().to_captured(Mode::Der);
691 
692         let roa = Roa::decode(roa.as_slice(), true).unwrap();
693         let cert = cert.validate_ta(
694             TalInfo::from_name("foo".into()).into_arc(), true
695         ).unwrap();
696         roa.clone().process(&cert, true, |_| Ok(())).unwrap();
697 
698         roa
699     }
700 
701     #[test]
encode_roa()702     fn encode_roa() {
703         make_roa();
704     }
705 
706     #[test]
707     #[cfg(feature = "serde")]
serde_roa()708     fn serde_roa() {
709         let roa = make_roa();
710 
711         let serialized = serde_json::to_string(&roa).unwrap();
712         let deser_roa: Roa = serde_json::from_str(&serialized).unwrap();
713 
714         assert_eq!(
715             roa.to_captured().into_bytes(),
716             deser_roa.to_captured().into_bytes()
717         )
718     }
719 }
720 
721 
722 //============ Specification Documentation ===================================
723 
724 /// ROA Specification.
725 ///
726 /// This is a documentation-only module. It summarizes the specification for
727 /// ROAs, how they are parsed and constructed.
728 ///
729 /// A Route Origin Authorization (ROA) is a [signed object] that assigns a
730 /// number of route prefixes to an AS number. It is specified in [RFC 6482].
731 ///
732 /// The content of a ROA signed object is of type `RouteOriginAttestation`
733 /// which is defined as follows:
734 ///
735 /// ```txt
736 /// RouteOriginAttestation  ::= SEQUENCE {
737 ///     version                 [0] INTEGER DEFAULT 0,
738 ///     asID                    ASID,
739 ///     ipAddrBlocks            SEQUENCE (SIZE(1..MAX)) OF ROAIPAddressFamily
740 /// }
741 ///
742 /// ASID                    ::= INTEGER
743 ///
744 /// ROAIPAddressFamily      ::= SEQUENCE {
745 ///     addressFamily           OCTET STRING (SIZE (2..3)),
746 ///     addresses               SEQUENCE (SIZE (1..MAX)) OF ROAIPAddress
747 /// }
748 ///
749 /// ROAIPAddress            ::= SEQUENCE {
750 ///     address                 IPAddress,
751 ///     maxLength               INTEGER OPTIONAL
752 /// }
753 ///
754 /// IPAddress               ::= BIT STRING
755 /// ```
756 ///
757 /// The _version_ must be 0. The _addressFamily_ is identical to the field
758 /// used in RPKI certificate IP resources, i.e, `"\0\x01"` for IPv4 and
759 /// `"\0\x02"` for IPv6.
760 ///
761 /// [signed object]: ../../sigobj/spec/index.html
762 /// [RFC 6482]: https://tools.ietf.org/html/rfc6482
763 pub mod spec { }
764 
765