aboutsummaryrefslogtreecommitdiff
path: root/ca
diff options
context:
space:
mode:
Diffstat (limited to 'ca')
-rwxr-xr-xca/irbe_cli80
-rw-r--r--ca/rpki-confgen.xml190
-rwxr-xr-xca/rpki-manage17
-rwxr-xr-xca/rpki-sql-backup2
-rwxr-xr-xca/rpki-sql-setup4
-rwxr-xr-xca/rpki-start-servers4
-rw-r--r--ca/rpki.wsgi3
-rwxr-xr-xca/rpkigui-apache-conf-gen64
-rw-r--r--ca/tests/Makefile.in41
-rw-r--r--ca/tests/publication-control-protocol-samples.xml155
-rw-r--r--ca/tests/publication-protocol-samples.xml451
-rw-r--r--ca/tests/rrdp-samples.xml88
-rw-r--r--ca/tests/smoketest.py395
-rw-r--r--ca/tests/sql-cleaner.py13
-rw-r--r--ca/tests/sql-dumper.py2
-rwxr-xr-xca/tests/test-rrdp.py121
-rw-r--r--ca/tests/testpoke.py4
-rw-r--r--ca/tests/xml-parse-test.py34
-rw-r--r--ca/tests/yamlconf.py35
-rw-r--r--ca/tests/yamltest.py298
20 files changed, 1152 insertions, 849 deletions
diff --git a/ca/irbe_cli b/ca/irbe_cli
index 1becd403..de907ca7 100755
--- a/ca/irbe_cli
+++ b/ca/irbe_cli
@@ -41,12 +41,11 @@ import sys
import getopt
import textwrap
import rpki.left_right
-import rpki.http
+import rpki.http_simple
import rpki.x509
import rpki.config
import rpki.log
import rpki.publication
-import rpki.async
pem_out = None
@@ -305,7 +304,7 @@ for o, a in opts:
if not argv:
usage(1)
-cfg = rpki.config.parser(cfg_file, "irbe_cli")
+cfg = rpki.config.parser(set_filename = cfg_file, section = "irbe_cli")
q_msg_left_right = []
q_msg_publication = []
@@ -322,19 +321,22 @@ while argv:
argv = q_pdu.client_getopt(argv[1:])
q_msg.append(q_pdu)
-from django.conf import settings
-
-settings.configure(
- DATABASES = { "default" : {
- "ENGINE" : "django.db.backends.mysql",
- "NAME" : cfg.get("sql-database", section = "irdbd"),
- "USER" : cfg.get("sql-username", section = "irdbd"),
- "PASSWORD" : cfg.get("sql-password", section = "irdbd"),
- "HOST" : "",
- "PORT" : "",
- "OPTIONS" : { "init_command": "SET storage_engine=INNODB" }}},
- INSTALLED_APPS = ("rpki.irdb",),
-)
+if True:
+ os.environ.update(DJANGO_SETTINGS_MODULE = "rpki.django_settings")
+
+else:
+ from django.conf import settings
+ settings.configure(
+ DATABASES = { "default" : {
+ "ENGINE" : "django.db.backends.mysql",
+ "NAME" : cfg.get("sql-database", section = "irdbd"),
+ "USER" : cfg.get("sql-username", section = "irdbd"),
+ "PASSWORD" : cfg.get("sql-password", section = "irdbd"),
+ "HOST" : "",
+ "PORT" : "",
+ "OPTIONS" : { "init_command": "SET storage_engine=INNODB" }}},
+ INSTALLED_APPS = ("rpki.irdb",),
+ )
import rpki.irdb
@@ -343,46 +345,36 @@ irbe = server_ca.ee_certificates.get(purpose = "irbe")
if q_msg_left_right:
- class left_right_proto(object):
- cms_msg = left_right_cms_msg
- msg = left_right_msg
-
rpkid = server_ca.ee_certificates.get(purpose = "rpkid")
rpkid_url = "http://%s:%s/left-right/" % (
cfg.get("server-host", section = "rpkid"),
cfg.get("server-port", section = "rpkid"))
- call_rpkid = rpki.async.sync_wrapper(rpki.http.caller(
- proto = left_right_proto,
- client_key = irbe.private_key,
- client_cert = irbe.certificate,
- server_ta = server_ca.certificate,
- server_cert = rpkid.certificate,
- url = rpkid_url,
- debug = verbose))
-
- call_rpkid(*q_msg_left_right)
+ rpki.http_simple.client(
+ proto_cms_msg = left_right_cms_msg,
+ client_key = irbe.private_key,
+ client_cert = irbe.certificate,
+ server_ta = server_ca.certificate,
+ server_cert = rpkid.certificate,
+ url = rpkid_url,
+ debug = verbose,
+ q_msg = left_right_msg(*q_msg_left_right))
if q_msg_publication:
- class publication_proto(object):
- msg = publication_msg
- cms_msg = publication_cms_msg
-
pubd = server_ca.ee_certificates.get(purpose = "pubd")
pubd_url = "http://%s:%s/control/" % (
cfg.get("server-host", section = "pubd"),
cfg.get("server-port", section = "pubd"))
- call_pubd = rpki.async.sync_wrapper(rpki.http.caller(
- proto = publication_proto,
- client_key = irbe.private_key,
- client_cert = irbe.certificate,
- server_ta = server_ca.certificate,
- server_cert = pubd.certificate,
- url = pubd_url,
- debug = verbose))
-
- call_pubd(*q_msg_publication)
+ rpki.http_simple.client(
+ proto_cms_msg = publication_cms_msg,
+ client_key = irbe.private_key,
+ client_cert = irbe.certificate,
+ server_ta = server_ca.certificate,
+ server_cert = pubd.certificate,
+ url = pubd_url,
+ debug = verbose,
+ q_msg = publication_msg(*q_msg_publication))
diff --git a/ca/rpki-confgen.xml b/ca/rpki-confgen.xml
index e0ed273a..b3e50823 100644
--- a/ca/rpki-confgen.xml
+++ b/ca/rpki-confgen.xml
@@ -186,17 +186,17 @@
</doc>
</option>
- <option name = "publication_root_cert_directory"
- value = "${myrpki::publication_base_directory}.root">
+ <option name = "rrdp_publication_base_directory"
+ value = "${autoconf::datarootdir}/rpki/rrdp-publication">
<doc>
- Root of local directory tree where rootd (sigh) should write out
- published data. This is just like publication_base_directory, but
- rootd is too dumb to use pubd and needs its own directory in
- which to write one certificate, one CRL, and one manifest.
- Neither rootd nor rsyncd much cares //where// you tell them to put
- this stuff, the important thing is that the rsync URIs in
- generated certificates match up with the published objects so that
- relying parties can find and verify rootd's published outputs.
+ Root of local directory tree where pubd should write out RRDP
+ files. You need to configure this, and the configuration
+ should match up with the directory where you point the web
+ server (usually Apache) that serves the RRDP files. Neither
+ pubd nor Apache much cares //where// you tell it to put this
+ stuff, the important thing is that all the URIs match up so
+ that relying parties can find and verify rpkid's published
+ outputs.
</doc>
</option>
@@ -209,15 +209,6 @@
</doc>
</option>
- <option name = "publication_root_module"
- value = "root">
- <doc>
- rsyncd module name corresponding to publication_root_cert_directory.
- This has to match the module you configured into `rsyncd.conf`.
- Leave this alone unless you have some need to change it.
- </doc>
- </option>
-
<option name = "publication_rsync_server"
value = "${myrpki::pubd_server_host}">
<doc>
@@ -577,6 +568,20 @@
</doc>
</option>
+ <option name = "rrdp-publication-base"
+ value = "${myrpki::rrdp_publication_base_directory}">
+ <doc>
+ Root of local directory tree where pubd should write out RRDP
+ files. You need to configure this, and the configuration
+ should match up with the directory where you point the web
+ server (usually Apache) that serves the RRDP files. Neither
+ pubd nor Apache much cares //where// you tell it to put this
+ stuff, the important thing is that all the URIs match up so
+ that relying parties can find and verify rpkid's published
+ outputs.
+ </doc>
+ </option>
+
<option name = "server-host"
value = "${myrpki::pubd_server_host}">
<doc>
@@ -618,6 +623,15 @@
</doc>
</option>
+ <option name = "pubd-crl"
+ value = "${myrpki::bpki_servers_directory}/ca.crl">
+ <doc>
+ Where pubd should look for the CRL covering its own BPKI EE
+ certificate. Don't change this unless you really know what
+ you are doing.
+ </doc>
+ </option>
+
<option name = "irbe-cert"
value = "${myrpki::bpki_servers_directory}/irbe.cer">
<doc>
@@ -638,10 +652,9 @@
</doc>
<doc>
- Ok, if that wasn't enough to scare you off: rootd is a mess, and
- needs to be rewritten, or, better, merged into rpkid. It
- doesn't use the publication protocol, and it requires far too
- many configuration parameters.
+ Ok, if that wasn't enough to scare you off: rootd is a mess,
+ needs to be rewritten, or, better, merged into rpkid, and
+ requires far too many configuration parameters.
</doc>
<doc>
@@ -712,6 +725,13 @@
</doc>
</option>
+ <option name = "pubd-bpki-cert">
+ <doc>
+ BPKI certificate for pubd. Don't set this unless you really
+ know what you are doing.
+ </doc>
+ </option>
+
<option name = "server-host"
value = "${myrpki::rootd_server_host}">
<doc>
@@ -726,72 +746,85 @@
</doc>
</option>
- <option name = "rpki-root-dir"
- value = "${myrpki::publication_base_directory}">
+ <option name = "rpki_data_dir"
+ value = "${myrpki::bpki_servers_directory}">
<doc>
- Where rootd should write its output. Yes, rootd should be using
- pubd instead of publishing directly, but it doesn't. This
- needs to match pubd's configuration.
+ Directory where rootd should store its RPKI data files. This
+ is only used to construct other variables, rootd itself
+ doesn't read it.
</doc>
</option>
- <option name = "rpki-base-uri"
- value = "rsync://${myrpki::publication_rsync_server}/${myrpki::publication_rsync_module}/">
+ <option name = "rpki_base_uri"
+ value = "rsync://${myrpki::publication_rsync_server}/${myrpki::publication_rsync_module}/${myrpki::handle}-root/root">
<doc>
- rsync URI corresponding to directory containing rootd's outputs.
+ rsync URI corresponding to directory containing rootd's
+ outputs. This is only used to construct other variables,
+ rootd itself doesn't read it.
</doc>
</option>
<option name = "rpki-root-cert-uri"
- value = "rsync://${myrpki::publication_rsync_server}/${myrpki::publication_root_module}/root.cer">
+ value = "${rootd::rpki_base_uri}.cer">
<doc>
rsync URI for rootd's root (self-signed) RPKI certificate.
</doc>
</option>
- <option name = "rpki-root-key"
- value = "${myrpki::bpki_servers_directory}/root.key">
+ <option name = "rpki-root-cert-file"
+ value = "${rootd::rpki_data_dir}/root.cer">
+ <doc>
+ Filename of rootd's root RPKI certificate.
+ </doc>
+ </option>
+
+ <option name = "rpki-root-key-file"
+ value = "${rootd::rpki_data_dir}/root.key">
<doc>
Private key corresponding to rootd's root RPKI certificate.
</doc>
</option>
- <option name = "rpki-root-cert"
- value = "${myrpki::publication_root_cert_directory}/root.cer">
+ <option name = "rpki-root-crl-uri"
+ value = "${rootd::rpki_base_uri}/root.crl">
<doc>
- Filename (as opposed to rsync URI) of rootd's root RPKI
- certificate.
+ URI of the CRL for rootd's root RPKI certificate.
</doc>
</option>
- <option name = "rpki-subject-pkcs10"
- value = "${myrpki::bpki_servers_directory}/rootd.subject.pkcs10">
+ <option name = "rpki-root-crl-file"
+ value = "${rootd::rpki_data_dir}/root.crl">
<doc>
- Where rootd should stash a copy of the PKCS #10 request it gets
- from its one (and only) child
+ Filename of the CRL for rootd's root RPKI certificate.
</doc>
</option>
- <option name = "rpki-subject-lifetime"
- value = "30d">
+ <option name = "rpki-root-manifest-uri"
+ value = "${rootd::rpki_base_uri}/root.mft">
<doc>
- Lifetime of the one and only RPKI certificate rootd issues.
+ URI of the manifest for rootd's root RPKI certificate.
</doc>
</option>
- <option name = "rpki-root-crl"
- value = "root.crl">
+ <option name = "rpki-root-manifest-file"
+ value = "${rootd::rpki_data_dir}/root.mft">
<doc>
- Filename (relative to rootd-base-uri and rpki-root-dir) of the CRL
- for rootd's root RPKI certificate.
+ Filename of the manifest for rootd's root RPKI certificate.
</doc>
</option>
- <option name = "rpki-root-manifest"
- value = "root.mft">
+ <option name = "rpki-subject-pkcs10-file"
+ value = "${rootd::rpki_data_dir}/subject.pkcs10">
<doc>
- Filename (relative to rootd-base-uri and rpki-root-dir) of the
- manifest for rootd's root RPKI certificate.
+ Where rootd should stash a copy of the PKCS #10 request it gets
+ from its one (and only) child
+ </doc>
+ </option>
+
+ <option name = "rpki-subject-lifetime"
+ value = "30d">
+ <doc>
+ Lifetime of the one and only RPKI certificate rootd issues.
</doc>
</option>
@@ -803,43 +836,44 @@
</doc>
</option>
- <option name = "rpki-subject-cert"
- value = "${myrpki::handle}.cer">
+ <option name = "rpki-subject-cert-uri"
+ value = "${rootd::rpki_base_uri}/${myrpki::handle}.cer">
<doc>
- Filename (relative to rootd-base-uri and rpki-root-dir) of the one
- (and only) RPKI certificate rootd issues.
+ URI of the one (and only) RPKI certificate rootd issues.
</doc>
</option>
- </section>
-
- <section name = "web_portal">
-
- <doc>
- Glue to allow the Django application to pull user configuration
- from this file rather than directly editing settings.py.
- </doc>
-
- <option name = "sql-database"
- value = "${myrpki::irdbd_sql_database}">
+ <option name = "rpki-subject-cert-file"
+ value = "${rootd::rpki_data_dir}/${myrpki::handle}.cer">
<doc>
- SQL database name the web portal should use.
+ Filename of the one (and only) RPKI certificate rootd issues.
</doc>
</option>
- <option name = "sql-username"
- value = "${myrpki::irdbd_sql_username}">
+ <option name = "pubd-contact-uri"
+ value = "http://${myrpki::pubd_server_host}:${myrpki::pubd_server_port}/client/${myrpki::handle}-root">
<doc>
- SQL user name the web portal should use.
+ URI at which rootd should contact pubd for service.
</doc>
</option>
- <option name = "sql-password"
- value = "${myrpki::irdbd_sql_password}">
- <doc>
- SQL password the web portal should use.
- </doc>
- </option>
+ </section>
+
+ <section name = "web_portal">
+
+ <doc>
+ Glue to allow Django to pull user configuration from this file
+ rather than requiring the user to edit settings.py.
+ </doc>
+
+ <!--
+ We used to have SQL settings for the GUI here, but since
+ they're pretty much required to be identical to the ones for
+ irdbd at this point, the duplicate entries were just another
+ chance to misconfigure something, so I removed them. Not yet
+ sure whether this was the right approach. Too much historical
+ baggage in this file.
+ -->
<option name = "secret-key">
<doc>
diff --git a/ca/rpki-manage b/ca/rpki-manage
index 0d581ce9..db1e9ce3 100755
--- a/ca/rpki-manage
+++ b/ca/rpki-manage
@@ -5,9 +5,20 @@ from django.core.management import execute_from_command_line
# django-admin seems to have problems creating the superuser account when
# $LANG is unset or is set to something totally incompatible with UTF-8.
-if os.environ.get('LANG') in (None, "", "C"):
- os.environ['LANG'] = 'en_US.UTF-8'
-os.environ['DJANGO_SETTINGS_MODULE'] = 'rpki.gui.default_settings'
+if os.environ.get("LANG") in (None, "", "C"):
+ os.environ["LANG"] = "en_US.UTF-8"
+
+# Where to find the Django settings module
+
+os.environ.update(DJANGO_SETTINGS_MODULE = "rpki.django_settings")
+
+# We don't know whether we're being used to configure the GUI or not
+# (well, not without examining the specific command, which we'd like
+# to avoid). Default to enabling the GUI so that such commands will
+# work, but allow the user to override via the environment variable.
+
+if not os.environ.get("RPKI_GUI_ENABLE"):
+ os.environ["RPKI_GUI_ENABLE"] = "yes"
execute_from_command_line()
diff --git a/ca/rpki-sql-backup b/ca/rpki-sql-backup
index e60f9ae3..02835956 100755
--- a/ca/rpki-sql-backup
+++ b/ca/rpki-sql-backup
@@ -41,7 +41,7 @@ parser.add_argument("-o", "--output",
help = "destination for SQL dump (default: stdout)")
args = parser.parse_args()
-cfg = rpki.config.parser(args.config, "myrpki")
+cfg = rpki.config.parser(set_filename = args.config, section = "myrpki")
for name in ("rpkid", "irdbd", "pubd"):
if cfg.getboolean("start_" + name, False):
diff --git a/ca/rpki-sql-setup b/ca/rpki-sql-setup
index edc2c242..848e3d0f 100755
--- a/ca/rpki-sql-setup
+++ b/ca/rpki-sql-setup
@@ -54,7 +54,7 @@ class RootDB(object):
user = "root",
passwd = getpass.getpass("Please enter your MySQL root password: "))
else:
- mysql_cfg = rpki.config.parser(self.mysql_defaults, "client")
+ mysql_cfg = rpki.config.parser(set_filename = self.mysql_defaults, section = "client")
self.db = MySQLdb.connect(db = "mysql",
user = mysql_cfg.get("user"),
passwd = mysql_cfg.get("password"))
@@ -299,7 +299,7 @@ parser.set_defaults(dispatch = do_create_if_missing)
args = parser.parse_args()
try:
- cfg = rpki.config.parser(args.config, "myrpki")
+ cfg = rpki.config.parser(set_filename = args.config, section = "myrpki")
root = RootDB(args.mysql_defaults)
current_version = Version(rpki.version.VERSION)
for program_name in ("irdbd", "rpkid", "pubd"):
diff --git a/ca/rpki-start-servers b/ca/rpki-start-servers
index 8a745896..f1f70aa8 100755
--- a/ca/rpki-start-servers
+++ b/ca/rpki-start-servers
@@ -64,13 +64,13 @@ group.add_argument("--log-syslog", default = "daemon", nargs = "?",
help = "log syslog")
args = parser.parse_args()
-cfg = rpki.config.parser(args.config, "myrpki")
+cfg = rpki.config.parser(set_filename = args.config, section = "myrpki")
def run(name, old_flag = None):
if cfg.getboolean("start_" + name, cfg.getboolean("run_" + name if old_flag is None else old_flag, False)):
# pylint: disable=E1103
log_file = os.path.join(args.log_directory, name + ".log")
- cmd = (os.path.join(rpki.autoconf.libexecdir, name), "--config", cfg.filename, "--log-level", args.log_level)
+ cmd = (os.path.join(rpki.autoconf.libexecdir, name), "--log-level", args.log_level)
if args.log_file:
cmd += ("--log-file", log_file)
elif args.log_rotating_file_kbytes:
diff --git a/ca/rpki.wsgi b/ca/rpki.wsgi
index 72ba75ac..7fa85d73 100644
--- a/ca/rpki.wsgi
+++ b/ca/rpki.wsgi
@@ -21,7 +21,8 @@ import sys
import os
import rpki.autoconf
-os.environ['DJANGO_SETTINGS_MODULE'] = 'rpki.gui.default_settings'
+os.environ.update(DJANGO_SETTINGS_MODULE = "rpki.django_settings",
+ RPKI_GUI_ENABLE = "yes")
# Needed for local_settings.py
sys.path.insert(1, rpki.autoconf.sysconfdir + '/rpki')
diff --git a/ca/rpkigui-apache-conf-gen b/ca/rpkigui-apache-conf-gen
index f28bb7b3..1bd29e16 100755
--- a/ca/rpkigui-apache-conf-gen
+++ b/ca/rpkigui-apache-conf-gen
@@ -29,6 +29,50 @@ import rpki.autoconf
fqdn = socket.getfqdn()
vhost_template = """\
+
+#
+# Stuff that should be visible with both HTTP and HTTPS is (now)
+# outside the vhost block (see if this works properly...).
+#
+
+#
+# Allow access to the directory where rcynic-html writes
+# its output files.
+#
+<Directory %(RCYNIC_HTML_DIR)s>
+%(allow)s
+</Directory>
+
+#
+# Add alias pointing to rcynic-html's output files.
+#
+# If for some reason you need to change this, be careful to leave
+# the trailing slash off the URL, otherwise /rcynic will be
+# swallowed by the WSGIScriptAlias
+#
+Alias /rcynic %(RCYNIC_HTML_DIR)s/
+
+#
+# Allow access to the directory where pubd writes RRDP files.
+#
+<Directory %(datarootdir)s/rpki/rrdp-publication/>
+%(allow)s
+</Directory>
+
+#
+# Add alias pointing to pubd's RRD output files.
+#
+Alias /rrdp %(datarootdir)s/rpki/rrdp-publication/
+
+#
+# RRDP "notification" file needs a short expiration: this is
+# a critical part of how RRDP interacts with HTTP caching.
+#
+<LocationMatch ^/rrdp/updates[.]xml$>
+ ExpiresActive on
+ ExpiresDefault "access plus 5 minutes"
+</LocationMatch>
+
#
# By default, this configuration assumes that you use name-based
# virtual hosting. If that's not what you want, you may need
@@ -78,23 +122,6 @@ vhost_template = """\
Alias /site_media/ %(datarootdir)s/rpki/media/
#
- # Allow access to the directory where rcynic-html writes
- # its output files.
- #
- <Directory %(RCYNIC_HTML_DIR)s>
-%(allow)s
- </Directory>
-
- #
- # Add alias pointing to rcynic-html's output files.
- #
- # If for some reason you need to change this, be careful to leave
- # the trailing slash off the URL, otherwise /rcynic will be
- # swallowed by the WSGIScriptAlias
- #
- Alias /rcynic %(RCYNIC_HTML_DIR)s/
-
- #
# Redirect to the GUI dashboard when someone hits the bare vhost.
#
RedirectMatch ^/$ /rpki/
@@ -102,7 +129,7 @@ vhost_template = """\
#
# Enable HTTPS
#
- SSLEngine on
+ SSLEngine on
#
# Specify HTTPS server certificate and key files for this virtual host.
@@ -402,6 +429,7 @@ class Debian(Platform):
def enable(self):
self.run("a2enmod", "ssl")
+ self.run("a2enmod", "expires")
self.run("a2ensite", "rpki")
#
# In light of BREACH and CRIME attacks, mod_deflate is looking
diff --git a/ca/tests/Makefile.in b/ca/tests/Makefile.in
index 9796dd2b..618a741e 100644
--- a/ca/tests/Makefile.in
+++ b/ca/tests/Makefile.in
@@ -3,12 +3,11 @@
PYTHON = @PYTHON@
abs_top_builddir = @abs_top_builddir@
-all: protocol-samples
+all:
+ @true
clean:
- rm -rf smoketest.dir left-right-protocol-samples publication-protocol-samples yamltest.dir rcynic.xml rcynic-data
-
-protocol-samples: left-right-protocol-samples/.stamp publication-protocol-samples/.stamp
+ rm -rf smoketest.dir left-right-protocol-samples publication-protocol-samples publication-control-protocol-samples rrdp-samples yamltest.dir rcynic.xml rcynic-data
left-right-protocol-samples/.stamp: left-right-protocol-samples.xml split-protocol-samples.xsl
rm -rf left-right-protocol-samples
@@ -16,20 +15,44 @@ left-right-protocol-samples/.stamp: left-right-protocol-samples.xml split-protoc
xsltproc --param verbose 0 --stringparam dir left-right-protocol-samples split-protocol-samples.xsl left-right-protocol-samples.xml
touch $@
+left-right-relaxng: left-right-protocol-samples/.stamp
+ xmllint --noout --relaxng ../../schemas/relaxng/left-right.rng left-right-protocol-samples/*.xml
+
publication-protocol-samples/.stamp: publication-protocol-samples.xml split-protocol-samples.xsl
rm -rf publication-protocol-samples
mkdir publication-protocol-samples
xsltproc --param verbose 0 --stringparam dir publication-protocol-samples split-protocol-samples.xsl publication-protocol-samples.xml
touch $@
-relaxng: protocol-samples
- xmllint --noout --relaxng ../../schemas/relaxng/left-right-schema.rng left-right-protocol-samples/*.xml
- xmllint --noout --relaxng ../../schemas/relaxng/up-down-schema.rng up-down-protocol-samples/*.xml
- xmllint --noout --relaxng ../../schemas/relaxng/publication-schema.rng publication-protocol-samples/*.xml
+publication-relaxng: publication-protocol-samples/.stamp
+ xmllint --noout --relaxng ../../schemas/relaxng/publication.rng publication-protocol-samples/*.xml
+
+publication-control-protocol-samples/.stamp: publication-control-protocol-samples.xml split-protocol-samples.xsl
+ rm -rf publication-control-protocol-samples
+ mkdir publication-control-protocol-samples
+ xsltproc --param verbose 0 --stringparam dir publication-control-protocol-samples split-protocol-samples.xsl publication-control-protocol-samples.xml
+ touch $@
+
+publication-control-relaxng: publication-control-protocol-samples/.stamp
+ xmllint --noout --relaxng ../../schemas/relaxng/publication-control.rng publication-control-protocol-samples/*.xml
+
+rrdp-samples/.stamp: rrdp-samples.xml split-protocol-samples.xsl
+ rm -rf rrdp-samples
+ mkdir rrdp-samples
+ xsltproc --param verbose 0 --stringparam dir rrdp-samples split-protocol-samples.xsl rrdp-samples.xml
+ touch $@
+
+rrdp-relaxng: rrdp-samples/.stamp
+ xmllint --noout --relaxng ../../schemas/relaxng/rrdp.rng rrdp-samples/*.xml
+
+up-down-relaxng:
+ xmllint --noout --relaxng ../../schemas/relaxng/up-down.rng up-down-protocol-samples/*.xml
+
+relaxng: up-down-relaxng left-right-relaxng publication-relaxng publication-control-relaxng rrdp-relaxng
all-tests:: relaxng
-parse-test: protocol-samples
+parse-test: left-right-protocol-samples publication-protocol-samples publication-control-protocol-samples
${PYTHON} xml-parse-test.py
all-tests:: parse-test
diff --git a/ca/tests/publication-control-protocol-samples.xml b/ca/tests/publication-control-protocol-samples.xml
new file mode 100644
index 00000000..e094f3f6
--- /dev/null
+++ b/ca/tests/publication-control-protocol-samples.xml
@@ -0,0 +1,155 @@
+<!-- -*- SGML -*-
+ - $Id$
+ -
+ - 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.
+ -
+ -
+ - This is a collection of sample publication protocol PDU samples
+ - to use as test cases for the publication protocol RelaxNG schema.
+ -->
+
+<completely_gratuitous_wrapper_element_to_let_me_run_this_through_xmllint>
+
+ <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-control/">
+ <client action="create" client_handle="3" base_uri="rsync://wombat.invalid/">
+ <bpki_cert>
+ MIIDGzCCAgOgAwIBAgIJAKi+/+wUhQlxMA0GCSqGSIb3DQEBBQUAMCQxIjAgBgNV
+ BAMTGVRlc3QgQ2VydGlmaWNhdGUgQm9iIFJvb3QwHhcNMDcwODAxMTk1MzEwWhcN
+ MDcwODMxMTk1MzEwWjAkMSIwIAYDVQQDExlUZXN0IENlcnRpZmljYXRlIEJvYiBS
+ b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArKYUtJaM5PH5917S
+ G2ACc7iBYdQO2HYyu8Gb6i9Q2Gxc3cWEX7RTBvgOL79pWf3GIdnoupzMnoZVtY3G
+ Ux2G/0WkmLui2TCeDhcfXdQ4rcp8J3V/6ESj+yuEPPOG8UN17mUKKgujrch6ZvgC
+ DO9AyOK/uXu+ABQXTPsn2pVe2EVh3V004ShLi8GKgVdqb/rW/6GTg0Xb/zLT6WWM
+ uT++6sXTlztJdQYkRamJvKfQDU1naC8mAkGf79Tba0xyBGAUII0GfREY6t4/+NAP
+ 2Yyb3xNlBqcJoTov0JfNKHZcCZePr79j7LK/hkZxxip+Na9xDpE+oQRV+DRukCRJ
+ diqg+wIDAQABo1AwTjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBTDEsXJe6pjAQD4
+ ULlB7+GMDBlimTAfBgNVHSMEGDAWgBTDEsXJe6pjAQD4ULlB7+GMDBlimTANBgkq
+ hkiG9w0BAQUFAAOCAQEAWWkNcW6S1tKKqtzJsdfhjJiAAPQmOXJskv0ta/8f6Acg
+ cum1YieNdtT0n96P7CUHOWP8QBb91JzeewR7b6WJLwb1Offs3wNq3kk75pJe89r4
+ XY39EZHhMW+Dv0PhIKu2CgD4LeyH1FVTQkF/QObGEmkn+s+HTsuzd1l2VLwcP1Sm
+ sqep6LAlFj62qqaIJzNeQ9NVkBqtkygnYlBOkaBTHfQTux3jYNpEo8JJB5e/WFdH
+ YyMNrG2xMOtIC7T4+IOHgT8PgrNhaeDg9ctewj0X8Qi9nI9nXeinicLX8vj6hdEq
+ 3ORv7RZMJNYqv1HQ3wUE2B7fCPFv7EUwzaCds1kgRQ==
+ </bpki_cert>
+ </client>
+ </msg>
+
+ <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-control/">
+ <client action="create" client_handle="3"/>
+ </msg>
+
+ <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-control/">
+ <client action="set" client_handle="3">
+ <bpki_glue>
+ MIIDGzCCAgOgAwIBAgIJAKi+/+wUhQlxMA0GCSqGSIb3DQEBBQUAMCQxIjAgBgNV
+ BAMTGVRlc3QgQ2VydGlmaWNhdGUgQm9iIFJvb3QwHhcNMDcwODAxMTk1MzEwWhcN
+ MDcwODMxMTk1MzEwWjAkMSIwIAYDVQQDExlUZXN0IENlcnRpZmljYXRlIEJvYiBS
+ b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArKYUtJaM5PH5917S
+ G2ACc7iBYdQO2HYyu8Gb6i9Q2Gxc3cWEX7RTBvgOL79pWf3GIdnoupzMnoZVtY3G
+ Ux2G/0WkmLui2TCeDhcfXdQ4rcp8J3V/6ESj+yuEPPOG8UN17mUKKgujrch6ZvgC
+ DO9AyOK/uXu+ABQXTPsn2pVe2EVh3V004ShLi8GKgVdqb/rW/6GTg0Xb/zLT6WWM
+ uT++6sXTlztJdQYkRamJvKfQDU1naC8mAkGf79Tba0xyBGAUII0GfREY6t4/+NAP
+ 2Yyb3xNlBqcJoTov0JfNKHZcCZePr79j7LK/hkZxxip+Na9xDpE+oQRV+DRukCRJ
+ diqg+wIDAQABo1AwTjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBTDEsXJe6pjAQD4
+ ULlB7+GMDBlimTAfBgNVHSMEGDAWgBTDEsXJe6pjAQD4ULlB7+GMDBlimTANBgkq
+ hkiG9w0BAQUFAAOCAQEAWWkNcW6S1tKKqtzJsdfhjJiAAPQmOXJskv0ta/8f6Acg
+ cum1YieNdtT0n96P7CUHOWP8QBb91JzeewR7b6WJLwb1Offs3wNq3kk75pJe89r4
+ XY39EZHhMW+Dv0PhIKu2CgD4LeyH1FVTQkF/QObGEmkn+s+HTsuzd1l2VLwcP1Sm
+ sqep6LAlFj62qqaIJzNeQ9NVkBqtkygnYlBOkaBTHfQTux3jYNpEo8JJB5e/WFdH
+ YyMNrG2xMOtIC7T4+IOHgT8PgrNhaeDg9ctewj0X8Qi9nI9nXeinicLX8vj6hdEq
+ 3ORv7RZMJNYqv1HQ3wUE2B7fCPFv7EUwzaCds1kgRQ==
+ </bpki_glue>
+ </client>
+ </msg>
+
+ <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-control/">
+ <client action="set" client_handle="3"/>
+ </msg>
+
+ <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-control/">
+ <client action="get" client_handle="3"/>
+ </msg>
+
+ <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-control/">
+ <client action="get" client_handle="3" base_uri="rsync://wombat.invalid/">
+ <bpki_cert>
+ MIIDGzCCAgOgAwIBAgIJAKi+/+wUhQlxMA0GCSqGSIb3DQEBBQUAMCQxIjAgBgNV
+ BAMTGVRlc3QgQ2VydGlmaWNhdGUgQm9iIFJvb3QwHhcNMDcwODAxMTk1MzEwWhcN
+ MDcwODMxMTk1MzEwWjAkMSIwIAYDVQQDExlUZXN0IENlcnRpZmljYXRlIEJvYiBS
+ b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArKYUtJaM5PH5917S
+ G2ACc7iBYdQO2HYyu8Gb6i9Q2Gxc3cWEX7RTBvgOL79pWf3GIdnoupzMnoZVtY3G
+ Ux2G/0WkmLui2TCeDhcfXdQ4rcp8J3V/6ESj+yuEPPOG8UN17mUKKgujrch6ZvgC
+ DO9AyOK/uXu+ABQXTPsn2pVe2EVh3V004ShLi8GKgVdqb/rW/6GTg0Xb/zLT6WWM
+ uT++6sXTlztJdQYkRamJvKfQDU1naC8mAkGf79Tba0xyBGAUII0GfREY6t4/+NAP
+ 2Yyb3xNlBqcJoTov0JfNKHZcCZePr79j7LK/hkZxxip+Na9xDpE+oQRV+DRukCRJ
+ diqg+wIDAQABo1AwTjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBTDEsXJe6pjAQD4
+ ULlB7+GMDBlimTAfBgNVHSMEGDAWgBTDEsXJe6pjAQD4ULlB7+GMDBlimTANBgkq
+ hkiG9w0BAQUFAAOCAQEAWWkNcW6S1tKKqtzJsdfhjJiAAPQmOXJskv0ta/8f6Acg
+ cum1YieNdtT0n96P7CUHOWP8QBb91JzeewR7b6WJLwb1Offs3wNq3kk75pJe89r4
+ XY39EZHhMW+Dv0PhIKu2CgD4LeyH1FVTQkF/QObGEmkn+s+HTsuzd1l2VLwcP1Sm
+ sqep6LAlFj62qqaIJzNeQ9NVkBqtkygnYlBOkaBTHfQTux3jYNpEo8JJB5e/WFdH
+ YyMNrG2xMOtIC7T4+IOHgT8PgrNhaeDg9ctewj0X8Qi9nI9nXeinicLX8vj6hdEq
+ 3ORv7RZMJNYqv1HQ3wUE2B7fCPFv7EUwzaCds1kgRQ==
+ </bpki_cert>
+ </client>
+ </msg>
+
+ <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-control/">
+ <client action="list"/>
+ </msg>
+
+ <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-control/">
+ <client action="list" client_handle="3">
+ <bpki_cert>
+ MIIDGzCCAgOgAwIBAgIJAKi+/+wUhQlxMA0GCSqGSIb3DQEBBQUAMCQxIjAgBgNV
+ BAMTGVRlc3QgQ2VydGlmaWNhdGUgQm9iIFJvb3QwHhcNMDcwODAxMTk1MzEwWhcN
+ MDcwODMxMTk1MzEwWjAkMSIwIAYDVQQDExlUZXN0IENlcnRpZmljYXRlIEJvYiBS
+ b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArKYUtJaM5PH5917S
+ G2ACc7iBYdQO2HYyu8Gb6i9Q2Gxc3cWEX7RTBvgOL79pWf3GIdnoupzMnoZVtY3G
+ Ux2G/0WkmLui2TCeDhcfXdQ4rcp8J3V/6ESj+yuEPPOG8UN17mUKKgujrch6ZvgC
+ DO9AyOK/uXu+ABQXTPsn2pVe2EVh3V004ShLi8GKgVdqb/rW/6GTg0Xb/zLT6WWM
+ uT++6sXTlztJdQYkRamJvKfQDU1naC8mAkGf79Tba0xyBGAUII0GfREY6t4/+NAP
+ 2Yyb3xNlBqcJoTov0JfNKHZcCZePr79j7LK/hkZxxip+Na9xDpE+oQRV+DRukCRJ
+ diqg+wIDAQABo1AwTjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBTDEsXJe6pjAQD4
+ ULlB7+GMDBlimTAfBgNVHSMEGDAWgBTDEsXJe6pjAQD4ULlB7+GMDBlimTANBgkq
+ hkiG9w0BAQUFAAOCAQEAWWkNcW6S1tKKqtzJsdfhjJiAAPQmOXJskv0ta/8f6Acg
+ cum1YieNdtT0n96P7CUHOWP8QBb91JzeewR7b6WJLwb1Offs3wNq3kk75pJe89r4
+ XY39EZHhMW+Dv0PhIKu2CgD4LeyH1FVTQkF/QObGEmkn+s+HTsuzd1l2VLwcP1Sm
+ sqep6LAlFj62qqaIJzNeQ9NVkBqtkygnYlBOkaBTHfQTux3jYNpEo8JJB5e/WFdH
+ YyMNrG2xMOtIC7T4+IOHgT8PgrNhaeDg9ctewj0X8Qi9nI9nXeinicLX8vj6hdEq
+ 3ORv7RZMJNYqv1HQ3wUE2B7fCPFv7EUwzaCds1kgRQ==
+ </bpki_cert>
+ </client>
+ </msg>
+
+ <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-control/">
+ <client action="destroy" client_handle="3"/>
+ </msg>
+
+ <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-control/">
+ <client action="destroy" client_handle="3"/>
+ </msg>
+
+ <!-- === -->
+
+ <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-control/">
+ <report_error error_code="your_hair_is_on_fire">text string</report_error>
+ </msg>
+
+ <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-control/">
+ <report_error error_code="your_hair_is_on_fire"/>
+ </msg>
+
+</completely_gratuitous_wrapper_element_to_let_me_run_this_through_xmllint>
diff --git a/ca/tests/publication-protocol-samples.xml b/ca/tests/publication-protocol-samples.xml
index 96b095a7..6d0a99a9 100644
--- a/ca/tests/publication-protocol-samples.xml
+++ b/ca/tests/publication-protocol-samples.xml
@@ -1,370 +1,107 @@
<!-- -*- SGML -*-
- - $Id$
+ - $Id$
-
- - Copyright (C) 2008 American Registry for Internet Numbers ("ARIN")
+ - Sample PDUs for RPKI publication protocol, from current I-D.
-
- - 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 (c) 2014 IETF Trust and the persons identified as authors
+ - of the code. All rights reserved.
-
- - 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.
+ - 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.
-
- - This is a collection of sample publication protocol PDU samples
- - to use as test cases for the publication protocol RelaxNG schema.
+ - * 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.
-->
<completely_gratuitous_wrapper_element_to_let_me_run_this_through_xmllint>
- <msg xmlns="http://www.hactrn.net/uris/rpki/publication-spec/" type="query" version="1">
- <config action="set">
- <bpki_crl>
- MIIBezBlAgEBMA0GCSqGSIb3DQEBCwUAMCMxITAfBgNVBAMTGFRlc3QgQ2VydGlm
- aWNhdGUgcHViZCBUQRcNMDgwNjAyMjE0OTQ1WhcNMDgwNzAyMjE0OTQ1WqAOMAww
- CgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggEBAFWCWgBl4ljVqX/CHo+RpqYt
- vmKMnjPVflMXUB7i28RGP4DAq4l7deDU7Q82xEJyE4TXMWDWAV6UG6uUGum0VHWO
- cj9ohqyiZUGfOsKg2hbwkETm8sAENOsi1yNdyKGk6jZ16aF5fubxQqZa1pdGCSac
- 1/ZYC5sLLhEz3kmz+B9z9mXFVc5TgAh4dN3Gy5ftF8zZAFpDGnS4biCnRVqhGv6R
- 0Lh/5xmii+ZU6kNDhbeMsjJg+ZOmtN+wMeHSIbjiy0WuuaZ3k2xSh0C94anrHBZA
- vvCRhbazjR0Ef5OMZ5lcllw3uO8IHuoisHKkehy4Y0GySdj98fV+OuiRTH9vt/M=
- </bpki_crl>
- </config>
- </msg>
-
- <msg xmlns="http://www.hactrn.net/uris/rpki/publication-spec/" type="reply" version="1">
- <config action="set"/>
- </msg>
-
- <msg xmlns="http://www.hactrn.net/uris/rpki/publication-spec/" type="query" version="1">
- <config action="get"/>
- </msg>
-
- <msg xmlns="http://www.hactrn.net/uris/rpki/publication-spec/" type="reply" version="1">
- <config action="get">
- <bpki_crl>
- MIIBezBlAgEBMA0GCSqGSIb3DQEBCwUAMCMxITAfBgNVBAMTGFRlc3QgQ2VydGlm
- aWNhdGUgcHViZCBUQRcNMDgwNjAyMjE0OTQ1WhcNMDgwNzAyMjE0OTQ1WqAOMAww
- CgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggEBAFWCWgBl4ljVqX/CHo+RpqYt
- vmKMnjPVflMXUB7i28RGP4DAq4l7deDU7Q82xEJyE4TXMWDWAV6UG6uUGum0VHWO
- cj9ohqyiZUGfOsKg2hbwkETm8sAENOsi1yNdyKGk6jZ16aF5fubxQqZa1pdGCSac
- 1/ZYC5sLLhEz3kmz+B9z9mXFVc5TgAh4dN3Gy5ftF8zZAFpDGnS4biCnRVqhGv6R
- 0Lh/5xmii+ZU6kNDhbeMsjJg+ZOmtN+wMeHSIbjiy0WuuaZ3k2xSh0C94anrHBZA
- vvCRhbazjR0Ef5OMZ5lcllw3uO8IHuoisHKkehy4Y0GySdj98fV+OuiRTH9vt/M=
- </bpki_crl>
- </config>
- </msg>
-
- <!-- === -->
-
- <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <client action="create" client_handle="3" base_uri="rsync://wombat.invalid/">
- <bpki_cert>
- MIIDGzCCAgOgAwIBAgIJAKi+/+wUhQlxMA0GCSqGSIb3DQEBBQUAMCQxIjAgBgNV
- BAMTGVRlc3QgQ2VydGlmaWNhdGUgQm9iIFJvb3QwHhcNMDcwODAxMTk1MzEwWhcN
- MDcwODMxMTk1MzEwWjAkMSIwIAYDVQQDExlUZXN0IENlcnRpZmljYXRlIEJvYiBS
- b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArKYUtJaM5PH5917S
- G2ACc7iBYdQO2HYyu8Gb6i9Q2Gxc3cWEX7RTBvgOL79pWf3GIdnoupzMnoZVtY3G
- Ux2G/0WkmLui2TCeDhcfXdQ4rcp8J3V/6ESj+yuEPPOG8UN17mUKKgujrch6ZvgC
- DO9AyOK/uXu+ABQXTPsn2pVe2EVh3V004ShLi8GKgVdqb/rW/6GTg0Xb/zLT6WWM
- uT++6sXTlztJdQYkRamJvKfQDU1naC8mAkGf79Tba0xyBGAUII0GfREY6t4/+NAP
- 2Yyb3xNlBqcJoTov0JfNKHZcCZePr79j7LK/hkZxxip+Na9xDpE+oQRV+DRukCRJ
- diqg+wIDAQABo1AwTjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBTDEsXJe6pjAQD4
- ULlB7+GMDBlimTAfBgNVHSMEGDAWgBTDEsXJe6pjAQD4ULlB7+GMDBlimTANBgkq
- hkiG9w0BAQUFAAOCAQEAWWkNcW6S1tKKqtzJsdfhjJiAAPQmOXJskv0ta/8f6Acg
- cum1YieNdtT0n96P7CUHOWP8QBb91JzeewR7b6WJLwb1Offs3wNq3kk75pJe89r4
- XY39EZHhMW+Dv0PhIKu2CgD4LeyH1FVTQkF/QObGEmkn+s+HTsuzd1l2VLwcP1Sm
- sqep6LAlFj62qqaIJzNeQ9NVkBqtkygnYlBOkaBTHfQTux3jYNpEo8JJB5e/WFdH
- YyMNrG2xMOtIC7T4+IOHgT8PgrNhaeDg9ctewj0X8Qi9nI9nXeinicLX8vj6hdEq
- 3ORv7RZMJNYqv1HQ3wUE2B7fCPFv7EUwzaCds1kgRQ==
- </bpki_cert>
- </client>
- </msg>
-
- <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <client action="create" client_handle="3"/>
- </msg>
-
- <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <client action="set" client_handle="3">
- <bpki_glue>
- MIIDGzCCAgOgAwIBAgIJAKi+/+wUhQlxMA0GCSqGSIb3DQEBBQUAMCQxIjAgBgNV
- BAMTGVRlc3QgQ2VydGlmaWNhdGUgQm9iIFJvb3QwHhcNMDcwODAxMTk1MzEwWhcN
- MDcwODMxMTk1MzEwWjAkMSIwIAYDVQQDExlUZXN0IENlcnRpZmljYXRlIEJvYiBS
- b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArKYUtJaM5PH5917S
- G2ACc7iBYdQO2HYyu8Gb6i9Q2Gxc3cWEX7RTBvgOL79pWf3GIdnoupzMnoZVtY3G
- Ux2G/0WkmLui2TCeDhcfXdQ4rcp8J3V/6ESj+yuEPPOG8UN17mUKKgujrch6ZvgC
- DO9AyOK/uXu+ABQXTPsn2pVe2EVh3V004ShLi8GKgVdqb/rW/6GTg0Xb/zLT6WWM
- uT++6sXTlztJdQYkRamJvKfQDU1naC8mAkGf79Tba0xyBGAUII0GfREY6t4/+NAP
- 2Yyb3xNlBqcJoTov0JfNKHZcCZePr79j7LK/hkZxxip+Na9xDpE+oQRV+DRukCRJ
- diqg+wIDAQABo1AwTjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBTDEsXJe6pjAQD4
- ULlB7+GMDBlimTAfBgNVHSMEGDAWgBTDEsXJe6pjAQD4ULlB7+GMDBlimTANBgkq
- hkiG9w0BAQUFAAOCAQEAWWkNcW6S1tKKqtzJsdfhjJiAAPQmOXJskv0ta/8f6Acg
- cum1YieNdtT0n96P7CUHOWP8QBb91JzeewR7b6WJLwb1Offs3wNq3kk75pJe89r4
- XY39EZHhMW+Dv0PhIKu2CgD4LeyH1FVTQkF/QObGEmkn+s+HTsuzd1l2VLwcP1Sm
- sqep6LAlFj62qqaIJzNeQ9NVkBqtkygnYlBOkaBTHfQTux3jYNpEo8JJB5e/WFdH
- YyMNrG2xMOtIC7T4+IOHgT8PgrNhaeDg9ctewj0X8Qi9nI9nXeinicLX8vj6hdEq
- 3ORv7RZMJNYqv1HQ3wUE2B7fCPFv7EUwzaCds1kgRQ==
- </bpki_glue>
- </client>
- </msg>
-
- <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <client action="set" client_handle="3"/>
- </msg>
-
- <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <client action="get" client_handle="3"/>
- </msg>
-
- <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <client action="get" client_handle="3" base_uri="rsync://wombat.invalid/">
- <bpki_cert>
- MIIDGzCCAgOgAwIBAgIJAKi+/+wUhQlxMA0GCSqGSIb3DQEBBQUAMCQxIjAgBgNV
- BAMTGVRlc3QgQ2VydGlmaWNhdGUgQm9iIFJvb3QwHhcNMDcwODAxMTk1MzEwWhcN
- MDcwODMxMTk1MzEwWjAkMSIwIAYDVQQDExlUZXN0IENlcnRpZmljYXRlIEJvYiBS
- b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArKYUtJaM5PH5917S
- G2ACc7iBYdQO2HYyu8Gb6i9Q2Gxc3cWEX7RTBvgOL79pWf3GIdnoupzMnoZVtY3G
- Ux2G/0WkmLui2TCeDhcfXdQ4rcp8J3V/6ESj+yuEPPOG8UN17mUKKgujrch6ZvgC
- DO9AyOK/uXu+ABQXTPsn2pVe2EVh3V004ShLi8GKgVdqb/rW/6GTg0Xb/zLT6WWM
- uT++6sXTlztJdQYkRamJvKfQDU1naC8mAkGf79Tba0xyBGAUII0GfREY6t4/+NAP
- 2Yyb3xNlBqcJoTov0JfNKHZcCZePr79j7LK/hkZxxip+Na9xDpE+oQRV+DRukCRJ
- diqg+wIDAQABo1AwTjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBTDEsXJe6pjAQD4
- ULlB7+GMDBlimTAfBgNVHSMEGDAWgBTDEsXJe6pjAQD4ULlB7+GMDBlimTANBgkq
- hkiG9w0BAQUFAAOCAQEAWWkNcW6S1tKKqtzJsdfhjJiAAPQmOXJskv0ta/8f6Acg
- cum1YieNdtT0n96P7CUHOWP8QBb91JzeewR7b6WJLwb1Offs3wNq3kk75pJe89r4
- XY39EZHhMW+Dv0PhIKu2CgD4LeyH1FVTQkF/QObGEmkn+s+HTsuzd1l2VLwcP1Sm
- sqep6LAlFj62qqaIJzNeQ9NVkBqtkygnYlBOkaBTHfQTux3jYNpEo8JJB5e/WFdH
- YyMNrG2xMOtIC7T4+IOHgT8PgrNhaeDg9ctewj0X8Qi9nI9nXeinicLX8vj6hdEq
- 3ORv7RZMJNYqv1HQ3wUE2B7fCPFv7EUwzaCds1kgRQ==
- </bpki_cert>
- </client>
- </msg>
-
- <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <client action="list"/>
- </msg>
-
- <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <client action="list" client_handle="3">
- <bpki_cert>
- MIIDGzCCAgOgAwIBAgIJAKi+/+wUhQlxMA0GCSqGSIb3DQEBBQUAMCQxIjAgBgNV
- BAMTGVRlc3QgQ2VydGlmaWNhdGUgQm9iIFJvb3QwHhcNMDcwODAxMTk1MzEwWhcN
- MDcwODMxMTk1MzEwWjAkMSIwIAYDVQQDExlUZXN0IENlcnRpZmljYXRlIEJvYiBS
- b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArKYUtJaM5PH5917S
- G2ACc7iBYdQO2HYyu8Gb6i9Q2Gxc3cWEX7RTBvgOL79pWf3GIdnoupzMnoZVtY3G
- Ux2G/0WkmLui2TCeDhcfXdQ4rcp8J3V/6ESj+yuEPPOG8UN17mUKKgujrch6ZvgC
- DO9AyOK/uXu+ABQXTPsn2pVe2EVh3V004ShLi8GKgVdqb/rW/6GTg0Xb/zLT6WWM
- uT++6sXTlztJdQYkRamJvKfQDU1naC8mAkGf79Tba0xyBGAUII0GfREY6t4/+NAP
- 2Yyb3xNlBqcJoTov0JfNKHZcCZePr79j7LK/hkZxxip+Na9xDpE+oQRV+DRukCRJ
- diqg+wIDAQABo1AwTjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBTDEsXJe6pjAQD4
- ULlB7+GMDBlimTAfBgNVHSMEGDAWgBTDEsXJe6pjAQD4ULlB7+GMDBlimTANBgkq
- hkiG9w0BAQUFAAOCAQEAWWkNcW6S1tKKqtzJsdfhjJiAAPQmOXJskv0ta/8f6Acg
- cum1YieNdtT0n96P7CUHOWP8QBb91JzeewR7b6WJLwb1Offs3wNq3kk75pJe89r4
- XY39EZHhMW+Dv0PhIKu2CgD4LeyH1FVTQkF/QObGEmkn+s+HTsuzd1l2VLwcP1Sm
- sqep6LAlFj62qqaIJzNeQ9NVkBqtkygnYlBOkaBTHfQTux3jYNpEo8JJB5e/WFdH
- YyMNrG2xMOtIC7T4+IOHgT8PgrNhaeDg9ctewj0X8Qi9nI9nXeinicLX8vj6hdEq
- 3ORv7RZMJNYqv1HQ3wUE2B7fCPFv7EUwzaCds1kgRQ==
- </bpki_cert>
- </client>
- </msg>
-
- <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <client action="destroy" client_handle="3"/>
- </msg>
-
- <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <client action="destroy" client_handle="3"/>
- </msg>
-
- <!-- === -->
-
- <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <certificate action="publish" uri="rsync://wombat.invalid/testbed/RIR/1/j7ghjwblCrcCp9ltyPDNzYKPfxc.cer">
- MIIE+jCCA+KgAwIBAgIBDTANBgkqhkiG9w0BAQsFADAzMTEwLwYDVQQDEyhERjRBODAxN0U2
- NkE5RTkxNzJFNDYxMkQ4Q0Y0QzgzRjIzOERFMkEzMB4XDTA4MDUyMjE4MDUxMloXDTA4MDUy
- NDE3NTQ1M1owMzExMC8GA1UEAxMoOEZCODIxOEYwNkU1MEFCNzAyQTdEOTZEQzhGMENEQ0Q4
- MjhGN0YxNzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMeziKp0k5nP7v6SZoNs
- XIMQYRgNtC6Fr/9Xm/1yQHomiPqHUk47rHhGojYiK5AhkrwoYhkH4UjJl2iwklDYczXuaBU3
- F5qrKlZ4aZnjIxdlP7+hktVpeApL6yuJTUAYeC3UIxnLDVdD6phydZ/FOQluffiNDjzteCCv
- oyOUatqt8WB+oND6LToHp028g1YUYLHG6mur0dPdcHOVXLSmUDuZ1HDz1nDuYvIVKjB/MpH9
- aW9XeaQ6ZFIlZVPwuuvI2brR+ThH7Gv27GL/o8qFdC300VQfoTZ+rKPGDE8K1cI906BL4kiw
- x9z0oiDcE96QCz+B0vsjc9mGaA1jgAxlXWsCAwEAAaOCAhcwggITMB0GA1UdDgQWBBSPuCGP
- BuUKtwKn2W3I8M3Ngo9/FzAfBgNVHSMEGDAWgBTfSoAX5mqekXLkYS2M9Mg/I43iozBVBgNV
- HR8ETjBMMEqgSKBGhkRyc3luYzovL2xvY2FsaG9zdDo0NDAwL3Rlc3RiZWQvUklSLzEvMzBx
- QUYtWnFucEZ5NUdFdGpQVElQeU9ONHFNLmNybDBFBggrBgEFBQcBAQQ5MDcwNQYIKwYBBQUH
- MAKGKXJzeW5jOi8vbG9jYWxob3N0OjQ0MDAvdGVzdGJlZC9XT01CQVQuY2VyMBgGA1UdIAEB
- /wQOMAwwCgYIKwYBBQUHDgIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgZsG
- CCsGAQUFBwELBIGOMIGLMDQGCCsGAQUFBzAFhihyc3luYzovL2xvY2FsaG9zdDo0NDAwL3Rl
- c3RiZWQvUklSL1IwLzEvMFMGCCsGAQUFBzAKhkdyc3luYzovL2xvY2FsaG9zdDo0NDAwL3Rl
- c3RiZWQvUklSL1IwLzEvajdnaGp3YmxDcmNDcDlsdHlQRE56WUtQZnhjLm1uZjAaBggrBgEF
- BQcBCAEB/wQLMAmgBzAFAgMA/BUwPgYIKwYBBQUHAQcBAf8ELzAtMCsEAgABMCUDAwAKAzAO
- AwUAwAACAQMFAcAAAiAwDgMFAsAAAiwDBQDAAAJkMA0GCSqGSIb3DQEBCwUAA4IBAQCEhuH7
- jtI2PJY6+zwv306vmCuXhtu9Lr2mmRw2ZErB8EMcb5xypMrNqMoKeu14K2x4a4RPJkK4yATh
- M81FPNRsU5mM0acIRnAPtxjHvPME7PHN2w2nGLASRsZmaa+b8A7SSOxVcFURazENztppsolH
- eTpm0cpLItK7mNpudUg1JGuFo94VLf1MnE2EqARG1vTsNhel/SM/UvOArCCOBvf0Gz7kSuup
- DSZ7qx+LiDmtEsLdbGNQBiYPbLrDk41PHrxdx28qIj7ejZkRzNFw/3pi8/XK281h8zeHoFVu
- 6ghRPy5dbOA4akX/KG6b8XIx0iwPYdLiDbdWFbtTdPcXBauY
- </certificate>
- </msg>
-
- <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <certificate action="publish" uri="rsync://wombat.invalid/testbed/RIR/1/j7ghjwblCrcCp9ltyPDNzYKPfxc.cer"/>
- </msg>
+ <msg xmlns="http://www.hactrn.net/uris/rpki/publication-spec/" type="query" version="3">
+ <!-- Zero or more PDUs -->
+ </msg>
+
+ <msg xmlns="http://www.hactrn.net/uris/rpki/publication-spec/" type="reply" version="3">
+ <!-- Zero or more PDUs -->
+ </msg>
+
+ <msg xmlns="http://www.hactrn.net/uris/rpki/publication-spec/" type="query" version="3">
+ <publish uri="rsync://wombat.example/Alice/blCrcCp9ltyPDNzYKPfxc.cer">
+ MIIE+jCCA+KgAwIBAgIBDTANBgkqhkiG9w0BAQsFADAzMTEwLwYDVQQDEyhE
+ RjRBODAxN0U2NkE5RTkxNzJFNDYxMkQ4Q0Y0QzgzRjIzOERFMkEzMB4XDTA4
+ MDUyMjE4MDUxMloXDTA4MDUyNDE3NTQ1M1owMzExMC8GA1UEAxMoOEZCODIx
+ OEYwNkU1MEFCNzAyQTdEOTZEQzhGMENEQ0Q4MjhGN0YxNzCCASIwDQYJKoZI
+ hvcNAQEBBQADggEPADCCAQoCggEBAMeziKp0k5nP7v6SZoNsXIMQYRgNtC6F
+ r/9Xm/1yQHomiPqHUk47rHhGojYiK5AhkrwoYhkH4UjJl2iwklDYczXuaBU3
+ F5qrKlZ4aZnjIxdlP7+hktVpeApL6yuJTUAYeC3UIxnLDVdD6phydZ/FOQlu
+ ffiNDjzteCCvoyOUatqt8WB+oND6LToHp028g1YUYLHG6mur0dPdcHOVXLSm
+ UDuZ1HDz1nDuYvIVKjB/MpH9aW9XeaQ6ZFIlZVPwuuvI2brR+ThH7Gv27GL/
+ o8qFdC300VQfoTZ+rKPGDE8K1cI906BL4kiwx9z0oiDcE96QCz+B0vsjc9mG
+ aA1jgAxlXWsCAwEAAaOCAhcwggITMB0GA1UdDgQWBBSPuCGPBuUKtwKn2W3I
+ 8M3Ngo9/FzAfBgNVHSMEGDAWgBTfSoAX5mqekXLkYS2M9Mg/I43iozBVBgNV
+ HR8ETjBMMEqgSKBGhkRyc3luYzovL2xvY2FsaG9zdDo0NDAwL3Rlc3RiZWQv
+ UklSLzEvMzBxQUYtWnFucEZ5NUdFdGpQVElQeU9ONHFNLmNybDBFBggrBgEF
+ BQcBAQQ5MDcwNQYIKwYBBQUHMAKGKXJzeW5jOi8vbG9jYWxob3N0OjQ0MDAv
+ dGVzdGJlZC9XT01CQVQuY2VyMBgGA1UdIAEB/wQOMAwwCgYIKwYBBQUHDgIw
+ DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgZsGCCsGAQUFBwEL
+ BIGOMIGLMDQGCCsGAQUFBzAFhihyc3luYzovL2xvY2FsaG9zdDo0NDAwL3Rl
+ c3RiZWQvUklSL1IwLzEvMFMGCCsGAQUFBzAKhkdyc3luYzovL2xvY2FsaG9z
+ dDo0NDAwL3Rlc3RiZWQvUklSL1IwLzEvajdnaGp3YmxDcmNDcDlsdHlQRE56
+ WUtQZnhjLm1uZjAaBggrBgEFBQcBCAEB/wQLMAmgBzAFAgMA/BUwPgYIKwYB
+ BQUHAQcBAf8ELzAtMCsEAgABMCUDAwAKAzAOAwUAwAACAQMFAcAAAiAwDgMF
+ AsAAAiwDBQDAAAJkMA0GCSqGSIb3DQEBCwUAA4IBAQCEhuH7jtI2PJY6+zwv
+ 306vmCuXhtu9Lr2mmRw2ZErB8EMcb5xypMrNqMoKeu14K2x4a4RPJkK4yATh
+ M81FPNRsU5mM0acIRnAPtxjHvPME7PHN2w2nGLASRsZmaa+b8A7SSOxVcFUR
+ azENztppsolHeTpm0cpLItK7mNpudUg1JGuFo94VLf1MnE2EqARG1vTsNhel
+ /SM/UvOArCCOBvf0Gz7kSuupDSZ7qx+LiDmtEsLdbGNQBiYPbLrDk41PHrxd
+ x28qIj7ejZkRzNFw/3pi8/XK281h8zeHoFVu6ghRPy5dbOA4akX/KG6b8XIx
+ 0iwPYdLiDbdWFbtTdPcXBauY
+ </publish>
+ </msg>
+
+ <msg xmlns="http://www.hactrn.net/uris/rpki/publication-spec/" type="reply" version="3">
+ <publish uri="rsync://wombat.example/Alice/blCrcCp9ltyPDNzYKPfxc.cer"/>
+ </msg>
+
+ <msg xmlns="http://www.hactrn.net/uris/rpki/publication-spec/" type="reply" version="3">
+ <report_error error_code="your_hair_is_on_fire">
+ Shampooing with sterno again, are we?
+ </report_error>
+ </msg>
+
+ <msg xmlns="http://www.hactrn.net/uris/rpki/publication-spec/" type="reply" version="3">
+ <report_error error_code="your_hair_is_on_fire"/>
+ </msg>
+
+ <msg xmlns="http://www.hactrn.net/uris/rpki/publication-spec/" type="query" version="3">
+ <withdraw uri="rsync://wombat.example/Alice/blCrcCp9ltyPDNzYKPfxc.cer" hash="deadf00d"/>
+ </msg>
+
+ <msg xmlns="http://www.hactrn.net/uris/rpki/publication-spec/" type="reply" version="3">
+ <withdraw uri="rsync://wombat.example/Alice/blCrcCp9ltyPDNzYKPfxc.cer"/>
+ </msg>
- <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <certificate action="withdraw" uri="rsync://wombat.invalid/testbed/RIR/1/j7ghjwblCrcCp9ltyPDNzYKPfxc.cer"/>
- </msg>
-
- <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <certificate action="withdraw" uri="rsync://wombat.invalid/testbed/RIR/1/j7ghjwblCrcCp9ltyPDNzYKPfxc.cer"/>
- </msg>
-
- <!-- === -->
-
- <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <crl action="publish" uri="rsync://wombat.invalid/testbed/RIR/1/30qAF-ZqnpFy5GEtjPTIPyON4qM.crl">
- MIIBwzCBrAIBATANBgkqhkiG9w0BAQsFADAzMTEwLwYDVQQDEyhERjRBODAxN0U2NkE5RTkx
- NzJFNDYxMkQ4Q0Y0QzgzRjIzOERFMkEzFw0wODA1MjIxODA0MTZaFw0wODA1MjIxODA1MTZa
- MBQwEgIBAhcNMDgwNTIyMTc1ODQwWqAvMC0wHwYDVR0jBBgwFoAU30qAF+ZqnpFy5GEtjPTI
- PyON4qMwCgYDVR0UBAMCAQYwDQYJKoZIhvcNAQELBQADggEBAKkM0Fb/pJpHVHWZyjp4wojH
- W2KkvA/DFtBiz3moxocSnkDVP3QI19uVvqdC6nH3hJyFmsAMwULR0f1XU/V4j+X+FqYEl6Nv
- p8zAEPIB4r8xbEFs7udRwXRAjkJmOQbv9aomF2i+d7jpTFVJxShZWOgsoGEhIy/aktKQrOIR
- c4ZDrXpQwXVj2Y7+cGVfQ4gvnPOdlyLcnNovoegazATvA3EcidBNPWRg7XTCz0LVBEB7JgPd
- nNyXRg35HdMEHBl7U9uUQJXP7S02oaQ1ehNDMfaJPgBBpQtAnM1lIzJfevd9+e4ywGsRpxAV
- 8wxTXSPd1jwuKtS0kwrgsrQ8Ya85xUE=
- </crl>
- </msg>
-
- <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <crl action="publish" uri="rsync://wombat.invalid/testbed/RIR/1/30qAF-ZqnpFy5GEtjPTIPyON4qM.crl"/>
- </msg>
-
- <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <crl action="withdraw" uri="rsync://wombat.invalid/testbed/RIR/1/30qAF-ZqnpFy5GEtjPTIPyON4qM.crl"/>
- </msg>
-
- <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <crl action="withdraw" uri="rsync://wombat.invalid/testbed/RIR/1/30qAF-ZqnpFy5GEtjPTIPyON4qM.crl"/>
- </msg>
-
- <!-- === -->
-
- <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <manifest action="publish" uri="rsync://wombat.invalid/testbed/RIR/R0/1/j7ghjwblCrcCp9ltyPDNzYKPfxc.mft">
- MIIHCgYJKoZIhvcNAQcCoIIG+zCCBvcCAQMxDTALBglghkgBZQMEAgEwggEeBgsqhkiG9w0B
- CRABGqCCAQ0EggEJMIIBBQIBEhgPMjAwODA1MjIxODA1MTVaGA8yMDA4MDUyMjE4MDYxNVoG
- CWCGSAFlAwQCATCB0jBEFh9ZbTVUTzRJYnlDb0pNZ3E2R2o4dG41Mng5U0UuY2VyAyEA4L8Z
- WMyuhOx+o6kUfsRR++QjSaRaATy4UOeVtjvZVqYwRBYfWnRxbjB3NEVFbU9hclAzQmd1SUY3
- MDhhNTM4LmNlcgMhAGQI1gYJotxWmwzcmpLNFZJ656uWOjcPYANlbNz80xm8MEQWH2xxa1Vx
- RHEwMDBESW9ZVjlybXdLTGdrN2F6by5jZXIDIQB7jRAEpkPvc4s4PX9vDvnTifj3BIE145FO
- 1ne2kEejVqCCBBEwggQNMIIC9aADAgECAgEFMA0GCSqGSIb3DQEBCwUAMDMxMTAvBgNVBAMT
- KDhGQjgyMThGMDZFNTBBQjcwMkE3RDk2REM4RjBDRENEODI4RjdGMTcwHhcNMDgwNTIyMTc1
- NzQ5WhcNMDgwNTI0MTc1NDUzWjAzMTEwLwYDVQQDEyhERkRBMjMyMUJENEVCMDNFQTE1RkUy
- N0NGRkRGMEFGRkU1QjBFNjY4MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2/Gk
- AHW5pDqye0+TvUp7sl0rVgmTfeHpVp18ypxvuovogVJgkjEtBEikfaFU0646wYD6JM6IJFJX
- lWLWd7bVmhkWViKuZL0VmT2wpUToNHCLUGUQUVVX8R7oSHFdTArv2AqH+6yt0LmczDH1y2M6
- 2Tgkz9wZ9ryyuPx3VX4PkHzUMlkGFICj1fvyXkcAu8jBaxR9UME1c413TPaMi6lMh1HUmtVN
- LJMP5+/SnwEAW/Z3dPClCFIgQXK3nAKPVzAIwADEiqhK7cSchhO7ikI1CVt0XzG4n7oaILc3
- Hq/DAxyiutw5GlkUlKPri2YJzJ3+H4P+TveSa/b02fVA5csm/QIDAQABo4IBKjCCASYwHQYD
- VR0OBBYEFN/aIyG9TrA+oV/ifP/fCv/lsOZoMB8GA1UdIwQYMBaAFI+4IY8G5Qq3AqfZbcjw
- zc2Cj38XMFgGA1UdHwRRME8wTaBLoEmGR3JzeW5jOi8vbG9jYWxob3N0OjQ0MDAvdGVzdGJl
- ZC9SSVIvUjAvMS9qN2doandibENyY0NwOWx0eVBETnpZS1BmeGMuY3JsMGAGCCsGAQUFBwEB
- BFQwUjBQBggrBgEFBQcwAoZEcnN5bmM6Ly9sb2NhbGhvc3Q6NDQwMC90ZXN0YmVkL1JJUi8x
- L2o3Z2hqd2JsQ3JjQ3A5bHR5UEROellLUGZ4Yy5jZXIwGAYDVR0gAQH/BA4wDDAKBggrBgEF
- BQcOAjAOBgNVHQ8BAf8EBAMCB4AwDQYJKoZIhvcNAQELBQADggEBADpsE9HfgVTgmX1WeJTE
- fm87CXuOoGH85RFiAngSt5kR4gYCyadklOZ7Eta+ERUZVu4tcKO6sJOTuHPfVrAvR0VpgH+j
- PvXboYWSfwJdi00BC28ScrVM2zarA7B10+J6Oq8tbFlAyVBkrbuPet/axmndBtGWhrBTynGl
- nc/5L371Lxy6CrOYqXO0Qx3SrOKaailAe3zTIpHQeACqnPdL00zIBw/hVy/VNaH1wy+FmhAz
- TsmsQUrMyovJcu/ry5w0KHlP8BTnqfykikCWR+Lw0VQHmpJGAbtrmsOeIbfLY1zl7A81lDAl
- AG/ZH1DUdDOUIXMLHWur+D2rwjp7RL16LHYxggGqMIIBpgIBA4AU39ojIb1OsD6hX+J8/98K
- /+Ww5mgwCwYJYIZIAWUDBAIBoGswGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEaMBwGCSqG
- SIb3DQEJBTEPFw0wODA1MjIxODA1MTVaMC8GCSqGSIb3DQEJBDEiBCBj/GjEQw3LgKPf5DTz
- 8eu1fcp6/cQjqqne6ZqFkF42azANBgkqhkiG9w0BAQEFAASCAQBOY0uHNMwy/o1nFANSgha5
- PZxt8fz+wTrbeomCb+lxqQKq1clcSiQORVGc8NmqC8sS5OR3eTw/3qnK9yPHxz2UQ4hn1pBa
- +Zy5veM61qMaXCw6w98EyNcvUfA1AkezAjkabfHQDs3o4Ezh49thXXyRcBoF+O6Lmi+LZbT2
- 4jvfFbaXW9zsb6/DaoDkeHnlk+YYgfSP4wOnkK5uqxtDW8QpMPq3GGdIp0oJDkzEdj7VsWIL
- 9JP2mxxL8fTPVUyAPOmURYwYDXqhke2O9eVDiCYhrEfB8/84Rint4Cj8n5aCujnAtqtwxHpD
- 0NRYO/V1MjhG+ARy1vRH1Dm0r92RBam3
- </manifest>
- </msg>
-
- <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <manifest action="publish" uri="rsync://wombat.invalid/testbed/RIR/R0/1/j7ghjwblCrcCp9ltyPDNzYKPfxc.mft"/>
- </msg>
-
- <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <manifest action="withdraw" uri="rsync://wombat.invalid/testbed/RIR/R0/1/j7ghjwblCrcCp9ltyPDNzYKPfxc.mft"/>
- </msg>
-
- <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <manifest action="withdraw" uri="rsync://wombat.invalid/testbed/RIR/R0/1/j7ghjwblCrcCp9ltyPDNzYKPfxc.mft"/>
- </msg>
-
- <!-- === -->
-
- <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <roa action="publish" uri="rsync://wombat.invalid/testbed/RIR/R0/1/lqkUqDq000DIoYV9rmwKLgk7azo.roa">
- MIIGmwYJKoZIhvcNAQcCoIIGjDCCBogCAQMxDTALBglghkgBZQMEAgEwKgYLKoZIhvcNAQkQ
- ARigGwQZMBcCAgKaMBEwDwQCAAEwCTAHAwUACgMALKCCBJgwggSUMIIDfKADAgECAgEJMA0G
- CSqGSIb3DQEBCwUAMDMxMTAvBgNVBAMTKDhGQjgyMThGMDZFNTBBQjcwMkE3RDk2REM4RjBD
- RENEODI4RjdGMTcwHhcNMDgwNTIyMTc1ODI0WhcNMDgwNTI0MTc1NDUzWjAzMTEwLwYDVQQD
- Eyg5NkE5MTRBODNBQjREMzQwQzhBMTg1N0RBRTZDMEEyRTA5M0I2QjNBMIIBIjANBgkqhkiG
- 9w0BAQEFAAOCAQ8AMIIBCgKCAQEApoK50BjW5bcF4gsdaYhndtVADZvQk3RCsvuqDElF6uLi
- 9BYQq/NHyDOIMyJtvCmzjdv3Y135n1sNO7YvssqHlt7dMfCQTD5ND1GpFnQLdWP7stWM5AbO
- nJV6+PtDITUA/QHOli7Do0YCUgR6G+1QJsMu0DK+TRSzBJ6WP7WIYOBOOg3y/NKc1rkWhS1Q
- dcQepbHgQYZHzzpjNDR6+oYVuhuUEWx1P6O4pv/p+tpE0SDua7jBjMywIYHkPQBecf2IX1RU
- WNojB9dJlnRx5YUUneP2SvF2MrmdDbclgzwhf6alqD2OjiMuoBOG8yeTKcuhzCMnrFAklbst
- 6x3Rnq9BswIDAQABo4IBsTCCAa0wHQYDVR0OBBYEFJapFKg6tNNAyKGFfa5sCi4JO2s6MB8G
- A1UdIwQYMBaAFI+4IY8G5Qq3AqfZbcjwzc2Cj38XMFgGA1UdHwRRME8wTaBLoEmGR3JzeW5j
- Oi8vbG9jYWxob3N0OjQ0MDAvdGVzdGJlZC9SSVIvUjAvMS9qN2doandibENyY0NwOWx0eVBE
- TnpZS1BmeGMuY3JsMGAGCCsGAQUFBwEBBFQwUjBQBggrBgEFBQcwAoZEcnN5bmM6Ly9sb2Nh
- bGhvc3Q6NDQwMC90ZXN0YmVkL1JJUi8xL2o3Z2hqd2JsQ3JjQ3A5bHR5UEROellLUGZ4Yy5j
- ZXIwGAYDVR0gAQH/BA4wDDAKBggrBgEFBQcOAjAOBgNVHQ8BAf8EBAMCB4AwYwYIKwYBBQUH
- AQsEVzBVMFMGCCsGAQUFBzALhkdyc3luYzovL2xvY2FsaG9zdDo0NDAwL3Rlc3RiZWQvUklS
- L1IwLzEvbHFrVXFEcTAwMERJb1lWOXJtd0tMZ2s3YXpvLnJvYTAgBggrBgEFBQcBBwEB/wQR
- MA8wDQQCAAEwBwMFAAoDACwwDQYJKoZIhvcNAQELBQADggEBAL8iHwsyGOYhhIf3nVuL361y
- TOJSP8SR0mtQLHULPl+GkYk+5MRNWtL8ucTXFvniYJtOCXEGGEIO9eDXvkQIXQSz/qbF9URQ
- fuf38ghRza257syVhal6UHTgCFYuRIO9CUjcU1vkWUxH05BBIHlYdtlIQbAG/mRsCPCEgSmG
- bbQaomGlUOqmJMlKxLLcoAtz2vDrwVotgHyfS5h2mgINFjnlLcNLTci+sfs7/aQAkDYx7K98
- se/ZlMorvGkFNhHoOTcGIrWkYsfkbTygVwWRm278PaB3o4449Kvsg/gb8BZeHXRs68cr5Mcf
- jP7Q6jeypjTgDBnwb1yzoJIKWszFuSgxggGqMIIBpgIBA4AUlqkUqDq000DIoYV9rmwKLgk7
- azowCwYJYIZIAWUDBAIBoGswGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEYMBwGCSqGSIb3
- DQEJBTEPFw0wODA1MjIxNzU4MjRaMC8GCSqGSIb3DQEJBDEiBCDCyf9v9Wed515TRp2WwnyM
- 1rk6dB///X+aqIym2e9jdTANBgkqhkiG9w0BAQEFAASCAQAFvzrHeRPW+wn4WSyoyBEq0zKS
- Cyh5tu1qTR0NHs6Rr/p8Pk81P1HQLND/U+znJZKLWlO2niEHUXPIicPDYchbj8ApH9VxKA+1
- lCWllOzFAsYyZFr3/VNs9pVp2eT4F9eEYBrBVDSNrD72MMTlWm1T5MEXqltTJJOCKzUEX96x
- 91iW6A+4erop7S8hpCnxqkTin4bFVreqYcGc4CC4bh+L9pPqJnURcEk7Qeu/WEHQBm38voB4
- S11qRZNrJMQ99oiJR7hXDIBm66HjGqoUL2gPCfpgJEVVnM9pVv2k889z4eTTck2Qj54gga2W
- Xkvw4Je420aDx88s9T2+PqXcbZ4g
- </roa>
- </msg>
-
- <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <roa action="publish" uri="rsync://wombat.invalid/testbed/RIR/R0/1/lqkUqDq000DIoYV9rmwKLgk7azo.roa"/>
- </msg>
-
- <msg version="1" type="query" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <roa action="withdraw" uri="rsync://wombat.invalid/testbed/RIR/R0/1/lqkUqDq000DIoYV9rmwKLgk7azo.roa"/>
- </msg>
-
- <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <roa action="withdraw" uri="rsync://wombat.invalid/testbed/RIR/R0/1/lqkUqDq000DIoYV9rmwKLgk7azo.roa"/>
- </msg>
-
- <!-- === -->
-
- <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <report_error error_code="your_hair_is_on_fire">text string</report_error>
- </msg>
-
- <msg version="1" type="reply" xmlns="http://www.hactrn.net/uris/rpki/publication-spec/">
- <report_error error_code="your_hair_is_on_fire"/>
- </msg>
</completely_gratuitous_wrapper_element_to_let_me_run_this_through_xmllint>
diff --git a/ca/tests/rrdp-samples.xml b/ca/tests/rrdp-samples.xml
new file mode 100644
index 00000000..0318b169
--- /dev/null
+++ b/ca/tests/rrdp-samples.xml
@@ -0,0 +1,88 @@
+<!-- -*- SGML -*-
+ - $Id$
+ -
+ - This is a collection of sample RRDP PDU samples to use as test
+ - cases for the RRDP RelaxNG schema.
+ -
+ - Need to figure out whose copyright should be on these examples.
+ - BSD in any case so makes little practical difference, just need to
+ - be sure we give proper credit. Might be RIPE, might be IETF
+ - Trust, might be us for derivative work. Slap ours on for the
+ - moment, fix when we figure this out.
+ -
+ - Copyright (C) 2014 Dragon Research Labs ("DRL")
+ -
+ - 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 DRL DISCLAIMS ALL WARRANTIES WITH
+ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ - AND FITNESS. IN NO EVENT SHALL DRL 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.
+ -->
+
+<completely_gratuitous_wrapper_element_to_let_me_run_this_through_xmllint>
+
+ <!-- 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="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 -->
+
+ <snapshot version="1" xmlns="http://www.ripe.net/rpki/rrdp" session_id="d9f6dc91-0394-40b9-9663-66aef4bb623a" serial="1">
+ <publish uri="http://host.example/foo/bar/cer1.cer">
+ MIIE+jCCA+KgAwIBAgIBDTANBgkqhkiG9w0BAQsFADAzMTEwLwYDVQQD
+ jRBODAxN0U2NkE5RTkxNzJFNDYxMkQ4Q0Y0QzgzRjIzOERFMkEzMB4XE
+ h8zeHoFVu6ghRPy5dbOA4akX/KG6b8XIx0iwPYdLiDbdWFbtTdPcXBau
+ </publish>
+ <publish uri="http://host.example/foo/bar/cer2.cer">
+ MIIE+jCCA+KgAwIBAgIBDTANBgkqhkiG9w0BAQsFADAzMTEwLwYDVQQD
+ h8zeHoFVu6ghRPy5dbOA4akX/KG6b8XIx0iwPYdLiDbdWFbtTdPcXBau
+ jRBODAxN0U2NkE5RTkxNzJFNDYxMkQ4Q0Y0QzgzRjIzOERFMkEzMB4XD
+ </publish>
+ <publish uri="http://host.example/foo/bar/cer3.cer">
+ MIIE+jCCA+KgAwIBAgIBDTANBgkqhkiG9w0BAQsFADAzMTEwLwYDVQQD
+ h8zeHoFVu6ghRPy5dbOA4akX/KG6b8XIx0iwPYdLiDbdWFbtTdPcXBau
+ jRBODAxN0U2NkE5RTkxNzJFNDYxMkQ4Q0Y0QzgzRjIzOERFMkEzMB4XD
+ </publish>
+ </snapshot>
+
+ <!-- Delta segment: think DNS IXFR -->
+
+ <deltas version="1" xmlns="http://www.ripe.net/rpki/rrdp" session_id="d9f6dc91-0394-40b9-9663-66aef4bb623a" from="0" to="3">
+ <delta serial="1">
+ <publish uri="http://host.example/foo/bar/cer1.cer">
+ MIIE+jCCA+KgAwIBAgIBDTANBgkqhkiG9w0BAQsFADAzMTEw
+ jRBODAxN0U2NkE5RTkxNzJFNDYxMkQ4Q0Y0QzgzRjIzOERFM
+ h8zeHoFVu6ghRPy5dbOA4akX/KG6b8XIx0iwPYdLiDbdWFbt
+ </publish>
+ </delta>
+ <delta serial="2">
+ <withdraw uri="http://host.example/foo/bar/cer1.cer" hash="deadf00d"/>
+ <publish uri="http://host.example/foo/bar/cer2.cer">
+ MIIE+jCCA+KgAwIBAgIBDTANBgkqhkiG9w0BAQsFADAzMTEw
+ h8zeHoFVu6ghRPy5dbOA4akX/KG6b8XIx0iwPYdLiDbdWFbt
+ jRBODAxN0U2NkE5RTkxNzJFNDYxMkQ4Q0Y0QzgzRjIzOERFM
+ </publish>
+ <publish uri="http://host.example/foo/bar/cer3.cer" hash="deadf00d">
+ MIIE+jCCA+KgAwIBAgIBDTANBgkqhkiG9w0BAQsFADAzMTEw
+ h8zeHoFVu6ghRPy5dbOA4akX/KG6b8XIx0iwPYdLiDbdWFbt
+ jRBODAxN0U2NkE5RTkxNzJFNDYxMkQ4Q0Y0QzgzRjIzOERFM
+ </publish>
+ </delta>
+ <delta serial="3">
+ <withdraw uri="http://host.example/foo/bar/cer2.cer" hash="deadf00d"/>
+ </delta>
+ </deltas>
+
+</completely_gratuitous_wrapper_element_to_let_me_run_this_through_xmllint>
diff --git a/ca/tests/smoketest.py b/ca/tests/smoketest.py
index 32f11cc3..d24fc460 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
@@ -68,7 +68,7 @@ parser.add_argument("yaml_file", type = argparse.FileType("r"),
help = "YAML description of test network")
args = parser.parse_args()
-cfg = rpki.config.parser(args.config, "smoketest", allow_missing = True)
+cfg = rpki.config.parser(set_filename = args.config, section = "smoketest", allow_missing = True)
# Load the YAML script early, so we can report errors ASAP
@@ -80,6 +80,7 @@ def allocate_port():
"""
Allocate a TCP port number.
"""
+
global base_port
p = base_port
base_port += 1
@@ -219,8 +220,8 @@ def main():
for a in db:
a.setup_bpki_certs()
- setup_publication(pubd_sql)
- setup_rootd(db.root, y.get("rootd", {}))
+ setup_publication(pubd_sql, db.root.irdb_db_name)
+ setup_rootd(db.root, y.get("rootd", {}), db)
setup_rsyncd()
setup_rcynic()
@@ -232,11 +233,13 @@ def main():
try:
logger.info("Starting rootd")
- rootd_process = subprocess.Popen((prog_python, prog_rootd, "--foreground", "--log-stdout", "--log-level", "debug", "--config", rootd_name + ".conf"))
+ rootd_process = subprocess.Popen((prog_python, prog_rootd, "--foreground", "--log-stdout", "--log-level", "debug"),
+ env = dict(os.environ, RPKI_CONF = rootd_name + ".conf"))
logger.info("Starting pubd")
- pubd_process = subprocess.Popen((prog_python, prog_pubd, "--foreground", "--log-stdout", "--log-level", "debug", "--config", pubd_name + ".conf") +
- (("-p", pubd_name + ".prof") if args.profile else ()))
+ pubd_process = subprocess.Popen((prog_python, prog_pubd, "--foreground", "--log-stdout", "--log-level", "debug") +
+ (("-p", pubd_name + ".prof") if args.profile else ()),
+ env = dict(os.environ, RPKI_CONF = pubd_name + ".conf"))
logger.info("Starting rsyncd")
rsyncd_process = subprocess.Popen((prog_rsyncd, "--daemon", "--no-detach", "--config", rsyncd_name + ".conf"))
@@ -249,15 +252,17 @@ def main():
# the code until final exit is all closures.
def start():
- rpki.async.iterator(db.engines, create_rpki_objects, created_rpki_objects)
+ rpki.async.iterator(db.engines, create_rpki_objects, create_pubd_objects)
def create_rpki_objects(iterator, a):
a.create_rpki_objects(iterator)
- def created_rpki_objects():
-
- # Set pubd's BPKI CRL
- set_pubd_crl(yaml_loop)
+ def create_pubd_objects():
+ call_pubd([rpki.publication_control.client_elt.make_pdu(action = "create",
+ client_handle = db.root.client_handle + "-" + rootd_name,
+ base_uri = rootd_sia,
+ bpki_cert = cross_certify(rootd_name + "-TA", pubd_name + "-TA"))],
+ cb = lambda ignored: yaml_loop())
def yaml_loop():
@@ -324,6 +329,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)
@@ -332,6 +338,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)
@@ -341,6 +348,7 @@ def cmd_echo(cb, *words):
"""
Echo some text to the log.
"""
+
logger.info(" ".join(words))
cb()
@@ -498,6 +506,7 @@ class allocation_db(list):
"""
Print content of the database.
"""
+
for a in self:
print a
@@ -518,6 +527,7 @@ class allocation(object):
"""
Initialize one entity and insert it into the database.
"""
+
db.append(self)
self.name = yaml["name"]
self.parent = parent
@@ -554,6 +564,7 @@ class allocation(object):
"""
Compute the transitive resource closure.
"""
+
resources = self.base
for kid in self.kids:
resources |= kid.closure()
@@ -708,6 +719,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
@@ -717,6 +729,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
@@ -728,6 +741,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"),
@@ -741,15 +755,16 @@ 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,
- "irdb_db_name" : self.irdb_db_name,
- "irdb_db_pass" : irdb_db_pass,
- "irdb_port" : self.irdb_port,
- "rpki_db_name" : self.rpki_db_name,
- "rpki_db_pass" : rpki_db_pass,
- "rpki_port" : self.rpki_port }
+ d = dict(my_name = self.name,
+ irdb_db_name = self.irdb_db_name,
+ irdb_db_pass = irdb_db_pass,
+ irdb_port = self.irdb_port,
+ rpki_db_name = self.rpki_db_name,
+ rpki_db_pass = rpki_db_pass,
+ rpki_port = self.rpki_port)
f = open(self.name + ".conf", "w")
f.write(conf_fmt_1 % d)
for line in self.extra_conf:
@@ -760,6 +775,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)
@@ -794,6 +810,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)
@@ -847,15 +864,20 @@ 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 ()))
- self.irdbd_process = subprocess.Popen((prog_python, prog_irdbd, "--foreground", "--log-stdout", "--log-level", "debug", "--config", self.name + ".conf"))
+ env = dict(os.environ, RPKI_CONF = self.name + ".conf")
+ self.rpkid_process = subprocess.Popen((prog_python, prog_rpkid, "--foreground", "--log-stdout", "--log-level", "debug") +
+ (("--profile", self.name + ".prof") if args.profile else ()),
+ env = env)
+ self.irdbd_process = subprocess.Popen((prog_python, prog_irdbd, "--foreground", "--log-stdout", "--log-level", "debug"),
+ env = env)
def kill_daemons(self):
"""
Kill daemons for this entity.
"""
+
# pylint: disable=E1103
for proc, name in ((self.rpkid_process, "rpkid"),
(self.irdbd_process, "irdbd")):
@@ -925,45 +947,7 @@ class allocation(object):
certificant = self.name + "-SELF"
else:
certifier = self.name + "-SELF"
- certfile = certifier + "-" + certificant + ".cer"
-
- logger.info("Cross certifying %s into %s's BPKI (%s)", certificant, certifier, certfile)
-
- child = rpki.x509.X509(Auto_file = certificant + ".cer")
- parent = rpki.x509.X509(Auto_file = certifier + ".cer")
- keypair = rpki.x509.RSA(Auto_file = certifier + ".key")
- serial_file = certifier + ".srl"
-
- now = rpki.sundial.now()
- notAfter = now + rpki.sundial.timedelta(days = 30)
-
- try:
- f = open(serial_file, "r")
- serial = f.read()
- f.close()
- serial = int(serial.splitlines()[0], 16)
- except IOError:
- serial = 1
-
- x = parent.bpki_cross_certify(
- keypair = keypair,
- source_cert = child,
- serial = serial,
- notAfter = notAfter,
- now = now)
-
- f = open(serial_file, "w")
- f.write("%02x\n" % (serial + 1))
- f.close()
-
- f = open(certfile, "w")
- f.write(x.get_PEM())
- f.close()
-
- logger.debug("Cross certified %s:", certfile)
- logger.debug(" Issuer %s [%s]", x.getIssuer(), x.hAKI())
- logger.debug(" Subject %s [%s]", x.getSubject(), x.hSKI())
- return x
+ return cross_certify(certificant, certifier)
def create_rpki_objects(self, cb):
"""
@@ -982,13 +966,11 @@ class allocation(object):
selves = [self] + self.hosts
- for i, s in enumerate(selves):
- logger.info("Creating RPKI objects for [%d] %s", i, s.name)
-
rpkid_pdus = []
pubd_pdus = []
- for s in selves:
+ for i, s in enumerate(selves):
+ logger.info("Creating RPKI objects for [%d] %s", i, s.name)
rpkid_pdus.append(rpki.left_right.self_elt.make_pdu(
action = "create",
@@ -1005,7 +987,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,
@@ -1126,18 +1108,6 @@ class allocation(object):
self.cross_certify(self.parent.name + "-SELF")
self.cross_certify(parent_host + "-TA")
- logger.info("Writing leaf YAML for %s", self.name)
- f = open(self.name + ".yaml", "w")
- f.write(yaml_fmt_1 % {
- "parent_name" : self.parent.name,
- "parent_host" : parent_host,
- "my_name" : self.name,
- "http_port" : self.parent.get_rpki_port(),
- "class_name" : 2 if self.parent.is_hosted else 1,
- "sia" : self.sia_base,
- "ski" : ski })
- f.close()
-
def run_cron(self, cb):
"""
Trigger cron run for this engine.
@@ -1174,20 +1144,22 @@ 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:
- d = { "name" : name,
- "kind" : kind,
- "ca" : "false" if kind in ee else "true",
- "openssl" : prog_openssl }
+ d = dict(name = name,
+ kind = kind,
+ ca = "false" if kind in ee else "true",
+ openssl = prog_openssl)
f = open("%(name)s-%(kind)s.conf" % d, "w")
f.write(bpki_cert_fmt_1 % d)
f.close()
if not os.path.exists("%(name)s-%(kind)s.key" % d):
s += bpki_cert_fmt_2 % d
s += bpki_cert_fmt_3 % d
- d = { "name" : name, "openssl" : prog_openssl }
+ d = dict(name = name,
+ openssl = prog_openssl)
s += bpki_cert_fmt_4 % d
for kind in ee + ca:
d["kind"] = kind
@@ -1197,19 +1169,24 @@ def setup_bpki_cert_chain(name, ee = (), ca = ()):
s += bpki_cert_fmt_6 % d
subprocess.check_call(s, shell = True)
-def setup_rootd(rpkid, rootd_yaml):
+def setup_rootd(rpkid, rootd_yaml, db):
"""
Write the config files for rootd.
"""
+
rpkid.cross_certify(rootd_name + "-TA", reverse = True)
+ cross_certify(pubd_name + "-TA", rootd_name + "-TA")
logger.info("Writing config files for %s", rootd_name)
- d = { "rootd_name" : rootd_name,
- "rootd_port" : rootd_port,
- "rpkid_name" : rpkid.name,
- "rootd_sia" : rootd_sia,
- "rsyncd_dir" : rsyncd_dir,
- "openssl" : prog_openssl,
- "lifetime" : rootd_yaml.get("lifetime", "30d") }
+ d = dict(rootd_name = rootd_name,
+ rootd_port = rootd_port,
+ rpkid_name = rpkid.name,
+ pubd_name = pubd_name,
+ rootd_sia = rootd_sia,
+ rsyncd_dir = rsyncd_dir,
+ openssl = prog_openssl,
+ lifetime = rootd_yaml.get("lifetime", "30d"),
+ pubd_port = pubd_port,
+ rootd_handle = db.root.client_handle + "-" + rootd_name)
f = open(rootd_name + ".conf", "w")
f.write(rootd_fmt_1 % d)
f.close()
@@ -1224,10 +1201,11 @@ def setup_rcynic():
"""
Write the config file for rcynic.
"""
+
logger.info("Config file for rcynic")
- d = { "rcynic_name" : rcynic_name,
- "rootd_name" : rootd_name,
- "rootd_sia" : rootd_sia }
+ d = dict(rcynic_name = rcynic_name,
+ rootd_name = rootd_name,
+ rootd_sia = rootd_sia)
f = open(rcynic_name + ".conf", "w")
f.write(rcynic_fmt_1 % d)
f.close()
@@ -1236,19 +1214,21 @@ def setup_rsyncd():
"""
Write the config file for rsyncd.
"""
+
logger.info("Config file for rsyncd")
- d = { "rsyncd_name" : rsyncd_name,
- "rsyncd_port" : rsyncd_port,
- "rsyncd_module" : rsyncd_module,
- "rsyncd_dir" : rsyncd_dir }
+ d = dict(rsyncd_name = rsyncd_name,
+ rsyncd_port = rsyncd_port,
+ rsyncd_module = rsyncd_module,
+ rsyncd_dir = rsyncd_dir)
f = open(rsyncd_name + ".conf", "w")
f.write(rsyncd_fmt_1 % d)
f.close()
-def setup_publication(pubd_sql):
+def setup_publication(pubd_sql, irdb_db_name):
"""
Set up publication daemon.
"""
+
logger.info("Configure publication daemon")
publication_dir = os.getcwd() + "/publication"
assert rootd_sia.startswith("rsync://")
@@ -1268,12 +1248,14 @@ def setup_publication(pubd_sql):
if "DROP TABLE IF EXISTS" not in sql.upper():
raise
db.close()
- d = { "pubd_name" : pubd_name,
- "pubd_port" : pubd_port,
- "pubd_db_name" : pubd_db_name,
- "pubd_db_user" : pubd_db_user,
- "pubd_db_pass" : pubd_db_pass,
- "pubd_dir" : rsyncd_dir }
+ d = dict(pubd_name = pubd_name,
+ pubd_port = pubd_port,
+ pubd_db_name = pubd_db_name,
+ pubd_db_user = pubd_db_user,
+ pubd_db_pass = pubd_db_pass,
+ pubd_dir = rsyncd_dir,
+ irdb_db_name = irdb_db_name,
+ irdb_db_pass = irdb_db_pass)
f = open(pubd_name + ".conf", "w")
f.write(pubd_fmt_1 % d)
f.close()
@@ -1288,12 +1270,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
@@ -1301,13 +1284,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)
+ r_pdu.raise_if_error()
cb(r_msg)
def call_pubd_eb(e):
@@ -1319,15 +1302,47 @@ def call_pubd(pdus, cb):
callback = call_pubd_cb,
errback = call_pubd_eb)
-def set_pubd_crl(cb):
+
+def cross_certify(certificant, certifier):
"""
- Whack publication daemon's bpki_crl. This must be configured before
- publication daemon starts talking to its clients, and must be
- updated whenever we update the CRL.
+ Cross-certify and return the resulting certificate.
"""
- 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())
+
+ certfile = certifier + "-" + certificant + ".cer"
+
+ logger.info("Cross certifying %s into %s's BPKI (%s)", certificant, certifier, certfile)
+
+ child = rpki.x509.X509(Auto_file = certificant + ".cer")
+ parent = rpki.x509.X509(Auto_file = certifier + ".cer")
+ keypair = rpki.x509.RSA(Auto_file = certifier + ".key")
+ serial_file = certifier + ".srl"
+
+ now = rpki.sundial.now()
+ notAfter = now + rpki.sundial.timedelta(days = 30)
+
+ try:
+ with open(serial_file, "r") as f:
+ serial = int(f.read().splitlines()[0], 16)
+ except IOError:
+ serial = 1
+
+ x = parent.bpki_cross_certify(
+ keypair = keypair,
+ source_cert = child,
+ serial = serial,
+ notAfter = notAfter,
+ now = now)
+
+ with open(serial_file, "w") as f:
+ f.write("%02x\n" % (serial + 1))
+
+ with open(certfile, "w") as f:
+ f.write(x.get_PEM())
+
+ logger.debug("Cross certified %s:", certfile)
+ logger.debug(" Issuer %s [%s]", x.getIssuer(), x.hAKI())
+ logger.debug(" Subject %s [%s]", x.getSubject(), x.hSKI())
+ return x
last_rcynic_run = None
@@ -1335,6 +1350,7 @@ def run_rcynic():
"""
Run rcynic to see whether what was published makes sense.
"""
+
logger.info("Running rcynic")
env = os.environ.copy()
env["TZ"] = ""
@@ -1350,6 +1366,7 @@ def mangle_sql(filename):
"""
Mangle an SQL file into a sequence of SQL statements.
"""
+
words = []
f = open(filename)
for line in f:
@@ -1432,88 +1449,57 @@ bpki_cert_fmt_6 = ''' && \
-config %(name)s-%(kind)s.conf \
'''
-yaml_fmt_1 = '''---
-version: 1
-posturl: http://localhost:%(http_port)s/up-down/%(parent_name)s/%(my_name)s
-recipient-id: "%(parent_name)s"
-sender-id: "%(my_name)s"
-
-cms-cert-file: %(my_name)s-RPKI.cer
-cms-key-file: %(my_name)s-RPKI.key
-cms-ca-cert-file: %(my_name)s-TA.cer
-cms-crl-file: %(my_name)s-TA.crl
-cms-ca-certs-file:
- - %(my_name)s-TA-%(parent_name)s-SELF.cer
-
-ssl-cert-file: %(my_name)s-RPKI.cer
-ssl-key-file: %(my_name)s-RPKI.key
-ssl-ca-cert-file: %(my_name)s-TA.cer
-ssl-ca-certs-file:
- - %(my_name)s-TA-%(parent_host)s-TA.cer
-
-# We're cheating here by hardwiring the class name
-
-requests:
- list:
- type: list
- issue:
- type: issue
- class: %(class_name)s
- sia:
- - %(sia)s
- cert-request-key-file: %(my_name)s.key
- revoke:
- type: revoke
- class: %(class_name)s
- ski: %(ski)s
-'''
-
conf_fmt_1 = '''\
[irdbd]
-startup-message = This is %(my_name)s irdbd
+startup-message = This is %(my_name)s irdbd
-sql-database = %(irdb_db_name)s
-sql-username = irdb
-sql-password = %(irdb_db_pass)s
-bpki-ta = %(my_name)s-TA.cer
-rpkid-cert = %(my_name)s-RPKI.cer
-irdbd-cert = %(my_name)s-IRDB.cer
-irdbd-key = %(my_name)s-IRDB.key
-http-url = http://localhost:%(irdb_port)d/
-enable_tracebacks = yes
+sql-database = %(irdb_db_name)s
+sql-username = irdb
+sql-password = %(irdb_db_pass)s
+bpki-ta = %(my_name)s-TA.cer
+rpkid-cert = %(my_name)s-RPKI.cer
+irdbd-cert = %(my_name)s-IRDB.cer
+irdbd-key = %(my_name)s-IRDB.key
+http-url = http://localhost:%(irdb_port)d/
+enable_tracebacks = yes
[irbe_cli]
-rpkid-bpki-ta = %(my_name)s-TA.cer
-rpkid-cert = %(my_name)s-RPKI.cer
-rpkid-irbe-cert = %(my_name)s-IRBE.cer
-rpkid-irbe-key = %(my_name)s-IRBE.key
-rpkid-url = http://localhost:%(rpki_port)d/left-right
-enable_tracebacks = yes
+rpkid-bpki-ta = %(my_name)s-TA.cer
+rpkid-cert = %(my_name)s-RPKI.cer
+rpkid-irbe-cert = %(my_name)s-IRBE.cer
+rpkid-irbe-key = %(my_name)s-IRBE.key
+rpkid-url = http://localhost:%(rpki_port)d/left-right
+enable_tracebacks = yes
[rpkid]
-startup-message = This is %(my_name)s rpkid
+startup-message = This is %(my_name)s rpkid
-sql-database = %(rpki_db_name)s
-sql-username = rpki
-sql-password = %(rpki_db_pass)s
+sql-database = %(rpki_db_name)s
+sql-username = rpki
+sql-password = %(rpki_db_pass)s
-bpki-ta = %(my_name)s-TA.cer
-rpkid-key = %(my_name)s-RPKI.key
-rpkid-cert = %(my_name)s-RPKI.cer
-irdb-cert = %(my_name)s-IRDB.cer
-irbe-cert = %(my_name)s-IRBE.cer
+bpki-ta = %(my_name)s-TA.cer
+rpkid-key = %(my_name)s-RPKI.key
+rpkid-cert = %(my_name)s-RPKI.cer
+irdb-cert = %(my_name)s-IRDB.cer
+irbe-cert = %(my_name)s-IRBE.cer
-irdb-url = http://localhost:%(irdb_port)d/
+irdb-url = http://localhost:%(irdb_port)d/
-server-host = localhost
-server-port = %(rpki_port)d
+server-host = localhost
+server-port = %(rpki_port)d
+
+use-internal-cron = false
+enable_tracebacks = yes
-use-internal-cron = false
-enable_tracebacks = yes
+[myrpki]
+start_rpkid = yes
+start_irdbd = yes
+start_pubd = no
'''
rootd_fmt_1 = '''\
@@ -1525,24 +1511,28 @@ rootd-bpki-cert = %(rootd_name)s-RPKI.cer
rootd-bpki-key = %(rootd_name)s-RPKI.key
rootd-bpki-crl = %(rootd_name)s-TA.crl
child-bpki-cert = %(rootd_name)s-TA-%(rpkid_name)s-SELF.cer
+pubd-bpki-cert = %(rootd_name)s-TA-%(pubd_name)s-TA.cer
server-port = %(rootd_port)s
-rpki-root-dir = %(rsyncd_dir)sroot
-rpki-base-uri = %(rootd_sia)sroot/
-rpki-root-cert-uri = %(rootd_sia)sroot.cer
+rpki-class-name = trunk
+
+pubd-contact-uri = http://localhost:%(pubd_port)d/client/%(rootd_handle)s
-rpki-root-key = root.key
-rpki-root-cert = root.cer
+rpki-root-cert-file = root.cer
+rpki-root-cert-uri = %(rootd_sia)sroot.cer
+rpki-root-key-file = root.key
-rpki-subject-pkcs10 = %(rootd_name)s.subject.pkcs10
+rpki-subject-cert-file = trunk.cer
+rpki-subject-cert-uri = %(rootd_sia)sroot/trunk.cer
+rpki-subject-pkcs10-file= trunk.p10
rpki-subject-lifetime = %(lifetime)s
-rpki-root-crl = root.crl
-rpki-root-manifest = root.mft
+rpki-root-crl-file = root.crl
+rpki-root-crl-uri = %(rootd_sia)sroot/root.crl
-rpki-class-name = trunk
-rpki-subject-cert = trunk.cer
+rpki-root-manifest-file = root.mft
+rpki-root-manifest-uri = %(rootd_sia)sroot/root.mft
include-bpki-crl = yes
enable_tracebacks = yes
@@ -1579,7 +1569,7 @@ certificatePolicies = critical, @rpki_certificate_policy
[rpki_certificate_policy]
-policyIdentifier = 1.3.6.1.5.5.7.14.2
+policyIdentifier = 1.3.6.1.5.5.7.14.2
'''
rootd_fmt_2 = '''\
@@ -1602,8 +1592,7 @@ awk '!/-----(BEGIN|END)/' >>%(rootd_name)s.tal &&
-outform DER \
-extfile %(rootd_name)s.conf \
-extensions req_x509_rpki_ext \
- -signkey root.key &&
-ln -f root.cer %(rsyncd_dir)s
+ -signkey root.key
'''
rcynic_fmt_1 = '''\
@@ -1636,6 +1625,7 @@ sql-database = %(pubd_db_name)s
sql-username = %(pubd_db_user)s
sql-password = %(pubd_db_pass)s
bpki-ta = %(pubd_name)s-TA.cer
+pubd-crl = %(pubd_name)s-TA.crl
pubd-cert = %(pubd_name)s-PUBD.cer
pubd-key = %(pubd_name)s-PUBD.key
irbe-cert = %(pubd_name)s-IRBE.cer
@@ -1643,6 +1633,17 @@ server-host = localhost
server-port = %(pubd_port)d
publication-base = %(pubd_dir)s
enable_tracebacks = yes
+
+[irdbd]
+
+sql-database = %(irdb_db_name)s
+sql-username = irdb
+sql-password = %(irdb_db_pass)s
+
+[myrpki]
+start_rpkid = no
+start_irdbd = no
+start_pubd = yes
'''
main()
diff --git a/ca/tests/sql-cleaner.py b/ca/tests/sql-cleaner.py
index ca88d456..369a68ea 100644
--- a/ca/tests/sql-cleaner.py
+++ b/ca/tests/sql-cleaner.py
@@ -22,18 +22,21 @@ import rpki.config
import rpki.sql_schemas
from rpki.mysql_import import MySQLdb
-cfg = rpki.config.parser(None, "yamltest", allow_missing = True)
+cfg = rpki.config.parser(section = "yamltest", allow_missing = True)
for name in ("rpkid", "irdbd", "pubd"):
username = cfg.get("%s_sql_username" % name, name[:4])
password = cfg.get("%s_sql_password" % name, "fnord")
+ # All of this schema creation stuff will go away once we're on Django ORM.
+ # For the moment, a quick kludge for testing.
schema = []
- for line in getattr(rpki.sql_schemas, name, "").splitlines():
- schema.extend(line.partition("--")[0].split())
- schema = " ".join(schema).strip(";").split(";")
- schema = [statement.strip() for statement in schema if statement and "DROP TABLE" not in statement]
+ if name == "rpkid":
+ for line in getattr(rpki.sql_schemas, name, "").splitlines():
+ schema.extend(line.partition("--")[0].split())
+ schema = " ".join(schema).strip(";").split(";")
+ schema = [statement.strip() for statement in schema if statement and "DROP TABLE" not in statement]
db = MySQLdb.connect(user = username, passwd = password)
cur = db.cursor()
diff --git a/ca/tests/sql-dumper.py b/ca/tests/sql-dumper.py
index 19cc1b34..d0fe3489 100644
--- a/ca/tests/sql-dumper.py
+++ b/ca/tests/sql-dumper.py
@@ -22,7 +22,7 @@ import subprocess
import rpki.config
from rpki.mysql_import import MySQLdb
-cfg = rpki.config.parser(None, "yamltest", allow_missing = True)
+cfg = rpki.config.parser(section = "yamltest", allow_missing = True)
for name in ("rpkid", "irdbd", "pubd"):
diff --git a/ca/tests/test-rrdp.py b/ca/tests/test-rrdp.py
new file mode 100755
index 00000000..db626a35
--- /dev/null
+++ b/ca/tests/test-rrdp.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+# $Id$
+#
+# Copyright (C) 2013 Dragon Research Labs ("DRL")
+#
+# 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 DRL DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL DRL 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.
+
+"""
+Proof-of-concept test driver for RRDP code. Still fairly kludgy in places.
+"""
+
+import os
+import sys
+import glob
+import time
+import signal
+import textwrap
+import argparse
+import subprocess
+
+parser = argparse.ArgumentParser(description = __doc__)
+parser.add_argument("--use-smoketest", action = "store_true")
+parser.add_argument("--yaml-file", default = "smoketest.2.yaml")
+parser.add_argument("--delay", type = int, default = 30)
+parser.add_argument("--exhaustive", action = "store_true")
+parser.add_argument("--skip-daemons", action = "store_true")
+args = parser.parse_args()
+
+def log(msg):
+ sys.stdout.write(msg + "\n")
+ sys.stdout.flush()
+
+def run(*argv):
+ log("Running: " + " ".join(argv))
+ subprocess.check_call(argv)
+
+def dataglob(pattern):
+ return glob.iglob(os.path.join(("smoketest.dir" if args.use_smoketest else "yamltest.dir/RIR"), pattern))
+
+def snapshot_to_serial(fn):
+ return int(os.path.splitext(os.path.basename(fn))[0])
+
+def delta_to_serial(fn):
+ return int(os.path.splitext(os.path.basename(fn))[0].split("-")[1])
+
+top = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "..", ".."))
+
+rrdp_test_tool = os.path.join(top, "potpourri/rrdp-test-tool")
+rcynic = os.path.join(top, "rp/rcynic/rcynic")
+rcynic_text = os.path.join(top, "rp/rcynic/rcynic-text")
+
+with open("rcynic-rrdp.conf", "w") as f:
+ f.write(textwrap.dedent('''# Automatically generated for RRDP tests, do not edit.
+ [rcynic]
+ xml-summary = rcynic.xml
+ jitter = 0
+ use-links = yes
+ use-syslog = no
+ use-stderr = yes
+ log-level = log_debug
+ run-rsync = no
+ '''))
+ if args.use_smoketest:
+ f.write("trust-anchor = smoketest.dir/root.cer\n")
+ else:
+ f.write("trust-anchor = yamltest.dir/RIR/publication/RIR-root/root.cer\n")
+
+if args.skip_daemons:
+ log("--skip-daemons specified, so running neither smoketest nor yamltest")
+elif args.use_smoketest:
+ run("python", "smoketest.py", args.yaml_file)
+else:
+ run("python", "sql-cleaner.py")
+ class GotSIGUSR1(Exception):
+ pass
+ def handle_sigusr1(signum, frame):
+ raise GotSIGUSR1
+ old_sigusr1 = signal.signal(signal.SIGUSR1, handle_sigusr1)
+ argv = ("python", "yamltest.py", args.yaml_file, "--notify-when-startup-complete", str(os.getpid()))
+ log("Running: " + " ".join(argv))
+ yamltest = subprocess.Popen(argv)
+ log("Waiting for SIGUSR1 from yamltest")
+ try:
+ while True:
+ signal.pause()
+ except GotSIGUSR1:
+ signal.signal(signal.SIGUSR1, old_sigusr1)
+ log("Sleeping %s" % args.delay)
+ time.sleep(args.delay)
+ yamltest.terminate()
+
+snapshots = dict((snapshot_to_serial(fn), fn) for fn in dataglob("rrdp-publication/*/snapshot/*.xml"))
+deltas = dict((delta_to_serial(fn), fn) for fn in dataglob("rrdp-publication/*/deltas/*.xml"))
+
+for snapshot in sorted(snapshots):
+
+ time.sleep(1)
+ run("rm", "-rf", "rcynic-data")
+ run(rrdp_test_tool, snapshots[snapshot])
+ run(rcynic, "-c", "rcynic-rrdp.conf")
+ run(rcynic_text, "rcynic.xml")
+
+ for delta in sorted(deltas):
+ if delta > snapshot:
+ time.sleep(1)
+ run(rrdp_test_tool, deltas[delta])
+ run(rcynic, "-c", "rcynic-rrdp.conf")
+ run(rcynic_text, "rcynic.xml")
+
+ if not args.exhaustive:
+ break
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/ca/tests/yamlconf.py b/ca/tests/yamlconf.py
index 1b339a89..bb82ef74 100644
--- a/ca/tests/yamlconf.py
+++ b/ca/tests/yamlconf.py
@@ -125,7 +125,7 @@ class router_cert(object):
def __init__(self, asn, router_id):
self.asn = rpki.resource_set.resource_set_as("".join(str(asn).split()))
self.router_id = router_id
- self.keypair = rpki.x509.ECDSA.generate(self.ecparams())
+ self.keypair = rpki.x509.ECDSA.generate(params = self.ecparams(), quiet = True)
self.pkcs10 = rpki.x509.PKCS10.create(keypair = self.keypair)
self.gski = self.pkcs10.gSKI()
@@ -491,16 +491,18 @@ class allocation(object):
def syncdb(self):
import django.core.management
assert not self.is_hosted
- django.core.management.call_command("syncdb",
- database = self.irdb_name,
- load_initial_data = False,
- interactive = False,
- verbosity = 0)
+ django.core.management.call_command(
+ "syncdb",
+ verbosity = 0,
+ database = self.irdb_name,
+ migrate = True,
+ load_initial_data = False,
+ interactive = False)
def hire_zookeeper(self):
assert not self.is_hosted
self._zoo = rpki.irdb.Zookeeper(
- cfg = rpki.config.parser(self.path("rpki.conf")),
+ cfg = rpki.config.parser(filename = self.path("rpki.conf")),
logstream = None if quiet else sys.stdout)
@property
@@ -530,15 +532,15 @@ class allocation(object):
notAfter = rpki.sundial.now() + rpki.sundial.timedelta(days = 365),
resources = root_resources)
- with open(self.path("publication.root", "root.cer"), "wb") as f:
+ with open(self.path("root.cer"), "wb") as f:
f.write(root_cert.get_DER())
with open(self.path("root.key"), "wb") as f:
f.write(root_key.get_DER())
with open(cleanpath(test_dir, "root.tal"), "w") as f:
- f.write("rsync://%s/root/root.cer\n\n%s" % (
- self.rsync_server, root_key.get_public().get_Base64()))
+ f.write("rsync://%s/root/root.cer\n\n" % self.rsync_server)
+ f.write(root_key.get_public().get_Base64())
def mkdir(self, *path):
path = self.path(*path)
@@ -681,7 +683,7 @@ def main():
# passwords: this is mostly so that I can show a complete working
# example without publishing my own server's passwords.
- cfg = rpki.config.parser(args.config, "yamlconf", allow_missing = True)
+ cfg = rpki.config.parser(set_filename = args.config, section = "yamlconf", allow_missing = True)
try:
cfg.set_global_flags()
except:
@@ -755,9 +757,13 @@ def body():
pre_django_sql_setup(set(d.irdb_name for d in db if not d.is_hosted))
# Now ready for fun with multiple databases in Django!
-
+ #
# https://docs.djangoproject.com/en/1.4/topics/db/multi-db/
# https://docs.djangoproject.com/en/1.4/topics/db/sql/
+ #
+ # This program's use of the ORM is sufficiently different that it's
+ # not worth straining to use rpki.django_settings, so we just use
+ # Django's settings API directly.
database_template = {
"ENGINE" : "django.db.backends.mysql",
@@ -767,8 +773,7 @@ def body():
"PORT" : "",
"OPTIONS" : { "init_command": "SET storage_engine=INNODB" }}
- databases = dict((d.irdb_name,
- dict(database_template, NAME = d.irdb_name))
+ databases = dict((d.irdb_name, dict(database_template, NAME = d.irdb_name))
for d in db if not d.is_hosted)
databases["default"] = databases[db.root.irdb_name]
@@ -778,7 +783,7 @@ def body():
settings.configure(
DATABASES = databases,
DATABASE_ROUTERS = ["rpki.irdb.router.DBContextRouter"],
- INSTALLED_APPS = ("rpki.irdb",))
+ INSTALLED_APPS = ("rpki.irdb", "south"))
import rpki.irdb
diff --git a/ca/tests/yamltest.py b/ca/tests/yamltest.py
index 2b65dbd2..6ef63382 100644
--- a/ca/tests/yamltest.py
+++ b/ca/tests/yamltest.py
@@ -43,6 +43,7 @@ import re
import os
import logging
import argparse
+import webbrowser
import sys
import yaml
import signal
@@ -67,19 +68,21 @@ def cleanpath(*names):
"""
Construct normalized pathnames.
"""
+
return os.path.normpath(os.path.join(*names))
# Pathnames for various things we need
this_dir = os.getcwd()
test_dir = cleanpath(this_dir, "yamltest.dir")
-rpkid_dir = cleanpath(this_dir, "..")
+ca_dir = cleanpath(this_dir, "..")
-prog_rpkic = cleanpath(rpkid_dir, "rpkic")
-prog_rpkid = cleanpath(rpkid_dir, "rpkid")
-prog_irdbd = cleanpath(rpkid_dir, "irdbd")
-prog_pubd = cleanpath(rpkid_dir, "pubd")
-prog_rootd = cleanpath(rpkid_dir, "rootd")
+prog_rpkic = cleanpath(ca_dir, "rpkic")
+prog_rpkid = cleanpath(ca_dir, "rpkid")
+prog_irdbd = cleanpath(ca_dir, "irdbd")
+prog_pubd = cleanpath(ca_dir, "pubd")
+prog_rootd = cleanpath(ca_dir, "rootd")
+prog_rpki_manage = cleanpath(ca_dir, "rpki-manage")
class roa_request(object):
"""
@@ -110,6 +113,7 @@ class roa_request(object):
"""
Parse a ROA request from YAML format.
"""
+
return cls(y.get("asn"), y.get("ipv4"), y.get("ipv6"))
@@ -129,7 +133,7 @@ class router_cert(object):
def __init__(self, asn, router_id):
self.asn = rpki.resource_set.resource_set_as("".join(str(asn).split()))
self.router_id = router_id
- self.keypair = rpki.x509.ECDSA.generate(self.ecparams())
+ self.keypair = rpki.x509.ECDSA.generate(params = self.ecparams(), quiet = True)
self.pkcs10 = rpki.x509.PKCS10.create(keypair = self.keypair)
self.gski = self.pkcs10.gSKI()
@@ -154,7 +158,7 @@ class allocation_db(list):
def __init__(self, yaml):
list.__init__(self)
self.root = allocation(yaml, self)
- assert self.root.is_root
+ assert self.root.is_root and not any(a.is_root for a in self if a is not self.root) and self[0] is self.root
if self.root.crl_interval is None:
self.root.crl_interval = 60 * 60
if self.root.regen_margin is None:
@@ -180,6 +184,7 @@ class allocation_db(list):
"""
Show contents of allocation database.
"""
+
for a in self:
a.dump()
@@ -210,6 +215,7 @@ class allocation(object):
"""
Allocate a TCP port.
"""
+
cls.base_port += 1
return cls.base_port
@@ -221,6 +227,7 @@ class allocation(object):
Allocate an engine number, mostly used to construct MySQL database
names.
"""
+
cls.base_engine += 1
return cls.base_engine
@@ -275,6 +282,7 @@ class allocation(object):
Compute resource closure of this node and its children, to avoid a
lot of tedious (and error-prone) duplication in the YAML file.
"""
+
resources = self.base
for kid in self.kids:
resources |= kid.closure()
@@ -285,6 +293,7 @@ class allocation(object):
"""
Show content of this allocation node.
"""
+
print str(self)
def __str__(self):
@@ -309,6 +318,7 @@ class allocation(object):
"""
Is this the root node?
"""
+
return self.parent is None
@property
@@ -316,6 +326,7 @@ class allocation(object):
"""
Is this entity hosted?
"""
+
return self.hosted_by is not None
@property
@@ -323,18 +334,21 @@ class allocation(object):
"""
Does this entity run a pubd?
"""
+
return self.is_root or not (self.is_hosted or only_one_pubd)
def path(self, *names):
"""
Construct pathnames in this entity's test directory.
"""
+
return cleanpath(test_dir, self.host.name, *names)
def csvout(self, fn):
"""
Open and log a CSV output file.
"""
+
path = self.path(fn)
print "Writing", path
return rpki.csv_utils.csv_writer(path)
@@ -343,6 +357,7 @@ class allocation(object):
"""
Construct service URL for this node's parent.
"""
+
return "http://localhost:%d/up-down/%s/%s" % (self.parent.host.rpkid_port,
self.parent.name,
self.name)
@@ -351,12 +366,12 @@ class allocation(object):
"""
Write Autonomous System Numbers CSV file.
"""
+
fn = "%s.asns.csv" % d.name
if not args.skip_config:
- f = self.csvout(fn)
- for k in self.kids:
- f.writerows((k.name, a) for a in k.resources.asn)
- f.close()
+ with self.csvout(fn) as f:
+ for k in self.kids:
+ f.writerows((k.name, a) for a in k.resources.asn)
if not args.stop_after_config:
self.run_rpkic("load_asns", fn)
@@ -364,12 +379,12 @@ class allocation(object):
"""
Write prefixes CSV file.
"""
+
fn = "%s.prefixes.csv" % d.name
if not args.skip_config:
- f = self.csvout(fn)
- for k in self.kids:
- f.writerows((k.name, p) for p in (k.resources.v4 + k.resources.v6))
- f.close()
+ with self.csvout(fn) as f:
+ for k in self.kids:
+ f.writerows((k.name, p) for p in (k.resources.v4 + k.resources.v6))
if not args.stop_after_config:
self.run_rpkic("load_prefixes", fn)
@@ -377,13 +392,13 @@ class allocation(object):
"""
Write ROA CSV file.
"""
+
fn = "%s.roas.csv" % d.name
if not args.skip_config:
- f = self.csvout(fn)
- for g1, r in enumerate(self.roa_requests):
- f.writerows((p, r.asn, "G%08d%08d" % (g1, g2))
- for g2, p in enumerate((r.v4 + r.v6 if r.v4 and r.v6 else r.v4 or r.v6 or ())))
- f.close()
+ with self.csvout(fn) as f:
+ for g1, r in enumerate(self.roa_requests):
+ f.writerows((p, r.asn, "G%08d%08d" % (g1, g2))
+ for g2, p in enumerate((r.v4 + r.v6 if r.v4 and r.v6 else r.v4 or r.v6 or ())))
if not args.stop_after_config:
self.run_rpkic("load_roa_requests", fn)
@@ -391,17 +406,14 @@ class allocation(object):
"""
Write Ghostbusters vCard file.
"""
+
if self.ghostbusters:
fn = "%s.ghostbusters.vcard" % d.name
if not args.skip_config:
path = self.path(fn)
print "Writing", path
- f = open(path, "w")
- for i, g in enumerate(self.ghostbusters):
- if i:
- f.write("\n")
- f.write(g)
- f.close()
+ with open(path, "w") as f:
+ f.write("\n".join(self.ghostbusters))
if not args.stop_after_config:
self.run_rpkic("load_ghostbuster_requests", fn)
@@ -409,6 +421,7 @@ class allocation(object):
"""
Write EE certificates (router certificates, etc).
"""
+
if self.router_certs:
fn = "%s.routercerts.xml" % d.name
if not args.skip_config:
@@ -434,6 +447,7 @@ class allocation(object):
"""
Walk up tree until we find somebody who runs pubd.
"""
+
s = self
while not s.runs_pubd:
s = s.parent
@@ -444,6 +458,7 @@ class allocation(object):
"""
Work out what pubd configure_publication_client will call us.
"""
+
path = []
s = self
if not args.flat_publication:
@@ -463,46 +478,45 @@ class allocation(object):
"""
r = dict(
- handle = self.name,
- run_rpkid = str(not self.is_hosted),
- run_pubd = str(self.runs_pubd),
- run_rootd = str(self.is_root),
- irdbd_sql_database = "irdb%d" % self.engine,
- irdbd_sql_username = "irdb",
- rpkid_sql_database = "rpki%d" % self.engine,
- rpkid_sql_username = "rpki",
- rpkid_server_host = "localhost",
- rpkid_server_port = str(self.rpkid_port),
- irdbd_server_host = "localhost",
- irdbd_server_port = str(self.irdbd_port),
- rootd_server_port = str(self.rootd_port),
- pubd_sql_database = "pubd%d" % self.engine,
- pubd_sql_username = "pubd",
- pubd_server_host = "localhost",
- pubd_server_port = str(self.pubd.pubd_port),
- publication_rsync_server = "localhost:%s" % self.pubd.rsync_port,
- bpki_servers_directory = self.path(),
- publication_base_directory = self.path("publication"),
- shared_sql_password = "fnord")
+ handle = self.name,
+ run_rpkid = str(not self.is_hosted),
+ run_pubd = str(self.runs_pubd),
+ run_rootd = str(self.is_root),
+ irdbd_sql_database = "irdb%d" % self.engine,
+ irdbd_sql_username = "irdb",
+ rpkid_sql_database = "rpki%d" % self.engine,
+ rpkid_sql_username = "rpki",
+ rpkid_server_host = "localhost",
+ rpkid_server_port = str(self.rpkid_port),
+ irdbd_server_host = "localhost",
+ irdbd_server_port = str(self.irdbd_port),
+ rootd_server_port = str(self.rootd_port),
+ pubd_sql_database = "pubd%d" % self.engine,
+ pubd_sql_username = "pubd",
+ pubd_server_host = "localhost",
+ pubd_server_port = str(self.pubd.pubd_port),
+ publication_rsync_server = "localhost:%s" % self.pubd.rsync_port,
+ bpki_servers_directory = self.path(),
+ publication_base_directory = self.path("publication"),
+ rrdp_publication_base_directory = self.path("rrdp-publication"),
+ shared_sql_password = "fnord")
r.update(config_overrides)
- f = open(self.path("rpki.conf"), "w")
- f.write("# Automatically generated, do not edit\n")
- print "Writing", f.name
-
- section = None
- for line in open(cleanpath(rpkid_dir, "examples/rpki.conf")):
- m = section_regexp.match(line)
- if m:
- section = m.group(1)
- m = variable_regexp.match(line)
- option = m.group(1) if m and section == "myrpki" else None
- if option and option in r:
- line = "%s = %s\n" % (option, r[option])
- f.write(line)
+ with open(self.path("rpki.conf"), "w") as f:
+ f.write("# Automatically generated, do not edit\n")
+ print "Writing", f.name
- f.close()
+ section = None
+ for line in open(cleanpath(ca_dir, "examples/rpki.conf")):
+ m = section_regexp.match(line)
+ if m:
+ section = m.group(1)
+ m = variable_regexp.match(line)
+ option = m.group(1) if m and section == "myrpki" else None
+ if option and option in r:
+ line = "%s = %s\n" % (option, r[option])
+ f.write(line)
def dump_rsyncd(self):
"""
@@ -510,25 +524,24 @@ class allocation(object):
"""
if self.runs_pubd:
- f = open(self.path("rsyncd.conf"), "w")
- print "Writing", f.name
- f.writelines(s + "\n" for s in
- ("# Automatically generated, do not edit",
- "port = %d" % self.rsync_port,
- "address = localhost",
- "[rpki]",
- "log file = rsyncd.log",
- "read only = yes",
- "use chroot = no",
- "path = %s" % self.path("publication"),
- "comment = RPKI test",
- "[root]",
- "log file = rsyncd_root.log",
- "read only = yes",
- "use chroot = no",
- "path = %s" % self.path("publication.root"),
- "comment = RPKI test root"))
- f.close()
+ with open(self.path("rsyncd.conf"), "w") as f:
+ print "Writing", f.name
+ f.writelines(s + "\n" for s in
+ ("# Automatically generated, do not edit",
+ "port = %d" % self.rsync_port,
+ "address = localhost",
+ "[rpki]",
+ "log file = rsyncd.log",
+ "read only = yes",
+ "use chroot = no",
+ "path = %s" % self.path("publication"),
+ "comment = RPKI test",
+ "[root]",
+ "log file = rsyncd_root.log",
+ "read only = yes",
+ "use chroot = no",
+ "path = %s" % self.path("publication.root"),
+ "comment = RPKI test root"))
@classmethod
def next_rpkic_counter(cls):
@@ -539,65 +552,116 @@ class allocation(object):
"""
Run rpkic for this entity.
"""
- cmd = [prog_rpkic, "-i", self.name, "-c", self.path("rpki.conf")]
+
+ cmd = [prog_rpkic, "-i", self.name]
if args.profile:
cmd.append("--profile")
cmd.append(self.path("rpkic.%s.prof" % rpki.sundial.now()))
cmd.extend(str(a) for a in argv if a is not None)
print 'Running "%s"' % " ".join(cmd)
- env = os.environ.copy()
- env["YAMLTEST_RPKIC_COUNTER"] = self.next_rpkic_counter()
+ env = dict(os.environ,
+ YAMLTEST_RPKIC_COUNTER = self.next_rpkic_counter(),
+ RPKI_CONF = self.path("rpki.conf"))
subprocess.check_call(cmd, cwd = self.host.path(), env = env)
+ def syncdb(self):
+ """
+ Run whatever Django ORM commands are necessary to set up the
+ database this week.
+ """
+
+ verbosity = 1
+
+ if verbosity > 0:
+ print "Running Django setup for", self.name
+
+ if not os.fork():
+ os.environ.update(RPKI_CONF = self.path("rpki.conf"),
+ RPKI_GUI_ENABLE = "yes")
+ logging.getLogger().setLevel(logging.WARNING)
+ import django.core.management
+ django.core.management.call_command("syncdb", migrate = True, verbosity = verbosity,
+ load_initial_data = False, interactive = False)
+ from django.contrib.auth.models import User
+ User.objects.create_superuser("root", "root@example.org", "fnord")
+ sys.exit(0)
+
+ if os.wait()[1]:
+ raise RuntimeError("Django setup failed for %s" % self.name)
+
def run_python_daemon(self, prog):
"""
Start a Python daemon and return a subprocess.Popen object
representing the running daemon.
"""
+
basename = os.path.splitext(os.path.basename(prog))[0]
cmd = [prog, "--foreground", "--log-level", "debug",
- "--log-file", self.path(basename + ".log"),
- "--config", self.path("rpki.conf")]
+ "--log-file", self.path(basename + ".log")]
if args.profile and basename != "rootd":
cmd.extend((
"--profile", self.path(basename + ".prof")))
- p = subprocess.Popen(cmd, cwd = self.path())
- print 'Running %s for %s: pid %d process %r' % (" ".join(cmd), self.name, p.pid, p)
+ env = dict(os.environ, RPKI_CONF = self.path("rpki.conf"))
+ p = subprocess.Popen(cmd, cwd = self.path(), env = env)
+ print "Running %s for %s: pid %d process %r" % (" ".join(cmd), self.name, p.pid, p)
return p
def run_rpkid(self):
"""
Run rpkid.
"""
+
return self.run_python_daemon(prog_rpkid)
def run_irdbd(self):
"""
Run irdbd.
"""
+
return self.run_python_daemon(prog_irdbd)
def run_pubd(self):
"""
Run pubd.
"""
+
return self.run_python_daemon(prog_pubd)
def run_rootd(self):
"""
Run rootd.
"""
+
return self.run_python_daemon(prog_rootd)
def run_rsyncd(self):
"""
Run rsyncd.
"""
+
p = subprocess.Popen(("rsync", "--daemon", "--no-detach", "--config", "rsyncd.conf"),
cwd = self.path())
print "Running rsyncd for %s: pid %d process %r" % (self.name, p.pid, p)
return p
+ def run_gui(self):
+ """
+ Start an instance of the RPKI GUI under the Django test server and
+ return a subprocess.Popen object representing the running daemon.
+ """
+
+ port = 8000 + self.engine
+ cmd = (prog_rpki_manage, "runserver", str(port))
+ env = dict(os.environ,
+ RPKI_CONF = self.path("rpki.conf"),
+ RPKI_DJANGO_DEBUG = "yes",
+ ALLOW_PLAIN_HTTP_FOR_TESTING = "I solemnly swear that I am not running this in production")
+ p = subprocess.Popen(cmd, cwd = self.path(), env = env,
+ stdout = open(self.path("gui.log"), "w"), stderr = subprocess.STDOUT)
+ print "Running %s for %s: pid %d process %r" % (" ".join(cmd), self.name, p.pid, p)
+ return p
+
+
def create_root_certificate(db_root):
print "Creating rootd RPKI root certificate"
@@ -609,9 +673,9 @@ def create_root_certificate(db_root):
root_key = rpki.x509.RSA.generate(quiet = True)
- root_uri = "rsync://localhost:%d/rpki/" % db_root.pubd.rsync_port
+ root_uri = "rsync://localhost:%d/rpki/%s-root/root" % (db_root.pubd.rsync_port, db_root.name)
- root_sia = (root_uri, root_uri + "root.mft", None)
+ root_sia = (root_uri + "/", root_uri + "/root.mft", None)
root_cert = rpki.x509.X509.self_certify(
keypair = root_key,
@@ -621,22 +685,21 @@ def create_root_certificate(db_root):
notAfter = rpki.sundial.now() + rpki.sundial.timedelta(days = 365),
resources = root_resources)
- f = open(db_root.path("publication.root/root.cer"), "wb")
- f.write(root_cert.get_DER())
- f.close()
+ with open(db_root.path("root.cer"), "wb") as f:
+ f.write(root_cert.get_DER())
- f = open(db_root.path("root.key"), "wb")
- f.write(root_key.get_DER())
- f.close()
+ with open(db_root.path("root.key"), "wb") as f:
+ f.write(root_key.get_DER())
- f = open(os.path.join(test_dir, "root.tal"), "w")
- f.write("rsync://localhost:%d/root/root.cer\n\n" % db_root.pubd.rsync_port)
- f.write(root_key.get_public().get_Base64())
- f.close()
+ with open(os.path.join(test_dir, "root.tal"), "w") as f:
+ f.write(root_uri + ".cer\n\n")
+ f.write(root_key.get_public().get_Base64())
+logger = logging.getLogger(__name__)
-os.environ["TZ"] = "UTC"
+os.environ.update(DJANGO_SETTINGS_MODULE = "rpki.django_settings",
+ TZ = "UTC")
time.tzset()
parser = argparse.ArgumentParser(description = __doc__)
@@ -656,6 +719,12 @@ parser.add_argument("--synchronize", action = "store_true",
help = "synchronize IRDB with daemons")
parser.add_argument("--profile", action = "store_true",
help = "enable profiling")
+parser.add_argument("-g", "--run_gui", action = "store_true",
+ help = "enable GUI using django-admin runserver")
+parser.add_argument("--browser", action = "store_true",
+ help = "create web browser tabs for GUI")
+parser.add_argument("--notify-when-startup-complete", type = int,
+ help = "send SIGUSR1 to this process when startup is complete")
parser.add_argument("yaml_file", type = argparse.FileType("r"),
help = "YAML description of test network")
args = parser.parse_args()
@@ -672,7 +741,7 @@ try:
# passwords: this is mostly so that I can show a complete working
# example without publishing my own server's passwords.
- cfg = rpki.config.parser(args.config, "yamltest", allow_missing = True)
+ cfg = rpki.config.parser(set_filename = args.config, section = "yamltest", allow_missing = True)
only_one_pubd = cfg.getboolean("only_one_pubd", True)
allocation.base_port = cfg.getint("base_port", 4400)
@@ -713,6 +782,7 @@ try:
for d in db:
if not d.is_hosted:
+ print "Initializing", d.name
os.makedirs(d.path())
d.dump_conf()
if d.runs_pubd:
@@ -720,7 +790,9 @@ try:
d.dump_rsyncd()
if d.is_root:
os.makedirs(d.path("publication.root"))
+ d.syncdb()
d.run_rpkic("initialize_server_bpki")
+ print
# Initialize resource holding BPKI and generate self-descriptor
# for each entity.
@@ -758,6 +830,8 @@ try:
if d.runs_pubd:
progs.append(d.run_pubd())
progs.append(d.run_rsyncd())
+ if args.run_gui:
+ progs.append(d.run_gui())
if args.synchronize or not args.skip_config:
@@ -826,9 +900,27 @@ try:
d.dump_ghostbusters()
d.dump_router_certificates()
+ if args.run_gui:
+ print
+ print 'GUI user "root", password "fnord"'
+ for d in db:
+ if not d.is_hosted:
+ url = "http://127.0.0.1:%d/rpki/" % (8000 + d.engine)
+ print "GUI URL", url, "for", d.name
+ if args.browser:
+ if d is db.root:
+ webbrowser.open_new(url)
+ else:
+ webbrowser.open_new_tab(url)
+ time.sleep(2)
+
# Wait until something terminates.
if not args.stop_after_config or args.keep_going:
+ if args.notify_when_startup_complete:
+ print
+ print "Sending SIGUSR1 to process", args.notify_when_startup_complete
+ os.kill(args.notify_when_startup_complete, signal.SIGUSR1)
print
print "Waiting for daemons to exit"
signal.signal(signal.SIGCHLD, lambda *dont_care: None)