aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rpkid/left-right-schema.rnc18
-rw-r--r--rpkid/left-right-schema.rng31
-rw-r--r--rpkid/rpki/left_right.py50
-rw-r--r--rpkid/rpki/relaxng.py31
-rw-r--r--rpkid/rpki/resource_set.py30
-rw-r--r--rpkid/rpki/roa.py32
-rw-r--r--rpkid/rpki/x509.py3
-rw-r--r--rpkid/rpkid.sql11
-rw-r--r--rpkid/testbed.py6
9 files changed, 94 insertions, 118 deletions
diff --git a/rpkid/left-right-schema.rnc b/rpkid/left-right-schema.rnc
index 3f4e6e96..14559205 100644
--- a/rpkid/left-right-schema.rnc
+++ b/rpkid/left-right-schema.rnc
@@ -45,13 +45,9 @@ uri = xsd:anyURI { maxLength="4096" }
up_down_name = xsd:token { maxLength="1024" }
# Resource lists
-asn_list = xsd:string { maxLength="512000" pattern="[\-,/0-9]*" }
-ipv4_address_list = xsd:string { maxLength="512000" pattern="[\-,/.0-9]*" }
-ipv6_address_list = xsd:string { maxLength="512000" pattern="[\-,/:0-9a-fA-F]*" }
-
-# Prefix resource lists, same as address resource lists not no ranges allowed
-ipv4_prefix_list = xsd:string { maxLength="512000" pattern="[,/.0-9]*" }
-ipv6_prefix_list = xsd:string { maxLength="512000" pattern="[,/:0-9a-fA-F]*" }
+asn_list = xsd:string { maxLength="512000" pattern="[\-,0-9]*" }
+ipv4_list = xsd:string { maxLength="512000" pattern="[\-,0-9/.]*" }
+ipv6_list = xsd:string { maxLength="512000" pattern="[\-,0-9/:a-fA-F]*" }
# <self/> element
@@ -191,8 +187,8 @@ route_origin_bool = attribute suppress_publication { "yes" }?
route_origin_payload = (attribute as_number { xsd:positiveInteger }?,
attribute exact_match { xsd:boolean }?,
- attribute ipv4 { ipv4_prefix_list }?,
- attribute ipv6 { ipv6_prefix_list }?)
+ attribute ipv4 { ipv4_list }?,
+ attribute ipv6 { ipv6_list }?)
route_origin_elt |= element route_origin { ctl_cq, self_id, route_origin_bool, route_origin_payload }
route_origin_elt |= element route_origin { ctl_cr, self_id, route_origin_id }
@@ -213,8 +209,8 @@ list_resources_elt = element list_resources {
attribute valid_until { xsd:dateTime { pattern=".*Z" } },
attribute subject_name { xsd:token { maxLength="1024" } }?,
attribute asn { asn_list }?,
- attribute ipv4 { ipv4_address_list }?,
- attribute ipv6 { ipv6_address_list }?
+ attribute ipv4 { ipv4_list }?,
+ attribute ipv6 { ipv6_list }?
)
}
diff --git a/rpkid/left-right-schema.rng b/rpkid/left-right-schema.rng
index 93f79d32..6c5b9d6b 100644
--- a/rpkid/left-right-schema.rng
+++ b/rpkid/left-right-schema.rng
@@ -160,32 +160,19 @@
<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 -->
@@ -838,12 +825,12 @@
</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>
@@ -959,12 +946,12 @@
</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/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)
diff --git a/rpkid/rpkid.sql b/rpkid/rpkid.sql
index d13eb370..fa50c1d6 100644
--- a/rpkid/rpkid.sql
+++ b/rpkid/rpkid.sql
@@ -177,13 +177,14 @@ CREATE TABLE route_origin (
FOREIGN KEY (ca_detail_id) REFERENCES ca_detail
);
-DROP TABLE IF EXISTS route_origin_range;
+DROP TABLE IF EXISTS route_origin_prefix;
-CREATE TABLE route_origin_range (
- start_ip VARCHAR(40),
- end_ip VARCHAR(40),
+CREATE TABLE route_origin_prefix (
+ address VARCHAR(40) NOT NULL,
+ prefixlen TINYINT NOT NULL,
+ max_prefixlen TINYINT NOT NULL,
route_origin_id BIGINT unsigned NOT NULL,
- PRIMARY KEY (route_origin_id, start_ip, end_ip),
+ PRIMARY KEY (route_origin_id, address, prefixlen, max_prefixlen),
FOREIGN KEY (route_origin_id) REFERENCES route_origin
);
diff --git a/rpkid/testbed.py b/rpkid/testbed.py
index 3d01c7d1..2c697b42 100644
--- a/rpkid/testbed.py
+++ b/rpkid/testbed.py
@@ -255,8 +255,8 @@ class route_origin(object):
def __init__(self, asn, ipv4, ipv6, exact_match):
self.asn = asn
- self.v4 = rpki.resource_set.resource_set_ipv4("".join(ipv4.split())) if ipv4 else None
- self.v6 = rpki.resource_set.resource_set_ipv6("".join(ipv6.split())) if ipv6 else None
+ self.v4 = rpki.resource_set.roa_prefix_set_ipv4("".join(ipv4.split())) if ipv4 else None
+ self.v6 = rpki.resource_set.roa_prefix_set_ipv6("".join(ipv6.split())) if ipv6 else None
self.exact_match = exact_match
def __eq__(self, other):
@@ -308,6 +308,8 @@ class allocation_db(list):
def apply_delta(self, delta):
"""Apply a delta or run a command."""
+ if delta is None:
+ return
for d in delta:
if isinstance(d, str):
c = d.split()