aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2014-07-03 16:55:02 +0000
committerRob Austein <sra@hactrn.net>2014-07-03 16:55:02 +0000
commitafb06330d3b3f6fdeb32012ee8626d88ba2ed381 (patch)
tree1978c18042358a7d73f7cf7f37aef359a4fb295d
parent1cab1084f94884a7a71f0a7cbca79d7772209c5c (diff)
Convert to current IETF I-D version of publication protocol. See #705.
svn path=/branches/tk705/; revision=5881
-rw-r--r--Makefile.in28
-rwxr-xr-xca/tests/bgpsec-yaml.py4
-rw-r--r--ca/tests/rrdp-samples.xml10
-rw-r--r--ca/tests/smoketest.py42
-rw-r--r--ca/tests/testpoke.py4
-rw-r--r--ca/tests/xml-parse-test.py34
-rw-r--r--rpki/irdb/zookeeper.py27
-rw-r--r--rpki/left_right.py14
-rw-r--r--rpki/pubd.py50
-rw-r--r--rpki/publication.py347
-rw-r--r--rpki/publication_control.py292
-rw-r--r--rpki/relaxng.py349
-rw-r--r--rpki/rpkid.py48
-rw-r--r--rpki/rpkid_tasks.py1
-rwxr-xr-xrpki/rtr/bgpdump.py2
-rw-r--r--rpki/sql_schemas.py74
-rw-r--r--rpki/up_down.py2
-rw-r--r--rpki/xml_utils.py2
-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.rnc96
-rw-r--r--schemas/relaxng/publication.rng169
-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.sql39
-rw-r--r--schemas/sql/rpkid.sql35
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).