diff options
Diffstat (limited to 'rpkid/rpki')
-rw-r--r-- | rpkid/rpki/left_right.py | 50 | ||||
-rw-r--r-- | rpkid/rpki/relaxng.py | 31 | ||||
-rw-r--r-- | rpkid/rpki/resource_set.py | 30 | ||||
-rw-r--r-- | rpkid/rpki/roa.py | 32 | ||||
-rw-r--r-- | rpkid/rpki/x509.py | 3 |
5 files changed, 68 insertions, 78 deletions
diff --git a/rpkid/rpki/left_right.py b/rpkid/rpki/left_right.py index e9bb7a92..209302f4 100644 --- a/rpkid/rpki/left_right.py +++ b/rpkid/rpki/left_right.py @@ -826,11 +826,11 @@ class route_origin_elt(data_elt): """<route_origin/> element.""" element_name = "route_origin" - attributes = ("action", "type", "tag", "self_id", "route_origin_id", "as_number", "exact_match", "ipv4", "ipv6") + attributes = ("action", "type", "tag", "self_id", "route_origin_id", "as_number", "ipv4", "ipv6") booleans = ("suppress_publication",) sql_template = rpki.sql.template("route_origin", "route_origin_id", "ca_detail_id", - "self_id", "as_number", "exact_match", + "self_id", "as_number", ("roa", rpki.x509.ROA), ("cert", rpki.x509.X509)) @@ -839,28 +839,28 @@ class route_origin_elt(data_elt): roa = None def sql_fetch_hook(self): - """Extra SQL fetch actions for route_origin_elt -- handle address ranges.""" - self.ipv4 = rpki.resource_set.resource_set_ipv4.from_sql(self.gctx.cur, """ - SELECT start_ip, end_ip FROM route_origin_range - WHERE route_origin_id = %s AND start_ip NOT LIKE '%:%' + """Extra SQL fetch actions for route_origin_elt -- handle prefix list.""" + self.ipv4 = rpki.resource_set.roa_prefix_set_ipv4.from_sql(self.gctx.cur, """ + SELECT address, prefixlen, max_prefixlen FROM route_origin_prefix + WHERE route_origin_id = %s AND address NOT LIKE '%:%' """, (self.route_origin_id,)) - self.ipv6 = rpki.resource_set.resource_set_ipv6.from_sql(self.gctx.cur, """ - SELECT start_ip, end_ip FROM route_origin_range - WHERE route_origin_id = %s AND start_ip LIKE '%:%' + self.ipv6 = rpki.resource_set.roa_prefix_set_ipv6.from_sql(self.gctx.cur, """ + SELECT address, prefixlen, max_prefixlen FROM route_origin_prefix + WHERE route_origin_id = %s AND address LIKE '%:%' """, (self.route_origin_id,)) def sql_insert_hook(self): """Extra SQL insert actions for route_origin_elt -- handle address ranges.""" if self.ipv4 or self.ipv6: self.gctx.cur.executemany(""" - INSERT route_origin_range (route_origin_id, start_ip, end_ip) - VALUES (%s, %s, %s)""", - ((self.route_origin_id, x.min, x.max) + INSERT route_origin_prefix (route_origin_id, address, prefixlen, max_prefixlen) + VALUES (%s, %s, %s, %s)""", + ((self.route_origin_id, x.address, x.prefixlen, x.max_prefixlen) for x in (self.ipv4 or []) + (self.ipv6 or []))) def sql_delete_hook(self): """Extra SQL delete actions for route_origin_elt -- handle address ranges.""" - self.gctx.cur.execute("DELETE FROM route_origin_range WHERE route_origin_id = %s", (self.route_origin_id,)) + self.gctx.cur.execute("DELETE FROM route_origin_prefix WHERE route_origin_id = %s", (self.route_origin_id,)) def ca_detail(self): """Fetch all ca_detail objects that link to this route_origin object.""" @@ -877,9 +877,9 @@ class route_origin_elt(data_elt): if self.as_number is not None: self.as_number = long(self.as_number) if self.ipv4 is not None: - self.ipv4 = rpki.resource_set.resource_set_ipv4(self.ipv4) + self.ipv4 = rpki.resource_set.roa_prefix_set_ipv4(self.ipv4) if self.ipv6 is not None: - self.ipv6 = rpki.resource_set.resource_set_ipv6(self.ipv6) + self.ipv6 = rpki.resource_set.roa_prefix_set_ipv6(self.ipv6) def endElement(self, stack, name, text): """Handle <route_origin/> element.""" @@ -912,8 +912,8 @@ class route_origin_elt(data_elt): if ee_resources.oversized(ca_resources): return self.regenerate_roa() - v4 = self.ipv4 if self.ipv4 is not None else rpki.resource_set.resource_set_ipv4() - v6 = self.ipv6 if self.ipv6 is not None else rpki.resource_set.resource_set_ipv6() + v4 = self.ipv4.to_resource_set() if self.ipv4 is not None else rpki.resource_set.resource_set_ipv4() + v6 = self.ipv6.to_resource_set() if self.ipv6 is not None else rpki.resource_set.resource_set_ipv6() if ee_resources.v4 != v4 or ee_resources.v6 != v6: return self.regenerate_roa() @@ -938,12 +938,8 @@ class route_origin_elt(data_elt): /dev/random, but there is not much we can do about that. """ - if self.exact_match is None: - rpki.log.warn("Can't generate ROA with undefined exactMatch") - return - if self.ipv4 is None and self.ipv6 is None: - rpki.log.warn("Can't generate ROA for empty address list") + rpki.log.warn("Can't generate ROA for empty prefix list") return # Ugly and expensive search for covering ca_detail, there has to @@ -953,6 +949,9 @@ class route_origin_elt(data_elt): # first checking the ca_detail we used last time, but it may not # be active, in which we have to check the ca_detail that replaced it. + v4 = self.ipv4.to_resource_set() if self.ipv4 is not None else rpki.resource_set.resource_set_ipv4() + v6 = self.ipv6.to_resource_set() if self.ipv6 is not None else rpki.resource_set.resource_set_ipv6() + ca_detail = self.ca_detail() if ca_detail is None or ca_detail.state != "active": ca_detail = None @@ -961,8 +960,7 @@ class route_origin_elt(data_elt): ca_detail = ca.fetch_active() if ca_detail is not None: resources = ca_detail.latest_ca_cert.get_3779resources() - if ((self.ipv4 is None or self.ipv4.issubset(resources.v4)) and - (self.ipv6 is None or self.ipv6.issubset(resources.v6))): + if v4.issubset(resources.v4) and v6.issubset(resources.v6): break ca_detail = None if ca_detail is not None: @@ -972,7 +970,7 @@ class route_origin_elt(data_elt): rpki.log.warn("generate_roa() could not find a covering certificate") return - resources = rpki.resource_set.resource_bag(v4 = self.ipv4, v6 = self.ipv6) + resources = rpki.resource_set.resource_bag(v4 = v4, v6 = v6) keypair = rpki.x509.RSA() keypair.generate() @@ -980,7 +978,7 @@ class route_origin_elt(data_elt): sia = ((rpki.oids.name2oid["id-ad-signedObject"], ("uri", self.roa_uri(ca, keypair))),) self.cert = ca_detail.issue_ee(ca, resources, keypair.get_RSApublic(), sia = sia) - self.roa = rpki.x509.ROA.build(self.as_number, self.exact_match, self.ipv4, self.ipv6, keypair, (self.cert,)) + self.roa = rpki.x509.ROA.build(self.as_number, self.ipv4, self.ipv6, keypair, (self.cert,)) self.ca_detail_id = ca_detail.ca_detail_id self.sql_store() diff --git a/rpkid/rpki/relaxng.py b/rpkid/rpki/relaxng.py index 4baf7723..fecb4c2a 100644 --- a/rpkid/rpki/relaxng.py +++ b/rpkid/rpki/relaxng.py @@ -166,32 +166,19 @@ left_right = lxml.etree.RelaxNG(lxml.etree.fromstring('''<?xml version="1.0" enc <define name="asn_list"> <data type="string"> <param name="maxLength">512000</param> - <param name="pattern">[\-,/0-9]*</param> + <param name="pattern">[\-,0-9]*</param> </data> </define> - <define name="ipv4_address_list"> + <define name="ipv4_list"> <data type="string"> <param name="maxLength">512000</param> - <param name="pattern">[\-,/.0-9]*</param> + <param name="pattern">[\-,0-9/.]*</param> </data> </define> - <define name="ipv6_address_list"> + <define name="ipv6_list"> <data type="string"> <param name="maxLength">512000</param> - <param name="pattern">[\-,/:0-9a-fA-F]*</param> - </data> - </define> - <!-- Prefix resource lists, same as address resource lists not no ranges allowed --> - <define name="ipv4_prefix_list"> - <data type="string"> - <param name="maxLength">512000</param> - <param name="pattern">[,/.0-9]*</param> - </data> - </define> - <define name="ipv6_prefix_list"> - <data type="string"> - <param name="maxLength">512000</param> - <param name="pattern">[,/:0-9a-fA-F]*</param> + <param name="pattern">[\-,0-9/:a-fA-F]*</param> </data> </define> <!-- <self/> element --> @@ -844,12 +831,12 @@ left_right = lxml.etree.RelaxNG(lxml.etree.fromstring('''<?xml version="1.0" enc </optional> <optional> <attribute name="ipv4"> - <ref name="ipv4_prefix_list"/> + <ref name="ipv4_list"/> </attribute> </optional> <optional> <attribute name="ipv6"> - <ref name="ipv6_prefix_list"/> + <ref name="ipv6_list"/> </attribute> </optional> </define> @@ -965,12 +952,12 @@ left_right = lxml.etree.RelaxNG(lxml.etree.fromstring('''<?xml version="1.0" enc </optional> <optional> <attribute name="ipv4"> - <ref name="ipv4_address_list"/> + <ref name="ipv4_list"/> </attribute> </optional> <optional> <attribute name="ipv6"> - <ref name="ipv6_address_list"/> + <ref name="ipv6_list"/> </attribute> </optional> </group> diff --git a/rpkid/rpki/resource_set.py b/rpkid/rpki/resource_set.py index cd8a68d6..3d92b2ce 100644 --- a/rpkid/rpki/resource_set.py +++ b/rpkid/rpki/resource_set.py @@ -57,6 +57,7 @@ class resource_range(object): def __cmp__(self, other): """Compare two resource_range objects.""" + assert self.__class__ is other.__class__ c = self.min - other.min if c == 0: c = self.max - other.max if c < 0: c = -1 @@ -125,13 +126,6 @@ class resource_range_ip(resource_range): else: return ("addressPrefix", _long2bs(self.min, self.datum_type.bits, prefixlen = prefixlen)) - def to_roa_tuple(self): - """Convert a resource_range_ip to tuple format for ROA ASN.1 encoding.""" - prefixlen = self._prefixlen() - if prefixlen < 0: - raise rpki.exceptions.MustBePrefix, "%s cannot be expressed as a prefix" % str(self) - return _long2bs(self.min, self.datum_type.bits, prefixlen = prefixlen) - @classmethod def make_prefix(cls, address, prefixlen): """Construct a resource range corresponding to a prefix.""" @@ -401,14 +395,6 @@ class resource_set_ip(resource_set): else: return None - def to_roa_tuple(self): - """Convert IP resource set into tuple format used by ROA ASN.1 encoder. - This is a variation on the format used in RFC 3779.""" - if self: - return (self.afi, tuple(a.to_roa_tuple() for a in self)) - else: - return None - class resource_set_ipv4(resource_set_ip): """IPv4 address resource set.""" @@ -592,6 +578,7 @@ class roa_prefix(object): """Compare two ROA prefix objects. Comparision is based on address, prefixlen, and max_prefixlen, in that order. """ + assert self.__class__ is other.__class__ c = self.address - other.address if c == 0: c = self.prefixlen - other.prefixlen if c == 0: c = self.max_prefixlen - other.max_prefixlen @@ -622,6 +609,11 @@ class roa_prefix(object): t = self.range_type.datum_type return t(self.address | ((1 << (t.bits - self.prefixlen)) - 1)) + def to_roa_tuple(self): + """Convert a resource_range_ip to tuple format for ROA ASN.1 encoding.""" + return (_long2bs(self.address, self.range_type.datum_type.bits, prefixlen = self.prefixlen), + None if self.prefixlen == self.max_prefixlen else self.max_prefixlen) + class roa_prefix_ipv4(roa_prefix): """IPv4 ROA prefix.""" @@ -685,6 +677,14 @@ class roa_prefix_set(list): return cls([cls.prefix_type(cls.prefix_type.range_type.datum_type(x), int(y), int(z)) for (x,y,z) in cur.fetchall()]) + def to_roa_tuple(self): + """Convert ROA prefix set into tuple format used by ROA ASN.1 encoder. + This is a variation on the format used in RFC 3779.""" + if self: + return (self.resource_set_type.afi, tuple(a.to_roa_tuple() for a in self)) + else: + return None + class roa_prefix_set_ipv4(roa_prefix_set): """Set of IPv4 ROA prefixes.""" diff --git a/rpkid/rpki/roa.py b/rpkid/rpki/roa.py index 2b1ba7fd..b059e851 100644 --- a/rpkid/rpki/roa.py +++ b/rpkid/rpki/roa.py @@ -18,13 +18,13 @@ At the moment this is just the ASN.1 encoder. -This corresponds to draft-ietf-sidr-roa-format-02, which is a work in +This corresponds to draft-ietf-sidr-roa-format, which is a work in progress, so this may need updating later. """ from POW._der import * -# draft-ietf-sidr-roa-format-02 2.1.3.2 +# draft-ietf-sidr-roa-format-02 2.1.3.2 specifies: # # RouteOriginAttestation ::= SEQUENCE { # version [0] INTEGER DEFAULT 0, @@ -41,9 +41,9 @@ from POW._der import * # addresses SEQUENCE OF IPAddress } # # IPAddress ::= BIT STRING - -# Proposed new format, neither in draft nor in this code yet, but -# included here for reference anyway: +# +# ... but we now implement the new format that will supposedly appear +# in the upcoming draft-ietf-sidr-roa-format-03: # # RouteOriginAttestation ::= SEQUENCE { # version [0] INTEGER DEFAULT 0, @@ -58,22 +58,29 @@ from POW._der import * # # ROAIPAddress ::= { # address IPAddress, -# maxLength INTEGER } +# maxLength INTEGER OPTIONAL } # # IPAddress ::= BIT STRING -class IPAddresses(SequenceOf): +class ROAIPAddress(Sequence): + def __init__(self, optional=0, default=''): + self.address = BitString() + self.maxLength = Integer(1) + contents = [ self.address, self.maxLength ] + Sequence.__init__(self, contents, optional, default) + +class ROAIPAddresses(SequenceOf): def __init__(self, optional=0, default=''): - SequenceOf.__init__(self, BitString, optional, default) + SequenceOf.__init__(self, ROAIPAddress, optional, default) class ROAIPAddressFamily(Sequence): def __init__(self, optional=0, default=''): self.addressFamily = OctetString() - self.addresses = IPAddresses() + self.addresses = ROAIPAddresses() contents = [ self.addressFamily, self.addresses ] Sequence.__init__(self, contents, optional, default) -class ROAIPAddrBlocks(SequenceOf): +class ROAIPAddressFamilies(SequenceOf): def __init__(self, optional=0, default=''): SequenceOf.__init__(self, ROAIPAddressFamily, optional, default) @@ -82,7 +89,6 @@ class RouteOriginAttestation(Sequence): self.version = Integer() self.explicitVersion = Explicit(CLASS_CONTEXT, FORM_CONSTRUCTED, 0, self.version, 0, 'oAMCAQA=') self.asID = Integer() - self.exactMatch = Boolean() - self.ipAddrBlocks = ROAIPAddrBlocks() - contents = [ self.explicitVersion, self.asID, self.exactMatch, self.ipAddrBlocks ] + self.ipAddrBlocks = ROAIPAddressFamilies() + contents = [ self.explicitVersion, self.asID, self.ipAddrBlocks ] Sequence.__init__(self, contents, optional, default) diff --git a/rpkid/rpki/x509.py b/rpkid/rpki/x509.py index 09238370..83cd31e5 100644 --- a/rpkid/rpki/x509.py +++ b/rpkid/rpki/x509.py @@ -801,13 +801,12 @@ class ROA(DER_CMS_object): econtent_oid = POWify_OID("id-ct-routeOriginAttestation") @classmethod - def build(cls, as_number, exact_match, ipv4, ipv6, keypair, certs, version = 0): + def build(cls, as_number, ipv4, ipv6, keypair, certs, version = 0): """Build a ROA.""" self = cls() r = rpki.roa.RouteOriginAttestation() r.version.set(version) r.asID.set(as_number) - r.exactMatch.set(exact_match) r.ipAddrBlocks.set((a.to_roa_tuple() for a in (ipv4, ipv6) if a)) self.set_content(r) self.sign(keypair, certs) |