aboutsummaryrefslogtreecommitdiff
path: root/rpkid
diff options
context:
space:
mode:
Diffstat (limited to 'rpkid')
-rw-r--r--rpkid/left-right-schema.rnc2
-rw-r--r--rpkid/left-right-schema.rng4
-rw-r--r--rpkid/rpki/http.py9
-rw-r--r--rpkid/rpki/left_right.py100
-rw-r--r--rpkid/rpki/publication.py11
-rw-r--r--rpkid/rpki/relaxng.py4
-rw-r--r--rpkid/rpki/rootd.py73
-rw-r--r--rpkid/rpki/rpkid.py78
-rw-r--r--rpkid/tests/revoke.yaml198
-rw-r--r--rpkid/tests/smoketest.py1
10 files changed, 414 insertions, 66 deletions
diff --git a/rpkid/left-right-schema.rnc b/rpkid/left-right-schema.rnc
index 3b058502..a2759f56 100644
--- a/rpkid/left-right-schema.rnc
+++ b/rpkid/left-right-schema.rnc
@@ -247,7 +247,7 @@ list_roa_requests_query = element list_roa_requests {
list_roa_requests_reply = element list_roa_requests {
tag, self_handle,
- attribute asn { xsd:positiveInteger },
+ attribute asn { xsd:nonNegativeInteger },
attribute ipv4 { ipv4_list }?,
attribute ipv6 { ipv6_list }?
}
diff --git a/rpkid/left-right-schema.rng b/rpkid/left-right-schema.rng
index 1ab21668..80beb1f5 100644
--- a/rpkid/left-right-schema.rng
+++ b/rpkid/left-right-schema.rng
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- $Id: left-right-schema.rnc 3730 2011-03-21 12:42:43Z sra $
+ $Id: left-right-schema.rnc 4346 2012-02-17 01:11:06Z sra $
RelaxNG Schema for RPKI left-right protocol.
@@ -875,7 +875,7 @@
<ref name="tag"/>
<ref name="self_handle"/>
<attribute name="asn">
- <data type="positiveInteger"/>
+ <data type="nonNegativeInteger"/>
</attribute>
<optional>
<attribute name="ipv4">
diff --git a/rpkid/rpki/http.py b/rpkid/rpki/http.py
index 7d7e81ba..a0055ac9 100644
--- a/rpkid/rpki/http.py
+++ b/rpkid/rpki/http.py
@@ -766,7 +766,14 @@ class http_client(http_stream):
self.update_timeout()
if self.msg.code != 200:
- raise rpki.exceptions.HTTPRequestFailed, "HTTP request failed with status %s, reason %s, response %s" % (self.msg.code, self.msg.reason, self.msg.body)
+ errmsg = "HTTP request failed"
+ if self.msg.code is not None:
+ errmsg += " with status %s" % self.msg.code
+ if self.msg.reason:
+ errmsg += ", reason %s" % self.msg.reason
+ if self.msg.body:
+ errmsg += ", response %s" % self.msg.body
+ raise rpki.exceptions.HTTPRequestFailed(errmsg)
self.queue.return_result(self, self.msg, detach = self.expect_close)
def handle_close(self):
diff --git a/rpkid/rpki/left_right.py b/rpkid/rpki/left_right.py
index ac480ff0..17d665c9 100644
--- a/rpkid/rpki/left_right.py
+++ b/rpkid/rpki/left_right.py
@@ -190,6 +190,7 @@ class self_elt(data_elt):
"""
return rpki.rpkid.ghostbuster_obj.sql_fetch_where(self.gctx, "self_id = %s", (self.self_id,))
+
def serve_post_save_hook(self, q_pdu, r_pdu, cb, eb):
"""
Extra server actions for self_elt.
@@ -248,6 +249,16 @@ class self_elt(data_elt):
parent.serve_revoke_forgotten(iterator, eb)
rpki.async.iterator(self.parents, loop, cb)
+ def serve_destroy_hook(self, cb, eb):
+ """
+ Extra cleanup actions when destroying a self_elt.
+ """
+ rpki.log.trace()
+ def loop(iterator, parent):
+ parent.delete(iterator)
+ rpki.async.iterator(self.parents, loop, cb)
+
+
def serve_publish_world_now(self, cb, eb):
"""
Handle a left-right publish_world_now action for this self.
@@ -704,6 +715,7 @@ class self_elt(data_elt):
self.gctx.sql.sweep()
self.gctx.irdb_query_roa_requests(self.self_handle, got_roa_requests, roa_requests_failed)
+
class bsc_elt(data_elt):
"""
<bsc/> (Business Signing Context) element.
@@ -931,6 +943,39 @@ class parent_elt(data_elt):
ca.reissue(cb = iterator, eb = eb)
rpki.async.iterator(self.cas, loop, cb)
+
+ def get_skis(self, cb, eb):
+ """
+ Fetch SKIs that this parent thinks we have. In theory this should
+ agree with our own database, but in practice stuff can happen, so
+ sometimes we need to know what our parent thinks.
+
+ Result is a dictionary with the resource class name as key and a
+ set of SKIs as value.
+ """
+
+ def done(r_msg):
+ cb(dict((rc.class_name, set(c.cert.gSKI() for c in rc.certs))
+ for rc in r_msg.payload.classes))
+
+ rpki.up_down.list_pdu.query(self, done, eb)
+
+
+ def revoke_skis(self, rc_name, skis_to_revoke, cb, eb):
+ """
+ Revoke a set of SKIs within a particular resource class.
+ """
+
+ def loop(iterator, ski):
+ rpki.log.debug("Asking parent %r to revoke class %r, SKI %s" % (self, rc_name, ski))
+ q_pdu = rpki.up_down.revoke_pdu()
+ q_pdu.class_name = rc_name
+ q_pdu.ski = ski
+ self.query_up_down(q_pdu, lambda r_pdu: iterator(), eb)
+
+ rpki.async.iterator(skis_to_revoke, loop, cb)
+
+
def serve_revoke_forgotten(self, cb, eb):
"""
Handle a left-right revoke_forgotten action for this parent.
@@ -945,30 +990,55 @@ class parent_elt(data_elt):
require an explicit trigger.
"""
- def got_list(r_msg):
+ def got_skis(skis_from_parent):
+
+ def loop(iterator, item):
+ rc_name, skis_to_revoke = item
+ if rc_name in ca_map:
+ for ca_detail in ca_map[rc_name].issue_response_candidate_ca_details:
+ skis_to_revoke.discard(ca_detail.latest_ca_cert.gSKI())
+ self.revoke_skis(rc_name, skis_to_revoke, iterator, eb)
ca_map = dict((ca.parent_resource_class, ca) for ca in self.cas)
+ rpki.async.iterator(skis_from_parent.items(), loop, cb)
- def rc_loop(rc_iterator, rc):
+ self.get_skis(got_skis, eb)
- 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, lambda x: ski_iterator(), eb)
+ def delete(self, cb, delete_parent = True):
+ """
+ Delete all the CA stuff under this parent, and perhaps the parent
+ itself.
+ """
- 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.issue_response_candidate_ca_details)
- 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)
+ def loop(iterator, ca):
+ self.gctx.checkpoint()
+ ca.delete(self, iterator)
- else:
- rc_iterator()
+ def revoke():
+ self.gctx.checkpoint()
+ self.serve_revoke_forgotten(done, fail)
+
+ def fail(e):
+ rpki.log.warn("Trouble getting parent to revoke certificates, blundering onwards: %s" % e)
+ done()
- rpki.async.iterator(r_msg.payload.classes, rc_loop, cb)
+ def done():
+ self.gctx.checkpoint()
+ self.gctx.sql.sweep()
+ if delete_parent:
+ self.sql_delete()
+ cb()
+
+ rpki.async.iterator(self.cas, loop, revoke)
+
+
+ def serve_destroy_hook(self, cb, eb):
+ """
+ Extra server actions when destroying a parent_elt.
+ """
- rpki.up_down.list_pdu.query(self, got_list, eb)
+ self.delete(cb, delete_parent = False)
def query_up_down(self, q_pdu, cb, eb):
diff --git a/rpkid/rpki/publication.py b/rpkid/rpki/publication.py
index 14e3d36a..f60e3af5 100644
--- a/rpkid/rpki/publication.py
+++ b/rpkid/rpki/publication.py
@@ -219,7 +219,7 @@ class publication_object_elt(rpki.xml_utils.base_elt, publication_namespace):
def serve_withdraw(self):
"""
- Withdraw an object.
+ Withdraw an object, then recursively delete empty directories.
"""
rpki.log.info("Withdrawing %s" % self.uri)
filename = self.uri_to_filename()
@@ -230,6 +230,15 @@ class publication_object_elt(rpki.xml_utils.base_elt, publication_namespace):
raise rpki.exceptions.NoObjectAtURI, "No object published at %s" % self.uri
else:
raise
+ min_path_len = len(self.gctx.publication_base.rstrip("/"))
+ dirname = os.path.dirname(filename)
+ while len(dirname) > min_path_len:
+ try:
+ os.rmdir(dirname)
+ except OSError:
+ break
+ else:
+ dirname = os.path.dirname(dirname)
def uri_to_filename(self):
"""
diff --git a/rpkid/rpki/relaxng.py b/rpkid/rpki/relaxng.py
index 24b3ab75..28fbe64a 100644
--- a/rpkid/rpki/relaxng.py
+++ b/rpkid/rpki/relaxng.py
@@ -6,7 +6,7 @@ import lxml.etree
## Parsed RelaxNG left_right schema
left_right = lxml.etree.RelaxNG(lxml.etree.fromstring('''<?xml version="1.0" encoding="UTF-8"?>
<!--
- $Id: left-right-schema.rnc 3730 2011-03-21 12:42:43Z sra $
+ $Id: left-right-schema.rnc 4346 2012-02-17 01:11:06Z sra $
RelaxNG Schema for RPKI left-right protocol.
@@ -881,7 +881,7 @@ left_right = lxml.etree.RelaxNG(lxml.etree.fromstring('''<?xml version="1.0" enc
<ref name="tag"/>
<ref name="self_handle"/>
<attribute name="asn">
- <data type="positiveInteger"/>
+ <data type="nonNegativeInteger"/>
</attribute>
<optional>
<attribute name="ipv4">
diff --git a/rpkid/rpki/rootd.py b/rpkid/rpki/rootd.py
index 8f3e6264..feceffc5 100644
--- a/rpkid/rpki/rootd.py
+++ b/rpkid/rpki/rootd.py
@@ -58,11 +58,15 @@ class issue_pdu(rpki.up_down.issue_pdu):
class revoke_pdu(rpki.up_down.revoke_pdu):
def serve_pdu(self, q_msg, r_msg, ignored, callback, errback):
- rootd.subject_cert = get_subject_cert()
+ rpki.log.debug("Revocation requested for SKI %s" % self.ski)
+ subject_cert = rootd.get_subject_cert()
if subject_cert is None or subject_cert.gSKI() != self.ski:
raise rpki.exceptions.NotInDatabase
+ now = rpki.sundial.now()
+ rootd.revoke_subject_cert(now)
rootd.del_subject_cert()
rootd.del_subject_pkcs10()
+ rootd.generate_crl_and_manifest(now)
r_msg.payload = rpki.up_down.revoke_response_pdu()
r_msg.payload.class_name = self.class_name
r_msg.payload.ski = self.ski
@@ -95,8 +99,6 @@ class cms_msg(rpki.up_down.cms_msg):
class main(object):
- rpki_root_cert = None
-
def get_root_cert(self):
rpki.log.debug("Read root cert %s" % self.rpki_root_cert_file)
self.rpki_root_cert = rpki.x509.X509(Auto_file = self.rpki_root_cert_file)
@@ -172,54 +174,65 @@ class main(object):
rpki.log.info("Generating subject cert with resources " + str(resources))
req_key = pkcs10.getPublicKey()
req_sia = pkcs10.get_SIA()
- crldp = self.rpki_base_uri + self.rpki_root_crl
- serial = now.totimestamp()
+ self.next_serial_number()
subject_cert = self.rpki_root_cert.issue(
keypair = self.rpki_root_key,
subject_key = req_key,
- serial = serial,
+ serial = self.serial_number,
sia = req_sia,
aia = self.rpki_root_cert_uri,
- crldp = crldp,
+ crldp = self.rpki_base_uri + self.rpki_root_crl,
resources = resources,
notAfter = now + self.rpki_subject_lifetime)
+ self.set_subject_cert(subject_cert)
+ self.generate_crl_and_manifest(now)
+ return subject_cert
+
+ def generate_crl_and_manifest(self, now):
+ subject_cert = self.get_subject_cert()
+ self.next_serial_number()
+ self.next_crl_number()
crl = rpki.x509.CRL.generate(
keypair = self.rpki_root_key,
issuer = self.rpki_root_cert,
- serial = serial,
+ serial = self.crl_number,
thisUpdate = now,
nextUpdate = now + self.rpki_subject_lifetime,
- revokedCertificates = ())
+ revokedCertificates = self.revoked)
rpki.log.debug("Writing CRL %s" % (self.rpki_root_dir + self.rpki_root_crl))
f = open(self.rpki_root_dir + self.rpki_root_crl, "wb")
f.write(crl.get_DER())
f.close()
+ manifest_content = [(self.rpki_root_crl, crl)]
+ if subject_cert is not None:
+ manifest_content.append((self.rpki_subject_cert, subject_cert))
manifest_resources = rpki.resource_set.resource_bag.from_inheritance()
manifest_keypair = rpki.x509.RSA.generate()
manifest_cert = self.rpki_root_cert.issue(
keypair = self.rpki_root_key,
subject_key = manifest_keypair.get_RSApublic(),
- serial = serial + 1,
+ serial = self.serial_number,
sia = ((rpki.oids.name2oid["id-ad-signedObject"],
("uri", self.rpki_base_uri + self.rpki_root_manifest)),),
aia = self.rpki_root_cert_uri,
- crldp = crldp,
+ crldp = self.rpki_base_uri + self.rpki_root_crl,
resources = manifest_resources,
notAfter = now + self.rpki_subject_lifetime,
is_ca = False)
manifest = rpki.x509.SignedManifest.build(
- serial = serial,
+ serial = self.crl_number,
thisUpdate = now,
nextUpdate = now + self.rpki_subject_lifetime,
- names_and_objs = [(self.rpki_subject_cert, subject_cert), (self.rpki_root_crl, crl)],
+ names_and_objs = manifest_content,
keypair = manifest_keypair,
certs = manifest_cert)
rpki.log.debug("Writing manifest %s" % (self.rpki_root_dir + self.rpki_root_manifest))
f = open(self.rpki_root_dir + self.rpki_root_manifest, "wb")
f.write(manifest.get_DER())
f.close()
- self.set_subject_cert(subject_cert)
- return subject_cert
+
+ def revoke_subject_cert(self, now):
+ self.revoked.append((self.get_subject_cert().getSerial(), now.toASN1tuple(), ()))
def compose_response(self, r_msg, pkcs10 = None):
subject_cert = self.issue_subject_cert_maybe(pkcs10)
@@ -260,11 +273,39 @@ class main(object):
rpki.log.traceback()
cb(500, reason = "Could not process PDU: %s" % e)
+
+ def next_crl_number(self):
+ if self.crl_number is None:
+ try:
+ crl = rpki.x509.CRL(DER_file = self.rpki_root_dir + self.rpki_root_crl)
+ self.crl_number = crl.get_POWpkix().getExtension(rpki.oids.name2oid["cRLNumber"])[2]
+ except:
+ self.crl_number = 0
+ self.crl_number += 1
+ return self.crl_number
+
+
+ def next_serial_number(self):
+ if self.serial_number is None:
+ subject_cert = self.get_subject_cert()
+ if subject_cert is not None:
+ self.serial_number = subject_cert.getSerial() + 1
+ else:
+ self.serial_number = 0
+ self.serial_number += 1
+ return self.serial_number
+
+
def __init__(self):
global rootd
rootd = self # Gross, but simpler than what we'd have to do otherwise
+ self.rpki_root_cert = None
+ self.serial_number = None
+ self.crl_number = None
+ self.revoked = []
+
os.environ["TZ"] = "UTC"
time.tzset()
@@ -286,6 +327,8 @@ class main(object):
self.cfg = rpki.config.parser(self.cfg_file, "rootd")
+ rpki.log.enable_tracebacks = True
+
self.cfg.set_global_flags()
self.bpki_ta = rpki.x509.X509(Auto_update = self.cfg.get("bpki-ta"))
diff --git a/rpkid/rpki/rpkid.py b/rpkid/rpki/rpkid.py
index 715a8aa2..7501a16a 100644
--- a/rpkid/rpki/rpkid.py
+++ b/rpkid/rpki/rpkid.py
@@ -462,8 +462,8 @@ class ca_obj(rpki.sql.sql_persistent):
if rc_cert is None:
- rpki.log.warn("SKI %s in resource class %s is in my database but missing from list_response received from %s, maybe parent certificate went away?"
- % (ca_detail.public_key.gSKI(), rc.class_name, parent.parent_handle))
+ rpki.log.warn("SKI %s in resource class %s is in database but missing from list_response to %s from %s, maybe parent certificate went away?"
+ % (ca_detail.public_key.gSKI(), rc.class_name, parent.self.self_handle, parent.parent_handle))
publisher = publication_queue()
ca_detail.delete(ca = ca_detail.ca, publisher = publisher)
return publisher.call_pubd(iterator, eb)
@@ -495,8 +495,10 @@ class ca_obj(rpki.sql.sql_persistent):
def done():
if cert_map:
- rpki.log.warn("Certificate SKIs in resource class %s in list_response from parent %s that are missing from our database: %s"
- % (rc.class_name, parent.parent_handle, ", ".join(c.cert.gSKI() for c in cert_map.values())))
+ rpki.log.warn("Unknown certificate SKI%s %s in resource class %s in list_response to %s from %s, maybe you want to \"revoke_forgotten\"?"
+ % ("" if len(cert_map) == 1 else "s",
+ ", ".join(c.cert.gSKI() for c in cert_map.values()),
+ rc.class_name, parent.self.self_handle, parent.parent_handle))
self.gctx.checkpoint()
cb()
@@ -509,19 +511,19 @@ class ca_obj(rpki.sql.sql_persistent):
for x in ca_details
if x.latest_ca_cert is not None)
for ski in skis_parent & skis_me:
- rpki.log.debug("Parent %s and I agree that I have SKI %s in resource class %s"
- % (parent.parent_handle, ski, rc.class_name))
+ rpki.log.debug("Parent %s agrees that %s has SKI %s in resource class %s"
+ % (parent.parent_handle, parent.self.self_handle, ski, rc.class_name))
for ski in skis_parent - skis_me:
- rpki.log.debug("Parent %s thinks I have SKI %s in resource class %s but I don't think so"
- % (parent.parent_handle, ski, rc.class_name))
+ rpki.log.debug("Parent %s thinks %s has SKI %s in resource class %s but I don't think so"
+ % (parent.parent_handle, parent.self.self_handle, ski, rc.class_name))
for ski in skis_me - skis_parent:
- rpki.log.debug("I think I have SKI %s in resource class %s but parent %s doesn't think so"
- % (ski, rc.class_name, parent.parent_handle))
+ rpki.log.debug("I think %s has SKI %s in resource class %s but parent %s doesn't think so"
+ % (parent.self.self_handle, ski, rc.class_name, parent.parent_handle))
if ca_details:
rpki.async.iterator(ca_details, loop, done)
else:
- rpki.log.warn("Existing resource class %s from parent %s with no certificates, rekeying" % (rc.class_name, parent.parent_handle))
+ rpki.log.warn("Existing resource class %s to %s from %s with no certificates, rekeying" % (rc.class_name, parent.self.self_handle, parent.parent_handle))
self.gctx.checkpoint()
self.rekey(cb, eb)
@@ -625,9 +627,10 @@ class ca_obj(rpki.sql.sql_persistent):
rpki.up_down.issue_pdu.query(parent, self, new_detail, done, eb)
- def revoke(self, cb, eb):
+ def revoke(self, cb, eb, revoke_all = False):
"""
- Revoke deprecated ca_detail objects associated with this ca.
+ Revoke deprecated ca_detail objects associated with this CA, or
+ all ca_details associated with this CA if revoke_all is set.
"""
rpki.log.trace()
@@ -635,7 +638,9 @@ class ca_obj(rpki.sql.sql_persistent):
def loop(iterator, ca_detail):
ca_detail.revoke(cb = iterator, eb = eb)
- rpki.async.iterator(self.deprecated_ca_details, loop, cb)
+ ca_details = self.ca_details if revoke_all else self.deprecated_ca_details
+
+ rpki.async.iterator(ca_details, loop, cb)
def reissue(self, cb, eb):
"""
@@ -763,17 +768,23 @@ class ca_detail_obj(rpki.sql.sql_persistent):
self.state = "active"
self.generate_crl(publisher = publisher)
self.generate_manifest(publisher = publisher)
- self.sql_mark_dirty()
+ self.sql_store()
if predecessor is not None:
predecessor.state = "deprecated"
- predecessor.sql_mark_dirty()
+ predecessor.sql_store()
for child_cert in predecessor.child_certs:
child_cert.reissue(ca_detail = self, publisher = publisher)
for roa in predecessor.roas:
roa.regenerate(publisher = publisher)
# Need to do something to regenerate ghostbusters here?
+ # Yes, I suspect so, since presumably we want the ghostbuster to
+ # be issued by the new ca_detail at this point. But check code.
+
+ if predecessor.ghostbusters:
+ rpki.log.warn("Probably should be regenerating Ghostbusters %r here" % ghostbuster)
+
publisher.call_pubd(callback, errback)
@@ -842,6 +853,8 @@ class ca_detail_obj(rpki.sql.sql_persistent):
if r_msg.payload.ski != self.latest_ca_cert.gSKI():
raise rpki.exceptions.SKIMismatch
+ rpki.log.debug("Parent revoked %s, starting cleanup" % self.latest_ca_cert.gSKI())
+
crl_interval = rpki.sundial.timedelta(seconds = parent.self.crl_interval)
nextUpdate = rpki.sundial.now()
@@ -881,6 +894,7 @@ class ca_detail_obj(rpki.sql.sql_persistent):
self.sql_mark_dirty()
publisher.call_pubd(cb, eb)
+ rpki.log.debug("Asking parent to revoke CA certificate %s" % self.latest_ca_cert.gSKI())
rpki.up_down.revoke_pdu.query(ca, self.latest_ca_cert.gSKI(), parent_revoked, eb)
def update(self, parent, ca, rc, sia_uri_changed, old_resources, callback, errback):
@@ -963,8 +977,7 @@ class ca_detail_obj(rpki.sql.sql_persistent):
containing the newly issued cert.
"""
- assert child_cert is None or (child_cert.child_id == child.child_id and
- child_cert.ca_detail_id == self.ca_detail_id)
+ assert child_cert is None or child_cert.child_id == child.child_id
cert = self.latest_ca_cert.issue(
keypair = self.private_key_id,
@@ -985,6 +998,7 @@ class ca_detail_obj(rpki.sql.sql_persistent):
rpki.log.debug("Created new child_cert %r" % child_cert)
else:
child_cert.cert = cert
+ child_cert.ca_detail_id = self.ca_detail_id
rpki.log.debug("Reusing existing child_cert %r" % child_cert)
child_cert.ski = cert.get_SKI()
@@ -1155,7 +1169,7 @@ class child_cert_obj(rpki.sql.sql_persistent):
"""
return self.ca_detail.ca.sia_uri + self.uri_tail
- def revoke(self, publisher, generate_crl_and_manifest = False):
+ def revoke(self, publisher, generate_crl_and_manifest = True):
"""
Revoke a child cert.
"""
@@ -1207,7 +1221,7 @@ class child_cert_obj(rpki.sql.sql_persistent):
needed = True
if ca_detail != old_ca_detail:
- rpki.log.debug("Issuer changed for %r" % self)
+ rpki.log.debug("Issuer changed for %r %s" % (self, self.uri))
needed = True
must_revoke = old_resources.oversized(resources) or old_resources.valid_until > resources.valid_until
@@ -1215,11 +1229,6 @@ class child_cert_obj(rpki.sql.sql_persistent):
rpki.log.debug("Must revoke any existing cert(s) for %r" % self)
needed = True
- new_issuer = ca_detail != old_ca_detail
- if new_issuer:
- rpki.log.debug("Issuer changed for %r" % self)
- needed = True
-
if resources.valid_until != old_resources.valid_until:
rpki.log.debug("Validity changed for %r: %s %s" % (self, old_resources.valid_until, resources.valid_until))
needed = True
@@ -1245,7 +1254,7 @@ class child_cert_obj(rpki.sql.sql_persistent):
subject_key = self.cert.getPublicKey(),
sia = sia,
resources = resources,
- child_cert = None if must_revoke or new_issuer else self,
+ child_cert = None if must_revoke else self,
publisher = publisher)
rpki.log.debug("New child_cert %r uri %s" % (child_cert, child_cert.uri))
@@ -1496,10 +1505,12 @@ class roa_obj(rpki.sql.sql_persistent):
ca_detail = self.ca_detail
if ca_detail is None or ca_detail.state != "active" or ca_detail.has_expired():
+ rpki.log.debug("Searching for new ca_detail for ROA %r" % self)
ca_detail = None
for parent in self.self.parents:
for ca in parent.cas:
ca_detail = ca.active_ca_detail
+ assert ca_detail is None or ca_detail.state == "active"
if ca_detail is not None and not ca_detail.has_expired():
resources = ca_detail.latest_ca_cert.get_3779resources()
if v4.issubset(resources.v4) and v6.issubset(resources.v6):
@@ -1507,10 +1518,15 @@ class roa_obj(rpki.sql.sql_persistent):
ca_detail = None
if ca_detail is not None:
break
+ else:
+ rpki.log.debug("Keeping old ca_detail for ROA %r" % self)
if ca_detail is None:
raise rpki.exceptions.NoCoveringCertForROA, "Could not find a certificate covering %r" % self
+ rpki.log.debug("Using new ca_detail %r for ROA %r, ca_detail_state %s" % (
+ ca_detail, self, ca_detail.state))
+
ca = ca_detail.ca
resources = rpki.resource_set.resource_bag(v4 = v4, v6 = v6)
keypair = rpki.x509.RSA.generate()
@@ -1530,6 +1546,7 @@ class roa_obj(rpki.sql.sql_persistent):
if not fast:
ca_detail.generate_manifest(publisher = publisher)
+
def published_callback(self, pdu):
"""
Check publication result.
@@ -1559,8 +1576,8 @@ class roa_obj(rpki.sql.sql_persistent):
roa = self.roa
uri = self.uri
- if ca_detail.state != 'active':
- self.ca_detail_id = None
+ rpki.log.debug("Regenerating ROA %r, ca_detail %r state is %s" % (
+ self, ca_detail, ca_detail.state))
if regenerate:
self.generate(publisher = publisher, fast = fast)
@@ -1569,7 +1586,10 @@ class roa_obj(rpki.sql.sql_persistent):
rpki.rpkid.revoked_cert_obj.revoke(cert = cert, ca_detail = ca_detail)
publisher.withdraw(cls = rpki.publication.roa_elt, uri = uri, obj = roa, repository = ca_detail.ca.parent.repository,
handler = False if allow_failure else None)
- self.sql_mark_deleted()
+
+ if not regenerate:
+ self.sql_mark_deleted()
+
if not fast:
ca_detail.generate_crl(publisher = publisher)
ca_detail.generate_manifest(publisher = publisher)
diff --git a/rpkid/tests/revoke.yaml b/rpkid/tests/revoke.yaml
new file mode 100644
index 00000000..c006460d
--- /dev/null
+++ b/rpkid/tests/revoke.yaml
@@ -0,0 +1,198 @@
+# $Id: smoketest.1.yaml 3881 2011-06-17 18:32:54Z sra $
+
+# Copyright (C) 2009-2012 Internet Systems Consortium ("ISC")
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+#
+# Portions copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN")
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+name: RIR
+crl_interval: 5m
+regen_margin: 2m
+valid_for: 2d
+kids:
+ - name: R0
+ kids:
+ - name: Alice
+ ipv4: 192.0.2.1-192.0.2.33
+ asn: 64533
+ roa_request:
+ - asn: 42
+ ipv4: 192.0.2.32/32
+ - name: Bob
+ ipv4: 192.0.2.44-192.0.2.100
+ ipv4: 10.3.0.0/16
+ roa_request:
+ - asn: 666
+ ipv4: 10.3.0.44/32
+
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ rekey:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ revoke:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- sleep 30
+
+
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ rekey:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ revoke:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- sleep 30
+
+
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ rekey:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ revoke:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- sleep 30
+
+
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ rekey:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ revoke:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- sleep 30
+
+
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ rekey:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ revoke:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- sleep 30
+
+
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ rekey:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ revoke:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- sleep 30
+
+
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ rekey:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ revoke:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- sleep 30
+
+
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ rekey:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ revoke:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- sleep 30
+
+
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ rekey:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ revoke:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- sleep 30
+
+
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ rekey:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- name: R0
+ revoke:
+- sleep 10
+---
+- shell sleep 1; dir=rcynic.`date +%s`.data; mkdir $dir; cd rcynic-data; pax -rwl . ../$dir; find . -type f -name '*.cer' | sort | xargs ../../../../utils/uri/uri -s >../${dir%.data}.uris; sleep 1
+- sleep 30
diff --git a/rpkid/tests/smoketest.py b/rpkid/tests/smoketest.py
index fa686afd..3cb90d11 100644
--- a/rpkid/tests/smoketest.py
+++ b/rpkid/tests/smoketest.py
@@ -1264,6 +1264,7 @@ def run_rcynic():
subprocess.check_call((prog_rcynic, "-c", rcynic_name + ".conf"), env = env)
subprocess.call(rcynic_stats, shell = True, env = env)
last_rcynic_run = int(time.time())
+ os.link("%s.xml" % rcynic_name, "%s.%s.xml" % (rcynic_name, last_rcynic_run))
def mangle_sql(filename):
"""