diff options
author | Rob Austein <sra@hactrn.net> | 2009-09-29 05:26:38 +0000 |
---|---|---|
committer | Rob Austein <sra@hactrn.net> | 2009-09-29 05:26:38 +0000 |
commit | fec2a3ac5fc5c3a58090bd8a58137bfb0a31581c (patch) | |
tree | d53b8612de630b77e716044bc02a46c50509f0e4 | |
parent | a95a30342c5533bf620833ad20ba70993cc34cf2 (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.rnc | 6 | ||||
-rw-r--r-- | rpkid/left-right-schema.rng | 10 | ||||
-rw-r--r-- | rpkid/rpki/left_right.py | 63 | ||||
-rw-r--r-- | rpkid/rpki/relaxng.py | 10 | ||||
-rw-r--r-- | rpkid/rpki/rpki_engine.py | 8 | ||||
-rw-r--r-- | rpkid/rpki/up_down.py | 7 |
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): |