diff options
-rw-r--r-- | Makefile.in | 28 | ||||
-rwxr-xr-x | ca/tests/bgpsec-yaml.py | 4 | ||||
-rw-r--r-- | ca/tests/rrdp-samples.xml | 10 | ||||
-rw-r--r-- | ca/tests/smoketest.py | 42 | ||||
-rw-r--r-- | ca/tests/testpoke.py | 4 | ||||
-rw-r--r-- | ca/tests/xml-parse-test.py | 34 | ||||
-rw-r--r-- | rpki/irdb/zookeeper.py | 27 | ||||
-rw-r--r-- | rpki/left_right.py | 14 | ||||
-rw-r--r-- | rpki/pubd.py | 50 | ||||
-rw-r--r-- | rpki/publication.py | 347 | ||||
-rw-r--r-- | rpki/publication_control.py | 292 | ||||
-rw-r--r-- | rpki/relaxng.py | 349 | ||||
-rw-r--r-- | rpki/rpkid.py | 48 | ||||
-rw-r--r-- | rpki/rpkid_tasks.py | 1 | ||||
-rwxr-xr-x | rpki/rtr/bgpdump.py | 2 | ||||
-rw-r--r-- | rpki/sql_schemas.py | 74 | ||||
-rw-r--r-- | rpki/up_down.py | 2 | ||||
-rw-r--r-- | rpki/xml_utils.py | 2 | ||||
-rw-r--r-- | schemas/relaxng/left-right.rnc (renamed from schemas/relaxng/left-right-schema.rnc) | 0 | ||||
-rw-r--r-- | schemas/relaxng/left-right.rng (renamed from schemas/relaxng/left-right-schema.rng) | 0 | ||||
-rw-r--r-- | schemas/relaxng/publication-control.rnc (renamed from schemas/relaxng/publication-schema.rnc) | 47 | ||||
-rw-r--r-- | schemas/relaxng/publication-control.rng (renamed from schemas/relaxng/publication-schema.rng) | 246 | ||||
-rw-r--r-- | schemas/relaxng/publication.rnc | 96 | ||||
-rw-r--r-- | schemas/relaxng/publication.rng | 169 | ||||
-rw-r--r-- | schemas/relaxng/router-certificate.rnc (renamed from schemas/relaxng/router-certificate-schema.rnc) | 0 | ||||
-rw-r--r-- | schemas/relaxng/router-certificate.rng (renamed from schemas/relaxng/router-certificate-schema.rng) | 0 | ||||
-rw-r--r-- | schemas/relaxng/up-down.rnc (renamed from schemas/relaxng/up-down-schema.rnc) | 0 | ||||
-rw-r--r-- | schemas/relaxng/up-down.rng (renamed from schemas/relaxng/up-down-schema.rng) | 0 | ||||
-rw-r--r-- | schemas/sql/pubd.sql | 39 | ||||
-rw-r--r-- | schemas/sql/rpkid.sql | 35 |
30 files changed, 987 insertions, 975 deletions
diff --git a/Makefile.in b/Makefile.in index 3e24b6b3..3724a2f6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -45,11 +45,12 @@ SETUP_PY_ROOT = `${PYTHON} -c 'import sys; print "--root " + sys.argv[1] if sys. POW_SO = rpki/POW/_POW.so -RNGS = schemas/relaxng/left-right-schema.rng \ - schemas/relaxng/up-down-schema.rng \ - schemas/relaxng/publication-schema.rng \ +RNGS = schemas/relaxng/left-right.rng \ + schemas/relaxng/up-down.rng \ + schemas/relaxng/publication.rng \ + schemas/relaxng/publication-control.rng \ schemas/relaxng/myrpki.rng \ - schemas/relaxng/router-certificate-schema.rng \ + schemas/relaxng/router-certificate.rng \ schemas/relaxng/rrdp.rng SQLS = schemas/sql/rpkid.sql \ @@ -188,20 +189,23 @@ ${abs_top_srcdir}/rpki/sql_schemas.py: buildtools/make-sql-schemas.py ${SQLS} cd schemas/sql; ${PYTHON} ${abs_top_srcdir}/buildtools/make-sql-schemas.py >$@.tmp mv $@.tmp $@ -schemas/relaxng/left-right-schema.rng: schemas/relaxng/left-right-schema.rnc - ${TRANG} schemas/relaxng/left-right-schema.rnc schemas/relaxng/left-right-schema.rng +schemas/relaxng/left-right.rng: schemas/relaxng/left-right.rnc + ${TRANG} schemas/relaxng/left-right.rnc schemas/relaxng/left-right.rng -schemas/relaxng/up-down-schema.rng: schemas/relaxng/up-down-schema.rnc - ${TRANG} schemas/relaxng/up-down-schema.rnc schemas/relaxng/up-down-schema.rng +schemas/relaxng/up-down.rng: schemas/relaxng/up-down.rnc + ${TRANG} schemas/relaxng/up-down.rnc schemas/relaxng/up-down.rng -schemas/relaxng/publication-schema.rng: schemas/relaxng/publication-schema.rnc - ${TRANG} schemas/relaxng/publication-schema.rnc schemas/relaxng/publication-schema.rng +schemas/relaxng/publication.rng: schemas/relaxng/publication.rnc + ${TRANG} schemas/relaxng/publication.rnc schemas/relaxng/publication.rng + +schemas/relaxng/publication-control.rng: schemas/relaxng/publication-control.rnc + ${TRANG} schemas/relaxng/publication-control.rnc schemas/relaxng/publication-control.rng schemas/relaxng/myrpki.rng: schemas/relaxng/myrpki.rnc ${TRANG} schemas/relaxng/myrpki.rnc schemas/relaxng/myrpki.rng -schemas/relaxng/router-certificate-schema.rng: schemas/relaxng/router-certificate-schema.rnc - ${TRANG} schemas/relaxng/router-certificate-schema.rnc schemas/relaxng/router-certificate-schema.rng +schemas/relaxng/router-certificate.rng: schemas/relaxng/router-certificate.rnc + ${TRANG} schemas/relaxng/router-certificate.rnc schemas/relaxng/router-certificate.rng schemas/relaxng/rrdp.rng: schemas/relaxng/rrdp.rnc ${TRANG} schemas/relaxng/rrdp.rnc schemas/relaxng/rrdp.rng diff --git a/ca/tests/bgpsec-yaml.py b/ca/tests/bgpsec-yaml.py index fafaf7bd..32388056 100755 --- a/ca/tests/bgpsec-yaml.py +++ b/ca/tests/bgpsec-yaml.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # $Id$ -# +# # Copyright (C) 2014 Dragon Research Labs ("DRL") # # Permission to use, copy, modify, and distribute this software for any @@ -28,7 +28,7 @@ import yaml root = "Root" -def kid(n): +def kid(n): # pylint: disable=W0621 name = "ISP-%03d" % n ipv4 = "10.%d.0.0/16" % n asn = n diff --git a/ca/tests/rrdp-samples.xml b/ca/tests/rrdp-samples.xml index 54f5010f..563eb73c 100644 --- a/ca/tests/rrdp-samples.xml +++ b/ca/tests/rrdp-samples.xml @@ -30,11 +30,11 @@ <!-- Notification file: lists current snapshots and deltas --> <notification version="1" xmlns="http://www.ripe.net/rpki/rrdp" session_id="d9f6dc91-0394-40b9-9663-66aef4bb623a" serial="203"> - <snapshot uri="http://host.example/d9f6dc91-0394-40b9-9663-66aeb623a/snapshot/202.xml" hash="279b79fd8389e20585f26735ee70e0e4d4b8af23bb2e2e611c70e92d2433e"/> - <delta from="156" to="183" uri="http://host.example/d9f6c91-0394-40b9-9663-66aeb623a/deltas/156/183.xml" hash="a2d56ec180f2dde2a46bf90565932e25829b852a0b43107d5de6e41394c291"/> - <delta from="183" to="184" uri="http://host.example/d9f6c91-0394-40b9-9663-66aeb623a/deltas/183/184.xml" hash="a2d56ec180f2dde2a46b2e0565932e25829b852a0b43107d5de6e41394c292"/> - <delta from="184" to="197" uri="http://host.example/d9f6c91-0394-40b9-9663-66aeb623a/deltas/184/197.xml" hash="a2d56ec180f2dde2a46b2e0565932e25829b852a0b43107d5de6e41394c292"/> - <delta from="197" to="203" uri="http://host.example/d9f6c91-0394-40b9-9663-66aeb623a/deltas/197/203.xml" hash="a2d56ec180f2dde2a4f92e0565932e25829b852a0b43107d5de6e41394c293"/> + <snapshot uri="http://host.example/d9f6dc91-0394-40b9-9663-66aeb623a/snapshot/202.xml" hash="279b79fd8389e20585f26735ee70e0e4d4b8af23bb2e2e611c70e92d2433edea"/> + <delta from="156" to="183" uri="http://host.example/d9f6c91-0394-40b9-9663-66aeb623a/deltas/156/183.xml" hash="a2d56ec180f2dde2a46bf90565932e25829b852a0b43107d5de6e41394c29100"/> + <delta from="183" to="184" uri="http://host.example/d9f6c91-0394-40b9-9663-66aeb623a/deltas/183/184.xml" hash="a2d56ec180f2dde2a46b2e0565932e25829b852a0b43107d5de6e41394c29200"/> + <delta from="184" to="197" uri="http://host.example/d9f6c91-0394-40b9-9663-66aeb623a/deltas/184/197.xml" hash="a2d56ec180f2dde2a46b2e0565932e25829b852a0b43107d5de6e41394c29201"/> + <delta from="197" to="203" uri="http://host.example/d9f6c91-0394-40b9-9663-66aeb623a/deltas/197/203.xml" hash="a2d56ec180f2dde2a4f92e0565932e25829b852a0b43107d5de6e41394c29300"/> </notification> <!-- Snapshot segment: think DNS AXFR --> diff --git a/ca/tests/smoketest.py b/ca/tests/smoketest.py index 7f56843f..4f49af41 100644 --- a/ca/tests/smoketest.py +++ b/ca/tests/smoketest.py @@ -47,7 +47,7 @@ import rpki.http import rpki.log import rpki.left_right import rpki.config -import rpki.publication +import rpki.publication_control import rpki.async from rpki.mysql_import import MySQLdb @@ -80,6 +80,7 @@ def allocate_port(): """ Allocate a TCP port number. """ + global base_port p = base_port base_port += 1 @@ -322,6 +323,7 @@ def cmd_sleep(cb, interval): """ Set an alarm, then wait for it to go off. """ + howlong = rpki.sundial.timedelta.parse(interval) logger.info("Sleeping %r", howlong) rpki.async.timer(cb).set(howlong) @@ -330,6 +332,7 @@ def cmd_shell(cb, *cmd): """ Run a shell command. """ + cmd = " ".join(cmd) status = subprocess.call(cmd, shell = True) logger.info("Shell command returned status %d", status) @@ -339,6 +342,7 @@ def cmd_echo(cb, *words): """ Echo some text to the log. """ + logger.info(" ".join(words)) cb() @@ -478,6 +482,7 @@ class allocation_db(list): """ Print content of the database. """ + for a in self: print a @@ -498,6 +503,7 @@ class allocation(object): """ Initialize one entity and insert it into the database. """ + db.append(self) self.name = yaml["name"] self.parent = parent @@ -534,6 +540,7 @@ class allocation(object): """ Compute the transitive resource closure. """ + resources = self.base for kid in self.kids: resources |= kid.closure() @@ -688,6 +695,7 @@ class allocation(object): """ Set the engine number for this entity. """ + self.irdb_db_name = "irdb%d" % n self.irdb_port = allocate_port() self.rpki_db_name = "rpki%d" % n @@ -697,6 +705,7 @@ class allocation(object): """ Get rpki port to use for this entity. """ + if self.is_hosted: assert self.hosted_by.rpki_port is not None return self.hosted_by.rpki_port @@ -708,6 +717,7 @@ class allocation(object): """ Create BPKI certificates for this entity. """ + logger.info("Constructing BPKI keys and certs for %s", self.name) setup_bpki_cert_chain(name = self.name, ee = ("RPKI", "IRDB", "IRBE"), @@ -721,6 +731,7 @@ class allocation(object): """ Write config files for this entity. """ + logger.info("Writing config files for %s", self.name) assert self.rpki_port is not None d = { "my_name" : self.name, @@ -740,6 +751,7 @@ class allocation(object): """ Set up this entity's IRDB. """ + logger.info("Setting up MySQL for %s", self.name) db = MySQLdb.connect(user = "rpki", db = self.rpki_db_name, passwd = rpki_db_pass, conv = sql_conversions) @@ -774,6 +786,7 @@ class allocation(object): once during setup, then do it again every time we apply a delta to this entity. """ + logger.info("Updating MySQL data for IRDB %s", self.name) db = MySQLdb.connect(user = "irdb", db = self.irdb_db_name, passwd = irdb_db_pass, conv = sql_conversions) @@ -827,6 +840,7 @@ class allocation(object): """ Run daemons for this entity. """ + logger.info("Running daemons for %s", self.name) self.rpkid_process = subprocess.Popen((prog_python, prog_rpkid, "--foreground", "--log-stdout", "--log-level", "debug", "--config", self.name + ".conf") + (("--profile", self.name + ".prof") if args.profile else ())) @@ -836,6 +850,7 @@ class allocation(object): """ Kill daemons for this entity. """ + # pylint: disable=E1103 for proc, name in ((self.rpkid_process, "rpkid"), (self.irdbd_process, "irdbd")): @@ -985,7 +1000,7 @@ class allocation(object): bsc_handle = "b", generate_keypair = True)) - pubd_pdus.append(rpki.publication.client_elt.make_pdu( + pubd_pdus.append(rpki.publication_control.client_elt.make_pdu( action = "create", client_handle = s.client_handle, base_uri = s.sia_base, @@ -1154,6 +1169,7 @@ def setup_bpki_cert_chain(name, ee = (), ca = ()): """ Build a set of BPKI certificates. """ + s = "exec >/dev/null 2>&1\n" #s = "set -x\n" for kind in ("TA",) + ee + ca: @@ -1181,6 +1197,7 @@ def setup_rootd(rpkid, rootd_yaml): """ Write the config files for rootd. """ + rpkid.cross_certify(rootd_name + "-TA", reverse = True) logger.info("Writing config files for %s", rootd_name) d = { "rootd_name" : rootd_name, @@ -1204,6 +1221,7 @@ def setup_rcynic(): """ Write the config file for rcynic. """ + logger.info("Config file for rcynic") d = { "rcynic_name" : rcynic_name, "rootd_name" : rootd_name, @@ -1216,6 +1234,7 @@ def setup_rsyncd(): """ Write the config file for rsyncd. """ + logger.info("Config file for rsyncd") d = { "rsyncd_name" : rsyncd_name, "rsyncd_port" : rsyncd_port, @@ -1229,6 +1248,7 @@ def setup_publication(pubd_sql): """ Set up publication daemon. """ + logger.info("Configure publication daemon") publication_dir = os.getcwd() + "/publication" assert rootd_sia.startswith("rsync://") @@ -1268,12 +1288,13 @@ def setup_publication(pubd_sql): def call_pubd(pdus, cb): """ - Send a publication message to publication daemon and return the - response. + Send a publication control message to publication daemon and return + the response. """ + logger.info("Calling pubd") - q_msg = rpki.publication.msg.query(*pdus) - q_cms = rpki.publication.cms_msg() + q_msg = rpki.publication_control.msg.query(*pdus) + q_cms = rpki.publication_control.cms_msg() q_der = q_cms.wrap(q_msg, pubd_irbe_key, pubd_irbe_cert) q_url = "http://localhost:%d/control" % pubd_port @@ -1281,13 +1302,13 @@ def call_pubd(pdus, cb): def call_pubd_cb(r_der): global pubd_last_cms_time - r_cms = rpki.publication.cms_msg(DER = r_der) + r_cms = rpki.publication_control.cms_msg(DER = r_der) r_msg = r_cms.unwrap((pubd_ta, pubd_pubd_cert)) pubd_last_cms_time = r_cms.check_replay(pubd_last_cms_time, q_url) logger.debug(r_cms.pretty_print_content()) assert r_msg.is_reply for r_pdu in r_msg: - assert not isinstance(r_pdu, rpki.publication.report_error_elt) + assert not isinstance(r_pdu, rpki.publication_control.report_error_elt) cb(r_msg) def call_pubd_eb(e): @@ -1305,9 +1326,10 @@ def set_pubd_crl(cb): publication daemon starts talking to its clients, and must be updated whenever we update the CRL. """ + logger.info("Setting pubd's BPKI CRL") crl = rpki.x509.CRL(Auto_file = pubd_name + "-TA.crl") - call_pubd([rpki.publication.config_elt.make_pdu(action = "set", bpki_crl = crl)], cb = lambda ignored: cb()) + call_pubd([rpki.publication_control.config_elt.make_pdu(action = "set", bpki_crl = crl)], cb = lambda ignored: cb()) last_rcynic_run = None @@ -1315,6 +1337,7 @@ def run_rcynic(): """ Run rcynic to see whether what was published makes sense. """ + logger.info("Running rcynic") env = os.environ.copy() env["TZ"] = "" @@ -1330,6 +1353,7 @@ def mangle_sql(filename): """ Mangle an SQL file into a sequence of SQL statements. """ + words = [] f = open(filename) for line in f: diff --git a/ca/tests/testpoke.py b/ca/tests/testpoke.py index efa068c9..8a443e0d 100644 --- a/ca/tests/testpoke.py +++ b/ca/tests/testpoke.py @@ -74,9 +74,9 @@ def get_PEM_chain(name, cert = None): if cert is not None: chain.append(cert) if name in yaml_data: - chain.extend([rpki.x509.X509(PEM = x) for x in yaml_data[name]]) + chain.extend(rpki.x509.X509(PEM = x) for x in yaml_data[name]) elif name + "-file" in yaml_data: - chain.extend([rpki.x509.X509(PEM_file = x) for x in yaml_data[name + "-file"]]) + chain.extend(rpki.x509.X509(PEM_file = x) for x in yaml_data[name + "-file"]) return chain def query_up_down(q_pdu): diff --git a/ca/tests/xml-parse-test.py b/ca/tests/xml-parse-test.py index 5ea25492..85f4453e 100644 --- a/ca/tests/xml-parse-test.py +++ b/ca/tests/xml-parse-test.py @@ -28,8 +28,14 @@ # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # PERFORMANCE OF THIS SOFTWARE. -import glob, lxml.etree, lxml.sax -import rpki.up_down, rpki.left_right, rpki.publication, rpki.relaxng +import glob +import lxml.etree +import lxml.sax +import rpki.up_down +import rpki.left_right +import rpki.publication +import rpki.publication_control +import rpki.relaxng verbose = False @@ -88,17 +94,17 @@ def lr_tester(elt_in, elt_out, msg): def pp_tester(elt_in, elt_out, msg): assert isinstance(msg, rpki.publication.msg) for obj in msg: - if isinstance(obj, rpki.publication.client_elt): + if isinstance(obj, rpki.publication.publish_elt): + pprint(((obj.payload, "Publish object"),)) + if isinstance(obj, rpki.publication.withdraw_elt): + pprint(((None, "Withdraw object"),)) + +def pc_tester(elt_in, elt_out, msg): + assert isinstance(msg, rpki.publication_control.msg) + for obj in msg: + if isinstance(obj, rpki.publication_control.client_elt): pprint(((obj.bpki_cert, "BPKI cert"), (obj.bpki_glue, "BPKI glue"))) - if isinstance(obj, rpki.publication.certificate_elt): - pprint(((obj.payload, "RPKI cert"),)) - if isinstance(obj, rpki.publication.crl_elt): - pprint(((obj.payload, "RPKI CRL"),)) - if isinstance(obj, rpki.publication.manifest_elt): - pprint(((obj.payload, "RPKI manifest"),)) - if isinstance(obj, rpki.publication.roa_elt): - pprint(((obj.payload, "ROA"),)) test(fileglob = "up-down-protocol-samples/*.xml", rng = rpki.relaxng.up_down, @@ -117,3 +123,9 @@ test(fileglob = "publication-protocol-samples/*.xml", sax_handler = rpki.publication.sax_handler, encoding = "us-ascii", tester = pp_tester) + +test(fileglob = "publication-control-protocol-samples/*.xml", + rng = rpki.relaxng.publication_control, + sax_handler = rpki.publication_control.sax_handler, + encoding = "us-ascii", + tester = pc_tester) diff --git a/rpki/irdb/zookeeper.py b/rpki/irdb/zookeeper.py index 6b762b0f..2c600ee5 100644 --- a/rpki/irdb/zookeeper.py +++ b/rpki/irdb/zookeeper.py @@ -35,6 +35,7 @@ import rpki.left_right import rpki.x509 import rpki.async import rpki.irdb +import rpki.publication_control import django.db.transaction from lxml.etree import (Element, SubElement, ElementTree, @@ -536,12 +537,12 @@ class Zookeeper(object): updates = [] updates.append( - rpki.publication.config_elt.make_pdu( + rpki.publication_control.config_elt.make_pdu( action = "set", bpki_crl = self.server_ca.latest_crl)) updates.extend( - rpki.publication.client_elt.make_pdu( + rpki.publication_control.client_elt.make_pdu( action = "set", client_handle = client.handle, bpki_cert = client.certificate) @@ -1143,9 +1144,9 @@ class Zookeeper(object): clear_replay_protection = "yes") for ca in rpki.irdb.ResourceHolderCA.objects.all()) if self.run_pubd: - self.call_pubd(rpki.publication.client_elt.make_pdu(action = "set", - client_handle = client.handle, - clear_replay_protection = "yes") + self.call_pubd(rpki.publication_control.client_elt.make_pdu(action = "set", + client_handle = client.handle, + clear_replay_protection = "yes") for client in self.server_ca.clients.all()) @@ -1172,7 +1173,7 @@ class Zookeeper(object): pdus = pdus[0] call_pubd = rpki.async.sync_wrapper(rpki.http.caller( - proto = rpki.publication, + proto = rpki.publication_control, client_key = irbe.private_key, client_cert = irbe.certificate, server_ta = self.server_ca.certificate, @@ -1189,11 +1190,11 @@ class Zookeeper(object): throw exceptions as needed. """ - if any(isinstance(pdu, (rpki.left_right.report_error_elt, rpki.publication.report_error_elt)) for pdu in pdus): + if any(isinstance(pdu, (rpki.left_right.report_error_elt, rpki.publication_control.report_error_elt)) for pdu in pdus): for pdu in pdus: if isinstance(pdu, rpki.left_right.report_error_elt): self.log("rpkid reported failure: %s" % pdu.error_code) - elif isinstance(pdu, rpki.publication.report_error_elt): + elif isinstance(pdu, rpki.publication_control.report_error_elt): self.log("pubd reported failure: %s" % pdu.error_code) else: continue @@ -1531,14 +1532,14 @@ class Zookeeper(object): # Make sure that pubd's BPKI CRL is up to date. - self.call_pubd(rpki.publication.config_elt.make_pdu( + self.call_pubd(rpki.publication_control.config_elt.make_pdu( action = "set", bpki_crl = self.server_ca.latest_crl)) # See what pubd already has on file - pubd_reply = self.call_pubd(rpki.publication.client_elt.make_pdu(action = "list")) - client_pdus = dict((x.client_handle, x) for x in pubd_reply if isinstance(x, rpki.publication.client_elt)) + pubd_reply = self.call_pubd(rpki.publication_control.client_elt.make_pdu(action = "list")) + client_pdus = dict((x.client_handle, x) for x in pubd_reply if isinstance(x, rpki.publication_control.client_elt)) pubd_query = [] # Check all clients @@ -1550,7 +1551,7 @@ class Zookeeper(object): if (client_pdu is None or client_pdu.base_uri != client.sia_base or client_pdu.bpki_cert != client.certificate): - pubd_query.append(rpki.publication.client_elt.make_pdu( + pubd_query.append(rpki.publication_control.client_elt.make_pdu( action = "create" if client_pdu is None else "set", client_handle = client.handle, bpki_cert = client.certificate, @@ -1558,7 +1559,7 @@ class Zookeeper(object): # Delete any unknown clients - pubd_query.extend(rpki.publication.client_elt.make_pdu( + pubd_query.extend(rpki.publication_control.client_elt.make_pdu( action = "destroy", client_handle = p) for p in client_pdus) # If we changed anything, ship updates off to pubd diff --git a/rpki/left_right.py b/rpki/left_right.py index 12c69521..d05d0221 100644 --- a/rpki/left_right.py +++ b/rpki/left_right.py @@ -312,16 +312,18 @@ class self_elt(data_elt): for ca in parent.cas: ca_detail = ca.active_ca_detail if ca_detail is not None: - q_msg.append(rpki.publication.crl_elt.make_publish( + q_msg.append(rpki.publication.publish_elt.make( ca_detail.crl_uri, ca_detail.latest_crl)) - q_msg.append(rpki.publication.manifest_elt.make_publish( + q_msg.append(rpki.publication.publish_elt.make( ca_detail.manifest_uri, ca_detail.latest_manifest)) - q_msg.extend(rpki.publication.certificate_elt.make_publish( + q_msg.extend(rpki.publication.publish_elt.make( c.uri, c.cert) for c in ca_detail.child_certs) - q_msg.extend(rpki.publication.roa_elt.make_publish( + q_msg.extend(rpki.publication.publish_elt.make( r.uri, r.roa) for r in ca_detail.roas if r.roa is not None) - q_msg.extend(rpki.publication.ghostbuster_elt.make_publish( + q_msg.extend(rpki.publication.publish_elt.make( g.uri, g.ghostbuster) for g in ca_detail.ghostbusters) + q_msg.extend(rpki.publication.publish_elt.make( + c.uri, c.cert) for c in ca_detail.ee_certificates) parent.repository.call_pubd(iterator, eb, q_msg) rpki.async.iterator(self.parents, loop, cb) @@ -544,7 +546,7 @@ class repository_elt(data_elt): handlers = {} for q_pdu in q_msg: - logger.info("Sending %s %s to pubd", q_pdu.action, q_pdu.uri) + logger.info("Sending %r to pubd", q_pdu) bsc = self.bsc q_der = rpki.publication.cms_msg().wrap(q_msg, bsc.private_key_id, bsc.signing_cert, bsc.signing_cert_crl) diff --git a/rpki/pubd.py b/rpki/pubd.py index 79315a78..e932f686 100644 --- a/rpki/pubd.py +++ b/rpki/pubd.py @@ -36,6 +36,7 @@ import rpki.exceptions import rpki.relaxng import rpki.log import rpki.publication +import rpki.publication_control import rpki.daemonize logger = logging.getLogger(__name__) @@ -110,39 +111,28 @@ class main(object): handlers = (("/control", self.control_handler), ("/client/", self.client_handler))) - def handler_common(self, query, client, cb, certs, crl = None): - """ - Common PDU handler code. - """ - - def done(r_msg): - reply = rpki.publication.cms_msg().wrap(r_msg, self.pubd_key, self.pubd_cert, crl) - self.sql.sweep() - cb(reply) - - q_cms = rpki.publication.cms_msg(DER = query) - q_msg = q_cms.unwrap(certs) - if client is None: - self.irbe_cms_timestamp = q_cms.check_replay(self.irbe_cms_timestamp, "control") - else: - q_cms.check_replay_sql(client, client.client_handle) - q_msg.serve_top_level(self, client, done) def control_handler(self, query, path, cb): """ Process one PDU from the IRBE. """ - def done(body): - cb(200, body = body) + def done(r_msg): + self.sql.sweep() + cb(code = 200, + body = rpki.publication_control.cms_msg().wrap(r_msg, self.pubd_key, self.pubd_cert)) try: - self.handler_common(query, None, done, (self.bpki_ta, self.irbe_cert)) + q_cms = rpki.publication_control.cms_msg(DER = query) + q_msg = q_cms.unwrap((self.bpki_ta, self.irbe_cert)) + self.irbe_cms_timestamp = q_cms.check_replay(self.irbe_cms_timestamp, "control") + q_msg.serve_top_level(self, done) except (rpki.async.ExitNow, SystemExit): raise except Exception, e: logger.exception("Unhandled exception processing control query, path %r", path) - cb(500, reason = "Unhandled exception %s: %s" % (e.__class__.__name__, e)) + cb(code = 500, reason = "Unhandled exception %s: %s" % (e.__class__.__name__, e)) + client_url_regexp = re.compile("/client/([-A-Z0-9_/]+)$", re.I) @@ -151,23 +141,29 @@ class main(object): Process one PDU from a client. """ - def done(body): - cb(200, body = body) + def done(r_msg): + self.sql.sweep() + cb(code = 200, + body = rpki.publication.cms_msg().wrap(r_msg, self.pubd_key, self.pubd_cert, config.bpki_crl)) try: match = self.client_url_regexp.search(path) if match is None: raise rpki.exceptions.BadContactURL("Bad path: %s" % path) client_handle = match.group(1) - client = rpki.publication.client_elt.sql_fetch_where1(self, "client_handle = %s", (client_handle,)) + client = rpki.publication_control.client_elt.sql_fetch_where1(self, "client_handle = %s", (client_handle,)) if client is None: raise rpki.exceptions.ClientNotFound("Could not find client %s" % client_handle) - config = rpki.publication.config_elt.fetch(self) + config = rpki.publication_control.config_elt.fetch(self) if config is None or config.bpki_crl is None: raise rpki.exceptions.CMSCRLNotSet - self.handler_common(query, client, done, (self.bpki_ta, client.bpki_cert, client.bpki_glue), config.bpki_crl) + q_cms = rpki.publication.cms_msg(DER = query) + q_msg = q_cms.unwrap((self.bpki_ta, client.bpki_cert, client.bpki_glue)) + q_cms.check_replay_sql(client, client.client_handle) + q_msg.serve_top_level(self, client, done) except (rpki.async.ExitNow, SystemExit): raise except Exception, e: logger.exception("Unhandled exception processing client query, path %r", path) - cb(500, reason = "Could not process PDU: %s" % e) + cb(code = 500, + reason = "Could not process PDU: %s" % e) diff --git a/rpki/publication.py b/rpki/publication.py index 95f4f314..87a097c9 100644 --- a/rpki/publication.py +++ b/rpki/publication.py @@ -1,35 +1,24 @@ # $Id$ # -# 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. -# +# Copyright (C) 2013--2014 Dragon Research Labs ("DRL") +# Portions copyright (C) 2009--2012 Internet Systems Consortium ("ISC") # 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. +# copyright notices 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. +# THE SOFTWARE IS PROVIDED "AS IS" AND DRL, ISC, AND ARIN DISCLAIM ALL +# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL, +# ISC, OR 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. """ -RPKI "publication" protocol. +RPKI publication protocol. """ import os @@ -48,208 +37,95 @@ import rpki.log logger = logging.getLogger(__name__) + class publication_namespace(object): - """ - XML namespace parameters for publication protocol. - """ xmlns = "http://www.hactrn.net/uris/rpki/publication-spec/" nsmap = { None : xmlns } -class control_elt(rpki.xml_utils.data_elt, rpki.sql.sql_persistent, publication_namespace): - """ - Virtual class for control channel objects. - """ - def serve_dispatch(self, r_msg, cb, eb): - """ - Action dispatch handler. This needs special handling because we - need to make sure that this PDU arrived via the control channel. - """ - if self.client is not None: - raise rpki.exceptions.BadQuery("Control query received on client channel") - rpki.xml_utils.data_elt.serve_dispatch(self, r_msg, cb, eb) - -class config_elt(control_elt): +class base_publication_elt(rpki.xml_utils.base_elt, publication_namespace): """ - <config/> element. This is a little weird because there should - never be more than one row in the SQL config table, but we have to - put the BPKI CRL somewhere and SQL is the least bad place available. - - So we reuse a lot of the SQL machinery, but we nail config_id at 1, - we don't expose it in the XML protocol, and we only support the get - and set actions. + Base element for publication protocol. Publish and withdraw PDUs subclass this. """ - attributes = ("action", "tag") - element_name = "config" - elements = ("bpki_crl",) - - sql_template = rpki.sql.template( - "config", - "config_id", - ("bpki_crl", rpki.x509.CRL)) - - wired_in_config_id = 1 - - def startElement(self, stack, name, attrs): - """ - StartElement() handler for config object. This requires special - handling because of the weird way we treat config_id. - """ - control_elt.startElement(self, stack, name, attrs) - self.config_id = self.wired_in_config_id - - @classmethod - def fetch(cls, gctx): - """ - Fetch the config object from SQL. This requires special handling - because of the weird way we treat config_id. - """ - return cls.sql_fetch(gctx, cls.wired_in_config_id) + attributes = ("tag", "uri") + payload = None - def serve_set(self, r_msg, cb, eb): - """ - Handle a set action. This requires special handling because - config doesn't support the create method. - """ - if self.sql_fetch(self.gctx, self.config_id) is None: - control_elt.serve_create(self, r_msg, cb, eb) - else: - control_elt.serve_set(self, r_msg, cb, eb) + def __repr__(self): + return rpki.log.log_repr(self, self.uri, self.payload) - def serve_fetch_one_maybe(self): + def serve_dispatch(self, r_msg, cb, eb): """ - Find the config object on which a get or set method should - operate. + Action dispatch handler. """ - return self.sql_fetch(self.gctx, self.config_id) -class client_elt(control_elt): - """ - <client/> element. - """ + try: + self.client.check_allowed_uri(self.uri) + self.serve_action() + r_pdu = self.__class__() + r_pdu.tag = self.tag + r_pdu.uri = self.uri + r_msg.append(r_pdu) + cb() + except rpki.exceptions.NoObjectAtURI, e: + # This can happen when we're cleaning up from a prior mess, so + # we generate a <report_error/> PDU then carry on. + r_msg.append(report_error_elt.from_exception(e, self.tag)) + cb() - element_name = "client" - attributes = ("action", "tag", "client_handle", "base_uri") - elements = ("bpki_cert", "bpki_glue") - booleans = ("clear_replay_protection",) - - sql_template = rpki.sql.template( - "client", - "client_id", - "client_handle", - "base_uri", - ("bpki_cert", rpki.x509.X509), - ("bpki_glue", rpki.x509.X509), - ("last_cms_timestamp", rpki.sundial.datetime)) - - base_uri = None - bpki_cert = None - bpki_glue = None - last_cms_timestamp = None - - def serve_post_save_hook(self, q_pdu, r_pdu, cb, eb): - """ - Extra server actions for client_elt. - """ - actions = [] - if q_pdu.clear_replay_protection: - actions.append(self.serve_clear_replay_protection) - def loop(iterator, action): - action(iterator, eb) - rpki.async.iterator(actions, loop, cb) - - def serve_clear_replay_protection(self, cb, eb): + def uri_to_filename(self): """ - Handle a clear_replay_protection action for this client. + Convert a URI to a local filename. """ - self.last_cms_timestamp = None - self.sql_mark_dirty() - cb() - def serve_fetch_one_maybe(self): - """ - Find the client object on which a get, set, or destroy method - should operate, or which would conflict with a create method. - """ - return self.sql_fetch_where1(self.gctx, "client_handle = %s", (self.client_handle,)) + if not self.uri.startswith("rsync://"): + raise rpki.exceptions.BadURISyntax(self.uri) + path = self.uri.split("/")[3:] + if not self.gctx.publication_multimodule: + del path[0] + path.insert(0, self.gctx.publication_base.rstrip("/")) + filename = "/".join(path) + if "/../" in filename or filename.endswith("/.."): + raise rpki.exceptions.BadURISyntax(filename) + return filename - def serve_fetch_all(self): + def raise_if_error(self): """ - Find client objects on which a list method should operate. + No-op, since this is not a <report_error/> PDU. """ - return self.sql_fetch_all(self.gctx) + pass - def check_allowed_uri(self, uri): - """ - Make sure that a target URI is within this client's allowed URI space. - """ - if not uri.startswith(self.base_uri): - raise rpki.exceptions.ForbiddenURI -class publication_object_elt(rpki.xml_utils.base_elt, publication_namespace): - """ - Virtual class for publishable objects. These have very similar - syntax, differences lie in underlying datatype and methods. XML - methods are a little different from the pattern used for objects - that support the create/set/get/list/destroy actions, but - publishable objects don't go in SQL either so these classes would be - different in any case. - """ +class publish_elt(base_publication_elt): - attributes = ("action", "tag", "client_handle", "uri") - payload_type = None - payload = None + element_name = "publish" def endElement(self, stack, name, text): """ - Handle a publishable element element. + Handle reading of the object to be published """ + assert name == self.element_name, "Unexpected name %s, stack %s" % (name, stack) if text: - self.payload = self.payload_type(Base64 = text) # pylint: disable=E1102 + self.payload = rpki.x509.uri_dispatch(self.uri)(Base64 = text) stack.pop() def toXML(self): """ Generate XML element for publishable object. """ + elt = self.make_elt() - if self.payload: + if self.payload != None: elt.text = self.payload.get_Base64() return elt - def serve_dispatch(self, r_msg, cb, eb): - """ - Action dispatch handler. - """ - # pylint: disable=E0203 - try: - if self.client is None: - raise rpki.exceptions.BadQuery("Client query received on control channel") - dispatch = { "publish" : self.serve_publish, - "withdraw" : self.serve_withdraw } - if self.action not in dispatch: - raise rpki.exceptions.BadQuery("Unexpected query: action %s" % self.action) - self.client.check_allowed_uri(self.uri) - dispatch[self.action]() - r_pdu = self.__class__() - r_pdu.action = self.action - r_pdu.tag = self.tag - r_pdu.uri = self.uri - r_msg.append(r_pdu) - cb() - except rpki.exceptions.NoObjectAtURI, e: - # This can happen when we're cleaning up from a prior mess, so - # we generate a <report_error/> PDU then carry on. - r_msg.append(report_error_elt.from_exception(e, self.tag)) - cb() - - def serve_publish(self): + def serve_action(self): """ Publish an object. """ + logger.info("Publishing %s", self.payload.tracking_data(self.uri)) filename = self.uri_to_filename() filename_tmp = filename + ".tmp" @@ -261,10 +137,25 @@ class publication_object_elt(rpki.xml_utils.base_elt, publication_namespace): f.close() os.rename(filename_tmp, filename) - def serve_withdraw(self): + @classmethod + def make(cls, uri, obj, tag = None): + """ + Construct a publication PDU. + """ + + assert isinstance(obj, rpki.x509.uri_dispatch(uri)) + return cls.make_pdu(uri = uri, payload = obj, tag = tag) + + +class withdraw_elt(base_publication_elt): + + element_name = "withdraw" + + def serve_action(self): """ Withdraw an object, then recursively delete empty directories. """ + logger.info("Withdrawing %s", self.uri) filename = self.uri_to_filename() try: @@ -284,86 +175,15 @@ class publication_object_elt(rpki.xml_utils.base_elt, publication_namespace): else: dirname = os.path.dirname(dirname) - def uri_to_filename(self): - """ - Convert a URI to a local filename. - """ - if not self.uri.startswith("rsync://"): - raise rpki.exceptions.BadURISyntax(self.uri) - path = self.uri.split("/")[3:] - if not self.gctx.publication_multimodule: - del path[0] - path.insert(0, self.gctx.publication_base.rstrip("/")) - filename = "/".join(path) - if "/../" in filename or filename.endswith("/.."): - raise rpki.exceptions.BadURISyntax(filename) - return filename - @classmethod - def make_publish(cls, uri, obj, tag = None): - """ - Construct a publication PDU. - """ - assert cls.payload_type is not None and type(obj) is cls.payload_type - return cls.make_pdu(action = "publish", uri = uri, payload = obj, tag = tag) - - @classmethod - def make_withdraw(cls, uri, obj, tag = None): + def make(cls, uri, obj, tag = None): """ Construct a withdrawal PDU. """ - assert cls.payload_type is not None and type(obj) is cls.payload_type - return cls.make_pdu(action = "withdraw", uri = uri, tag = tag) - - def raise_if_error(self): - """ - No-op, since this is not a <report_error/> PDU. - """ - pass - -class certificate_elt(publication_object_elt): - """ - <certificate/> element. - """ - - element_name = "certificate" - payload_type = rpki.x509.X509 - -class crl_elt(publication_object_elt): - """ - <crl/> element. - """ - - element_name = "crl" - payload_type = rpki.x509.CRL - -class manifest_elt(publication_object_elt): - """ - <manifest/> element. - """ - - element_name = "manifest" - payload_type = rpki.x509.SignedManifest - -class roa_elt(publication_object_elt): - """ - <roa/> element. - """ - - element_name = "roa" - payload_type = rpki.x509.ROA - -class ghostbuster_elt(publication_object_elt): - """ - <ghostbuster/> element. - """ - element_name = "ghostbuster" - payload_type = rpki.x509.Ghostbuster + assert isinstance(obj, rpki.x509.uri_dispatch(uri)) + return cls.make_pdu(uri = uri, tag = tag) -publication_object_elt.obj2elt = dict( - (e.payload_type, e) for e in - (certificate_elt, crl_elt, manifest_elt, roa_elt, ghostbuster_elt)) class report_error_elt(rpki.xml_utils.text_elt, publication_namespace): """ @@ -376,6 +196,9 @@ class report_error_elt(rpki.xml_utils.text_elt, publication_namespace): error_text = None + def __repr__(self): + return rpki.log.log_repr(self) + @classmethod def from_exception(cls, e, tag = None): """ @@ -406,6 +229,7 @@ class report_error_elt(rpki.xml_utils.text_elt, publication_namespace): else: raise rpki.exceptions.BadPublicationReply("Unexpected response from pubd: %s" % self) + class msg(rpki.xml_utils.msg, publication_namespace): """ Publication PDU. @@ -413,12 +237,11 @@ class msg(rpki.xml_utils.msg, publication_namespace): ## @var version # Protocol version - version = 1 + version = 3 ## @var pdus # Dispatch table of PDUs for this protocol. - pdus = dict((x.element_name, x) for x in - (config_elt, client_elt, certificate_elt, crl_elt, manifest_elt, roa_elt, ghostbuster_elt, report_error_elt)) + pdus = dict((x.element_name, x) for x in (publish_elt, withdraw_elt, report_error_elt)) def serve_top_level(self, gctx, client, cb): """ @@ -450,6 +273,7 @@ class msg(rpki.xml_utils.msg, publication_namespace): rpki.async.iterator(self, loop, done) + class sax_handler(rpki.xml_utils.sax_handler): """ SAX handler for publication protocol. @@ -457,7 +281,8 @@ class sax_handler(rpki.xml_utils.sax_handler): pdu = msg name = "msg" - version = "1" + version = "3" + class cms_msg(rpki.x509.XML_CMS_object): """ diff --git a/rpki/publication_control.py b/rpki/publication_control.py new file mode 100644 index 00000000..bd6a8db2 --- /dev/null +++ b/rpki/publication_control.py @@ -0,0 +1,292 @@ +# $Id$ +# +# 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. + +""" +RPKI publication control protocol. + +Per IETF SIDR WG discussion, this is now separate from the publication +protocol itself. +""" + +import logging +import rpki.resource_set +import rpki.x509 +import rpki.sql +import rpki.exceptions +import rpki.xml_utils +import rpki.http +import rpki.up_down +import rpki.relaxng +import rpki.sundial +import rpki.log + +logger = logging.getLogger(__name__) + + +class publication_control_namespace(object): + """ + XML namespace parameters for publication control protocol. + """ + + xmlns = "http://www.hactrn.net/uris/rpki/publication-control/" + nsmap = { None : xmlns } + + +class control_elt(rpki.xml_utils.data_elt, rpki.sql.sql_persistent, publication_control_namespace): + """ + Virtual class for control channel objects. + """ + + pass + + +class config_elt(control_elt): + """ + <config/> element. This is a little weird because there should + never be more than one row in the SQL config table, but we have to + put the BPKI CRL somewhere and SQL is the least bad place available. + + So we reuse a lot of the SQL machinery, but we nail config_id at 1, + we don't expose it in the XML protocol, and we only support the get + and set actions. + """ + + attributes = ("action", "tag") + element_name = "config" + elements = ("bpki_crl",) + + sql_template = rpki.sql.template( + "config", + "config_id", + ("bpki_crl", rpki.x509.CRL)) + + wired_in_config_id = 1 + + def startElement(self, stack, name, attrs): + """ + StartElement() handler for config object. This requires special + handling because of the weird way we treat config_id. + """ + control_elt.startElement(self, stack, name, attrs) + self.config_id = self.wired_in_config_id + + @classmethod + def fetch(cls, gctx): + """ + Fetch the config object from SQL. This requires special handling + because of the weird way we treat config_id. + """ + return cls.sql_fetch(gctx, cls.wired_in_config_id) + + def serve_set(self, r_msg, cb, eb): + """ + Handle a set action. This requires special handling because + config doesn't support the create method. + """ + if self.sql_fetch(self.gctx, self.config_id) is None: + control_elt.serve_create(self, r_msg, cb, eb) + else: + control_elt.serve_set(self, r_msg, cb, eb) + + def serve_fetch_one_maybe(self): + """ + Find the config object on which a get or set method should + operate. + """ + return self.sql_fetch(self.gctx, self.config_id) + + +class client_elt(control_elt): + """ + <client/> element. + """ + + element_name = "client" + attributes = ("action", "tag", "client_handle", "base_uri") + elements = ("bpki_cert", "bpki_glue") + booleans = ("clear_replay_protection",) + + sql_template = rpki.sql.template( + "client", + "client_id", + "client_handle", + "base_uri", + ("bpki_cert", rpki.x509.X509), + ("bpki_glue", rpki.x509.X509), + ("last_cms_timestamp", rpki.sundial.datetime)) + + base_uri = None + bpki_cert = None + bpki_glue = None + last_cms_timestamp = None + + def serve_post_save_hook(self, q_pdu, r_pdu, cb, eb): + """ + Extra server actions for client_elt. + """ + actions = [] + if q_pdu.clear_replay_protection: + actions.append(self.serve_clear_replay_protection) + def loop(iterator, action): + action(iterator, eb) + rpki.async.iterator(actions, loop, cb) + + def serve_clear_replay_protection(self, cb, eb): + """ + Handle a clear_replay_protection action for this client. + """ + self.last_cms_timestamp = None + self.sql_mark_dirty() + cb() + + def serve_fetch_one_maybe(self): + """ + Find the client object on which a get, set, or destroy method + should operate, or which would conflict with a create method. + """ + return self.sql_fetch_where1(self.gctx, "client_handle = %s", (self.client_handle,)) + + def serve_fetch_all(self): + """ + Find client objects on which a list method should operate. + """ + return self.sql_fetch_all(self.gctx) + + def check_allowed_uri(self, uri): + """ + Make sure that a target URI is within this client's allowed URI space. + """ + if not uri.startswith(self.base_uri): + raise rpki.exceptions.ForbiddenURI + + +class report_error_elt(rpki.xml_utils.text_elt, publication_control_namespace): + """ + <report_error/> element. + """ + + element_name = "report_error" + attributes = ("tag", "error_code") + text_attribute = "error_text" + + error_text = None + + @classmethod + def from_exception(cls, e, tag = None): + """ + Generate a <report_error/> element from an exception. + """ + self = cls() + self.tag = tag + self.error_code = e.__class__.__name__ + self.error_text = str(e) + return self + + def __str__(self): + s = "" + if getattr(self, "tag", None) is not None: + s += "[%s] " % self.tag + s += self.error_code + if getattr(self, "error_text", None) is not None: + s += ": " + self.error_text + return s + + def raise_if_error(self): + """ + Raise exception associated with this <report_error/> PDU. + """ + t = rpki.exceptions.__dict__.get(self.error_code) + if isinstance(t, type) and issubclass(t, rpki.exceptions.RPKI_Exception): + raise t(getattr(self, "text", None)) + else: + raise rpki.exceptions.BadPublicationReply("Unexpected response from pubd: %s" % self) + + +class msg(rpki.xml_utils.msg, publication_control_namespace): + """ + Publication control PDU. + """ + + ## @var version + # Protocol version + version = 1 + + ## @var pdus + # Dispatch table of PDUs for this protocol. + pdus = dict((x.element_name, x) for x in (config_elt, client_elt, report_error_elt)) + + def serve_top_level(self, gctx, cb): + """ + Serve one msg PDU. + """ + if not self.is_query(): + raise rpki.exceptions.BadQuery("Message type is not query") + r_msg = self.__class__.reply() + + def loop(iterator, q_pdu): + + def fail(e): + if not isinstance(e, rpki.exceptions.NotFound): + logger.exception("Exception processing PDU %r", q_pdu) + r_msg.append(report_error_elt.from_exception(e, q_pdu.tag)) + cb(r_msg) + + try: + q_pdu.gctx = gctx + q_pdu.serve_dispatch(r_msg, iterator, fail) + except (rpki.async.ExitNow, SystemExit): + raise + except Exception, e: + fail(e) + + def done(): + cb(r_msg) + + rpki.async.iterator(self, loop, done) + + +class sax_handler(rpki.xml_utils.sax_handler): + """ + SAX handler for publication control protocol. + """ + + pdu = msg + name = "msg" + version = "1" + + +class cms_msg(rpki.x509.XML_CMS_object): + """ + Class to hold a CMS-signed publication control PDU. + """ + + encoding = "us-ascii" + schema = rpki.relaxng.publication_control + saxify = sax_handler.saxify diff --git a/rpki/relaxng.py b/rpki/relaxng.py index 07d7e05b..30a0824d 100644 --- a/rpki/relaxng.py +++ b/rpki/relaxng.py @@ -1478,9 +1478,9 @@ myrpki = lxml.etree.RelaxNG(lxml.etree.fromstring(r'''<?xml version="1.0" encodi --> ''')) -## @var publication -## Parsed RelaxNG publication schema -publication = lxml.etree.RelaxNG(lxml.etree.fromstring(r'''<?xml version="1.0" encoding="UTF-8"?> +## @var publication_control +## Parsed RelaxNG publication_control schema +publication_control = lxml.etree.RelaxNG(lxml.etree.fromstring(r'''<?xml version="1.0" encoding="UTF-8"?> <!-- $Id: publication-schema.rnc 5876 2014-06-26 19:00:12Z sra $ @@ -1503,7 +1503,7 @@ publication = lxml.etree.RelaxNG(lxml.etree.fromstring(r'''<?xml version="1.0" e NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --> -<grammar ns="http://www.hactrn.net/uris/rpki/publication-spec/" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> +<grammar ns="http://www.hactrn.net/uris/rpki/publication-control/" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <!-- Top level PDU --> <start> <element name="msg"> @@ -1537,11 +1537,6 @@ publication = lxml.etree.RelaxNG(lxml.etree.fromstring(r'''<?xml version="1.0" e <choice> <ref name="config_query"/> <ref name="client_query"/> - <ref name="certificate_query"/> - <ref name="crl_query"/> - <ref name="manifest_query"/> - <ref name="roa_query"/> - <ref name="ghostbuster_query"/> </choice> </define> <!-- PDUs allowed in a reply --> @@ -1549,11 +1544,6 @@ publication = lxml.etree.RelaxNG(lxml.etree.fromstring(r'''<?xml version="1.0" e <choice> <ref name="config_reply"/> <ref name="client_reply"/> - <ref name="certificate_reply"/> - <ref name="crl_reply"/> - <ref name="manifest_reply"/> - <ref name="roa_reply"/> - <ref name="ghostbuster_reply"/> <ref name="report_error_reply"/> </choice> </define> @@ -1598,7 +1588,7 @@ publication = lxml.etree.RelaxNG(lxml.etree.fromstring(r'''<?xml version="1.0" e </data> </define> <!-- - <config/> element (use restricted to repository operator) + <config/> element config_handle attribute, create, list, and destroy commands omitted deliberately, see code for details --> <define name="config_payload"> @@ -1650,7 +1640,7 @@ publication = lxml.etree.RelaxNG(lxml.etree.fromstring(r'''<?xml version="1.0" e <ref name="config_payload"/> </element> </define> - <!-- <client/> element (use restricted to repository operator) --> + <!-- <client/> element --> <define name="client_handle"> <attribute name="client_handle"> <ref name="object_handle"/> @@ -1795,196 +1785,152 @@ publication = lxml.etree.RelaxNG(lxml.etree.fromstring(r'''<?xml version="1.0" e <ref name="client_handle"/> </element> </define> - <!-- <certificate/> element --> - <define name="certificate_query" combine="choice"> - <element name="certificate"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - <ref name="base64"/> - </element> - </define> - <define name="certificate_reply" combine="choice"> - <element name="certificate"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <define name="certificate_query" combine="choice"> - <element name="certificate"> - <attribute name="action"> - <value>withdraw</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <define name="certificate_reply" combine="choice"> - <element name="certificate"> - <attribute name="action"> - <value>withdraw</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <!-- <crl/> element --> - <define name="crl_query" combine="choice"> - <element name="crl"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - <ref name="base64"/> - </element> - </define> - <define name="crl_reply" combine="choice"> - <element name="crl"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <define name="crl_query" combine="choice"> - <element name="crl"> - <attribute name="action"> - <value>withdraw</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> + <!-- <report_error/> element --> + <define name="error"> + <data type="token"> + <param name="maxLength">1024</param> + </data> </define> - <define name="crl_reply" combine="choice"> - <element name="crl"> - <attribute name="action"> - <value>withdraw</value> - </attribute> + <define name="report_error_reply"> + <element name="report_error"> <optional> <ref name="tag"/> </optional> - <ref name="uri"/> - </element> - </define> - <!-- <manifest/> element --> - <define name="manifest_query" combine="choice"> - <element name="manifest"> - <attribute name="action"> - <value>publish</value> + <attribute name="error_code"> + <ref name="error"/> </attribute> <optional> - <ref name="tag"/> + <data type="string"> + <param name="maxLength">512000</param> + </data> </optional> - <ref name="uri"/> - <ref name="base64"/> </element> </define> - <define name="manifest_reply" combine="choice"> - <element name="manifest"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> +</grammar> +<!-- + Local Variables: + indent-tabs-mode: nil + comment-start: "# " + comment-start-skip: "#[ \t]*" + End: +--> +''')) + +## @var publication +## Parsed RelaxNG publication schema +publication = lxml.etree.RelaxNG(lxml.etree.fromstring(r'''<?xml version="1.0" encoding="UTF-8"?> +<!-- + $Id: publication-schema.rnc 5876 2014-06-26 19:00:12Z sra $ + + RelaxNG schema for RPKI publication protocol, from current I-D. + + Copyright (c) 2014 IETF Trust and the persons identified as authors + of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of Internet Society, IETF or IETF Trust, nor the + names of specific contributors, may be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +--> +<grammar ns="http://www.hactrn.net/uris/rpki/publication-spec/" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> + <!-- This is version 3 of the protocol. --> + <define name="version"> + <value>3</value> </define> - <define name="manifest_query" combine="choice"> - <element name="manifest"> - <attribute name="action"> - <value>withdraw</value> + <!-- Top level PDU is either a query or a reply. --> + <start> + <element name="msg"> + <attribute name="version"> + <ref name="version"/> </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> + <choice> + <group> + <attribute name="type"> + <value>query</value> + </attribute> + <zeroOrMore> + <ref name="query_elt"/> + </zeroOrMore> + </group> + <group> + <attribute name="type"> + <value>reply</value> + </attribute> + <zeroOrMore> + <ref name="reply_elt"/> + </zeroOrMore> + </group> + </choice> </element> + </start> + <!-- PDUs allowed in queries and replies. --> + <define name="query_elt"> + <choice> + <ref name="publish_query"/> + <ref name="withdraw_query"/> + </choice> </define> - <define name="manifest_reply" combine="choice"> - <element name="manifest"> - <attribute name="action"> - <value>withdraw</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> + <define name="reply_elt"> + <choice> + <ref name="publish_reply"/> + <ref name="withdraw_reply"/> + <ref name="report_error_reply"/> + </choice> </define> - <!-- <roa/> element --> - <define name="roa_query" combine="choice"> - <element name="roa"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - <ref name="base64"/> - </element> + <!-- Tag attributes for bulk operations. --> + <define name="tag"> + <attribute name="tag"> + <data type="token"> + <param name="maxLength">1024</param> + </data> + </attribute> </define> - <define name="roa_reply" combine="choice"> - <element name="roa"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> + <!-- Base64 encoded DER stuff. --> + <define name="base64"> + <data type="base64Binary"/> </define> - <define name="roa_query" combine="choice"> - <element name="roa"> - <attribute name="action"> - <value>withdraw</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> + <!-- Publication URIs. --> + <define name="uri"> + <attribute name="uri"> + <data type="anyURI"> + <param name="maxLength">4096</param> + </data> + </attribute> </define> - <define name="roa_reply" combine="choice"> - <element name="roa"> - <attribute name="action"> - <value>withdraw</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> + <!-- Error codes. --> + <define name="error"> + <data type="token"> + <param name="maxLength">1024</param> + </data> </define> - <!-- <ghostbuster/> element --> - <define name="ghostbuster_query" combine="choice"> - <element name="ghostbuster"> - <attribute name="action"> - <value>publish</value> - </attribute> + <!-- <publish/> element --> + <define name="publish_query" combine="choice"> + <element name="publish"> <optional> <ref name="tag"/> </optional> @@ -1992,33 +1938,25 @@ publication = lxml.etree.RelaxNG(lxml.etree.fromstring(r'''<?xml version="1.0" e <ref name="base64"/> </element> </define> - <define name="ghostbuster_reply" combine="choice"> - <element name="ghostbuster"> - <attribute name="action"> - <value>publish</value> - </attribute> + <define name="publish_reply" combine="choice"> + <element name="publish"> <optional> <ref name="tag"/> </optional> <ref name="uri"/> </element> </define> - <define name="ghostbuster_query" combine="choice"> - <element name="ghostbuster"> - <attribute name="action"> - <value>withdraw</value> - </attribute> + <!-- <withdraw/> element --> + <define name="withdraw_query" combine="choice"> + <element name="withdraw"> <optional> <ref name="tag"/> </optional> <ref name="uri"/> </element> </define> - <define name="ghostbuster_reply" combine="choice"> - <element name="ghostbuster"> - <attribute name="action"> - <value>withdraw</value> - </attribute> + <define name="withdraw_reply" combine="choice"> + <element name="withdraw"> <optional> <ref name="tag"/> </optional> @@ -2026,11 +1964,6 @@ publication = lxml.etree.RelaxNG(lxml.etree.fromstring(r'''<?xml version="1.0" e </element> </define> <!-- <report_error/> element --> - <define name="error"> - <data type="token"> - <param name="maxLength">1024</param> - </data> - </define> <define name="report_error_reply"> <element name="report_error"> <optional> diff --git a/rpki/rpkid.py b/rpki/rpkid.py index 36ee2ea9..cb792572 100644 --- a/rpki/rpkid.py +++ b/rpki/rpkid.py @@ -933,8 +933,7 @@ class ca_detail_obj(rpki.sql.sql_persistent): repository = ca.parent.repository handler = False if allow_failure else None for child_cert in self.child_certs: - publisher.withdraw(cls = rpki.publication.certificate_elt, - uri = child_cert.uri, + publisher.withdraw(uri = child_cert.uri, obj = child_cert.cert, repository = repository, handler = handler) @@ -948,8 +947,7 @@ class ca_detail_obj(rpki.sql.sql_persistent): except AttributeError: latest_manifest = None if latest_manifest is not None: - publisher.withdraw(cls = rpki.publication.manifest_elt, - uri = self.manifest_uri, + publisher.withdraw(uri = self.manifest_uri, obj = self.latest_manifest, repository = repository, handler = handler) @@ -958,8 +956,7 @@ class ca_detail_obj(rpki.sql.sql_persistent): except AttributeError: latest_crl = None if latest_crl is not None: - publisher.withdraw(cls = rpki.publication.crl_elt, - uri = self.crl_uri, + publisher.withdraw(uri = self.crl_uri, obj = self.latest_crl, repository = repository, handler = handler) @@ -1188,7 +1185,6 @@ class ca_detail_obj(rpki.sql.sql_persistent): child_cert.published = rpki.sundial.now() child_cert.sql_store() publisher.publish( - cls = rpki.publication.certificate_elt, uri = child_cert.uri, obj = child_cert.cert, repository = ca.parent.repository, @@ -1232,7 +1228,6 @@ class ca_detail_obj(rpki.sql.sql_persistent): self.crl_published = rpki.sundial.now() self.sql_mark_dirty() publisher.publish( - cls = rpki.publication.crl_elt, uri = self.crl_uri, obj = self.latest_crl, repository = parent.repository, @@ -1290,8 +1285,7 @@ class ca_detail_obj(rpki.sql.sql_persistent): self.manifest_published = rpki.sundial.now() self.sql_mark_dirty() - publisher.publish(cls = rpki.publication.manifest_elt, - uri = uri, + publisher.publish(uri = uri, obj = self.latest_manifest, repository = parent.repository, handler = self.manifest_published_callback) @@ -1361,8 +1355,7 @@ class ca_detail_obj(rpki.sql.sql_persistent): self.crl_published is not None and \ self.crl_published < stale: logger.debug("Retrying publication for %s", self.crl_uri) - publisher.publish(cls = rpki.publication.crl_elt, - uri = self.crl_uri, + publisher.publish(uri = self.crl_uri, obj = self.latest_crl, repository = repository, handler = self.crl_published_callback) @@ -1371,8 +1364,7 @@ class ca_detail_obj(rpki.sql.sql_persistent): self.manifest_published is not None and \ self.manifest_published < stale: logger.debug("Retrying publication for %s", self.manifest_uri) - publisher.publish(cls = rpki.publication.manifest_elt, - uri = self.manifest_uri, + publisher.publish(uri = self.manifest_uri, obj = self.latest_manifest, repository = repository, handler = self.manifest_published_callback) @@ -1386,7 +1378,6 @@ class ca_detail_obj(rpki.sql.sql_persistent): for child_cert in self.unpublished_child_certs(stale): logger.debug("Retrying publication for %s", child_cert) publisher.publish( - cls = rpki.publication.certificate_elt, uri = child_cert.uri, obj = child_cert.cert, repository = repository, @@ -1395,7 +1386,6 @@ class ca_detail_obj(rpki.sql.sql_persistent): for roa in self.unpublished_roas(stale): logger.debug("Retrying publication for %s", roa) publisher.publish( - cls = rpki.publication.roa_elt, uri = roa.uri, obj = roa.roa, repository = repository, @@ -1404,7 +1394,6 @@ class ca_detail_obj(rpki.sql.sql_persistent): for ghostbuster in self.unpublished_ghostbusters(stale): logger.debug("Retrying publication for %s", ghostbuster) publisher.publish( - cls = rpki.publication.ghostbuster_elt, uri = ghostbuster.uri, obj = ghostbuster.ghostbuster, repository = repository, @@ -1492,7 +1481,6 @@ class child_cert_obj(rpki.sql.sql_persistent): logger.debug("Revoking %r %r", self, self.uri) revoked_cert_obj.revoke(cert = self.cert, ca_detail = ca_detail) publisher.withdraw( - cls = rpki.publication.certificate_elt, uri = self.uri, obj = self.cert, repository = ca.parent.repository) @@ -1895,7 +1883,6 @@ class roa_obj(rpki.sql.sql_persistent): logger.debug("Generating %r URI %s", self, self.uri) publisher.publish( - cls = rpki.publication.roa_elt, uri = self.uri, obj = self.roa, repository = ca.parent.repository, @@ -1942,7 +1929,8 @@ class roa_obj(rpki.sql.sql_persistent): logger.debug("Withdrawing %r %s and revoking its EE cert", self, uri) rpki.rpkid.revoked_cert_obj.revoke(cert = cert, ca_detail = ca_detail) - publisher.withdraw(cls = rpki.publication.roa_elt, uri = uri, obj = roa, + publisher.withdraw(uri = uri, + obj = roa, repository = ca_detail.ca.parent.repository, handler = False if allow_failure else None) @@ -2098,7 +2086,6 @@ class ghostbuster_obj(rpki.sql.sql_persistent): logger.debug("Generating Ghostbuster record %r", self.uri) publisher.publish( - cls = rpki.publication.ghostbuster_elt, uri = self.uri, obj = self.ghostbuster, repository = ca.parent.repository, @@ -2144,7 +2131,8 @@ class ghostbuster_obj(rpki.sql.sql_persistent): logger.debug("Withdrawing %r %s and revoking its EE cert", self, uri) rpki.rpkid.revoked_cert_obj.revoke(cert = cert, ca_detail = ca_detail) - publisher.withdraw(cls = rpki.publication.ghostbuster_elt, uri = uri, obj = ghostbuster, + publisher.withdraw(uri = uri, + obj = ghostbuster, repository = ca_detail.ca.parent.repository, handler = False if allow_failure else None) @@ -2293,7 +2281,6 @@ class ee_cert_obj(rpki.sql.sql_persistent): cert = cert) publisher.publish( - cls = rpki.publication.certificate_elt, uri = self.uri, obj = self.cert, repository = ca.parent.repository, @@ -2316,8 +2303,7 @@ class ee_cert_obj(rpki.sql.sql_persistent): ca = ca_detail.ca logger.debug("Revoking %r %r", self, self.uri) revoked_cert_obj.revoke(cert = self.cert, ca_detail = ca_detail) - publisher.withdraw(cls = rpki.publication.certificate_elt, - uri = self.uri, + publisher.withdraw(uri = self.uri, obj = self.cert, repository = ca.parent.repository) self.gctx.sql.sweep() @@ -2402,7 +2388,6 @@ class ee_cert_obj(rpki.sql.sql_persistent): self.sql_mark_dirty() publisher.publish( - cls = rpki.publication.certificate_elt, uri = self.uri, obj = self.cert, repository = ca_detail.ca.parent.repository, @@ -2457,8 +2442,7 @@ class publication_queue(object): self.repositories[rid] = repository self.msgs[rid] = rpki.publication.msg.query() if self.replace and uri in self.uris: - logger.debug("Removing publication duplicate <%s %r %r>", - self.uris[uri].action, self.uris[uri].uri, self.uris[uri].payload) + logger.debug("Removing publication duplicate %r", self.uris[uri]) self.msgs[rid].remove(self.uris.pop(uri)) pdu = make_pdu(uri = uri, obj = obj) if handler is not None: @@ -2468,11 +2452,11 @@ class publication_queue(object): if self.replace: self.uris[uri] = pdu - def publish(self, cls, uri, obj, repository, handler = None): - return self._add( uri, obj, repository, handler, cls.make_publish) + def publish(self, uri, obj, repository, handler = None): + return self._add(uri, obj, repository, handler, rpki.publication.publish_elt.make) - def withdraw(self, cls, uri, obj, repository, handler = None): - return self._add( uri, obj, repository, handler, cls.make_withdraw) + def withdraw(self, uri, obj, repository, handler = None): + return self._add(uri, obj, repository, handler, rpki.publication.withdraw_elt.make) def call_pubd(self, cb, eb): def loop(iterator, rid): diff --git a/rpki/rpkid_tasks.py b/rpki/rpkid_tasks.py index e0bb6904..49b5b968 100644 --- a/rpki/rpkid_tasks.py +++ b/rpki/rpkid_tasks.py @@ -309,7 +309,6 @@ class UpdateChildrenTask(AbstractTask): old_resources.valid_until, irdb_resources.valid_until) child_cert.sql_delete() self.publisher.withdraw( - cls = rpki.publication.certificate_elt, uri = child_cert.uri, obj = child_cert.cert, repository = ca.parent.repository) diff --git a/rpki/rtr/bgpdump.py b/rpki/rtr/bgpdump.py index fc3ae9df..5ffabc4d 100755 --- a/rpki/rtr/bgpdump.py +++ b/rpki/rtr/bgpdump.py @@ -295,7 +295,7 @@ def bgpdump_server_main(args): rpki.rtr.server.read_current = clock.read_current try: - server = rpki.rtr.server.ServerChannel(logger = logger) + server = rpki.rtr.server.ServerChannel(logger = logger, refresh = args.refresh, retry = args.retry, expire = args.expire) old_serial = server.get_serial() logger.debug("[Starting at serial %d (%s)]", old_serial, old_serial) while clock: diff --git a/rpki/sql_schemas.py b/rpki/sql_schemas.py index 07037970..2cd3bee7 100644 --- a/rpki/sql_schemas.py +++ b/rpki/sql_schemas.py @@ -4,33 +4,22 @@ ## SQL schema rpkid rpkid = '''-- $Id: rpkid.sql 5845 2014-05-29 22:31:15Z sra $ --- Copyright (C) 2009--2011 Internet Systems Consortium ("ISC") +-- Copyright (C) 2012--2014 Dragon Research Labs ("DRL") +-- Portions copyright (C) 2009--2011 Internet Systems Consortium ("ISC") +-- 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. +-- copyright notices 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. - --- 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. +-- THE SOFTWARE IS PROVIDED "AS IS" AND DRL, ISC, AND ARIN DISCLAIM ALL +-- WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +-- WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL, +-- ISC, OR 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. -- SQL objects needed by the RPKI engine (rpkid.py). @@ -258,39 +247,26 @@ CREATE TABLE ee_cert ( ## SQL schema pubd pubd = '''-- $Id: pubd.sql 5757 2014-04-05 22:42:12Z sra $ --- Copyright (C) 2009--2010 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. - --- Copyright (C) 2008 American Registry for Internet Numbers ("ARIN") +-- Copyright (C) 2012--2014 Dragon Research Labs ("DRL") +-- Portions copyright (C) 2009--2010 Internet Systems Consortium ("ISC") +-- Portions copyright (C) 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. +-- copyright notices 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. +-- THE SOFTWARE IS PROVIDED "AS IS" AND DRL, ISC, AND ARIN DISCLAIM ALL +-- WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +-- WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL, +-- ISC, OR 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. -- SQL objects needed by pubd.py. --- The config table is weird because we're really only using it --- to store one BPKI CRL, but putting this here lets us use a lot of --- existing machinery and the alternatives are whacky in other ways. +-- The config table is weird because it only has one row. DROP TABLE IF EXISTS client; DROP TABLE IF EXISTS config; diff --git a/rpki/up_down.py b/rpki/up_down.py index 262003a2..4c2604bf 100644 --- a/rpki/up_down.py +++ b/rpki/up_down.py @@ -208,7 +208,7 @@ class class_elt(base_elt): elt = self.make_elt("class", "class_name", "cert_url", "resource_set_as", "resource_set_ipv4", "resource_set_ipv6", "resource_set_notafter", "suggested_sia_head") - elt.extend([i.toXML() for i in self.certs]) + elt.extend(i.toXML() for i in self.certs) self.make_b64elt(elt, "issuer", self.issuer) return elt diff --git a/rpki/xml_utils.py b/rpki/xml_utils.py index e940d127..1574cd9e 100644 --- a/rpki/xml_utils.py +++ b/rpki/xml_utils.py @@ -460,7 +460,7 @@ class msg(list): Generate top-level PDU. """ elt = lxml.etree.Element("{%s}msg" % (self.xmlns), nsmap = self.nsmap, version = str(self.version), type = self.type) - elt.extend([i.toXML() for i in self]) + elt.extend(i.toXML() for i in self) return elt @classmethod diff --git a/schemas/relaxng/left-right-schema.rnc b/schemas/relaxng/left-right.rnc index 81c1e1e1..81c1e1e1 100644 --- a/schemas/relaxng/left-right-schema.rnc +++ b/schemas/relaxng/left-right.rnc diff --git a/schemas/relaxng/left-right-schema.rng b/schemas/relaxng/left-right.rng index 07ef52c7..07ef52c7 100644 --- a/schemas/relaxng/left-right-schema.rng +++ b/schemas/relaxng/left-right.rng diff --git a/schemas/relaxng/publication-schema.rnc b/schemas/relaxng/publication-control.rnc index 960922e0..520f6357 100644 --- a/schemas/relaxng/publication-schema.rnc +++ b/schemas/relaxng/publication-control.rnc @@ -19,7 +19,7 @@ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -default namespace = "http://www.hactrn.net/uris/rpki/publication-spec/" +default namespace = "http://www.hactrn.net/uris/rpki/publication-control/" # Top level PDU @@ -30,12 +30,10 @@ start = element msg { } # PDUs allowed in a query -query_elt = ( config_query | client_query | certificate_query | crl_query | - manifest_query | roa_query | ghostbuster_query ) +query_elt = ( config_query | client_query ) # PDUs allowed in a reply -reply_elt = ( config_reply | client_reply | certificate_reply | crl_reply | - manifest_reply | roa_reply | ghostbuster_reply | report_error_reply ) +reply_elt = ( config_reply | client_reply | report_error_reply ) # Tag attributes for bulk operations tag = attribute tag { xsd:token {maxLength="1024" } } @@ -56,7 +54,7 @@ uri = attribute uri { uri_t } # hierarchy delimiter. object_handle = xsd:string { maxLength="255" pattern="[\-_A-Za-z0-9/]+" } -# <config/> element (use restricted to repository operator) +# <config/> element # config_handle attribute, create, list, and destroy commands omitted deliberately, see code for details config_payload = (element bpki_crl { base64 }?) @@ -66,7 +64,7 @@ config_reply |= element config { attribute action { "set" }, tag? } config_query |= element config { attribute action { "get" }, tag? } config_reply |= element config { attribute action { "get" }, tag?, config_payload } -# <client/> element (use restricted to repository operator) +# <client/> element client_handle = attribute client_handle { object_handle } @@ -85,41 +83,6 @@ client_reply |= element client { attribute action { "list" }, tag?, client_ha client_query |= element client { attribute action { "destroy" }, tag?, client_handle } client_reply |= element client { attribute action { "destroy" }, tag?, client_handle } -# <certificate/> element - -certificate_query |= element certificate { attribute action { "publish" }, tag?, uri, base64 } -certificate_reply |= element certificate { attribute action { "publish" }, tag?, uri } -certificate_query |= element certificate { attribute action { "withdraw" }, tag?, uri } -certificate_reply |= element certificate { attribute action { "withdraw" }, tag?, uri } - -# <crl/> element - -crl_query |= element crl { attribute action { "publish" }, tag?, uri, base64 } -crl_reply |= element crl { attribute action { "publish" }, tag?, uri } -crl_query |= element crl { attribute action { "withdraw" }, tag?, uri } -crl_reply |= element crl { attribute action { "withdraw" }, tag?, uri } - -# <manifest/> element - -manifest_query |= element manifest { attribute action { "publish" }, tag?, uri, base64 } -manifest_reply |= element manifest { attribute action { "publish" }, tag?, uri } -manifest_query |= element manifest { attribute action { "withdraw" }, tag?, uri } -manifest_reply |= element manifest { attribute action { "withdraw" }, tag?, uri } - -# <roa/> element - -roa_query |= element roa { attribute action { "publish" }, tag?, uri, base64 } -roa_reply |= element roa { attribute action { "publish" }, tag?, uri } -roa_query |= element roa { attribute action { "withdraw" }, tag?, uri } -roa_reply |= element roa { attribute action { "withdraw" }, tag?, uri } - -# <ghostbuster/> element - -ghostbuster_query |= element ghostbuster { attribute action { "publish" }, tag?, uri, base64 } -ghostbuster_reply |= element ghostbuster { attribute action { "publish" }, tag?, uri } -ghostbuster_query |= element ghostbuster { attribute action { "withdraw" }, tag?, uri } -ghostbuster_reply |= element ghostbuster { attribute action { "withdraw" }, tag?, uri } - # <report_error/> element error = xsd:token { maxLength="1024" } diff --git a/schemas/relaxng/publication-schema.rng b/schemas/relaxng/publication-control.rng index aac61eae..318f3229 100644 --- a/schemas/relaxng/publication-schema.rng +++ b/schemas/relaxng/publication-control.rng @@ -21,7 +21,7 @@ NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. --> -<grammar ns="http://www.hactrn.net/uris/rpki/publication-spec/" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> +<grammar ns="http://www.hactrn.net/uris/rpki/publication-control/" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <!-- Top level PDU --> <start> <element name="msg"> @@ -55,11 +55,6 @@ <choice> <ref name="config_query"/> <ref name="client_query"/> - <ref name="certificate_query"/> - <ref name="crl_query"/> - <ref name="manifest_query"/> - <ref name="roa_query"/> - <ref name="ghostbuster_query"/> </choice> </define> <!-- PDUs allowed in a reply --> @@ -67,11 +62,6 @@ <choice> <ref name="config_reply"/> <ref name="client_reply"/> - <ref name="certificate_reply"/> - <ref name="crl_reply"/> - <ref name="manifest_reply"/> - <ref name="roa_reply"/> - <ref name="ghostbuster_reply"/> <ref name="report_error_reply"/> </choice> </define> @@ -116,7 +106,7 @@ </data> </define> <!-- - <config/> element (use restricted to repository operator) + <config/> element config_handle attribute, create, list, and destroy commands omitted deliberately, see code for details --> <define name="config_payload"> @@ -168,7 +158,7 @@ <ref name="config_payload"/> </element> </define> - <!-- <client/> element (use restricted to repository operator) --> + <!-- <client/> element --> <define name="client_handle"> <attribute name="client_handle"> <ref name="object_handle"/> @@ -313,236 +303,6 @@ <ref name="client_handle"/> </element> </define> - <!-- <certificate/> element --> - <define name="certificate_query" combine="choice"> - <element name="certificate"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - <ref name="base64"/> - </element> - </define> - <define name="certificate_reply" combine="choice"> - <element name="certificate"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <define name="certificate_query" combine="choice"> - <element name="certificate"> - <attribute name="action"> - <value>withdraw</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <define name="certificate_reply" combine="choice"> - <element name="certificate"> - <attribute name="action"> - <value>withdraw</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <!-- <crl/> element --> - <define name="crl_query" combine="choice"> - <element name="crl"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - <ref name="base64"/> - </element> - </define> - <define name="crl_reply" combine="choice"> - <element name="crl"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <define name="crl_query" combine="choice"> - <element name="crl"> - <attribute name="action"> - <value>withdraw</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <define name="crl_reply" combine="choice"> - <element name="crl"> - <attribute name="action"> - <value>withdraw</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <!-- <manifest/> element --> - <define name="manifest_query" combine="choice"> - <element name="manifest"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - <ref name="base64"/> - </element> - </define> - <define name="manifest_reply" combine="choice"> - <element name="manifest"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <define name="manifest_query" combine="choice"> - <element name="manifest"> - <attribute name="action"> - <value>withdraw</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <define name="manifest_reply" combine="choice"> - <element name="manifest"> - <attribute name="action"> - <value>withdraw</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <!-- <roa/> element --> - <define name="roa_query" combine="choice"> - <element name="roa"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - <ref name="base64"/> - </element> - </define> - <define name="roa_reply" combine="choice"> - <element name="roa"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <define name="roa_query" combine="choice"> - <element name="roa"> - <attribute name="action"> - <value>withdraw</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <define name="roa_reply" combine="choice"> - <element name="roa"> - <attribute name="action"> - <value>withdraw</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <!-- <ghostbuster/> element --> - <define name="ghostbuster_query" combine="choice"> - <element name="ghostbuster"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - <ref name="base64"/> - </element> - </define> - <define name="ghostbuster_reply" combine="choice"> - <element name="ghostbuster"> - <attribute name="action"> - <value>publish</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <define name="ghostbuster_query" combine="choice"> - <element name="ghostbuster"> - <attribute name="action"> - <value>withdraw</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> - <define name="ghostbuster_reply" combine="choice"> - <element name="ghostbuster"> - <attribute name="action"> - <value>withdraw</value> - </attribute> - <optional> - <ref name="tag"/> - </optional> - <ref name="uri"/> - </element> - </define> <!-- <report_error/> element --> <define name="error"> <data type="token"> diff --git a/schemas/relaxng/publication.rnc b/schemas/relaxng/publication.rnc new file mode 100644 index 00000000..3a519543 --- /dev/null +++ b/schemas/relaxng/publication.rnc @@ -0,0 +1,96 @@ +# $Id$ +# +# RelaxNG schema for RPKI publication protocol, from current I-D. +# +# Copyright (c) 2014 IETF Trust and the persons identified as authors +# of the code. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# * Neither the name of Internet Society, IETF or IETF Trust, nor the +# names of specific contributors, may be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +default namespace = + "http://www.hactrn.net/uris/rpki/publication-spec/" + +# This is version 3 of the protocol. + +version = "3" + +# Top level PDU is either a query or a reply. + +start = element msg { + attribute version { version } , + ( ( attribute type { "query" }, query_elt* ) | + ( attribute type { "reply" }, reply_elt* ) ) +} + +# PDUs allowed in queries and replies. + +query_elt = publish_query | withdraw_query +reply_elt = publish_reply | withdraw_reply | report_error_reply + +# Tag attributes for bulk operations. + +tag = attribute tag { xsd:token { maxLength="1024" } } + +# Base64 encoded DER stuff. + +base64 = xsd:base64Binary + +# Publication URIs. + +uri = attribute uri { xsd:anyURI { maxLength="4096" } } + +# Error codes. + +error = xsd:token { maxLength="1024" } + +# <publish/> element + +publish_query |= element publish { tag?, uri, base64 } +publish_reply |= element publish { tag?, uri } + +# <withdraw/> element + +withdraw_query |= element withdraw { tag?, uri } +withdraw_reply |= element withdraw { tag?, uri } + +# <report_error/> element + +report_error_reply = element report_error { + tag?, + attribute error_code { error }, + xsd:string { maxLength="512000" }? +} + +# Local Variables: +# indent-tabs-mode: nil +# comment-start: "# " +# comment-start-skip: "#[ \t]*" +# End: diff --git a/schemas/relaxng/publication.rng b/schemas/relaxng/publication.rng new file mode 100644 index 00000000..7e2fe779 --- /dev/null +++ b/schemas/relaxng/publication.rng @@ -0,0 +1,169 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + $Id: publication-schema.rnc 5876 2014-06-26 19:00:12Z sra $ + + RelaxNG schema for RPKI publication protocol, from current I-D. + + Copyright (c) 2014 IETF Trust and the persons identified as authors + of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of Internet Society, IETF or IETF Trust, nor the + names of specific contributors, may be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +--> +<grammar ns="http://www.hactrn.net/uris/rpki/publication-spec/" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> + <!-- This is version 3 of the protocol. --> + <define name="version"> + <value>3</value> + </define> + <!-- Top level PDU is either a query or a reply. --> + <start> + <element name="msg"> + <attribute name="version"> + <ref name="version"/> + </attribute> + <choice> + <group> + <attribute name="type"> + <value>query</value> + </attribute> + <zeroOrMore> + <ref name="query_elt"/> + </zeroOrMore> + </group> + <group> + <attribute name="type"> + <value>reply</value> + </attribute> + <zeroOrMore> + <ref name="reply_elt"/> + </zeroOrMore> + </group> + </choice> + </element> + </start> + <!-- PDUs allowed in queries and replies. --> + <define name="query_elt"> + <choice> + <ref name="publish_query"/> + <ref name="withdraw_query"/> + </choice> + </define> + <define name="reply_elt"> + <choice> + <ref name="publish_reply"/> + <ref name="withdraw_reply"/> + <ref name="report_error_reply"/> + </choice> + </define> + <!-- Tag attributes for bulk operations. --> + <define name="tag"> + <attribute name="tag"> + <data type="token"> + <param name="maxLength">1024</param> + </data> + </attribute> + </define> + <!-- Base64 encoded DER stuff. --> + <define name="base64"> + <data type="base64Binary"/> + </define> + <!-- Publication URIs. --> + <define name="uri"> + <attribute name="uri"> + <data type="anyURI"> + <param name="maxLength">4096</param> + </data> + </attribute> + </define> + <!-- Error codes. --> + <define name="error"> + <data type="token"> + <param name="maxLength">1024</param> + </data> + </define> + <!-- <publish/> element --> + <define name="publish_query" combine="choice"> + <element name="publish"> + <optional> + <ref name="tag"/> + </optional> + <ref name="uri"/> + <ref name="base64"/> + </element> + </define> + <define name="publish_reply" combine="choice"> + <element name="publish"> + <optional> + <ref name="tag"/> + </optional> + <ref name="uri"/> + </element> + </define> + <!-- <withdraw/> element --> + <define name="withdraw_query" combine="choice"> + <element name="withdraw"> + <optional> + <ref name="tag"/> + </optional> + <ref name="uri"/> + </element> + </define> + <define name="withdraw_reply" combine="choice"> + <element name="withdraw"> + <optional> + <ref name="tag"/> + </optional> + <ref name="uri"/> + </element> + </define> + <!-- <report_error/> element --> + <define name="report_error_reply"> + <element name="report_error"> + <optional> + <ref name="tag"/> + </optional> + <attribute name="error_code"> + <ref name="error"/> + </attribute> + <optional> + <data type="string"> + <param name="maxLength">512000</param> + </data> + </optional> + </element> + </define> +</grammar> +<!-- + Local Variables: + indent-tabs-mode: nil + comment-start: "# " + comment-start-skip: "#[ \t]*" + End: +--> diff --git a/schemas/relaxng/router-certificate-schema.rnc b/schemas/relaxng/router-certificate.rnc index 8cc325ce..8cc325ce 100644 --- a/schemas/relaxng/router-certificate-schema.rnc +++ b/schemas/relaxng/router-certificate.rnc diff --git a/schemas/relaxng/router-certificate-schema.rng b/schemas/relaxng/router-certificate.rng index 7ba0dd60..7ba0dd60 100644 --- a/schemas/relaxng/router-certificate-schema.rng +++ b/schemas/relaxng/router-certificate.rng diff --git a/schemas/relaxng/up-down-schema.rnc b/schemas/relaxng/up-down.rnc index a603b8fe..a603b8fe 100644 --- a/schemas/relaxng/up-down-schema.rnc +++ b/schemas/relaxng/up-down.rnc diff --git a/schemas/relaxng/up-down-schema.rng b/schemas/relaxng/up-down.rng index ba1f20ca..ba1f20ca 100644 --- a/schemas/relaxng/up-down-schema.rng +++ b/schemas/relaxng/up-down.rng diff --git a/schemas/sql/pubd.sql b/schemas/sql/pubd.sql index 3a58ec00..d867706b 100644 --- a/schemas/sql/pubd.sql +++ b/schemas/sql/pubd.sql @@ -1,38 +1,25 @@ -- $Id$ --- Copyright (C) 2009--2010 Internet Systems Consortium ("ISC") +-- Copyright (C) 2012--2014 Dragon Research Labs ("DRL") +-- Portions copyright (C) 2009--2010 Internet Systems Consortium ("ISC") +-- Portions copyright (C) 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. +-- copyright notices 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. - --- Copyright (C) 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. +-- THE SOFTWARE IS PROVIDED "AS IS" AND DRL, ISC, AND ARIN DISCLAIM ALL +-- WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +-- WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL, +-- ISC, OR 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. -- SQL objects needed by pubd.py. --- The config table is weird because we're really only using it --- to store one BPKI CRL, but putting this here lets us use a lot of --- existing machinery and the alternatives are whacky in other ways. +-- The config table is weird because it only has one row. DROP TABLE IF EXISTS client; DROP TABLE IF EXISTS config; diff --git a/schemas/sql/rpkid.sql b/schemas/sql/rpkid.sql index ad0c39b0..f3b899ee 100644 --- a/schemas/sql/rpkid.sql +++ b/schemas/sql/rpkid.sql @@ -1,32 +1,21 @@ -- $Id$ --- Copyright (C) 2009--2011 Internet Systems Consortium ("ISC") +-- Copyright (C) 2012--2014 Dragon Research Labs ("DRL") +-- Portions copyright (C) 2009--2011 Internet Systems Consortium ("ISC") +-- 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. +-- copyright notices 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. - --- 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. +-- THE SOFTWARE IS PROVIDED "AS IS" AND DRL, ISC, AND ARIN DISCLAIM ALL +-- WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +-- WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL, +-- ISC, OR 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. -- SQL objects needed by the RPKI engine (rpkid.py). |