aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2009-09-29 05:26:38 +0000
committerRob Austein <sra@hactrn.net>2009-09-29 05:26:38 +0000
commitfec2a3ac5fc5c3a58090bd8a58137bfb0a31581c (patch)
treed53b8612de630b77e716044bc02a46c50509f0e4
parenta95a30342c5533bf620833ad20ba70993cc34cf2 (diff)
Add left-right "revoke_forgotten" command to clean up certs that the
parent remembers but the child has forgotten. svn path=/rpkid/left-right-schema.rnc; revision=2793
-rw-r--r--rpkid/left-right-schema.rnc6
-rw-r--r--rpkid/left-right-schema.rng10
-rw-r--r--rpkid/rpki/left_right.py63
-rw-r--r--rpkid/rpki/relaxng.py10
-rw-r--r--rpkid/rpki/rpki_engine.py8
-rw-r--r--rpkid/rpki/up_down.py7
6 files changed, 87 insertions, 17 deletions
diff --git a/rpkid/left-right-schema.rnc b/rpkid/left-right-schema.rnc
index aa1c09ee..1a1e3ad8 100644
--- a/rpkid/left-right-schema.rnc
+++ b/rpkid/left-right-schema.rnc
@@ -76,7 +76,8 @@ self_bool = (attribute rekey { "yes" }?,
attribute reissue { "yes" }?,
attribute revoke { "yes" }?,
attribute run_now { "yes" }?,
- attribute publish_world_now { "yes" }?)
+ attribute publish_world_now { "yes" }?,
+ attribute revoke_forgotten { "yes" }?)
self_payload = (attribute use_hsm { "yes" | "no" }?,
attribute crl_interval { xsd:positiveInteger }?,
@@ -128,7 +129,8 @@ parent_handle = attribute parent_handle { object_handle }
parent_bool = (attribute rekey { "yes" }?,
attribute reissue { "yes" }?,
- attribute revoke { "yes" }?)
+ attribute revoke { "yes" }?,
+ attribute revoke_forgotten { "yes" }?)
parent_payload = (attribute peer_contact_uri { uri }?,
attribute sia_base { uri }?,
diff --git a/rpkid/left-right-schema.rng b/rpkid/left-right-schema.rng
index ede0c291..71e24ebc 100644
--- a/rpkid/left-right-schema.rng
+++ b/rpkid/left-right-schema.rng
@@ -213,6 +213,11 @@
<value>yes</value>
</attribute>
</optional>
+ <optional>
+ <attribute name="revoke_forgotten">
+ <value>yes</value>
+ </attribute>
+ </optional>
</define>
<define name="self_payload">
<optional>
@@ -462,6 +467,11 @@
<value>yes</value>
</attribute>
</optional>
+ <optional>
+ <attribute name="revoke_forgotten">
+ <value>yes</value>
+ </attribute>
+ </optional>
</define>
<define name="parent_payload">
<optional>
diff --git a/rpkid/rpki/left_right.py b/rpkid/rpki/left_right.py
index c8a8d2f8..fc08916d 100644
--- a/rpkid/rpki/left_right.py
+++ b/rpkid/rpki/left_right.py
@@ -129,7 +129,7 @@ class self_elt(data_elt):
element_name = "self"
attributes = ("action", "tag", "self_handle", "crl_interval", "regen_margin")
elements = ("bpki_cert", "bpki_glue")
- booleans = ("rekey", "reissue", "revoke", "run_now", "publish_world_now")
+ booleans = ("rekey", "reissue", "revoke", "run_now", "publish_world_now", "revoke_forgotten")
sql_template = rpki.sql.template("self", "self_id", "self_handle",
"use_hsm", "crl_interval", "regen_margin",
@@ -173,6 +173,8 @@ class self_elt(data_elt):
actions.append(self.serve_rekey)
if q_pdu.revoke:
actions.append(self.serve_revoke)
+ if q_pdu.revoke_forgotten:
+ actions.append(self.serve_revoke_forgotten)
if q_pdu.publish_world_now:
actions.append(self.serve_publish_world_now)
if q_pdu.run_now:
@@ -186,10 +188,8 @@ class self_elt(data_elt):
Handle a left-right rekey action for this self.
"""
rpki.log.trace()
-
def loop(iterator, parent):
parent.serve_rekey(iterator, eb)
-
rpki.async.iterator(self.parents(), loop, cb)
def serve_revoke(self, cb, eb):
@@ -197,10 +197,17 @@ class self_elt(data_elt):
Handle a left-right revoke action for this self.
"""
rpki.log.trace()
-
def loop(iterator, parent):
parent.serve_revoke(iterator, eb)
+ rpki.async.iterator(self.parents(), loop, cb)
+ def serve_revoke_forgotten(self, cb, eb):
+ """
+ Handle a left-right revoke_forgotten action for this self.
+ """
+ rpki.log.trace()
+ def loop(iterator, parent):
+ parent.serve_revoke_forgotten(iterator, eb)
rpki.async.iterator(self.parents(), loop, cb)
def serve_publish_world_now(self, cb, eb):
@@ -671,7 +678,7 @@ class parent_elt(data_elt):
attributes = ("action", "tag", "self_handle", "parent_handle", "bsc_handle", "repository_handle",
"peer_contact_uri", "sia_base", "sender_name", "recipient_name")
elements = ("bpki_cms_cert", "bpki_cms_glue", "bpki_https_cert", "bpki_https_glue")
- booleans = ("rekey", "reissue", "revoke")
+ booleans = ("rekey", "reissue", "revoke", "revoke_forgotten")
sql_template = rpki.sql.template("parent", "parent_id", "parent_handle",
"self_id", "bsc_id", "repository_id",
@@ -703,6 +710,8 @@ class parent_elt(data_elt):
actions.append(self.serve_rekey)
if q_pdu.revoke:
actions.append(self.serve_revoke)
+ if q_pdu.revoke_forgotten:
+ actions.append(self.serve_revoke_forgotten)
def loop(iterator, action):
action(iterator, eb)
rpki.async.iterator(actions, loop, cb)
@@ -711,22 +720,58 @@ class parent_elt(data_elt):
"""
Handle a left-right rekey action for this parent.
"""
-
def loop(iterator, ca):
ca.rekey(iterator, eb)
-
rpki.async.iterator(self.cas(), loop, cb)
def serve_revoke(self, cb, eb):
"""
Handle a left-right revoke action for this parent.
"""
-
def loop(iterator, ca):
ca.revoke(iterator, eb)
-
rpki.async.iterator(self.cas(), loop, cb)
+ def serve_revoke_forgotten(self, cb, eb):
+ """
+ Handle a left-right revoke_forgotten action for this parent.
+
+ This is a bit fiddly: we have to compare the result of an up-down
+ list query with what we have locally and identify the SKIs of any
+ certificates that have gone missing. This should never happen in
+ ordinary operation, but can arise if we have somehow lost a
+ private key, in which case there is nothing more we can do with
+ the issued cert, so we have to clear it. As this really is not
+ supposed to happen, we don't clear it automatically, instead we
+ require an explicit trigger.
+ """
+
+ def got_list(r_msg):
+
+ ca_map = dict((ca.parent_resource_class, ca) for ca in self.cas())
+
+ def rc_loop(rc_iterator, rc):
+
+ if rc.class_name in ca_map:
+
+ def ski_loop(ski_iterator, ski):
+ rpki.log.warn("Revoking certificates missing from our database, class %r, SKI %s" % (rc.class_name, ski))
+ rpki.up_down.revoke_pdu.query(ca, ski, ski_iterator, eb)
+
+ ca = ca_map[rc.class_name]
+ skis_parent_knows_about = set(c.cert.gSKI() for c in rc.certs)
+ skis_ca_knows_about = set(ca_detail.latest_ca_cert.gSKI() for ca_detail in ca.fetch_nonnull_nonrevoked())
+ skis_only_parent_knows_about = skis_parent_knows_about - skis_ca_knows_about
+ rpki.async.iterator(skis_only_parent_knows_about, ski_loop, rc_iterator)
+
+ else:
+ rc_iterator()
+
+ rpki.async.iterator(r_msg.payload.classes, rc_loop, cb)
+
+ rpki.up_down.list_pdu.query(self, got_list, eb)
+
+
def query_up_down(self, q_pdu, cb, eb):
"""
Client code for sending one up-down query PDU to this parent.
diff --git a/rpkid/rpki/relaxng.py b/rpkid/rpki/relaxng.py
index 67b72eaf..492e7f96 100644
--- a/rpkid/rpki/relaxng.py
+++ b/rpkid/rpki/relaxng.py
@@ -219,6 +219,11 @@ left_right = lxml.etree.RelaxNG(lxml.etree.fromstring('''<?xml version="1.0" enc
<value>yes</value>
</attribute>
</optional>
+ <optional>
+ <attribute name="revoke_forgotten">
+ <value>yes</value>
+ </attribute>
+ </optional>
</define>
<define name="self_payload">
<optional>
@@ -468,6 +473,11 @@ left_right = lxml.etree.RelaxNG(lxml.etree.fromstring('''<?xml version="1.0" enc
<value>yes</value>
</attribute>
</optional>
+ <optional>
+ <attribute name="revoke_forgotten">
+ <value>yes</value>
+ </attribute>
+ </optional>
</define>
<define name="parent_payload">
<optional>
diff --git a/rpkid/rpki/rpki_engine.py b/rpkid/rpki/rpki_engine.py
index ec51695c..619cbbcc 100644
--- a/rpkid/rpki/rpki_engine.py
+++ b/rpkid/rpki/rpki_engine.py
@@ -338,6 +338,10 @@ class ca_obj(rpki.sql.sql_persistent):
"""Fetch revoked ca_details for this CA, if any."""
return ca_detail_obj.sql_fetch_where(self.gctx, "ca_id = %s AND state = 'revoked'", (self.ca_id,))
+ def fetch_nonnull_nonrevoked(self):
+ """Fetch ca_details which have a CA cert and which are not revoked."""
+ return ca_detail_obj.sql_fetch_where(self.gctx, "ca_id = %s AND latest_ca_cert IS NOT NULL AND state != 'revoked'", (self.ca_id,))
+
def construct_sia_uri(self, parent, rc):
"""
Construct the sia_uri value for this CA given configured
@@ -406,7 +410,7 @@ class ca_obj(rpki.sql.sql_persistent):
% (rc.class_name, ", ".join(c.cert.gSKI() for c in cert_map.values())))
cb()
- ca_details = ca_detail_obj.sql_fetch_where(self.gctx, "ca_id = %s AND latest_ca_cert IS NOT NULL AND state != 'revoked'", (self.ca_id,))
+ ca_details = self.fetch_nonnull_nonrevoked()
if True:
for x in cert_map.itervalues():
@@ -716,7 +720,7 @@ class ca_detail_obj(rpki.sql.sql_persistent):
rpki.async.iterator(self.child_certs(), revoke_one_child, final_crl)
- rpki.up_down.revoke_pdu.query(self, parent_revoked, eb)
+ rpki.up_down.revoke_pdu.query(self.ca(), self.latest_ca_cert.gSKI(), parent_revoked, eb)
def update(self, parent, ca, rc, sia_uri_changed, old_resources, callback, errback):
"""
diff --git a/rpkid/rpki/up_down.py b/rpkid/rpki/up_down.py
index 8406d030..0919b7bc 100644
--- a/rpkid/rpki/up_down.py
+++ b/rpkid/rpki/up_down.py
@@ -483,15 +483,14 @@ class revoke_pdu(revoke_syntax):
rpki.async.iterator(child.ca_from_class_name(self.class_name).ca_details(), loop1, done)
@classmethod
- def query(cls, ca_detail, cb, eb):
+ def query(cls, ca, gski, cb, eb):
"""
- Send a "revoke" request to parent associated with ca_detail.
+ Send a "revoke" request for certificate(s) named by gski to parent associated with ca.
"""
- ca = ca_detail.ca()
parent = ca.parent()
self = cls()
self.class_name = ca.parent_resource_class
- self.ski = ca_detail.latest_ca_cert.gSKI()
+ self.ski = gski
parent.query_up_down(self, cb, eb)
class revoke_response_pdu(revoke_syntax):