diff options
-rw-r--r-- | scripts/rpki/left_right.py | 19 | ||||
-rw-r--r-- | scripts/rpki/log.py | 19 | ||||
-rw-r--r-- | scripts/rpki/sql.py | 45 | ||||
-rw-r--r-- | scripts/rpki/x509.py | 4 | ||||
-rwxr-xr-x | scripts/rpkid.py | 4 | ||||
-rw-r--r-- | scripts/testbed.1.yaml | 6 | ||||
-rw-r--r-- | scripts/testbed.py | 28 | ||||
-rw-r--r-- | scripts/testpoke.py | 2 |
8 files changed, 74 insertions, 53 deletions
diff --git a/scripts/rpki/left_right.py b/scripts/rpki/left_right.py index a8813927..b512d94e 100644 --- a/scripts/rpki/left_right.py +++ b/scripts/rpki/left_right.py @@ -264,33 +264,38 @@ class self_elt(data_elt): def serve_pre_save_hook(self, gctx, q_pdu, r_pdu): """Extra server actions for self_elt -- handle extension preferences.""" + rpki.log.trace() if self is not q_pdu: if q_pdu.clear_extension_preferences: self.prefs = [] - self.prefs.extend(pdu.prefs) + self.prefs.extend(q_pdu.prefs) def serve_post_save_hook(self, gctx, q_pdu, r_pdu): """Extra server actions for self_elt.""" - if self.rekey: + rpki.log.trace() + if q_pdu.rekey: self.serve_rekey(gctx) - if self.reissue: + if q_pdu.reissue: self.serve_reissue(gctx) - if self.revoke: + if q_pdu.revoke: self.serve_revoke(gctx) self.unimplemented_control("run_now", "publish_world_now") def serve_rekey(self, gctx): """Handle a left-right rekey action for this self.""" + rpki.log.trace() for parent in self.parents(gctx): parent.serve_rekey(gctx) def serve_revoke(self, gctx): """Handle a left-right revoke action for this self.""" + rpki.log.trace() for parent in self.parents(gctx): parent.serve_revoke(gctx) def serve_reissue(self, gctx): """Handle a left-right reissue action for this self.""" + rpki.log.trace() for parent in self.parents(gctx): parent.serve_reissue(gctx) @@ -537,11 +542,11 @@ class parent_elt(data_elt): def serve_post_save_hook(self, gctx, q_pdu, r_pdu): """Extra server actions for parent_elt.""" - if self.rekey: + if q_pdu.rekey: self.serve_rekey(gctx) - if self.reissue: + if q_pdu.reissue: self.serve_reissue(gctx) - if self.revoke: + if q_pdu.revoke: self.serve_revoke(gctx) def serve_rekey(self, gctx): diff --git a/scripts/rpki/log.py b/scripts/rpki/log.py index aeb0e0d2..1f85f667 100644 --- a/scripts/rpki/log.py +++ b/scripts/rpki/log.py @@ -21,14 +21,17 @@ import syslog, traceback enable_trace = False -def init(ident = "rpki", flags = syslog.LOG_PID | syslog.LOG_PERROR, facility = syslog.LOG_DAEMON, trace = False): +def init(ident = "rpki", flags = syslog.LOG_PID | syslog.LOG_PERROR, facility = syslog.LOG_DAEMON): """Initialize logging system.""" + return syslog.openlog(ident, flags, facility) + +def set_trace(trace): + """Enable or disable call tracing.""" + global enable_trace enable_trace = trace - return syslog.openlog(ident, flags, facility) - class logger(object): """Closure for logging.""" @@ -38,11 +41,11 @@ class logger(object): def __call__(self, message): return syslog.syslog(self.priority, message) -error = logger(syslog.LOG_ERR) -warning = logger(syslog.LOG_WARNING) -notice = logger(syslog.LOG_NOTICE) -info = logger(syslog.LOG_INFO) -debug = logger(syslog.LOG_DEBUG) +error = logger(syslog.LOG_ERR) +warn = logger(syslog.LOG_WARNING) +note = logger(syslog.LOG_NOTICE) +info = logger(syslog.LOG_INFO) +debug = logger(syslog.LOG_DEBUG) def trace(): """Execution trace -- where are we now, and whence came we here?""" diff --git a/scripts/rpki/sql.py b/scripts/rpki/sql.py index de18e1f1..92b4c48b 100644 --- a/scripts/rpki/sql.py +++ b/scripts/rpki/sql.py @@ -14,7 +14,7 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -import MySQLdb, time, traceback +import MySQLdb, time import rpki.x509, rpki.resource_set, rpki.sundial def connect(cfg): @@ -284,7 +284,7 @@ class ca_obj(sql_persistant): 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", (self.ca_id,)): + 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 in ("pending", "active"): current_resources = ca_detail.latest_ca_cert.get_3779resources() @@ -361,12 +361,6 @@ class ca_obj(sql_persistant): def rekey(self, gctx): """Initiate a rekey operation for this ca. - Noone who was at the meeting in Prague 2007 quite remembers why we - used this name for this operation, but discussion months later - concluded that it corresponds to the rollover operations in - Geoff's "Common Management Tasks" document, so that's what this - code does, with minor variations. - Tasks: - Generate a new keypair. @@ -376,27 +370,10 @@ class ca_obj(sql_persistant): - Mark result as our active ca_detail. - Reissue all child certs issued by this ca using the new ca_detail. - - - Schedule old ca_detail for removal. Geoff specifies a - timer-based method, opinions vary on whether this is ok or we - should instead just mark the old ca_detail as deprecated and - leave it that way until we receive an explicit trigger from the - IRBE. - - - Request revocation of old keypair by parent. - - - Revoke all certs (children, internal use certs like manifest, - whatever) issued by the old keypair. - - - Generate a final CRL, signed with the old keypair, listing all - the revoked certs, with a next CRL time after the last cert or - CRL signed by the old keypair will have expired. - - - Destroy old keypair. - - - Leave final CRL in place until its next CRL time has passed. """ + rpki.log.trace() + parent = self.parent(gctx) old_detail = self.fetch_active(gctx) new_detail = ca_detail_obj.create(gctx, self) @@ -414,6 +391,8 @@ class ca_obj(sql_persistant): def revoke(self, gctx): """Revoke deprecated ca_detail objects associated with this ca.""" + rpki.log.trace() + for ca_detail in self.fetch_deprecated(gctx): ca_detail.revoke(gctx) @@ -516,6 +495,10 @@ class ca_detail_obj(sql_persistant): if r_msg.payload.ski != self.latest_ca_cert.gSKI(): raise rpki.exceptions.SKIMismatch + ca = self.ca(gctx) + parent = ca.parent(gctx) + crl_interval = rpki.sundial.timedelta(seconds = parent.self(gctx).crl_interval) + nextUpdate = rpki.sundial.datetime.utcnow() if self.latest_manifest is not None: @@ -524,14 +507,14 @@ class ca_detail_obj(sql_persistant): if self.latest_crl is not None: nextUpdate = nextUpdate.later(self.latest_crl.getNextUpdate()) - for child_cert in self.chidl_certs(gctx): + for child_cert in self.child_certs(gctx): nextUpdate = nextUpdate.later(child_cert.cert.getNotAfter()) child_cert.revoke() - nextUpdate += rpki.sundial.timedelta(seconds = parent.self(gctx).crl_interval) + nextUpdate += crl_interval - generate_crl(gctx, nextUpdate) - generate_manifest(gctx, nextUpdate) + self.generate_crl(gctx, nextUpdate) + self.generate_manifest(gctx, nextUpdate) self.private_key_id = None self.manifest_private_key_id = None diff --git a/scripts/rpki/x509.py b/scripts/rpki/x509.py index 4d902351..c029e5f3 100644 --- a/scripts/rpki/x509.py +++ b/scripts/rpki/x509.py @@ -610,11 +610,11 @@ class SignedManifest(DER_object): def getThisUpdate(self): """Get thisUpdate value from this manifest.""" - return rpki.sundial.datetime.fromGeneralizedTime(self.get_content()) + return rpki.sundial.datetime.fromGeneralizedTime(self.get_content().thisUpdate.get()) def getNextUpdate(self): """Get nextUpdate value from this manifest.""" - return rpki.sundial.datetime.fromGeneralizedTime(self.get_content()) + return rpki.sundial.datetime.fromGeneralizedTime(self.get_content().nextUpdate.get()) def verify(self, ta): """Verify this manifest.""" diff --git a/scripts/rpkid.py b/scripts/rpkid.py index bf114c6e..5779753b 100755 --- a/scripts/rpkid.py +++ b/scripts/rpkid.py @@ -40,8 +40,8 @@ def left_right_handler(query, path): rpki.sql.sql_sweep(gctx) return 200, reply except lxml.etree.DocumentInvalid: - rpki.log.warning("Received reply document does not pass schema check: " + lxml.etree.tostring(r_elt, pretty_print = True)) - rpki.log.warning(traceback.format_exc()) + rpki.log.warn("Received reply document does not pass schema check: " + lxml.etree.tostring(r_elt, pretty_print = True)) + rpki.log.warn(traceback.format_exc()) return 500, "Schema violation" except Exception, data: rpki.log.error(traceback.format_exc()) diff --git a/scripts/testbed.1.yaml b/scripts/testbed.1.yaml index 5d9efeae..acee42e2 100644 --- a/scripts/testbed.1.yaml +++ b/scripts/testbed.1.yaml @@ -24,6 +24,12 @@ kids: ipv4: 192.0.2.1-192.0.2.33 asn: 64533 --- +- name: R0 + rekey: +--- +- name: R0 + revoke: +--- - name: Alice valid_add: 10 --- diff --git a/scripts/testbed.py b/scripts/testbed.py index 5dd3b4ad..a482c9b3 100644 --- a/scripts/testbed.py +++ b/scripts/testbed.py @@ -33,7 +33,7 @@ config_file contains settings for various implementation-specific things that don't belong in yaml_script. """ -import os, yaml, MySQLdb, subprocess, signal, time, datetime, re, getopt, sys +import os, yaml, MySQLdb, subprocess, signal, time, datetime, re, getopt, sys, lxml import rpki.resource_set, rpki.sundial, rpki.x509, rpki.https, rpki.log, rpki.left_right, rpki.config os.environ["TZ"] = "UTC" @@ -264,7 +264,7 @@ def main(): rpki.log.info("Killing %s" % n) os.kill(p.pid, signal.SIGTERM) except Exception, data: - rpki.log.warning("Couldn't clean up daemons (%s), continuing" % data) + rpki.log.warn("Couldn't clean up daemons (%s), continuing" % data) class timedelta(datetime.timedelta): """Timedelta with text parsing. This accepts two input formats: @@ -404,11 +404,33 @@ class allocation(object): def apply_sub_as(self, text): self.base.as = self.base.as.difference(rpki.resource_set.resource_set_as(text)) def apply_sub_v4(self, text): self.base.v4 = self.base.v4.difference(rpki.resource_set.resource_set_ipv4(text)) def apply_sub_v6(self, text): self.base.v6 = self.base.v6.difference(rpki.resource_set.resource_set_ipv6(text)) + def apply_valid_until(self, stamp): self.base.valid_until = stamp def apply_valid_for(self, text): self.base.valid_until = datetime.datetime.utcnow() + timedelta.parse(text) def apply_valid_add(self, text): self.base.valid_until += timedelta.parse(text) def apply_valid_sub(self, text): self.base.valid_until -= timedelta.parse(text) + def apply_rekey(self, target): + if self.is_leaf(): + raise RuntimeError, "Can't rekey YAML leaf %s, sorry" % self.name + elif target is None: + rpki.log.info("Rekeying <self/> %s" % self.name) + self.call_rpkid(rpki.left_right.self_elt.make_pdu(action = "set", self_id = self.self_id, rekey = "yes")) + else: + rpki.log.info("Rekeying <parent/> %s %s" % (self.name, target)) + self.call_rpkid(rpki.left_right.parent_elt.make_pdu(action = "set", self_id = self.self_id, parent_id = target, rekey = "yes")) + + def apply_revoke(self, target): + if self.is_leaf(): + rpki.log.info("Attempting to revoke YAML leaf %s" % self.name) + subprocess.check_call((prog_python, prog_poke, "-y", self.name + ".yaml", "-r", "revoke")) + elif target is None: + rpki.log.info("Revoking <self/> %s" % self.name) + self.call_rpkid(rpki.left_right.self_elt.make_pdu(action = "set", self_id = self.self_id, revoke = "yes")) + else: + rpki.log.info("Revoking <parent/> %s %s" % (self.name, target)) + self.call_rpkid(rpki.left_right.parent_elt.make_pdu(action = "set", self_id = self.self_id, parent_id = target, revoke = "yes")) + def __str__(self): s = self.name + "\n" if self.resources.as: s += " ASN: %s\n" % self.resources.as @@ -516,6 +538,7 @@ class allocation(object): pdu.type = "query" elt = rpki.left_right.msg((pdu,)).toXML() rpki.relaxng.left_right.assertValid(elt) + rpki.log.debug(lxml.etree.tostring(elt, pretty_print = True, encoding = "us-ascii")) cms = rpki.cms.xml_sign( elt = elt, key = testbed_key, @@ -530,6 +553,7 @@ class allocation(object): msg = cms) elt = rpki.cms.xml_verify(cms = cms, ta = self.rpkid_ta) rpki.relaxng.left_right.assertValid(elt) + rpki.log.debug(lxml.etree.tostring(elt, pretty_print = True, encoding = "us-ascii")) pdu = rpki.left_right.sax_handler.saxify(elt)[0] assert pdu.type == "reply" and not isinstance(pdu, rpki.left_right.report_error_elt) return pdu diff --git a/scripts/testpoke.py b/scripts/testpoke.py index 40fce102..3d23751b 100644 --- a/scripts/testpoke.py +++ b/scripts/testpoke.py @@ -26,7 +26,7 @@ Usage: python testpoke.py [ { -y | --yaml } configfile ] Default configuration file is testpoke.yaml, override with --yaml option. """ -import traceback, os, time, getopt, sys, lxml, yaml +import os, time, getopt, sys, lxml, yaml import rpki.resource_set, rpki.up_down, rpki.left_right, rpki.x509 import rpki.https, rpki.config, rpki.cms, rpki.exceptions import rpki.relaxng, rpki.oids |