aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/biz-certs/Bob-CA.srl2
-rw-r--r--scripts/pkcs10.py8
-rw-r--r--scripts/rpki/left_right.py23
-rw-r--r--scripts/rpki/resource_set.py79
-rw-r--r--scripts/rpki/sql.py61
-rw-r--r--scripts/rpki/up_down.py36
-rw-r--r--scripts/rpki/x509.py22
-rw-r--r--scripts/test-pow.py14
-rwxr-xr-xscripts/testroot.py8
9 files changed, 141 insertions, 112 deletions
diff --git a/scripts/biz-certs/Bob-CA.srl b/scripts/biz-certs/Bob-CA.srl
index a7659166..4c1a4d01 100644
--- a/scripts/biz-certs/Bob-CA.srl
+++ b/scripts/biz-certs/Bob-CA.srl
@@ -1 +1 @@
-90801F1ED194549C
+90801F1ED19454A1
diff --git a/scripts/pkcs10.py b/scripts/pkcs10.py
index 77272ff0..77cb8666 100644
--- a/scripts/pkcs10.py
+++ b/scripts/pkcs10.py
@@ -58,10 +58,10 @@ if parse_test:
exts = pkcs10.getExtensions()
- as, v4, v6 = rpki.resource_set.parse_extensions(exts)
- if as: print "ASN =", as
- if v4: print "IPv4 =", v4
- if v6: print "IPv6 =", v6
+ bag = rpki.resource_set.parse_extensions(exts)
+ if bag.as: print "ASN =", bag.as
+ if bag.v4: print "IPv4 =", bag.v4
+ if bag.v6: print "IPv6 =", bag.v6
for oid, crit, val in exts:
if oid in ((1, 3, 6, 1, 5, 5, 7, 1, 7), (1, 3, 6, 1, 5, 5, 7, 1, 8)):
diff --git a/scripts/rpki/left_right.py b/scripts/rpki/left_right.py
index 3979931b..3528152d 100644
--- a/scripts/rpki/left_right.py
+++ b/scripts/rpki/left_right.py
@@ -729,17 +729,14 @@ class sax_handler(rpki.sax_utils.handler):
return self.pdu()
def irdb_query(gctx, self_id, child_id = None):
- """Perform an IRDB callback query.
-
- In the long run this should not be a blocking routine, it should
- instead issue a query and set up a handler to receive the response.
- For the moment, though, we're doing simple lock step and damn the
- torpedos.
-
- Not yet doing anything useful with validity interval or subject
- name. Most likely this function should really be wrapped up in a
- class that carries both the query result and also the intermediate state
- needed for the event-driven code that this function will need to become.
+ """Perform an IRDB callback query. In the long run this should not
+ be a blocking routine, it should instead issue a query and set up a
+ handler to receive the response. For the moment, though, we are
+ doing simple lock step and damn the torpedos. Not yet doing
+ anything useful with validity interval or subject name. Most likely
+ this function should really be wrapped up in a class that carries
+ both the query result and also the intermediate state needed for the
+ event-driven code that this function will need to become.
"""
q_msg = msg()
@@ -760,4 +757,6 @@ def irdb_query(gctx, self_id, child_id = None):
r_msg = rpki.left_right.sax_handler.saxify(r_elt)
if len(r_msg) == 0 or not isinstance(r_msg[0], list_resources_elt) or r_msg[0].type != "reply":
raise rpki.exceptions.BadIRDBReply, "Unexpected response to IRDB query: %s" % r_msg.toXML()
- return r_msg[0].as, r_msg[0].ipv4, r_msg[0].ipv6
+ return rpki.resource_set.resource_bag(r_msg[0].as,
+ r_msg[0].ipv4,
+ r_msg[0].ipv6)
diff --git a/scripts/rpki/resource_set.py b/scripts/rpki/resource_set.py
index 0c09f19d..48c6cfb1 100644
--- a/scripts/rpki/resource_set.py
+++ b/scripts/rpki/resource_set.py
@@ -378,27 +378,64 @@ def _long2bs(number, addrlen, prefixlen = None, strip = None):
bs.pop()
return tuple(bs)
-def parse_extensions(exts):
- """Parse RFC 3779 extensions from intermediate form returned by ASN.1 decoder."""
- as = None
- v4 = None
- v6 = None
- for x in exts:
- if x[0] == (1, 3, 6, 1, 5, 5, 7, 1, 8): # sbgp-autonomousSysNum
- assert x[2][1] is None, "RDI not implemented: %s" % (str(x))
- assert as is None
- as = resource_set_as(x[2][0])
- if x[0] == (1, 3, 6, 1, 5, 5, 7, 1, 7): # sbgp-ipAddrBlock
- for fam in x[2]:
- if fam[0] == resource_set_ipv4.afi:
- assert v4 is None
- v4 = resource_set_ipv4(fam[1])
- if fam[0] == resource_set_ipv6.afi:
- assert v6 is None
- v6 = resource_set_ipv6(fam[1])
- return as or resource_set_as(), \
- v4 or resource_set_ipv4(), \
- v6 or resource_set_ipv6()
+class resource_bag(object):
+ """Container to simplify passing around the usual triple of AS,
+ IPv4, and IPv6 resource sets.
+ """
+
+ def __init__(self, as = None, v4 = None, v6 = None):
+ self.as = as or resource_set_as()
+ self.v4 = v4 or resource_set_ipv4()
+ self.v6 = v6 or resource_set_ipv6()
+
+ def oversized(self, other):
+ """True iff self is oversized with respect to other."""
+ return not self.as.issubset(other.as) or \
+ not self.v4.issubset(other.v4) or \
+ not self.v6.issubset(other.v6)
+
+ def undersized(self, other):
+ """True iff self is undersized with respect to other."""
+ return not other.as.issubset(self.as) or \
+ not other.v4.issubset(self.v4) or \
+ not other.v6.issubset(self.v6)
+
+ @classmethod
+ def from_asn1_tuples(cls, exts):
+ """Build a resource_bag from intermediate form returned by ASN.1 decoder."""
+ as = None
+ v4 = None
+ v6 = None
+ for x in exts:
+ if x[0] == (1, 3, 6, 1, 5, 5, 7, 1, 8): # sbgp-autonomousSysNum
+ assert x[2][1] is None, "RDI not implemented: %s" % (str(x))
+ assert as is None
+ as = resource_set_as(x[2][0])
+ if x[0] == (1, 3, 6, 1, 5, 5, 7, 1, 7): # sbgp-ipAddrBlock
+ for fam in x[2]:
+ if fam[0] == resource_set_ipv4.afi:
+ assert v4 is None
+ v4 = resource_set_ipv4(fam[1])
+ if fam[0] == resource_set_ipv6.afi:
+ assert v6 is None
+ v6 = resource_set_ipv6(fam[1])
+ return cls(as, v4, v6)
+
+ def empty(self):
+ """Return True iff all resource sets in this bag are empty."""
+ return not self.as and not self.v4 and not self.v6
+
+ def __eq__(self, other):
+ return self.as == other.as and self.v4 == other.v4 and self.v6 == other.v6
+
+ def __ne__(self, other):
+ return not (self == other)
+
+ def intersection(self, other):
+ """Compute intersection with another resource_bag."""
+ return self.__class__(self.as.intersection(other.as),
+ self.v4.intersection(other.v4),
+ self.v6.intersection(other.v6))
# Test suite for set operations. This will probably go away eventually
diff --git a/scripts/rpki/sql.py b/scripts/rpki/sql.py
index b3348f87..2ac0c210 100644
--- a/scripts/rpki/sql.py
+++ b/scripts/rpki/sql.py
@@ -223,24 +223,23 @@ class ca_obj(sql_persistant):
off to the affected ca_detail for processing.
"""
- cert_map = dict((c.cert.get_SKI(), c) for c in rc.certs)
- ca_details = ca_detail_obj.sql_fetch_where(gctx, "ca_id = %s AND latest_ca_cert IS NOT NULL" % self.ca_id)
- as, v4, v6 = ca_detail_obj.sql_fetch_active(gctx, self.ca_id).latest_ca_cert.get_3779resources()
- undersized = not rc.resource_set_as.issubset(as) or \
- not rc.resource_set_ipv4.issubset(v4) or \
- not rc.resource_set_ipv6.issubset(v6)
- oversized = not as.issubset(rc.resource_set_as) or \
- not v4.issubset(rc.resource_set_ipv4) or \
- not v6.issubset(rc.resource_set_ipv6)
sia_uri = self.construct_sia_uri(gctx, parent, rc)
sia_uri_changed = self.sia_uri != sia_uri
if sia_uri_changed:
self.sia_uri = sia_uri
self.sql_mark_dirty()
- for ca_detail in ca_details:
+
+ rc_resources = rc.to_resource_bag()
+ cert_map = dict((c.cert.get_SKI(), c) for c in rc.certs)
+
+ for ca_detail in ca_detail_obj.sql_fetch_where(gctx, "ca_id = %s AND latest_ca_cert IS NOT NULL AND state != 'revoked'" % self.ca_id):
ski = ca_detail.latest_ca_cert.get_SKI()
- if ca_detail.state not in ("deprecated", "revoked") and (undersized or oversized or sia_uri_changed or ca_detail.latest_ca_cert != cert_map[ski].cert):
- ca_detail.update(gctx, parent, self, rc, cert_map[ski].cert, undersized, oversized, sia_uri_changed, as, v4, v6)
+ if ca_detail.state != "deprecated":
+ current_resources = ca_detail_obj.sql_fetch_active(gctx, self.ca_id).latest_ca_cert.get_3779resources()
+ undersized = current_resources.undersized(rc_resources)
+ oversized = current_resources.oversized(rc_resources)
+ if undersized or oversized or sia_uri_changed or ca_detail.latest_ca_cert != cert_map[ski].cert:
+ ca_detail.update(gctx, parent, self, rc, cert_map[ski].cert, undersized, oversized, sia_uri_changed, current_resources, rc_resources)
del cert_map[ski]
assert not cert_map, "Certificates in list_response missing from our database, SKIs %s" % ", ".join(c.cert.hSKI() for c in cert_map.values())
@@ -341,7 +340,7 @@ class ca_detail_obj(sql_persistant):
"""Fetch the current active ca_detail_obj associated with a given ca_id."""
return cls.sql_fetch_where1(gctx, "ca_id = %s AND state = 'active'" % ca_id)
- def update(self, gctx, parent, ca, rc, newcert, undersized, oversized, sia_uri_changed, as, v4, v6):
+ def update(self, gctx, parent, ca, rc, newcert, undersized, oversized, sia_uri_changed, current_resources, rc_resources):
"""CA has received a cert for this ca_detail that doesn't match
the current one, figure out what to do about it. Cases:
@@ -358,17 +357,14 @@ class ca_detail_obj(sql_persistant):
"""
if undersized:
issue_response = rpki.up_down.issue_pdu.query(gctx, parent, ca, self)
- issue_response.check()
- self.latest_ca_cert = issue_response.classes[0].certs[0]
- as, v4, v6 = self.latest_ca_cert.get_3779resources()
+ issue_response.check_syntax()
+ self.latest_ca_cert = issue_response.classes[0].certs[0].cert
+ current_resources = self.latest_ca_cert.get_3779resources()
if oversized or sia_uri_changed:
for child_cert in child_cert_obj.sql_fetch_where(gctx, "ca_detail_id = %s" % self.ca_detail_id):
- child_as, child_v4, child_v6 = child_cert.cert.get_3779resources()
- if sia_uri_changed or \
- not child_as.issubset(as) or \
- not child_v4.issubset(v4) or \
- not child_v6.issubset(v6):
- child_cert.reissue(gctx, self, as, v4, v6, ca.sia_uri)
+ child_resources = child_cert.cert.get_3779resources()
+ if sia_uri_changed or child_resources.oversized(current_resources):
+ child_cert.reissue(gctx, self, child_resources.intersection(current_resources), ca.sia_uri)
@classmethod
def create(cls, gctx, ca):
@@ -391,18 +387,20 @@ class ca_detail_obj(sql_persistant):
def generate_manifest_cert(self, ca):
"""Generate a new manifest certificate for this ca_detail."""
+ resources = rpki.resource_set.resource_bag(as = rpki.resource_set.resource_set_as("<inherit>"),
+ v4 = rpki.resource_set.resource_set_ipv4("<inherit>"),
+ v6 = rpki.resource_set.resource_set_ipv6("<inherit>"))
+
self.latest_manifest_cert = self.latest_ca_cert.issue(keypair = self.private_key_id,
subject_key = self.manifest_public_key,
serial = ca.next_serial_number(),
sia = None,
aia = self.ca_cert_uri,
crldp = ca.sia_uri + self.latest_ca_cert.gSKI() + ".crl",
- as = rpki.resource_set.resource_set_as("<inherit>"),
- v4 = rpki.resource_set.resource_set_ipv4("<inherit>"),
- v6 = rpki.resource_set.resource_set_ipv6("<inherit>"),
+ resources = resources,
is_ca = False)
- def issue(self, gctx, ca, child, subject_key, sia, as, v4, v6, child_cert = None):
+ def issue(self, gctx, ca, child, subject_key, sia, resources, child_cert = None):
"""Issue a new certificate to a child.
Need to figure out how to share code between issuance of a new
@@ -425,10 +423,7 @@ class ca_detail_obj(sql_persistant):
aia = self.ca_cert_uri,
crldp = ca.sia_uri + self.latest_ca_cert.gSKI() + ".crl",
sia = sia,
- as = as,
- v4 = v4,
- v6 = v6)
-
+ resources = resources)
if child_cert is None:
child_cert = rpki.sql.child_cert_obj(child_id = child.child_id,
@@ -525,7 +520,7 @@ class child_cert_obj(sql_persistant):
d["cert"] = self.cert.get_DER()
return d
- def reissue(self, gctx, ca_detail, as, v4, v6, sia):
+ def reissue(self, gctx, ca_detail, resources, sia):
"""Reissue an existing child_cert_obj, reusing the public key."""
if sia is None:
sia = self.cert.get_SIA()
@@ -534,9 +529,7 @@ class child_cert_obj(sql_persistant):
child = rpki.left_right.child_elt.sql_fetch(gctx, self.child_id),
subject_key = self.cert.getPublicKey(),
sia = sia,
- as = as,
- v4 = v4,
- v6 = v6,
+ resources = resources,
child_cert = self)
def revoke(self):
diff --git a/scripts/rpki/up_down.py b/scripts/rpki/up_down.py
index 93fa2ec7..d4c0f287 100644
--- a/scripts/rpki/up_down.py
+++ b/scripts/rpki/up_down.py
@@ -142,6 +142,18 @@ class class_elt(base_elt):
self.make_b64elt(elt, "issuer", self.issuer.get_DER())
return elt
+ def to_resource_bag(self):
+ """Build a resource_bag from from this <class/> element."""
+ return rpki.resource_set.resource_bag(self.resource_set_as,
+ self.resource_set_ipv4,
+ self.resource_set_ipv6)
+
+ def from_resource_bag(self, bag):
+ """Set resources of this class element from a resource_bag."""
+ self.resource_set_as = bag.as
+ self.resource_set_ipv4 = bag.v4
+ self.resource_set_ipv6 = bag.v6
+
class list_pdu(base_elt):
"""Up-Down protocol "list" PDU."""
@@ -152,19 +164,19 @@ class list_pdu(base_elt):
def serve_pdu(self, gctx, q_msg, r_msg, child):
"""Serve one "list" PDU."""
r_msg.payload = list_response_pdu()
- irdb_as, irdb_v4, irdb_v6 = rpki.left_right.irdb_query(gctx, child.self_id, child.child_id)
+ irdb_resources = rpki.left_right.irdb_query(gctx, child.self_id, child.child_id)
for parent in rpki.left_right.parent_elt.sql_fetch_where(gctx, "parent.self_id = %s" % child.self_id):
for ca in rpki.sql.ca_obj.sql_fetch_where(gctx, "ca.parent_id = %s" % parent.parent_id):
ca_detail = rpki.sql.ca_detail_obj.sql_fetch_active(gctx, ca.ca_id)
if not ca_detail:
continue
- rc_as, rc_v4, rc_v6 = ca_detail.latest_ca_cert.get_3779resources(irdb_as, irdb_v4, irdb_v6)
- if not rc_as and not rc_v4 and not rc_v6:
+ resources = ca_detail.latest_ca_cert.get_3779resources().intersection(irdb_resources)
+ if resources.empty():
continue
rc = class_elt()
rc.class_name = str(ca.ca_id)
rc.cert_url = multi_uri(ca_detail.ca_cert_uri)
- rc.resource_set_as, rc.resource_set_ipv4, rc.resource_set_ipv6 = rc_as, rc_v4, rc_v6
+ rc.from_resource_bag(resources)
for child_cert in rpki.sql.child_cert_obj.sql_fetch_where(gctx, """
child_id = %s AND ca_detail_id = %s
""" % (child.child_id, ca_detail.ca_detail_id)):
@@ -243,7 +255,7 @@ class issue_pdu(base_elt):
# Check current cert, if any
irdb_resources = rpki.left_right.irdb_query(gctx, child.self_id, child.child_id)
- rc_as, rc_v4, rc_v6 = ca_detail.latest_ca_cert.get_3779resources(*irdb_resources)
+ resources = ca_detail.latest_ca_cert.get_3779resources().intersection(irdb_resources)
req_key = self.pkcs10.getPublicKey()
req_sia = self.pkcs10.get_SIA()
child_cert = rpki.sql.child_cert_obj.sql_fetch_where1(gctx, """
@@ -258,16 +270,12 @@ class issue_pdu(base_elt):
child = child,
subject_key = req_key,
sia = req_sia,
- as = rc_as,
- v4 = rc_v4,
- v6 = rc_v6)
- elif ((rc_as, rc_v4, rc_v6) != child_cert.cert.get_3779resources()) or child_cert.cert.get_SIA() != req_sia:
+ resources = resources)
+ elif resources != child_cert.cert.get_3779resources() or child_cert.cert.get_SIA() != req_sia:
child_cert.reissue(gctx = gctx,
ca_detail = ca_detail,
- as = rc_as,
- v4 = rc_v4,
- v6 = rc_v6,
- sia = req_sia)
+ sia = req_sia,
+ resources = resources)
# Save anything we modified and generate response
rpki.sql.sql_sweep(gctx)
@@ -278,7 +286,7 @@ class issue_pdu(base_elt):
rc = class_elt()
rc.class_name = str(ca_id)
rc.cert_url = multi_uri(ca_detail.ca_cert_uri)
- rc.resource_set_as, rc.resource_set_ipv4, rc.resource_set_ipv6 = rc_as, rc_v4, rc_v6
+ rc.from_resource_bag(resources)
rc.certs.append(c)
rc.issuer = ca_detail.latest_ca_cert
r_msg.payload = issue_response_pdu()
diff --git a/scripts/rpki/x509.py b/scripts/rpki/x509.py
index 069c84d6..a9ebf625 100644
--- a/scripts/rpki/x509.py
+++ b/scripts/rpki/x509.py
@@ -194,18 +194,11 @@ class DER_object(object):
"""Get the SIA extension from this object. Only works for subclasses that support getExtension()."""
return (self.get_POWpkix().getExtension(name2oid["subjectInfoAccess"]) or ((), 0, None))[2]
- def get_3779resources(self, as_intersector = None, v4_intersector = None, v6_intersector = None):
+ def get_3779resources(self):
"""Get RFC 3779 resources as rpki.resource_set objects.
Only works for subclasses that support getExtensions().
"""
- as, v4, v6 = rpki.resource_set.parse_extensions(self.get_POWpkix().getExtensions())
- if as_intersector is not None:
- as = as.intersection(as_intersector)
- if v4_intersector is not None:
- v4 = v4.intersection(v4_intersector)
- if v6_intersector is not None:
- v6 = v6.intersection(v6_intersector)
- return as, v4, v6
+ return rpki.resource_set.resource_bag.from_asn1_tuples(self.get_POWpkix().getExtensions())
class X509(DER_object):
"""X.509 certificates.
@@ -283,7 +276,7 @@ class X509(DER_object):
return RSApublic(DER = self.get_POWpkix().tbs.subjectPublicKeyInfo.toString())
def issue(self, keypair, subject_key, serial, sia, aia, crldp,
- cn = None, notAfter = None, as = None, v4 = None, v6 = None, is_ca = True):
+ cn = None, notAfter = None, resources = None, is_ca = True):
"""Issue a certificate."""
now = time.time()
@@ -322,10 +315,11 @@ class X509(DER_object):
else:
assert not is_ca
- if as:
- exts.append(["sbgp-autonomousSysNum", True, (as.to_tuple(), None)])
- if v4 or v6:
- exts.append(["sbgp-ipAddrBlock", True, [x for x in (v4.to_tuple(), v6.to_tuple()) if x is not None]])
+ if resources is not None and resources.as:
+ exts.append(["sbgp-autonomousSysNum", True, (resources.as.to_tuple(), None)])
+
+ if resources is not None and (resources.v4 or resources.v6):
+ exts.append(["sbgp-ipAddrBlock", True, [x for x in (resources.v4.to_tuple(), resources.v6.to_tuple()) if x is not None]])
for x in exts:
x[0] = name2oid[x[0]]
diff --git a/scripts/test-pow.py b/scripts/test-pow.py
index f371cc46..06827995 100644
--- a/scripts/test-pow.py
+++ b/scripts/test-pow.py
@@ -80,10 +80,10 @@ for der in (alice, apnic):
print " Crit: ", crit
print " Value:", val
print
- as, v4, v6 = rpki.resource_set.parse_extensions(cert.getExtensions())
- if as: print ",".join(map(lambda x: "AS:" + str(x), as))
- if v4: print ",".join(map(lambda x: "IPv4:" + str(x), v4))
- if v6: print ",".join(map(lambda x: "IPv6:" + str(x), v6))
- if as is not None: print as.to_tuple()
- if v4 is not None: print v4.to_tuple()
- if v6 is not None: print v6.to_tuple()
+ bag = rpki.resource_set.parse_extensions(cert.getExtensions())
+ if bag.as: print ",".join(map(lambda x: "AS:" + str(x), bag.as))
+ if bag.v4: print ",".join(map(lambda x: "IPv4:" + str(x), bag.v4))
+ if bag.v6: print ",".join(map(lambda x: "IPv6:" + str(x), bag.v6))
+ if bag.as is not None: print bag.as.to_tuple()
+ if bag.v4 is not None: print bag.v4.to_tuple()
+ if bag.v6 is not None: print bag.v6.to_tuple()
diff --git a/scripts/testroot.py b/scripts/testroot.py
index 6f959c3f..762a1757 100755
--- a/scripts/testroot.py
+++ b/scripts/testroot.py
@@ -40,7 +40,7 @@ def compose_response(r_msg):
rc = rpki.up_down.class_elt()
rc.class_name = root_name
rc.cert_url = rpki.up_down.multi_uri(root_cert)
- rc.resource_set_as, rc.resource_set_ipv4, rc.resource_set_ipv6 = rpki_issuer.get_3779resources()
+ rc.from_resource_bag(rpki_issuer.get_3779resources())
rc.issuer = rpki_issuer
r_msg.payload.classes.append(rc)
rpki_subject = get_subject_cert()
@@ -61,7 +61,7 @@ class issue_pdu(rpki.up_down.issue_pdu):
r_msg.payload = rpki.up_down.issue_response_pdu()
rpki_subject = get_subject_cert()
if rpki_subject is None:
- as, v4, v6 = rpki_issuer.get_3779resources()
+ resources = rpki_issuer.get_3779resources()
req_key = self.pkcs10.getPublicKey()
req_sia = self.pkcs10.get_SIA()
crldp = root_base + rpki_issuer.gSKI() + ".crl"
@@ -71,9 +71,7 @@ class issue_pdu(rpki.up_down.issue_pdu):
sia = req_sia,
aia = root_cert,
crldp = crldp,
- as = as,
- v4 = v4,
- v6 = v6))
+ resources = resources))
compose_response(r_msg)
class revoke_pdu(rpki.up_down.revoke_pdu):